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