@xano/xanoscript-monaco-editor 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +181 -0
  2. package/dist/.vite/manifest.json +300 -0
  3. package/dist/assets/_.contribution-BThlLkzn.js +1 -0
  4. package/dist/assets/_commonjsHelpers-CqkleIqs.js +1 -0
  5. package/dist/assets/codicon-MLkmQ__h.ttf +0 -0
  6. package/dist/assets/dark_modern-0rclP-7t.json +1 -0
  7. package/dist/assets/dark_vs-BL-mUvcK.json +1 -0
  8. package/dist/assets/editor-BivTGeL1.js +1 -0
  9. package/dist/assets/editor.worker-BF3gnKDz.js +28 -0
  10. package/dist/assets/extensionHost.worker-bYZXB0kM.js +144 -0
  11. package/dist/assets/fake-DXkbmQ09.html +10 -0
  12. package/dist/assets/files.contribution._fileEditorFactory-vS4ZLYi1.js +4 -0
  13. package/dist/assets/hc_black-BX9MT4w9.json +1 -0
  14. package/dist/assets/hc_light-Bzw0ew6e.json +1 -0
  15. package/dist/assets/iconv-lite-umd-DQaTktu2.js +11 -0
  16. package/dist/assets/iconv-lite-umd-DYWd8cEa.js +11 -0
  17. package/dist/assets/index-51WpeTZl.js +11 -0
  18. package/dist/assets/index-B0wc3Rza.css +1 -0
  19. package/dist/assets/index-B132pG6E.js +11 -0
  20. package/dist/assets/index-BGwiFEyd.js +1 -0
  21. package/dist/assets/index-BPOe4Pu5.css +1 -0
  22. package/dist/assets/index-BwfWF2CI.js +1433 -0
  23. package/dist/assets/index-C25FTAfE.js +15 -0
  24. package/dist/assets/index-C3pnKX8a.js +1 -0
  25. package/dist/assets/index-CEhqlLL9.css +1 -0
  26. package/dist/assets/index-Cg3XqiaZ.html +1284 -0
  27. package/dist/assets/index-CrbRjSB_.js +1 -0
  28. package/dist/assets/index-D1zNXs16.css +1 -0
  29. package/dist/assets/index-DgK2LcnW.js +2 -0
  30. package/dist/assets/index-VRHnXpb2.js +18 -0
  31. package/dist/assets/index-no-csp-DMfG5HRS.html +1251 -0
  32. package/dist/assets/index-yPQeQvu7.js +1 -0
  33. package/dist/assets/layout.contribution.darwin-gdaUfoJf.js +1 -0
  34. package/dist/assets/layout.contribution.linux-xMjRz7iy.js +1 -0
  35. package/dist/assets/layout.contribution.win-DZRWibbm.js +1 -0
  36. package/dist/assets/light_modern-Bbk8M7yq.json +1 -0
  37. package/dist/assets/light_vs-DwwM7VRG.json +1 -0
  38. package/dist/assets/main-D6ceXGB_.js +4 -0
  39. package/dist/assets/main-DNugpDp4.js +4 -0
  40. package/dist/assets/main-FP17jmvp.js +1 -0
  41. package/dist/assets/main-b5eBH2vx.js +1 -0
  42. package/dist/assets/onig-Du5pRr7Y.wasm +0 -0
  43. package/dist/assets/service-worker-Ce0epi43.js +371 -0
  44. package/dist/assets/tokenClassificationRegistry-DcBtqg2t.js +2 -0
  45. package/dist/assets/views-C4cPu3oQ.css +1 -0
  46. package/dist/assets/views-hUfpm9tT.js +55 -0
  47. package/dist/assets/webWorkerExtensionHostIframe-636UTAtK.html +156 -0
  48. package/dist/assets/workbenchThemeService.service-qBFVnuYD.js +1 -0
  49. package/dist/assets/worker-BIMDXoFp.js +8 -0
  50. package/dist/index.html +14 -0
  51. package/dist/logic-assistant-script.js +21798 -0
  52. package/dist/logic-assistant-script.js.map +7 -0
  53. package/dist/worker.js +32433 -0
  54. package/dist/worker.js.map +7 -0
  55. package/package.json +46 -0
