diff options
Diffstat (limited to 'content_scripts')
| -rw-r--r-- | content_scripts/hud.coffee | 20 | ||||
| -rw-r--r-- | content_scripts/ui_component.coffee | 136 |
2 files changed, 78 insertions, 78 deletions
diff --git a/content_scripts/hud.coffee b/content_scripts/hud.coffee index 62bcf03f..7ad13aaf 100644 --- a/content_scripts/hud.coffee +++ b/content_scripts/hud.coffee @@ -13,10 +13,8 @@ HUD = # it doesn't sit on top of horizontal scrollbars like Chrome's HUD does. init: -> - unless @hudUI? - @hudUI = new UIComponent "pages/hud.html", "vimiumHUDFrame", ({data}) => - this[data.name]? data - @tween = new Tween "iframe.vimiumHUDFrame.vimiumUIComponentVisible", @hudUI.shadowDOM + @hudUI ?= new UIComponent "pages/hud.html", "vimiumHUDFrame", ({data}) => this[data.name]? data + @tween ?= new Tween "iframe.vimiumHUDFrame.vimiumUIComponentVisible", @hudUI.shadowDOM showForDuration: (text, duration) -> @show(text) @@ -46,13 +44,13 @@ HUD = # If :updateIndicator is truthy, then we also refresh the mode indicator. The only time we don't update the # mode indicator, is when hide() is called for the mode indicator itself. hide: (immediate = false, updateIndicator = true) -> - return unless @hudUI?.uiComponentIsReady - clearTimeout(@_showForDurationTimerId) - @tween.stop() - if immediate - if updateIndicator then Mode.setIndicator() else @hudUI.hide() - else - @tween.fade 0, 150, => @hide true, updateIndicator + if @hudUI? and @tween? + clearTimeout @_showForDurationTimerId + @tween.stop() + if immediate + if updateIndicator then Mode.setIndicator() else @hudUI.hide() + else + @tween.fade 0, 150, => @hide true, updateIndicator hideFindMode: (data) -> @findMode.checkReturnToViewPort() diff --git a/content_scripts/ui_component.coffee b/content_scripts/ui_component.coffee index 0989bbc9..c7038f17 100644 --- a/content_scripts/ui_component.coffee +++ b/content_scripts/ui_component.coffee @@ -1,5 +1,4 @@ class UIComponent - uiComponentIsReady: false iframeElement: null iframePort: null showing: false @@ -13,64 +12,65 @@ class UIComponent @iframeElement.classList.add addClass constructor: (iframeUrl, className, @handleMessage) -> - styleSheet = DomUtils.createElement "style" - styleSheet.type = "text/css" - # Default to everything hidden while the stylesheet loads. - styleSheet.innerHTML = "iframe {display: none;}" + DomUtils.documentReady => + styleSheet = DomUtils.createElement "style" + styleSheet.type = "text/css" + # Default to everything hidden while the stylesheet loads. + styleSheet.innerHTML = "iframe {display: none;}" - # Use an XMLHttpRequest, possibly via the background page, to fetch the stylesheet. This allows us to - # catch and recover from failures that we could not have caught when using CSS @include (eg. #1817). - UIComponent::styleSheetGetter ?= new AsyncDataFetcher @fetchFileContents "content_scripts/vimium.css" - @styleSheetGetter.use (styles) -> styleSheet.innerHTML = styles + # Use an XMLHttpRequest, possibly via the background page, to fetch the stylesheet. This allows us to + # catch and recover from failures that we could not have caught when using CSS @include (eg. #1817). + UIComponent::styleSheetGetter ?= new AsyncDataFetcher @fetchFileContents "content_scripts/vimium.css" + @styleSheetGetter.use (styles) -> styleSheet.innerHTML = styles - @iframeElement = DomUtils.createElement "iframe" - extend @iframeElement, - className: className - seamless: "seamless" - shadowWrapper = DomUtils.createElement "div" - # PhantomJS doesn't support createShadowRoot, so guard against its non-existance. - @shadowDOM = shadowWrapper.createShadowRoot?() ? shadowWrapper - @shadowDOM.appendChild styleSheet - @shadowDOM.appendChild @iframeElement - @toggleIframeElementClasses "vimiumUIComponentVisible", "vimiumUIComponentHidden" + @iframeElement = DomUtils.createElement "iframe" + extend @iframeElement, + className: className + seamless: "seamless" + shadowWrapper = DomUtils.createElement "div" + # PhantomJS doesn't support createShadowRoot, so guard against its non-existance. + @shadowDOM = shadowWrapper.createShadowRoot?() ? shadowWrapper + @shadowDOM.appendChild styleSheet + @shadowDOM.appendChild @iframeElement + @toggleIframeElementClasses "vimiumUIComponentVisible", "vimiumUIComponentHidden" - # Open a port and pass it to the iframe via window.postMessage. We use an AsyncDataFetcher to handle - # requests which arrive before the iframe (and its message handlers) have completed initialization. See - # #1679. - @iframePort = new AsyncDataFetcher (setIframePort) => - # We set the iframe source and append the new element here (as opposed to above) to avoid a potential - # race condition vis-a-vis the "load" event (because this callback runs on "nextTick"). - @iframeElement.src = chrome.runtime.getURL iframeUrl - document.documentElement.appendChild shadowWrapper + # Open a port and pass it to the iframe via window.postMessage. We use an AsyncDataFetcher to handle + # requests which arrive before the iframe (and its message handlers) have completed initialization. See + # #1679. + @iframePort = new AsyncDataFetcher (setIframePort) => + # We set the iframe source and append the new element here (as opposed to above) to avoid a potential + # race condition vis-a-vis the "load" event (because this callback runs on "nextTick"). + @iframeElement.src = chrome.runtime.getURL iframeUrl + document.documentElement.appendChild shadowWrapper - @iframeElement.addEventListener "load", => - # Get vimiumSecret so the iframe can determine that our message isn't the page impersonating us. - chrome.storage.local.get "vimiumSecret", ({ vimiumSecret }) => - { port1, port2 } = new MessageChannel - @iframeElement.contentWindow.postMessage vimiumSecret, chrome.runtime.getURL(""), [ port2 ] - port1.onmessage = (event) => - switch event?.data?.name ? event?.data - when "uiComponentIsReady" - # If any other frame receives the focus, then hide the UI component. - chrome.runtime.onMessage.addListener ({name, focusFrameId}) => - if name == "frameFocused" and @options?.focus and focusFrameId not in [frameId, @iframeFrameId] - @hide false - false # We will not be calling sendResponse. - # If this frame receives the focus, then hide the UI component. - window.addEventListener "focus", (event) => - if event.target == window and @options?.focus and not @options?.allowBlur - @hide false - true # Continue propagating the event. - # Register the UI component as ready and post its iframe port. - @uiComponentIsReady = true - setIframePort port1 - when "setIframeFrameId" then @iframeFrameId = event.data.iframeFrameId - when "hide" then @hide() - else @handleMessage event + @iframeElement.addEventListener "load", => + # Get vimiumSecret so the iframe can determine that our message isn't the page impersonating us. + chrome.storage.local.get "vimiumSecret", ({ vimiumSecret }) => + { port1, port2 } = new MessageChannel + @iframeElement.contentWindow.postMessage vimiumSecret, chrome.runtime.getURL(""), [ port2 ] + port1.onmessage = (event) => + switch event?.data?.name ? event?.data + when "uiComponentIsReady" + # If any other frame receives the focus, then hide the UI component. + chrome.runtime.onMessage.addListener ({name, focusFrameId}) => + if name == "frameFocused" and @options?.focus and focusFrameId not in [frameId, @iframeFrameId] + @hide false + false # We will not be calling sendResponse. + # If this frame receives the focus, then hide the UI component. + window.addEventListener "focus", (event) => + if event.target == window and @options?.focus and not @options?.allowBlur + @hide false + true # Continue propagating the event. + # Set the iframe's port, thereby rendering the UI component ready. + setIframePort port1 + when "setIframeFrameId" then @iframeFrameId = event.data.iframeFrameId + when "hide" then @hide() + else @handleMessage event - # Post a message (if provided), then call continuation (if provided). + # Post a message (if provided), then call continuation (if provided). Because the constructor waits for + # documentReady(), @iframePort may not yet be ready. postMessage: (message = null, continuation = null) -> - @iframePort.use (port) => + @iframePort?.use (port) => port.postMessage message if message? continuation?() @@ -81,20 +81,22 @@ class UIComponent @showing = true hide: (shouldRefocusOriginalFrame = true) -> - if @showing - @showing = false - @toggleIframeElementClasses "vimiumUIComponentVisible", "vimiumUIComponentHidden" - if @options?.focus - @iframeElement.blur() - if shouldRefocusOriginalFrame - if @options?.sourceFrameId? - chrome.runtime.sendMessage - handler: "sendMessageToFrames", - message: name: "focusFrame", frameId: @options.sourceFrameId, forceFocusThisFrame: true - else - window.focus() - @options = null - @postMessage "hidden" # Inform the UI component that it is hidden. + # We post a non-message (null) to ensure that hide() requests cannot overtake activate() requests. + @postMessage null, => + if @showing + @showing = false + @toggleIframeElementClasses "vimiumUIComponentVisible", "vimiumUIComponentHidden" + if @options?.focus + @iframeElement.blur() + if shouldRefocusOriginalFrame + if @options?.sourceFrameId? + chrome.runtime.sendMessage + handler: "sendMessageToFrames", + message: name: "focusFrame", frameId: @options.sourceFrameId, forceFocusThisFrame: true + else + window.focus() + @options = null + @postMessage "hidden" # Inform the UI component that it is hidden. # Fetch a Vimium file/resource (such as "content_scripts/vimium.css"). # We try making an XMLHttpRequest request. That can fail (see #1817), in which case we fetch the |
