@codingame/monaco-vscode-views-service-override 4.4.1 → 4.5.0-improve-code-splitting.1

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