@@ -0,0 +1,1251 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" style="width: 100%; height: 100%;">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+
7
+ <!-- Disable pinch zooming -->
8
+ <meta name="viewport"
9
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
10
+ </head>
11
+
12
+ <body style="margin: 0; overflow: hidden; width: 100%; height: 100%; overscroll-behavior-x: none;" role="document">
13
+ <!-- TODO: Remove additional script tag once Firefox is fixed https://bugzilla.mozilla.org/show_bug.cgi?id=1737882 -->
14
+ <script></script>
15
+ <script async type="module">
16
+ // @ts-check
17
+ /// <reference lib="dom" />
18
+
19
+ const isSafari = (
20
+ navigator.vendor && navigator.vendor.indexOf('Apple') > -1 &&
21
+ navigator.userAgent &&
22
+ navigator.userAgent.indexOf('CriOS') === -1 &&
23
+ navigator.userAgent.indexOf('FxiOS') === -1
24
+ );
25
+
26
+ const isFirefox = (
27
+ navigator.userAgent &&
28
+ navigator.userAgent.indexOf('Firefox') >= 0
29
+ );
30
+
31
+ const searchParams = new URL(location.toString()).searchParams;
32
+ const ID = searchParams.get('id');
33
+ const webviewOrigin = searchParams.get('origin');
34
+ const onElectron = searchParams.get('platform') === 'electron';
35
+ const disableServiceWorker = searchParams.has('disableServiceWorker');
36
+ const expectedWorkerVersion = parseInt(searchParams.get('swVersion'));
37
+ const serviceWorkerUri = searchParams.get('serviceWorkerUri');
38
+ const fakeHtmlUri = searchParams.get('fakeHtmlUri');
39
+
40
+ /**
41
+ * Use polling to track focus of main webview and iframes within the webview
42
+ *
43
+ * @param {Object} handlers
44
+ * @param {() => void} handlers.onFocus
45
+ * @param {() => void} handlers.onBlur
46
+ */
47
+ const trackFocus = ({ onFocus, onBlur }) => {
48
+ const interval = 250;
49
+ let isFocused = document.hasFocus();
50
+ setInterval(() => {
51
+ const target = getActiveFrame();
52
+ const isCurrentlyFocused = document.hasFocus() || !!(target && target.contentDocument && target.contentDocument.body.classList.contains('vscode-context-menu-visible'));
53
+ if (isCurrentlyFocused === isFocused) {
54
+ return;
55
+ }
56
+ isFocused = isCurrentlyFocused;
57
+ if (isCurrentlyFocused) {
58
+ onFocus();
59
+ } else {
60
+ onBlur();
61
+ }
62
+ }, interval);
63
+ };
64
+
65
+ const getActiveFrame = () => {
66
+ return /** @type {HTMLIFrameElement | undefined} */ (document.getElementById('active-frame'));
67
+ };
68
+
69
+ const getPendingFrame = () => {
70
+ return /** @type {HTMLIFrameElement | undefined} */ (document.getElementById('pending-frame'));
71
+ };
72
+
73
+ /**
74
+ * @template T
75
+ * @param {T | undefined | null} obj
76
+ * @return {T}
77
+ */
78
+ function assertIsDefined(obj) {
79
+ if (typeof obj === 'undefined' || obj === null) {
80
+ throw new Error('Found unexpected null');
81
+ }
82
+ return obj;
83
+ }
84
+
85
+ const vscodePostMessageFuncName = '__vscode_post_message__';
86
+
87
+ const defaultStyles = document.createElement('style');
88
+ defaultStyles.id = '_defaultStyles';
89
+ defaultStyles.textContent = `
90
+ html {
91
+ scrollbar-color: var(--vscode-scrollbarSlider-background) var(--vscode-editor-background);
92
+ }
93
+
94
+ body {
95
+ overscroll-behavior-x: none;
96
+ background-color: transparent;
97
+ color: var(--vscode-editor-foreground);
98
+ font-family: var(--vscode-font-family);
99
+ font-weight: var(--vscode-font-weight);
100
+ font-size: var(--vscode-font-size);
101
+ margin: 0;
102
+ padding: 0 20px;
103
+ }
104
+
105
+ img, video {
106
+ max-width: 100%;
107
+ max-height: 100%;
108
+ }
109
+
110
+ a, a code {
111
+ color: var(--vscode-textLink-foreground);
112
+ }
113
+
114
+ a:hover {
115
+ color: var(--vscode-textLink-activeForeground);
116
+ }
117
+
118
+ a:focus,
119
+ input:focus,
120
+ select:focus,
121
+ textarea:focus {
122
+ outline: 1px solid -webkit-focus-ring-color;
123
+ outline-offset: -1px;
124
+ }
125
+
126
+ code {
127
+ font-family: var(--monaco-monospace-font);
128
+ color: var(--vscode-textPreformat-foreground);
129
+ background-color: var(--vscode-textPreformat-background);
130
+ padding: 1px 3px;
131
+ border-radius: 4px;
132
+ }
133
+
134
+ pre code {
135
+ padding: 0;
136
+ }
137
+
138
+ blockquote {
139
+ background: var(--vscode-textBlockQuote-background);
140
+ border-color: var(--vscode-textBlockQuote-border);
141
+ }
142
+
143
+ kbd {
144
+ background-color: var(--vscode-keybindingLabel-background);
145
+ color: var(--vscode-keybindingLabel-foreground);
146
+ border-style: solid;
147
+ border-width: 1px;
148
+ border-radius: 3px;
149
+ border-color: var(--vscode-keybindingLabel-border);
150
+ border-bottom-color: var(--vscode-keybindingLabel-bottomBorder);
151
+ box-shadow: inset 0 -1px 0 var(--vscode-widget-shadow);
152
+ vertical-align: middle;
153
+ padding: 1px 3px;
154
+ }
155
+
156
+ ::-webkit-scrollbar {
157
+ width: 10px;
158
+ height: 10px;
159
+ }
160
+
161
+ ::-webkit-scrollbar-corner {
162
+ background-color: var(--vscode-editor-background);
163
+ }
164
+
165
+ ::-webkit-scrollbar-thumb {
166
+ background-color: var(--vscode-scrollbarSlider-background);
167
+ }
168
+ ::-webkit-scrollbar-thumb:hover {
169
+ background-color: var(--vscode-scrollbarSlider-hoverBackground);
170
+ }
171
+ ::-webkit-scrollbar-thumb:active {
172
+ background-color: var(--vscode-scrollbarSlider-activeBackground);
173
+ }
174
+ ::highlight(find-highlight) {
175
+ background-color: var(--vscode-editor-findMatchHighlightBackground);
176
+ }
177
+ ::highlight(current-find-highlight) {
178
+ background-color: var(--vscode-editor-findMatchBackground);
179
+ }`;
180
+
181
+ /**
182
+ * @param {boolean} allowMultipleAPIAcquire
183
+ * @param {*} [state]
184
+ * @return {string}
185
+ */
186
+ function getVsCodeApiScript(allowMultipleAPIAcquire, state) {
187
+ const encodedState = state ? encodeURIComponent(state) : undefined;
188
+ return /* js */`
189
+ globalThis.acquireVsCodeApi = (function() {
190
+ const originalPostMessage = window.parent['${vscodePostMessageFuncName}'].bind(window.parent);
191
+ const doPostMessage = (channel, data, transfer) => {
192
+ originalPostMessage(channel, data, transfer);
193
+ };
194
+
195
+ let acquired = false;
196
+
197
+ let state = ${state ? `JSON.parse(decodeURIComponent("${encodedState}"))` : undefined};
198
+
199
+ return () => {
200
+ if (acquired && !${allowMultipleAPIAcquire}) {
201
+ throw new Error('An instance of the VS Code API has already been acquired');
202
+ }
203
+ acquired = true;
204
+ return Object.freeze({
205
+ postMessage: function(message, transfer) {
206
+ doPostMessage('onmessage', { message, transfer }, transfer);
207
+ },
208
+ setState: function(newState) {
209
+ state = newState;
210
+ doPostMessage('do-update-state', JSON.stringify(newState));
211
+ return newState;
212
+ },
213
+ getState: function() {
214
+ return state;
215
+ }
216
+ });
217
+ };
218
+ })();
219
+ delete window.parent;
220
+ delete window.top;
221
+ delete window.frameElement;
222
+ `;
223
+ }
224
+
225
+ /** @type {Promise<void>} */
226
+ const workerReady = new Promise((resolve, reject) => {
227
+ if (disableServiceWorker) {
228
+ return resolve();
229
+ }
230
+
231
+ if (!areServiceWorkersEnabled()) {
232
+ return reject(new Error('Service Workers are not enabled. Webviews will not work. Try disabling private/incognito mode.'));
233
+ }
234
+
235
+ const swPath = encodeURI(`${serviceWorkerUri}?v=${expectedWorkerVersion}&vscode-resource-base-authority=${searchParams.get('vscode-resource-base-authority')}&id=${ID}&remoteAuthority=${searchParams.get('remoteAuthority') ?? ''}`);
236
+ navigator.serviceWorker.register(swPath)
237
+ .then(async registration => {
238
+ /**
239
+ * @param {MessageEvent} event
240
+ */
241
+ const versionHandler = async (event) => {
242
+ if (event.data.channel !== 'version') {
243
+ return;
244
+ }
245
+
246
+ navigator.serviceWorker.removeEventListener('message', versionHandler);
247
+ if (event.data.version === expectedWorkerVersion) {
248
+ return resolve();
249
+ } else {
250
+ console.log(`Found unexpected service worker version. Found: ${event.data.version}. Expected: ${expectedWorkerVersion}`);
251
+ console.log(`Attempting to reload service worker`);
252
+
253
+ // If we have the wrong version, try once (and only once) to unregister and re-register
254
+ // Note that `.update` doesn't seem to work desktop electron at the moment so we use
255
+ // `unregister` and `register` here.
256
+ return registration.unregister()
257
+ .then(() => navigator.serviceWorker.register(swPath))
258
+ .finally(() => { resolve(); });
259
+ }
260
+ };
261
+ navigator.serviceWorker.addEventListener('message', versionHandler);
262
+
263
+ const postVersionMessage = (/** @type {ServiceWorker} */ controller) => {
264
+ controller.postMessage({ channel: 'version' });
265
+ };
266
+
267
+ // At this point, either the service worker is ready and
268
+ // became our controller, or we need to wait for it.
269
+ // Note that navigator.serviceWorker.controller could be a
270
+ // controller from a previously loaded service worker.
271
+ const currentController = navigator.serviceWorker.controller;
272
+ if (currentController?.scriptURL.endsWith(swPath)) {
273
+ // service worker already loaded & ready to receive messages
274
+ postVersionMessage(currentController);
275
+ } else {
276
+ if (currentController) {
277
+ console.log(`Found unexpected service worker controller. Found: ${currentController.scriptURL}. Expected: ${swPath}. Waiting for controllerchange.`);
278
+ } else {
279
+ console.log(`No service worker controller found. Waiting for controllerchange.`);
280
+ }
281
+
282
+ // Either there's no controlling service worker, or it's an old one.
283
+ // Wait for it to change before posting the message
284
+ const onControllerChange = () => {
285
+ navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange);
286
+ if (navigator.serviceWorker.controller) {
287
+ postVersionMessage(navigator.serviceWorker.controller);
288
+ } else {
289
+ return reject(new Error('No controller found.'));
290
+ }
291
+ };
292
+ navigator.serviceWorker.addEventListener('controllerchange', onControllerChange);
293
+ }
294
+ }).catch(error => {
295
+ if (!onElectron && error instanceof Error && error.message.includes('user denied permission')) {
296
+ return reject(new Error(`Could not register service worker. Please make sure third party cookies are enabled: ${error}`));
297
+ }
298
+ return reject(new Error(`Could not register service worker: ${error}.`));
299
+ });
300
+ });
301
+
302
+ /**
303
+ * @type {import('../webviewMessages').WebviewHostMessaging}
304
+ */
305
+ const hostMessaging = new class HostMessaging {
306
+
307
+ constructor() {
308
+ this.channel = new MessageChannel();
309
+
310
+ /** @type {Map<string, Array<(event: MessageEvent, data: any) => void>>} */
311
+ this.handlers = new Map();
312
+
313
+ this.channel.port1.onmessage = (e) => {
314
+ const channel = e.data.channel;
315
+ const handlers = this.handlers.get(channel);
316
+ if (handlers) {
317
+ for (const handler of handlers) {
318
+ handler(e, e.data.args);
319
+ }
320
+ } else {
321
+ console.log('no handler for ', e);
322
+ }
323
+ };
324
+ }
325
+
326
+ postMessage(channel, data, transfer) {
327
+ this.channel.port1.postMessage({ channel, data }, transfer);
328
+ }
329
+
330
+ onMessage(channel, handler) {
331
+ let handlers = this.handlers.get(channel);
332
+ if (!handlers) {
333
+ handlers = [];
334
+ this.handlers.set(channel, handlers);
335
+ }
336
+ handlers.push(handler);
337
+ }
338
+
339
+ async signalReady() {
340
+ const start = (/** @type {string} */ parentOrigin) => {
341
+ window.parent.postMessage({ target: ID, channel: 'webview-ready', data: {} }, parentOrigin, [this.channel.port2]);
342
+ };
343
+
344
+ const parentOrigin = searchParams.get('parentOrigin');
345
+
346
+ return start(parentOrigin);
347
+ }
348
+ }();
349
+
350
+ const unloadMonitor = new class {
351
+
352
+ constructor() {
353
+ this.confirmBeforeClose = 'keyboardOnly';
354
+ this.isModifierKeyDown = false;
355
+
356
+ hostMessaging.onMessage('set-confirm-before-close', (_e, data) => {
357
+ this.confirmBeforeClose = data;
358
+ });
359
+
360
+ hostMessaging.onMessage('content', (_e, data) => {
361
+ this.confirmBeforeClose = data.confirmBeforeClose;
362
+ });
363
+
364
+ window.addEventListener('beforeunload', (event) => {
365
+ if (onElectron) {
366
+ return;
367
+ }
368
+
369
+ switch (this.confirmBeforeClose) {
370
+ case 'always': {
371
+ event.preventDefault();
372
+ event.returnValue = '';
373
+ return '';
374
+ }
375
+ case 'never': {
376
+ break;
377
+ }
378
+ case 'keyboardOnly':
379
+ default: {
380
+ if (this.isModifierKeyDown) {
381
+ event.preventDefault();
382
+ event.returnValue = '';
383
+ return '';
384
+ }
385
+ break;
386
+ }
387
+ }
388
+ });
389
+ }
390
+
391
+ onIframeLoaded(/** @type {HTMLIFrameElement} */ frame) {
392
+ assertIsDefined(frame.contentWindow).addEventListener('keydown', e => {
393
+ this.isModifierKeyDown = e.metaKey || e.ctrlKey || e.altKey;
394
+ });
395
+
396
+ assertIsDefined(frame.contentWindow).addEventListener('keyup', () => {
397
+ this.isModifierKeyDown = false;
398
+ });
399
+ }
400
+ };
401
+
402
+ // state
403
+ let firstLoad = true;
404
+ /** @type {any} */
405
+ let loadTimeout;
406
+ let styleVersion = 0;
407
+
408
+ /** @type {Array<{ readonly message: any, transfer?: ArrayBuffer[] }>} */
409
+ let pendingMessages = [];
410
+
411
+ const initData = {
412
+ /** @type {number | undefined} */
413
+ initialScrollProgress: undefined,
414
+
415
+ /** @type {{ [key: string]: string } | undefined} */
416
+ styles: undefined,
417
+
418
+ /** @type {string | undefined} */
419
+ activeTheme: undefined,
420
+
421
+ /** @type {string | undefined} */
422
+ themeId: undefined,
423
+
424
+ /** @type {string | undefined} */
425
+ themeLabel: undefined,
426
+
427
+ /** @type {boolean} */
428
+ screenReader: false,
429
+
430
+ /** @type {boolean} */
431
+ reduceMotion: false,
432
+ };
433
+
434
+ if (!disableServiceWorker) {
435
+ hostMessaging.onMessage('did-load-resource', (_event, data) => {
436
+ assertIsDefined(navigator.serviceWorker.controller).postMessage({ channel: 'did-load-resource', data }, data.data?.buffer ? [data.data.buffer] : []);
437
+ });
438
+
439
+ hostMessaging.onMessage('did-load-localhost', (_event, data) => {
440
+ assertIsDefined(navigator.serviceWorker.controller).postMessage({ channel: 'did-load-localhost', data });
441
+ });
442
+
443
+ navigator.serviceWorker.addEventListener('message', event => {
444
+ switch (event.data.channel) {
445
+ case 'load-resource':
446
+ case 'load-localhost':
447
+ hostMessaging.postMessage(event.data.channel, event.data);
448
+ return;
449
+ }
450
+ });
451
+ }
452
+
453
+ /**
454
+ * @param {HTMLDocument?} document
455
+ * @param {HTMLElement?} body
456
+ */
457
+ const applyStyles = (document, body) => {
458
+ if (!document) {
459
+ return;
460
+ }
461
+
462
+ if (body) {
463
+ body.classList.remove('vscode-light', 'vscode-dark', 'vscode-high-contrast', 'vscode-high-contrast-light', 'vscode-reduce-motion', 'vscode-using-screen-reader');
464
+
465
+ if (initData.activeTheme) {
466
+ body.classList.add(initData.activeTheme);
467
+ if (initData.activeTheme === 'vscode-high-contrast-light') {
468
+ // backwards compatibility
469
+ body.classList.add('vscode-high-contrast');
470
+ }
471
+ }
472
+
473
+ if (initData.reduceMotion) {
474
+ body.classList.add('vscode-reduce-motion');
475
+ }
476
+
477
+ if (initData.screenReader) {
478
+ body.classList.add('vscode-using-screen-reader');
479
+ }
480
+
481
+ body.dataset.vscodeThemeKind = initData.activeTheme;
482
+ /** @deprecated data-vscode-theme-name will be removed, use data-vscode-theme-id instead */
483
+ body.dataset.vscodeThemeName = initData.themeLabel || '';
484
+ body.dataset.vscodeThemeId = initData.themeId || '';
485
+ }
486
+
487
+ if (initData.styles) {
488
+ const documentStyle = document.documentElement.style;
489
+
490
+ // Remove stale properties
491
+ for (let i = documentStyle.length - 1; i >= 0; i--) {
492
+ const property = documentStyle[i];
493
+
494
+ // Don't remove properties that the webview might have added separately
495
+ if (property && property.startsWith('--vscode-')) {
496
+ documentStyle.removeProperty(property);
497
+ }
498
+ }
499
+
500
+ // Re-add new properties
501
+ for (const [variable, value] of Object.entries(initData.styles)) {
502
+ documentStyle.setProperty(`--${variable}`, value);
503
+ }
504
+ }
505
+ };
506
+
507
+ /**
508
+ * @param {MouseEvent} event
509
+ */
510
+ const handleInnerClick = (event) => {
511
+ if (!event?.view?.document) {
512
+ return;
513
+ }
514
+
515
+ const baseElement = event.view.document.querySelector('base');
516
+
517
+ for (const pathElement of event.composedPath()) {
518
+ /** @type {any} */
519
+ const node = pathElement;
520
+ if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) {
521
+ if (node.getAttribute('href') === '#') {
522
+ event.view.scrollTo(0, 0);
523
+ } else if (node.hash && (node.getAttribute('href') === node.hash || (baseElement && node.href === baseElement.href + node.hash))) {
524
+ const fragment = node.hash.slice(1);
525
+ const decodedFragment = decodeURIComponent(fragment);
526
+ const scrollTarget = event.view.document.getElementById(fragment) ?? event.view.document.getElementById(decodedFragment);
527
+ if (scrollTarget) {
528
+ scrollTarget.scrollIntoView();
529
+ } else if (decodedFragment.toLowerCase() === 'top') {
530
+ event.view.scrollTo(0, 0);
531
+ }
532
+ } else {
533
+ hostMessaging.postMessage('did-click-link', { uri: node.href.baseVal || node.href });
534
+ }
535
+ event.preventDefault();
536
+ return;
537
+ }
538
+ }
539
+ };
540
+
541
+ /**
542
+ * @param {MouseEvent} event
543
+ */
544
+ const handleAuxClick = (event) => {
545
+ // Prevent middle clicks opening a broken link in the browser
546
+ if (!event?.view?.document) {
547
+ return;
548
+ }
549
+
550
+ if (event.button === 1) {
551
+ for (const pathElement of event.composedPath()) {
552
+ /** @type {any} */
553
+ const node = pathElement;
554
+ if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) {
555
+ event.preventDefault();
556
+ return;
557
+ }
558
+ }
559
+ }
560
+ };
561
+
562
+ /**
563
+ * @param {KeyboardEvent} e
564
+ */
565
+ const handleInnerKeydown = (e) => {
566
+ // If the keypress would trigger a browser event, such as copy or paste,
567
+ // make sure we block the browser from dispatching it. Instead VS Code
568
+ // handles these events and will dispatch a copy/paste back to the webview
569
+ // if needed
570
+ if (isUndoRedo(e) || isPrint(e) || isFindEvent(e) || isSaveEvent(e)) {
571
+ e.preventDefault();
572
+ } else if (isCopyPasteOrCut(e)) {
573
+ if (onElectron) {
574
+ e.preventDefault();
575
+ } else {
576
+ return; // let the browser handle this
577
+ }
578
+ } else if (!onElectron && (isCloseTab(e) || isNewWindow(e) || isHelp(e) || isRefresh(e))) {
579
+ // Prevent Ctrl+W closing window / Ctrl+N opening new window in PWA.
580
+ // (No effect in a regular browser tab.)
581
+ e.preventDefault();
582
+ }
583
+
584
+ hostMessaging.postMessage('did-keydown', {
585
+ key: e.key,
586
+ keyCode: e.keyCode,
587
+ code: e.code,
588
+ shiftKey: e.shiftKey,
589
+ altKey: e.altKey,
590
+ ctrlKey: e.ctrlKey,
591
+ metaKey: e.metaKey,
592
+ repeat: e.repeat
593
+ });
594
+ };
595
+ /**
596
+ * @param {KeyboardEvent} e
597
+ */
598
+ const handleInnerKeyup = (e) => {
599
+ hostMessaging.postMessage('did-keyup', {
600
+ key: e.key,
601
+ keyCode: e.keyCode,
602
+ code: e.code,
603
+ shiftKey: e.shiftKey,
604
+ altKey: e.altKey,
605
+ ctrlKey: e.ctrlKey,
606
+ metaKey: e.metaKey,
607
+ repeat: e.repeat
608
+ });
609
+ };
610
+
611
+ /**
612
+ * @param {KeyboardEvent} e
613
+ * @return {boolean}
614
+ */
615
+ function isCopyPasteOrCut(e) {
616
+ const hasMeta = e.ctrlKey || e.metaKey;
617
+ // 45: keyCode of "Insert"
618
+ const shiftInsert = e.shiftKey && e.keyCode === 45;
619
+ // 67, 86, 88: keyCode of "C", "V", "X"
620
+ return (hasMeta && [67, 86, 88].includes(e.keyCode)) || shiftInsert;
621
+ }
622
+
623
+ /**
624
+ * @param {KeyboardEvent} e
625
+ * @return {boolean}
626
+ */
627
+ function isUndoRedo(e) {
628
+ const hasMeta = e.ctrlKey || e.metaKey;
629
+ // 90, 89: keyCode of "Z", "Y"
630
+ return hasMeta && [90, 89].includes(e.keyCode);
631
+ }
632
+
633
+ /**
634
+ * @param {KeyboardEvent} e
635
+ * @return {boolean}
636
+ */
637
+ function isPrint(e) {
638
+ const hasMeta = e.ctrlKey || e.metaKey;
639
+ // 80: keyCode of "P"
640
+ return hasMeta && e.keyCode === 80;
641
+ }
642
+
643
+ /**
644
+ * @param {KeyboardEvent} e
645
+ * @return {boolean}
646
+ */
647
+ function isFindEvent(e) {
648
+ const hasMeta = e.ctrlKey || e.metaKey;
649
+ // 70: keyCode of "F"
650
+ return hasMeta && e.keyCode === 70;
651
+ }
652
+
653
+ /**
654
+ * @param {KeyboardEvent} e
655
+ * @return {boolean}
656
+ */
657
+ function isSaveEvent(e) {
658
+ const hasMeta = e.ctrlKey || e.metaKey;
659
+ // 83: keyCode of "S"
660
+ return hasMeta && e.keyCode === 83;
661
+ }
662
+
663
+ /**
664
+ * @param {KeyboardEvent} e
665
+ * @return {boolean}
666
+ */
667
+ function isCloseTab(e) {
668
+ const hasMeta = e.ctrlKey || e.metaKey;
669
+ // 87: keyCode of "W"
670
+ return hasMeta && e.keyCode === 87;
671
+ }
672
+
673
+ /**
674
+ * @param {KeyboardEvent} e
675
+ * @return {boolean}
676
+ */
677
+ function isNewWindow(e) {
678
+ const hasMeta = e.ctrlKey || e.metaKey;
679
+ // 78: keyCode of "N"
680
+ return hasMeta && e.keyCode === 78;
681
+ }
682
+
683
+ /**
684
+ * @param {KeyboardEvent} e
685
+ * @return {boolean}
686
+ */
687
+ function isHelp(e) {
688
+ // 112: keyCode of "F1"
689
+ return e.keyCode === 112;
690
+ }
691
+
692
+ /**
693
+ * @param {KeyboardEvent} e
694
+ * @return {boolean}
695
+ */
696
+ function isRefresh(e) {
697
+ // 116: keyCode of "F5"
698
+ return e.keyCode === 116;
699
+ }
700
+
701
+ let isHandlingScroll = false;
702
+
703
+ /**
704
+ * @param {WheelEvent} event
705
+ */
706
+ const handleWheel = (event) => {
707
+ if (isHandlingScroll) {
708
+ return;
709
+ }
710
+
711
+ hostMessaging.postMessage('did-scroll-wheel', {
712
+ deltaMode: event.deltaMode,
713
+ deltaX: event.deltaX,
714
+ deltaY: event.deltaY,
715
+ deltaZ: event.deltaZ,
716
+ detail: event.detail,
717
+ type: event.type
718
+ });
719
+ };
720
+
721
+ /**
722
+ * @param {Event} event
723
+ */
724
+ const handleInnerScroll = (event) => {
725
+ if (isHandlingScroll) {
726
+ return;
727
+ }
728
+
729
+ const target = /** @type {HTMLDocument | null} */ (event.target);
730
+ const currentTarget = /** @type {Window | null} */ (event.currentTarget);
731
+ if (!currentTarget || !target?.body) {
732
+ return;
733
+ }
734
+
735
+ const progress = currentTarget.scrollY / target.body.clientHeight;
736
+ if (isNaN(progress)) {
737
+ return;
738
+ }
739
+
740
+ isHandlingScroll = true;
741
+ window.requestAnimationFrame(() => {
742
+ try {
743
+ hostMessaging.postMessage('did-scroll', { scrollYPercentage: progress });
744
+ } catch (e) {
745
+ // noop
746
+ }
747
+ isHandlingScroll = false;
748
+ });
749
+ };
750
+
751
+ function handleInnerDragStartEvent(/** @type {DragEvent} */ e) {
752
+ if (e.defaultPrevented) {
753
+ // Extension code has already handled this event
754
+ return;
755
+ }
756
+
757
+ if (!e.dataTransfer || e.shiftKey) {
758
+ return;
759
+ }
760
+
761
+ // Only handle drags from outside editor for now
762
+ if (e.dataTransfer.items.length && Array.prototype.every.call(e.dataTransfer.items, item => item.kind === 'file')) {
763
+ hostMessaging.postMessage('drag-start', undefined);
764
+ }
765
+ }
766
+
767
+ /**
768
+ * @param {() => void} callback
769
+ */
770
+ function onDomReady(callback) {
771
+ if (document.readyState === 'interactive' || document.readyState === 'complete') {
772
+ callback();
773
+ } else {
774
+ document.addEventListener('DOMContentLoaded', callback);
775
+ }
776
+ }
777
+
778
+ function areServiceWorkersEnabled() {
779
+ try {
780
+ return !!navigator.serviceWorker;
781
+ } catch (e) {
782
+ return false;
783
+ }
784
+ }
785
+
786
+ /**
787
+ * @param {import('../webviewMessages').UpdateContentEvent} data
788
+ * @return {string}
789
+ */
790
+ function toContentHtml(data) {
791
+ const options = data.options;
792
+ const text = data.contents;
793
+ const newDocument = new DOMParser().parseFromString(text, 'text/html');
794
+
795
+ newDocument.querySelectorAll('a').forEach(a => {
796
+ if (!a.title) {
797
+ const href = a.getAttribute('href');
798
+ if (typeof href === 'string') {
799
+ a.title = href;
800
+ }
801
+ }
802
+ });
803
+
804
+ // Set default aria role
805
+ if (!newDocument.body.hasAttribute('role')) {
806
+ newDocument.body.setAttribute('role', 'document');
807
+ }
808
+
809
+ // Inject default script
810
+ if (options.allowScripts) {
811
+ const defaultScript = newDocument.createElement('script');
812
+ defaultScript.id = '_vscodeApiScript';
813
+ defaultScript.textContent = getVsCodeApiScript(options.allowMultipleAPIAcquire, data.state);
814
+ newDocument.head.prepend(defaultScript);
815
+ }
816
+
817
+ // Inject default styles
818
+ newDocument.head.prepend(defaultStyles.cloneNode(true));
819
+
820
+ applyStyles(newDocument, newDocument.body);
821
+
822
+ // Strip out unsupported http-equiv tags
823
+ for (const metaElement of Array.from(newDocument.querySelectorAll('meta'))) {
824
+ const httpEquiv = metaElement.getAttribute('http-equiv');
825
+ if (httpEquiv && !/^(content-security-policy|default-style|content-type)$/i.test(httpEquiv)) {
826
+ console.warn(`Removing unsupported meta http-equiv: ${httpEquiv}`);
827
+ metaElement.remove();
828
+ }
829
+ }
830
+
831
+ // Check for CSP
832
+ const csp = newDocument.querySelector('meta[http-equiv="Content-Security-Policy"]');
833
+ if (!csp) {
834
+ hostMessaging.postMessage('no-csp-found', undefined);
835
+ } else {
836
+ try {
837
+ // Attempt to rewrite CSPs that hardcode old-style resource endpoint
838
+ const cspContent = csp.getAttribute('content');
839
+ if (cspContent) {
840
+ const newCsp = cspContent.replace(/(vscode-webview-resource|vscode-resource):(?=(\s|;|$))/g, data.cspSource);
841
+ csp.setAttribute('content', newCsp);
842
+ }
843
+ } catch (e) {
844
+ console.error(`Could not rewrite csp: ${e}`);
845
+ }
846
+ }
847
+
848
+ // set DOCTYPE for newDocument explicitly as DOMParser.parseFromString strips it off
849
+ // and DOCTYPE is needed in the iframe to ensure that the user agent stylesheet is correctly overridden
850
+ return '<!DOCTYPE html>\n' + newDocument.documentElement.outerHTML;
851
+ }
852
+
853
+ // Also forward events before the contents of the webview have loaded
854
+ window.addEventListener('keydown', handleInnerKeydown);
855
+ window.addEventListener('keyup', handleInnerKeyup);
856
+ window.addEventListener('dragenter', handleInnerDragStartEvent);
857
+ window.addEventListener('dragover', handleInnerDragStartEvent);
858
+
859
+ onDomReady(() => {
860
+ if (!document.body) {
861
+ return;
862
+ }
863
+
864
+ hostMessaging.onMessage('styles', (_event, data) => {
865
+ ++styleVersion;
866
+
867
+ initData.styles = data.styles;
868
+ initData.activeTheme = data.activeTheme;
869
+ initData.themeLabel = data.themeLabel;
870
+ initData.themeId = data.themeId;
871
+ initData.reduceMotion = data.reduceMotion;
872
+ initData.screenReader = data.screenReader;
873
+
874
+ const target = getActiveFrame();
875
+ if (!target) {
876
+ return;
877
+ }
878
+
879
+ if (target.contentDocument) {
880
+ applyStyles(target.contentDocument, target.contentDocument.body);
881
+ }
882
+ });
883
+
884
+ // propagate focus
885
+ hostMessaging.onMessage('focus', () => {
886
+ const activeFrame = getActiveFrame();
887
+ if (!activeFrame || !activeFrame.contentWindow) {
888
+ // Focus the top level webview instead
889
+ window.focus();
890
+ return;
891
+ }
892
+
893
+ if (document.activeElement === activeFrame) {
894
+ // We are already focused on the iframe (or one of its children) so no need
895
+ // to refocus.
896
+ return;
897
+ }
898
+
899
+ activeFrame.contentWindow.focus();
900
+ });
901
+
902
+ // update iframe-contents
903
+ let updateId = 0;
904
+ hostMessaging.onMessage('content', async (_event, /** @type {import('../webviewMessages').UpdateContentEvent} */ data) => {
905
+ const currentUpdateId = ++updateId;
906
+ try {
907
+ await workerReady;
908
+ } catch (e) {
909
+ console.error(`Webview fatal error: ${e}`);
910
+ hostMessaging.postMessage('fatal-error', { message: e + '' });
911
+ return;
912
+ }
913
+
914
+ if (currentUpdateId !== updateId) {
915
+ return;
916
+ }
917
+
918
+ const options = data.options;
919
+ const newDocument = toContentHtml(data);
920
+
921
+ const initialStyleVersion = styleVersion;
922
+
923
+ const frame = getActiveFrame();
924
+ const wasFirstLoad = firstLoad;
925
+ // keep current scrollY around and use later
926
+ /** @type {(body: HTMLElement, window: Window) => void} */
927
+ let setInitialScrollPosition;
928
+ if (firstLoad) {
929
+ firstLoad = false;
930
+ setInitialScrollPosition = (body, window) => {
931
+ if (typeof initData.initialScrollProgress === 'number' && !isNaN(initData.initialScrollProgress)) {
932
+ if (window.scrollY === 0) {
933
+ window.scroll(0, body.clientHeight * initData.initialScrollProgress);
934
+ }
935
+ }
936
+ };
937
+ } else {
938
+ const scrollY = frame && frame.contentDocument && frame.contentDocument.body ? assertIsDefined(frame.contentWindow).scrollY : 0;
939
+ setInitialScrollPosition = (body, window) => {
940
+ if (window.scrollY === 0) {
941
+ window.scroll(0, scrollY);
942
+ }
943
+ };
944
+ }
945
+
946
+ // Clean up old pending frames and set current one as new one
947
+ const previousPendingFrame = getPendingFrame();
948
+ if (previousPendingFrame) {
949
+ previousPendingFrame.setAttribute('id', '');
950
+ previousPendingFrame.remove();
951
+ }
952
+ if (!wasFirstLoad) {
953
+ pendingMessages = [];
954
+ }
955
+
956
+ const newFrame = document.createElement('iframe');
957
+ newFrame.title = data.title;
958
+ newFrame.setAttribute('id', 'pending-frame');
959
+ newFrame.setAttribute('frameborder', '0');
960
+
961
+ const sandboxRules = new Set(['allow-same-origin', 'allow-pointer-lock']);
962
+ if (options.allowScripts) {
963
+ sandboxRules.add('allow-scripts');
964
+ sandboxRules.add('allow-downloads');
965
+ }
966
+ if (options.allowForms) {
967
+ sandboxRules.add('allow-forms');
968
+ }
969
+ newFrame.setAttribute('sandbox', Array.from(sandboxRules).join(' '));
970
+
971
+ const allowRules = ['cross-origin-isolated;', 'autoplay;'];
972
+ if (!isFirefox && options.allowScripts) {
973
+ allowRules.push('clipboard-read;', 'clipboard-write;');
974
+ }
975
+ newFrame.setAttribute('allow', allowRules.join(' '));
976
+ // We should just be able to use srcdoc, but I wasn't
977
+ // seeing the service worker applying properly.
978
+ // Fake load an empty on the correct origin and then write real html
979
+ // into it to get around this.
980
+ const fakeUrlParams = new URLSearchParams({ id: ID });
981
+ if (globalThis.crossOriginIsolated) {
982
+ fakeUrlParams.set('vscode-coi', '3'); /*COOP+COEP*/
983
+ }
984
+ newFrame.src = `${fakeHtmlUri}?${fakeUrlParams.toString()}`;
985
+
986
+ newFrame.style.cssText = 'display: block; margin: 0; overflow: hidden; position: absolute; width: 100%; height: 100%; visibility: hidden';
987
+ document.body.appendChild(newFrame);
988
+
989
+ newFrame.contentWindow.addEventListener('keydown', handleInnerKeydown);
990
+ newFrame.contentWindow.addEventListener('keyup', handleInnerKeyup);
991
+
992
+ /**
993
+ * @param {Document} contentDocument
994
+ */
995
+ function onFrameLoaded(contentDocument) {
996
+ // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=978325
997
+ setTimeout(() => {
998
+ contentDocument.open();
999
+ contentDocument.write(newDocument);
1000
+ contentDocument.close();
1001
+ hookupOnLoadHandlers(newFrame);
1002
+
1003
+ if (initialStyleVersion !== styleVersion) {
1004
+ applyStyles(contentDocument, contentDocument.body);
1005
+ }
1006
+ }, 0);
1007
+ }
1008
+
1009
+ if (!options.allowScripts && isSafari) {
1010
+ // On Safari for iframes with scripts disabled, the `DOMContentLoaded` never seems to be fired: https://bugs.webkit.org/show_bug.cgi?id=33604
1011
+ // Use polling instead.
1012
+ const interval = setInterval(() => {
1013
+ // If the frame is no longer mounted, loading has stopped
1014
+ if (!newFrame.parentElement) {
1015
+ clearInterval(interval);
1016
+ return;
1017
+ }
1018
+
1019
+ const contentDocument = assertIsDefined(newFrame.contentDocument);
1020
+ if (contentDocument.location.pathname.endsWith('/fake.html') && contentDocument.readyState !== 'loading') {
1021
+ clearInterval(interval);
1022
+ onFrameLoaded(contentDocument);
1023
+ }
1024
+ }, 10);
1025
+ } else {
1026
+ assertIsDefined(newFrame.contentWindow).addEventListener('DOMContentLoaded', e => {
1027
+ const contentDocument = e.target ? (/** @type {HTMLDocument} */ (e.target)) : undefined;
1028
+ onFrameLoaded(assertIsDefined(contentDocument));
1029
+ });
1030
+ }
1031
+
1032
+ /**
1033
+ * @param {Document} contentDocument
1034
+ * @param {Window} contentWindow
1035
+ */
1036
+ const onLoad = (contentDocument, contentWindow) => {
1037
+ if (contentDocument && contentDocument.body) {
1038
+ // Workaround for https://github.com/microsoft/vscode/issues/12865
1039
+ // check new scrollY and reset if necessary
1040
+ setInitialScrollPosition(contentDocument.body, contentWindow);
1041
+ }
1042
+
1043
+ const newFrame = getPendingFrame();
1044
+ if (newFrame && newFrame.contentDocument && newFrame.contentDocument === contentDocument) {
1045
+ const wasFocused = document.hasFocus();
1046
+ const oldActiveFrame = getActiveFrame();
1047
+ oldActiveFrame?.remove();
1048
+ // Styles may have changed since we created the element. Make sure we re-style
1049
+ if (initialStyleVersion !== styleVersion) {
1050
+ applyStyles(newFrame.contentDocument, newFrame.contentDocument.body);
1051
+ }
1052
+ newFrame.setAttribute('id', 'active-frame');
1053
+ newFrame.style.visibility = 'visible';
1054
+
1055
+ contentWindow.addEventListener('scroll', handleInnerScroll);
1056
+ contentWindow.addEventListener('wheel', handleWheel);
1057
+
1058
+ if (wasFocused) {
1059
+ contentWindow.focus();
1060
+ }
1061
+
1062
+ pendingMessages.forEach((message) => {
1063
+ contentWindow.postMessage(message.message, window.origin, message.transfer);
1064
+ });
1065
+ pendingMessages = [];
1066
+ }
1067
+ };
1068
+
1069
+ /**
1070
+ * @param {HTMLIFrameElement} newFrame
1071
+ */
1072
+ function hookupOnLoadHandlers(newFrame) {
1073
+ clearTimeout(loadTimeout);
1074
+ loadTimeout = undefined;
1075
+ loadTimeout = setTimeout(() => {
1076
+ clearTimeout(loadTimeout);
1077
+ loadTimeout = undefined;
1078
+ onLoad(assertIsDefined(newFrame.contentDocument), assertIsDefined(newFrame.contentWindow));
1079
+ }, 200);
1080
+
1081
+ const contentWindow = assertIsDefined(newFrame.contentWindow);
1082
+
1083
+ contentWindow.addEventListener('load', function (e) {
1084
+ const contentDocument = /** @type {Document} */ (e.target);
1085
+
1086
+ if (loadTimeout) {
1087
+ clearTimeout(loadTimeout);
1088
+ loadTimeout = undefined;
1089
+ onLoad(contentDocument, this);
1090
+ }
1091
+ });
1092
+
1093
+ // Bubble out various events
1094
+ contentWindow.addEventListener('click', handleInnerClick);
1095
+ contentWindow.addEventListener('auxclick', handleAuxClick);
1096
+ contentWindow.addEventListener('keydown', handleInnerKeydown);
1097
+ contentWindow.addEventListener('keyup', handleInnerKeyup);
1098
+ contentWindow.addEventListener('contextmenu', e => {
1099
+ if (e.defaultPrevented) {
1100
+ // Extension code has already handled this event
1101
+ return;
1102
+ }
1103
+
1104
+ e.preventDefault();
1105
+
1106
+ /** @type { Record<string, boolean>} */
1107
+ let context = {};
1108
+
1109
+ /** @type {HTMLElement | null} */
1110
+ let el = e.target;
1111
+ while (true) {
1112
+ if (!el) {
1113
+ break;
1114
+ }
1115
+
1116
+ // Search self/ancestors for the closest context data attribute
1117
+ el = el.closest('[data-vscode-context]');
1118
+ if (!el) {
1119
+ break;
1120
+ }
1121
+
1122
+ try {
1123
+ context = { ...JSON.parse(el.dataset.vscodeContext), ...context };
1124
+ } catch (e) {
1125
+ console.error(`Error parsing 'data-vscode-context' as json`, el, e);
1126
+ }
1127
+
1128
+ el = el.parentElement;
1129
+ }
1130
+
1131
+ hostMessaging.postMessage('did-context-menu', {
1132
+ clientX: e.clientX,
1133
+ clientY: e.clientY,
1134
+ context: context
1135
+ });
1136
+ });
1137
+
1138
+ contentWindow.addEventListener('dragenter', handleInnerDragStartEvent);
1139
+ contentWindow.addEventListener('dragover', handleInnerDragStartEvent);
1140
+
1141
+ unloadMonitor.onIframeLoaded(newFrame);
1142
+ }
1143
+ });
1144
+
1145
+ // propagate vscode-context-menu-visible class
1146
+ hostMessaging.onMessage('set-context-menu-visible', (_event, data) => {
1147
+ const target = getActiveFrame();
1148
+ if (target && target.contentDocument) {
1149
+ target.contentDocument.body.classList.toggle('vscode-context-menu-visible', data.visible);
1150
+ }
1151
+ });
1152
+
1153
+ hostMessaging.onMessage('set-title', async (_event, data) => {
1154
+ const target = getActiveFrame();
1155
+ if (target) {
1156
+ target.title = data;
1157
+ }
1158
+ });
1159
+
1160
+ // Forward message to the embedded iframe
1161
+ hostMessaging.onMessage('message', (_event, data) => {
1162
+ const pending = getPendingFrame();
1163
+ if (!pending) {
1164
+ const target = getActiveFrame();
1165
+ if (target) {
1166
+ assertIsDefined(target.contentWindow).postMessage(data.message, window.origin, data.transfer);
1167
+ return;
1168
+ }
1169
+ }
1170
+ pendingMessages.push(data);
1171
+ });
1172
+
1173
+ hostMessaging.onMessage('initial-scroll-position', (_event, progress) => {
1174
+ initData.initialScrollProgress = progress;
1175
+ });
1176
+
1177
+ hostMessaging.onMessage('execCommand', (_event, data) => {
1178
+ const target = getActiveFrame();
1179
+ if (!target) {
1180
+ return;
1181
+ }
1182
+ assertIsDefined(target.contentDocument).execCommand(data);
1183
+ });
1184
+
1185
+ /** @type {string | undefined} */
1186
+ let lastFindValue = undefined;
1187
+
1188
+ hostMessaging.onMessage('find', (_event, data) => {
1189
+ const target = getActiveFrame();
1190
+ if (!target) {
1191
+ return;
1192
+ }
1193
+
1194
+ if (!data.previous && lastFindValue !== data.value && target.contentWindow) {
1195
+ // Reset selection so we start search at the head of the last search
1196
+ const selection = target.contentWindow.getSelection();
1197
+ if (selection) {
1198
+ selection.collapse(selection.anchorNode);
1199
+ }
1200
+ }
1201
+ lastFindValue = data.value;
1202
+
1203
+ const didFind = (/** @type {any} */ (target.contentWindow)).find(
1204
+ data.value,
1205
+ /* caseSensitive*/ false,
1206
+ /* backwards*/ data.previous,
1207
+ /* wrapAround*/ true,
1208
+ /* wholeWord */ false,
1209
+ /* searchInFrames*/ false,
1210
+ false);
1211
+ hostMessaging.postMessage('did-find', didFind);
1212
+ });
1213
+
1214
+ hostMessaging.onMessage('find-stop', (_event, data) => {
1215
+ const target = getActiveFrame();
1216
+ if (!target) {
1217
+ return;
1218
+ }
1219
+
1220
+ lastFindValue = undefined;
1221
+
1222
+ if (!data.clearSelection && target.contentWindow) {
1223
+ const selection = target.contentWindow.getSelection();
1224
+ if (selection) {
1225
+ for (let i = 0; i < selection.rangeCount; i++) {
1226
+ selection.removeRange(selection.getRangeAt(i));
1227
+ }
1228
+ }
1229
+ }
1230
+ });
1231
+
1232
+ trackFocus({
1233
+ onFocus: () => hostMessaging.postMessage('did-focus', undefined),
1234
+ onBlur: () => hostMessaging.postMessage('did-blur', undefined)
1235
+ });
1236
+
1237
+ (/** @type {any} */ (window))[vscodePostMessageFuncName] = (/** @type {string} */ command, /** @type {any} */ data) => {
1238
+ switch (command) {
1239
+ case 'onmessage':
1240
+ case 'do-update-state':
1241
+ hostMessaging.postMessage(command, data);
1242
+ break;
1243
+ }
1244
+ };
1245
+
1246
+ hostMessaging.signalReady();
1247
+ });
1248
+ </script>
1249
+ </body>
1250
+
1251
+ </html>