diff options
| -rw-r--r-- | background_scripts/commands.coffee | 3 | ||||
| -rw-r--r-- | background_scripts/main.coffee | 5 | ||||
| -rw-r--r-- | content_scripts/ui_component.coffee | 52 | ||||
| -rw-r--r-- | content_scripts/vimium_frontend.coffee | 1 | ||||
| -rw-r--r-- | manifest.json | 1 | ||||
| -rw-r--r-- | pages/test_ui_component.coffee | 8 | ||||
| -rw-r--r-- | pages/test_ui_component.html | 11 | ||||
| -rw-r--r-- | pages/ui_component_server.coffee | 27 | ||||
| -rw-r--r-- | tests/dom_tests/chrome.coffee | 5 | ||||
| -rw-r--r-- | tests/dom_tests/dom_tests.html | 1 | ||||
| -rw-r--r-- | tests/unit_tests/test_chrome_stubs.coffee | 4 | 
11 files changed, 117 insertions, 1 deletions
| diff --git a/background_scripts/commands.coffee b/background_scripts/commands.coffee index 585ef572..63b870cc 100644 --- a/background_scripts/commands.coffee +++ b/background_scripts/commands.coffee @@ -91,6 +91,7 @@ Commands =    commandGroups:      pageNavigation:        ["scrollDown", +      "activateTestUIComponent",        "scrollUp",        "scrollLeft",        "scrollRight", @@ -252,6 +253,7 @@ defaultKeyMappings =    "m": "Marks.activateCreateMode"    "`": "Marks.activateGotoMode" +  "D": "activateTestUIComponent"  # This is a mapping of: commandIdentifier => [description, options]. @@ -263,6 +265,7 @@ commandDescriptions =    scrollUp: ["Scroll up"]    scrollLeft: ["Scroll left"]    scrollRight: ["Scroll right"] +  activateTestUIComponent: ["UI component test"]    scrollToTop: ["Scroll to the top of the page", { noRepeat: true }]    scrollToBottom: ["Scroll to the bottom of the page", { noRepeat: true }] diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index 3753fd75..d01a3f6c 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -19,6 +19,11 @@ namedKeyRegex = /^(<(?:[amc]-.|(?:[amc]-)?[a-z0-9]{2,5})>)(.*)$/  selectionChangedHandlers = []  tabLoadedHandlers = {} # tabId -> function() +# A secret, available only within the current instantiation of Vimium.  The secret is big, likely unguessable +# in practice, but less than 2^31. +chrome.storage.local.set +  vimiumSecret: Math.floor Math.random() * 2000000000 +  completionSources =    bookmarks: new BookmarkCompleter()    history: new HistoryCompleter() diff --git a/content_scripts/ui_component.coffee b/content_scripts/ui_component.coffee new file mode 100644 index 00000000..d89f0cc8 --- /dev/null +++ b/content_scripts/ui_component.coffee @@ -0,0 +1,52 @@ +class UIComponent +  iframeElement: null +  iframePort: null +  showing: null +  showStyle: "display: block;" +  hideStyle: "display: none;" + +  constructor: (iframeUrl, className, @handleMessage) -> +    @iframeElement = document.createElement "iframe" +    @iframeElement.className = className +    @iframeElement.seamless = "seamless" +    @iframeElement.src = chrome.runtime.getURL iframeUrl +    @iframeElement.addEventListener "load", => @openPort() +    document.documentElement.appendChild @iframeElement +    @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. +  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] + +  postMessage: (message) -> +    @iframePort.postMessage message + +  activate: (message) -> +    @postMessage message if message? +    if @showing +      # NOTE(smblott) Experimental.  Not sure this is a great idea. If the iframe was already showing, then +      # the user gets no visual feedback when it is re-focused.  So flash its border. +      borderWas = @iframeElement.style.border +      @iframeElement.style.border = '5px solid yellow' +      setTimeout((=> @iframeElement.style.border = borderWas), 200) +    else +      @iframeElement.setAttribute "style", @showStyle +      @showing = true +    @iframeElement.focus() + +  hide: (focusWindow=true)-> +    if @showing +      @iframeElement.setAttribute "style", @hideStyle +      window.focus() if focusWindow +      @showing = false + +root = exports ? window +root.UIComponent = UIComponent diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 2de08c39..114786e8 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -198,7 +198,6 @@ window.addEventListener "focus", ->  #  initializeOnDomReady = ->    enterInsertModeIfElementIsFocused() if isEnabledForUrl -    # Tell the background page we're in the dom ready state.    chrome.runtime.connect({ name: "domReady" })    CursorHider.init() diff --git a/manifest.json b/manifest.json index 4996d93f..96739d2e 100644 --- a/manifest.json +++ b/manifest.json @@ -37,6 +37,7 @@               "lib/dom_utils.js",               "lib/handler_stack.js",               "lib/clipboard.js", +             "content_scripts/ui_component.js",               "content_scripts/link_hints.js",               "content_scripts/vomnibar.js",               "content_scripts/scroller.js", diff --git a/pages/test_ui_component.coffee b/pages/test_ui_component.coffee new file mode 100644 index 00000000..e140fb14 --- /dev/null +++ b/pages/test_ui_component.coffee @@ -0,0 +1,8 @@ +UIComponentServer.registerHandler (event) -> +  document.body.innerHTML = event.data + +window.addEventListener "keydown", (event) -> +  if KeyboardUtils.isEscape event +    UIComponentServer.postMessage "hide" +  else +    UIComponentServer.postMessage event.keyCode diff --git a/pages/test_ui_component.html b/pages/test_ui_component.html new file mode 100644 index 00000000..06af346c --- /dev/null +++ b/pages/test_ui_component.html @@ -0,0 +1,11 @@ +<html> +  <head> +    <title>Test</title> +    <script type="text/javascript" src="../lib/keyboard_utils.js"></script> +    <script type="text/javascript" src="ui_component_server.js"></script> +    <script type="text/javascript" src="test_ui_component.js"></script> +    <link rel="stylesheet" type="text/css" href="../content_scripts/vimium.css" /> +  </head> +  <body> +  </body> +</html> diff --git a/pages/ui_component_server.coffee b/pages/ui_component_server.coffee new file mode 100644 index 00000000..8b43095b --- /dev/null +++ b/pages/ui_component_server.coffee @@ -0,0 +1,27 @@ + +# Fetch the Vimium secret, register the port recieved from the parent window, and stop listening for messages +# on the window object. vimiumSecret is accessible only within the current instantion of Vimium.  So a +# malicious host page trying to register its own port can do no better than guessing. +registerPort = (event) -> +  chrome.storage.local.get "vimiumSecret", ({vimiumSecret: secret}) -> +    return unless event.source == window.parent and event.data == secret +    UIComponentServer.portOpen event.ports[0] +    window.removeEventListener "message", registerPort + +window.addEventListener "message", registerPort + +UIComponentServer = +  ownerPagePort: null +  handleMessage: null + +  portOpen: (@ownerPagePort) -> +    @ownerPagePort.onmessage = (event) => +      @handleMessage event if @handleMessage + +  registerHandler: (@handleMessage) -> + +  postMessage: (message) -> +    @ownerPagePort.postMessage message if @ownerPagePort + +root = exports ? window +root.UIComponentServer = UIComponentServer diff --git a/tests/dom_tests/chrome.coffee b/tests/dom_tests/chrome.coffee index 15ed4339..ad4ae74b 100644 --- a/tests/dom_tests/chrome.coffee +++ b/tests/dom_tests/chrome.coffee @@ -20,5 +20,10 @@ root.chrome = {      }      sendMessage: ->      getManifest: -> +    getURL: (url) -> "../../#{url}"    } +  storage: +    local: +      get: -> +      set: ->  } diff --git a/tests/dom_tests/dom_tests.html b/tests/dom_tests/dom_tests.html index 6378807f..863c5611 100644 --- a/tests/dom_tests/dom_tests.html +++ b/tests/dom_tests/dom_tests.html @@ -34,6 +34,7 @@      <script type="text/javascript" src="../../lib/dom_utils.js"></script>      <script type="text/javascript" src="../../lib/handler_stack.js"></script>      <script type="text/javascript" src="../../lib/clipboard.js"></script> +    <script type="text/javascript" src="../../content_scripts/ui_component.js"></script>      <script type="text/javascript" src="../../content_scripts/link_hints.js"></script>      <!-- TODO(smblott) The following is being overridden by the inclusion of "../../pages/vomnibar.js", below,           because they both define the same Vomnibar class/object.  As a result, there are currently no tests diff --git a/tests/unit_tests/test_chrome_stubs.coffee b/tests/unit_tests/test_chrome_stubs.coffee index 80750337..3258bcd6 100644 --- a/tests/unit_tests/test_chrome_stubs.coffee +++ b/tests/unit_tests/test_chrome_stubs.coffee @@ -42,6 +42,10 @@ exports.chrome =      getAll: () -> true    storage: +    # chrome.storage.local +    local: +      set: -> +      # chrome.storage.onChanged      onChanged:        addListener: (func) -> @func = func | 
