diff options
| -rw-r--r-- | content_scripts/ui_component.coffee | 67 | ||||
| -rw-r--r-- | tests/dom_tests/phantom_runner.coffee | 29 | 
2 files changed, 53 insertions, 43 deletions
diff --git a/content_scripts/ui_component.coffee b/content_scripts/ui_component.coffee index e7cd3f82..ba141b23 100644 --- a/content_scripts/ui_component.coffee +++ b/content_scripts/ui_component.coffee @@ -15,19 +15,33 @@ class UIComponent      extend @iframeElement,        className: className        seamless: "seamless" -      src: chrome.runtime.getURL iframeUrl -    @iframeElement.addEventListener "load", => @openPort()      shadowWrapper = document.createElement "div"      # PhantomJS doesn't support createShadowRoot, so guard against its non-existance.      @shadowDOM = shadowWrapper.createShadowRoot?() ? shadowWrapper      @shadowDOM.appendChild styleSheet      @shadowDOM.appendChild @iframeElement -    document.documentElement.appendChild shadowWrapper      @showing = true # The iframe is visible now.      # Hide the iframe, but don't interfere with the focus.      @hide false +    # 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 +          port1.onmessage = (event) => @handleMessage event +          @iframeElement.contentWindow.postMessage vimiumSecret, chrome.runtime.getURL(""), [ port2 ] +          setIframePort port1 +      # If any other frame in the current tab receives the focus, then we hide the UI component.      # NOTE(smblott) This is correct for the vomnibar, but might be incorrect (and need to be revisited) for      # other UI components. @@ -35,40 +49,31 @@ class UIComponent        @postMessage "hide" if @showing and request.name == "frameFocused" and request.focusFrameId != frameId        false # Free up the sendResponse handler. -  # Open a port and pass it to the iframe via window.postMessage. -  openPort: -> -    messageChannel = new MessageChannel() -    @iframePort = messageChannel.port1 -    @iframePort.onmessage = (event) => @handleMessage event - -    # Get vimiumSecret so the iframe can determine that our message isn't the page impersonating us. -    chrome.storage.local.get "vimiumSecret", ({vimiumSecret: secret}) => -      @iframeElement.contentWindow.postMessage secret, chrome.runtime.getURL(""), [messageChannel.port2] - -  # Posts a message; returns true if the message was sent, false otherwise. -  postMessage: (message) -> -    # We use "?" here because the iframe port is initialized asynchronously, and may not yet be ready. -    @iframePort?.postMessage message -    @iframePort? +  # Posts a message (if one is provided), then calls continuation (if provided).  The continuation is only +  # ever called *after* the message has been posted. +  postMessage: (message = null, continuation = null) -> +    @iframePort.use (port) => +      port.postMessage message if message? +      continuation?()    activate: (@options) -> -    if @postMessage @options +    @postMessage @options, =>        @show() unless @showing        @iframeElement.focus()    show: (message) -> -    @postMessage message if message? -    @iframeElement.classList.remove "vimiumUIComponentHidden" -    @iframeElement.classList.add "vimiumUIComponentVisible" -    # The window may not have the focus.  We focus it now, to prevent the "focus" listener below from firing -    # immediately. -    window.focus() -    window.addEventListener "focus", @onFocus = (event) => -      if event.target == window -        window.removeEventListener "focus", @onFocus -        @onFocus = null -        @postMessage "hide" -    @showing = true +    @postMessage message, => +      @iframeElement.classList.remove "vimiumUIComponentHidden" +      @iframeElement.classList.add "vimiumUIComponentVisible" +      # The window may not have the focus.  We focus it now, to prevent the "focus" listener below from firing +      # immediately. +      window.focus() +      window.addEventListener "focus", @onFocus = (event) => +        if event.target == window +          window.removeEventListener "focus", @onFocus +          @onFocus = null +          @postMessage "hide" +      @showing = true    hide: (focusWindow = true)->      @refocusSourceFrame @options?.sourceFrameId if focusWindow diff --git a/tests/dom_tests/phantom_runner.coffee b/tests/dom_tests/phantom_runner.coffee index 93218724..e0382a35 100644 --- a/tests/dom_tests/phantom_runner.coffee +++ b/tests/dom_tests/phantom_runner.coffee @@ -37,15 +37,20 @@ page.open testfile, (status) ->      console.log 'Unable to load tests.'      phantom.exit 1 -  testsFailed = page.evaluate -> -    Tests.run() -    return Tests.testsFailed - -  if system.args[1] == '--coverage' -    data = page.evaluate -> JSON.stringify _$jscoverage -    fs.write dirname + 'dom_tests_coverage.json', data, 'w' - -  if testsFailed > 0 -    phantom.exit 1 -  else -    phantom.exit 0 +  runTests = -> +    testsFailed = page.evaluate -> +      Tests.run() +      return Tests.testsFailed + +    if system.args[1] == '--coverage' +      data = page.evaluate -> JSON.stringify _$jscoverage +      fs.write dirname + 'dom_tests_coverage.json', data, 'w' + +    if testsFailed > 0 +      phantom.exit 1 +    else +      phantom.exit 0 + +  # We add a short delay to allow asynchronous initialization (that is, initialization which happens on +  # "nextTick") to complete. +  setTimeout runTests, 10  | 
