浏览代码

Since we can't use traditional event handlers in the print iframe when
JS is blocked, we consider it safe to discard of the hidden iframe once
event handling has returned to the main content window.

Ian Rose 6 年之前
父节点
当前提交
1593668cd3
共有 1 个文件被更改,包括 22 次插入6 次删除
  1. 22 6
      packages/apputils/src/printing.ts

+ 22 - 6
packages/apputils/src/printing.ts

@@ -93,9 +93,10 @@ export namespace Printing {
       iframe.src = 'about:blank';
       setIFrameNode(iframe, textOrEl as HTMLElement);
     }
-    const printed = resolveAfterPrint(iframe);
-
+    const printed = resolveAfterEvent();
     launchPrint(iframe.contentWindow);
+    // Once the print dialog has been dismissed, we regain event handling,
+    // and it should be safe to discard the hidden iframe.
     await printed;
     parent.removeChild(iframe);
   }
@@ -140,9 +141,25 @@ export namespace Printing {
     });
   }
 
-  function resolveAfterPrint(iframe: HTMLIFrameElement): Promise<void> {
+  /**
+   * A promise that resolves after the next mousedown, mousemove, or
+   * keydown event. We use this as a proxy for determining when the
+   * main window has regained control after the print dialog is removed.
+   *
+   * We can't use the usual window.onafterprint handler because we
+   * disallow Javascript execution in the print iframe.
+   */
+  function resolveAfterEvent(): Promise<void> {
     return new Promise(resolve => {
-      iframe.contentWindow.onafterprint = () => resolve();
+      const onEvent = () => {
+        document.removeEventListener('mousemove', onEvent, true);
+        document.removeEventListener('mousedown', onEvent, true);
+        document.removeEventListener('keydown', onEvent, true);
+        resolve();
+      };
+      document.addEventListener('mousemove', onEvent, true);
+      document.addEventListener('mousedown', onEvent, true);
+      document.addEventListener('keydown', onEvent, true);
     });
   }
 
@@ -151,8 +168,7 @@ export namespace Printing {
    */
   function launchPrint(contentWindow: Window) {
     const result = contentWindow.document.execCommand('print', false, null);
-
-    // exeCommand won't work in firefox so we call the `print` method instead if it fails
+    // execCommand won't work in firefox so we call the `print` method instead if it fails
     // https://github.com/joseluisq/printd/blob/eb7948d602583c055ab6dee3ee294b6a421da4b6/src/index.ts#L148
     if (!result) {
       contentWindow.print();