(iframeUrl, className, messageHandler)
| 27 | // - className: the CSS class to add to the iframe. |
| 28 | // - messageHandler: optional; a function to handle messages from the iframe's page. |
| 29 | async load(iframeUrl, className, messageHandler) { |
| 30 | if (this.iframeFrameElement) throw new Error("init should only be called once."); |
| 31 | this.messageHandler = messageHandler; |
| 32 | const isDomTests = iframeUrl.includes("?dom_tests=true"); |
| 33 | this.iframeElement = DomUtils.createElement("iframe"); |
| 34 | |
| 35 | // Allow Vimium's iframes to have clipboard access in Chrome. This is needed when triggering |
| 36 | // some commands, like link hints or copyCurrentUrl, from within the help dialog. Firefox does |
| 37 | // not support clipboard-read and clipboard-write in the allow attribute. NOTE(philc): this |
| 38 | // permission has to be set before we append the iframe to the DOM, or Chrome will log the |
| 39 | // console error "Potential permissions policy violation: clipboard-read is not allowed in this |
| 40 | // document." |
| 41 | if (!Utils.isFirefox()) { |
| 42 | this.iframeElement.allow = "clipboard-read; clipboard-write"; |
| 43 | } |
| 44 | |
| 45 | const styleSheet = DomUtils.createElement("style"); |
| 46 | styleSheet.type = "text/css"; |
| 47 | // Default to everything hidden while the stylesheet loads. |
| 48 | styleSheet.innerHTML = "iframe {display: none;}"; |
| 49 | |
| 50 | // Fetch "content_scripts/vimium.css" from chrome.storage.session; the background page caches |
| 51 | // it there. |
| 52 | chrome.storage.session.get("vimiumCSSInChromeStorage") |
| 53 | .then((items) => styleSheet.innerHTML = items.vimiumCSSInChromeStorage); |
| 54 | |
| 55 | this.iframeElement.className = className; |
| 56 | |
| 57 | const shadowWrapper = DomUtils.createElement("div"); |
| 58 | // Prevent the page's CSS from interfering with this container div. |
| 59 | shadowWrapper.className = "vimium-reset"; |
| 60 | this.shadowDOM = shadowWrapper.attachShadow({ mode: "open" }); |
| 61 | this.shadowDOM.appendChild(styleSheet); |
| 62 | this.shadowDOM.appendChild(this.iframeElement); |
| 63 | |
| 64 | // Load the iframe and pass it a port via window.postMessage so we can communicate privately |
| 65 | // with the iframe. Use a promise here so that requests to message this iframe's port will |
| 66 | // block until it's ready. See #1679. |
| 67 | let resolveFn; |
| 68 | this.iframePort = new Promise((resolve, _reject) => { |
| 69 | resolveFn = resolve; |
| 70 | }); |
| 71 | |
| 72 | this.setIframeVisible(false); |
| 73 | this.iframeElement.src = chrome.runtime.getURL(iframeUrl); |
| 74 | await DomUtils.documentReady(); |
| 75 | this.handleDarkReaderFilter(); |
| 76 | document.documentElement.appendChild(shadowWrapper); |
| 77 | |
| 78 | const secret = (await chrome.storage.session.get("vimiumSecret")).vimiumSecret; |
| 79 | const { port1, port2 } = new MessageChannel(); |
| 80 | this.messageChannelPorts = [port1, port2]; |
| 81 | this.iframeElement.addEventListener("load", () => { |
| 82 | // Get vimiumSecret so the iframe can determine that our message isn't the page |
| 83 | // impersonating us. |
| 84 | // Outside of tests, target origin starts with chrome-extension://{vimium's-id} |
| 85 | const targetOrigin = isDomTests ? "*" : chrome.runtime.getURL(""); |
| 86 | this.iframeElement.contentWindow.postMessage(secret, targetOrigin, [port2]); |
no test coverage detected