|
148 | 148 | <div class="output spinner" id="output"> |
149 | 149 | <header>Output</header> |
150 | 150 | <vscode-progress-ring id="spinner"></vscode-progress-ring> |
151 | | - <iframe id="frame"></iframe> |
| 151 | + <iframe |
| 152 | + id="frame" |
| 153 | + sandbox="allow-same-origin allow-pointer-lock allow-scripts allow-downloads allow-forms" |
| 154 | + allow="cross-origin-isolated; clipboard-read; clipboard-write;" |
| 155 | + ></iframe> |
152 | 156 | <pre id="stdout"></pre> |
153 | 157 | <div class="alert-error" id="error"> |
154 | 158 | <span class="error-icon"> |
|
213 | 217 | </div> |
214 | 218 | </div> |
215 | 219 | <script> |
| 220 | + const isMac = navigator.platform.indexOf("Mac") >= 0; |
| 221 | + |
216 | 222 | class PageHandler { |
217 | 223 | formatDuration(duration) { |
218 | 224 | if (duration < 0 || duration === undefined) { |
|
257 | 263 | cl.remove("error"); |
258 | 264 | cl.add("html"); |
259 | 265 |
|
260 | | - var frame = document.getElementById("frame"); |
261 | | - var frame = frame.contentWindow || frame.contentDocument; |
| 266 | + const frameEl = document.getElementById("frame"); |
| 267 | + var frame = |
| 268 | + frameEl.contentWindow || frameEl.contentDocument; |
262 | 269 | if (frame.document) frame = frame.document; |
263 | 270 |
|
264 | 271 | frame.open(); |
265 | 272 | frame.write(html); |
266 | 273 | frame.close(); |
| 274 | + |
| 275 | + if (isMac) { |
| 276 | + // The clipboard doesn't work in iframes embedded in webviews |
| 277 | + // See https://github.com/microsoft/vscode/issues/65452 |
| 278 | + |
| 279 | + // forward keydown events to the webview and handle CTRL-A |
| 280 | + frame.addEventListener("keydown", (e) => { |
| 281 | + window.dispatchEvent( |
| 282 | + new KeyboardEvent("keydown", e) |
| 283 | + ); |
| 284 | + }); |
| 285 | + |
| 286 | + // forward copy commands to the iFrame |
| 287 | + document.addEventListener("copy", (e) => { |
| 288 | + frame.execCommand("copy"); |
| 289 | + }); |
| 290 | + |
| 291 | + // forward context menu events to the webview and make |
| 292 | + // clientX and clientY relative to the webview |
| 293 | + frame.addEventListener("contextmenu", (e) => { |
| 294 | + const rect = frameEl.getBoundingClientRect(); |
| 295 | + window.document.documentElement.dispatchEvent( |
| 296 | + new MouseEvent("contextmenu", { |
| 297 | + altKey: e.altKey, |
| 298 | + bubbles: e.bubbles, |
| 299 | + button: e.button, |
| 300 | + buttons: e.buttons, |
| 301 | + cancelable: e.cancelable, |
| 302 | + clientX: e.clientX + rect.left, |
| 303 | + clientY: e.clientY + rect.top, |
| 304 | + composed: e.composed, |
| 305 | + ctrlKey: e.ctrlKey, |
| 306 | + detail: e.detail, |
| 307 | + metaKey: e.metaKey, |
| 308 | + modifierAltGraph: e.modifierAltGraph, |
| 309 | + modifierCapsLock: e.modifierCapsLock, |
| 310 | + modifierFn: e.modifierFn, |
| 311 | + modifierFnLock: e.modifierFnLock, |
| 312 | + modifierHyper: e.modifierHyper, |
| 313 | + modifierNumLock: e.modifierNumLock, |
| 314 | + modifierScrollLock: e.modifierScrollLock, |
| 315 | + modifierSuper: e.modifierSuper, |
| 316 | + modifierSymbol: e.modifierSymbol, |
| 317 | + modifierSymbolLock: e.modifierSymbolLock, |
| 318 | + movementX: e.movementX, |
| 319 | + movementY: e.movementY, |
| 320 | + relatedTarget: e.relatedTarget, |
| 321 | + screenX: e.screenX, |
| 322 | + screenY: e.screenY, |
| 323 | + shiftKey: e.shiftKey, |
| 324 | + view: e.view, |
| 325 | + }) |
| 326 | + ); |
| 327 | + }); |
| 328 | + } |
267 | 329 | } |
268 | 330 |
|
269 | 331 | setStdout(stdout) { |
|
299 | 361 |
|
300 | 362 | if (vscode) { |
301 | 363 | window.addEventListener("message", (event) => { |
302 | | - page[event.data.fn](...event.data.args); |
| 364 | + page[event.data.fn] && |
| 365 | + page[event.data.fn](...event.data.args); |
303 | 366 | }); |
304 | 367 | } else { |
305 | 368 | // test code for iterating on the page in a web browser |
|
0 commit comments