diff options
| -rw-r--r-- | README.md | 7 | ||||
| -rw-r--r-- | background_scripts/commands.coffee | 49 | ||||
| -rw-r--r-- | lib/keyboard_utils.coffee | 5 | ||||
| -rw-r--r-- | lib/settings.coffee | 32 | ||||
| -rw-r--r-- | manifest.json | 4 | ||||
| -rw-r--r-- | pages/blank.html | 25 | ||||
| -rw-r--r-- | pages/completion_engines.html | 25 | ||||
| -rw-r--r-- | pages/content_script_loader.coffee | 28 | ||||
| -rw-r--r-- | pages/help_dialog.html | 25 | ||||
| -rw-r--r-- | pages/logging.html | 25 | ||||
| -rw-r--r-- | pages/options.html | 25 | ||||
| -rw-r--r-- | pages/vimium_resources.html | 24 | ||||
| -rw-r--r-- | tests/unit_tests/commands_test.coffee | 44 | 
13 files changed, 116 insertions, 202 deletions
| @@ -159,12 +159,15 @@ Please see [CONTRIBUTING.md](https://github.com/philc/vimium/blob/master/CONTRIB  Release Notes  ------------- +<!--  Changes since the previous release (not in the Chrome Store version) +--> + +1.57 (2016-10-01)  - New commands:      - `toggleMuteTab` - mute or unmute the current tab (default binding -      `<a-m>`), see also [advanced -      usage](https://github.com/philc/vimium/wiki/Tips-and-Tricks#muting-tabs). +      `<a-m>`), see also [advanced usage](https://github.com/philc/vimium/wiki/Tips-and-Tricks#muting-tabs).  - Other new features:      - You can now map `<backspace>` to a Vimium command (e.g. `map <backspace> goBack`).      - For link hints, when one hint marker is covered by another, `<Space>` now diff --git a/background_scripts/commands.coffee b/background_scripts/commands.coffee index e905c410..7ab09f24 100644 --- a/background_scripts/commands.coffee +++ b/background_scripts/commands.coffee @@ -23,13 +23,13 @@ Commands =      @availableCommands[command] = extend options, description: description -  mapKeyToCommand: ({ key, command, options }) -> +  mapKeyToCommand: ({ key, keySequence, command, options }) ->      unless @availableCommands[command]        BgUtils.log "#{command} doesn't exist!"        return      options ?= {} -    @keyToCommandRegistry[key] = extend { command, options }, @availableCommands[command] +    @keyToCommandRegistry[key] = extend { keySequence, command, options }, @availableCommands[command]    # Lower-case the appropriate portions of named keys.    # @@ -39,10 +39,20 @@ Commands =    # humans may prefer other forms <Left> or <C-a>.    # On the other hand, <c-a> and <c-A> are different named keys - for one of    # them you have to press "shift" as well. -  normalizeKey: (key) -> -    key.replace(/<[acm]-/ig, (match) -> match.toLowerCase()) -       .replace(/<([acm]-)?([a-zA-Z0-9]{2,})>/g, (match, optionalPrefix, keyName) -> -          "<" + (if optionalPrefix then optionalPrefix else "") + keyName.toLowerCase() + ">") +  # We sort modifiers here to match the order used in keyboard_utils.coffee. +  # The return value is a sequence of keys: e.g. "<Space><c-A>b" -> ["<space>", "<c-A>", "b"]. +  parseKeySequence: (key) -> +    if key.length == 0 +      [] +    # Parse "<c-a>bcd" as "<c-a>" and "bcd". +    else if 0 == key.search /^<((?:[acm]-)*(?:.|[a-zA-Z0-9]{2,}))>(.*)/i +      [modifiers..., keyChar] = RegExp.$1.split "-" +      keyChar = keyChar.toLowerCase() unless keyChar.length == 1 +      modifiers = (modifier.toLowerCase() for modifier in modifiers) +      modifiers.sort() +      ["<#{[modifiers..., keyChar].join '-'}>", @parseKeySequence(RegExp.$2)...] +    else +      [key[0], @parseKeySequence(key[1..])...]    parseCustomKeyMappings: (customKeyMappings) ->      for line in customKeyMappings.split "\n" @@ -52,13 +62,15 @@ Commands =            when "map"              [ _, key, command, optionList... ] = tokens              if command? and @availableCommands[command] -              key = @normalizeKey key +              keySequence = @parseKeySequence key +              key = keySequence.join ""                BgUtils.log "Mapping #{key} to #{command}" -              @mapKeyToCommand { key, command, options: @parseCommandOptions command, optionList } +              @mapKeyToCommand { key, command, keySequence, options: @parseCommandOptions command, optionList }            when "unmap"              if tokens.length == 2 -              key = @normalizeKey tokens[1] +              keySequence = @parseKeySequence tokens[1] +              key = keySequence.join ""                BgUtils.log "Unmapping #{key}"                delete @keyToCommandRegistry[key] @@ -90,24 +102,25 @@ Commands =    clearKeyMappingsAndSetDefaults: ->      @keyToCommandRegistry = {} -    @mapKeyToCommand { key, command } for own key, command of defaultKeyMappings +    for own key, command of defaultKeyMappings +      keySequence = @parseKeySequence key +      key = keySequence.join "" +      @mapKeyToCommand { key, command, keySequence }    # This generates a nested key-to-command mapping structure. There is an example in mode_key_handler.coffee.    generateKeyStateMapping: -> -    # Keys are either literal characters, or "named" - for example <a-b> (alt+b), <left> (left arrow) or <f12> -    # This regular expression captures two groups: the first is a named key, the second is the remainder of -    # the string. -    namedKeyRegex = /^(<(?:[amc]-.|(?:[amc]-)?[a-z0-9]{2,})>)(.*)$/      keyStateMapping = {}      for own keys, registryEntry of @keyToCommandRegistry        currentMapping = keyStateMapping -      while 0 < keys.length -        [key, keys] = if 0 == keys.search namedKeyRegex then [RegExp.$1, RegExp.$2] else [keys[0], keys[1..]] +      for key, index in registryEntry.keySequence          if currentMapping[key]?.command -          break # Do not overwrite existing command bindings, they take priority. -        else if 0 < keys.length +          # Do not overwrite existing command bindings, they take priority.  NOTE(smblott) This is the legacy +          # behaviour. +          break +        else if index < registryEntry.keySequence.length - 1            currentMapping = currentMapping[key] ?= {}          else +          delete registryEntry.keySequence # We don't need this any more.            currentMapping[key] = registryEntry      chrome.storage.local.set normalModeKeyStateMapping: keyStateMapping diff --git a/lib/keyboard_utils.coffee b/lib/keyboard_utils.coffee index dabf864d..f0e791d4 100644 --- a/lib/keyboard_utils.coffee +++ b/lib/keyboard_utils.coffee @@ -111,9 +111,10 @@ KeyboardUtils =            modifiers = []            keyChar = keyChar.toUpperCase() if event.shiftKey -          modifiers.push "m" if event.metaKey -          modifiers.push "c" if event.ctrlKey +          # These must be in alphabetical order (to match the sorted modifier order in Commands.normalizeKey).            modifiers.push "a" if event.altKey +          modifiers.push "c" if event.ctrlKey +          modifiers.push "m" if event.metaKey            keyChar = [modifiers..., keyChar].join "-"            if 1 < keyChar.length then "<#{keyChar}>" else keyChar diff --git a/lib/settings.coffee b/lib/settings.coffee index 92871ee2..e16261d0 100644 --- a/lib/settings.coffee +++ b/lib/settings.coffee @@ -184,40 +184,20 @@ Settings.init()  # Perform migration from old settings versions, if this is the background page.  if Utils.isBackgroundPage() -  if not Settings.get "settingsVersion" +  unless Settings.get "settingsVersion"      # This is a new install.  For some settings, we retain a legacy default behaviour for existing users but      # use a non-default behaviour for new users. -    # For waitForEnterForFilteredHints, we (smblott) think that "true" gives a better UX; see #1950.  However, -    # forcing the change on existing users would be unnecessarily disruptive.  So, only new users default to -    # "true". +    # For waitForEnterForFilteredHints, "true" gives a better UX; see #1950.  However, forcing the change on +    # existing users would be unnecessarily disruptive.  So, only new users default to "true".      Settings.set "waitForEnterForFilteredHints", true    # We use settingsVersion to coordinate any necessary schema changes.    Settings.set("settingsVersion", Utils.getCurrentVersion()) -  # In 1.46 we migrated the old "excludedUrls" setting to the new "exclusionRules" setting.  And we kept a -  # backup in "excludedUrlsBackup".  Now (post 1.54, post 2016-02-12) we can clear up that backup (and any -  # extraordinalrily old "excludedUrls" setting). -  Settings.nuke "excludedUrlsBackup" -  Settings.nuke "excludedUrls" - -  # Migration (post 1.54, post 2016-2-12).  Nuke legacy "findModeRawQuery" setting. -  Settings.nuke "findModeRawQuery" - -  # Migration (after 1.51, 2015/6/17). -  # Copy options with non-default values (and which are not in synced storage) to chrome.storage.local; -  # thereby making these settings accessible within content scripts. -  do (migrationKey = "copyNonDefaultsToChromeStorage-20150717") -> -    unless localStorage[migrationKey] -      chrome.storage.sync.get null, (items) -> -        unless chrome.runtime.lastError -          updates = {} -          for own key of localStorage -            if Settings.shouldSyncKey(key) and not items[key] -              updates[key] = localStorage[key] -          chrome.storage.local.set updates, -> -            localStorage[migrationKey] = not chrome.runtime.lastError +  # Remove legacy key which was used to control storage migration.  This was after 1.57 (2016-10-01), and can +  # be removed after 1.58 has been out for sufficiently long. +  Settings.nuke "copyNonDefaultsToChromeStorage-20150717"  root = exports ? window  root.Settings = Settings diff --git a/manifest.json b/manifest.json index 1409b272..a40cd134 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@  {    "manifest_version": 2,    "name": "Vimium", -  "version": "1.56", +  "version": "1.57",    "description": "The Hacker's Browser. Vimium provides keyboard shortcuts for navigation and control in the spirit of Vim.",    "icons": {  "16": "icons/icon16.png",                "48": "icons/icon48.png", @@ -35,6 +35,8 @@    ],    "content_scripts": [      { +      "_comment": +        "IMPORTANT: All resources listed here must also be listed in ./pages/vimium_resources.html.",        "matches": ["<all_urls>"],        "js": ["lib/utils.js",               "lib/keyboard_utils.js", diff --git a/pages/blank.html b/pages/blank.html index 4f0d7bfa..c238282d 100644 --- a/pages/blank.html +++ b/pages/blank.html @@ -1,30 +1,7 @@  <html>    <head>      <title>New Tab</title> -    <!-- <script src="content_script_loader.js"></script> --> -    <!-- NOTE(smblott) Temporarily, do not use the content-script loader (2016-09-27).  It appears no longer -      to be loading scripts synchronously, and so all dependent pages fail. --> -    <script src="../lib/utils.js"></script> -    <script src="../lib/keyboard_utils.js"></script> -    <script src="../lib/dom_utils.js"></script> -    <script src="../lib/rect.js"></script> -    <script src="../lib/handler_stack.js"></script> -    <script src="../lib/settings.js"></script> -    <script src="../lib/find_mode_history.js"></script> -    <script src="../content_scripts/mode.js"></script> -    <script src="../content_scripts/ui_component.js"></script> -    <script src="../content_scripts/link_hints.js"></script> -    <script src="../content_scripts/vomnibar.js"></script> -    <script src="../content_scripts/scroller.js"></script> -    <script src="../content_scripts/marks.js"></script> -    <script src="../content_scripts/mode_insert.js"></script> -    <script src="../content_scripts/mode_find.js"></script> -    <script src="../content_scripts/mode_key_handler.js"></script> -    <script src="../content_scripts/mode_visual.js"></script> -    <script src="../content_scripts/hud.js"></script> -    <script src="../content_scripts/vimium_frontend.js"></script> -    <link rel="stylesheet" type="text/css" href="../content_scripts/vimium.css" /> - +    <link rel="import" href="vimium_resources.html">    </head>    <body>    </body> diff --git a/pages/completion_engines.html b/pages/completion_engines.html index 114dc0db..d47bb87b 100644 --- a/pages/completion_engines.html +++ b/pages/completion_engines.html @@ -4,30 +4,7 @@      <!-- We re-use some styling from the options page, so that the look and feel here is similar -->      <link rel="stylesheet" type="text/css" href="options.css">      <link rel="stylesheet" type="text/css" href="completion_engines.css"> -    <!-- <script src="content_script_loader.js"></script> --> -    <!-- NOTE(smblott) Temporarily, do not use the content-script loader (2016-09-27).  It appears no longer -      to be loading scripts synchronously, and so all dependent pages fail. --> -    <script src="../lib/utils.js"></script> -    <script src="../lib/keyboard_utils.js"></script> -    <script src="../lib/dom_utils.js"></script> -    <script src="../lib/rect.js"></script> -    <script src="../lib/handler_stack.js"></script> -    <script src="../lib/settings.js"></script> -    <script src="../lib/find_mode_history.js"></script> -    <script src="../content_scripts/mode.js"></script> -    <script src="../content_scripts/ui_component.js"></script> -    <script src="../content_scripts/link_hints.js"></script> -    <script src="../content_scripts/vomnibar.js"></script> -    <script src="../content_scripts/scroller.js"></script> -    <script src="../content_scripts/marks.js"></script> -    <script src="../content_scripts/mode_insert.js"></script> -    <script src="../content_scripts/mode_find.js"></script> -    <script src="../content_scripts/mode_key_handler.js"></script> -    <script src="../content_scripts/mode_visual.js"></script> -    <script src="../content_scripts/hud.js"></script> -    <script src="../content_scripts/vimium_frontend.js"></script> -    <link rel="stylesheet" type="text/css" href="../content_scripts/vimium.css" /> - +    <link rel="import" href="vimium_resources.html">      <script src="../background_scripts/completion_engines.js"></script>      <script src="completion_engines.js"></script>    </head> diff --git a/pages/content_script_loader.coffee b/pages/content_script_loader.coffee deleted file mode 100644 index 5058bb7b..00000000 --- a/pages/content_script_loader.coffee +++ /dev/null @@ -1,28 +0,0 @@ -injectContentScripts = -> -  manifest = chrome.runtime.getManifest() -  content_scripts = manifest.content_scripts - -  insertLocation = document.head.firstChild - -  for scriptInfo in content_scripts -    continue if scriptInfo.matches.indexOf("<all_urls>") == -1 - -    if scriptInfo.js -      for script in scriptInfo.js -        scriptElement = document.createElement "script" -        scriptElement.type = "text/javascript" -        scriptElement.async = false # Don't load out of order! -        scriptElement.src = chrome.runtime.getURL script - -        insertLocation.parentElement.insertBefore scriptElement, insertLocation - -    if scriptInfo.css -      for style in scriptInfo.css -        styleElement = document.createElement "link" -        styleElement.rel = "stylesheet" -        styleElement.type = "text/css" -        styleElement.href = chrome.runtime.getURL style - -        insertLocation.parentElement.insertBefore styleElement, insertLocation - -injectContentScripts() diff --git a/pages/help_dialog.html b/pages/help_dialog.html index 1e7fdd80..c23b2ac1 100644 --- a/pages/help_dialog.html +++ b/pages/help_dialog.html @@ -1,30 +1,7 @@  <html>    <head>      <title>Vimium Help</title> -    <!-- <script src="content_script_loader.js"></script> --> -    <!-- NOTE(smblott) Temporarily, do not use the content-script loader (2016-09-27).  It appears no longer -      to be loading scripts synchronously, and so all dependent pages fail. --> -    <script src="../lib/utils.js"></script> -    <script src="../lib/keyboard_utils.js"></script> -    <script src="../lib/dom_utils.js"></script> -    <script src="../lib/rect.js"></script> -    <script src="../lib/handler_stack.js"></script> -    <script src="../lib/settings.js"></script> -    <script src="../lib/find_mode_history.js"></script> -    <script src="../content_scripts/mode.js"></script> -    <script src="../content_scripts/ui_component.js"></script> -    <script src="../content_scripts/link_hints.js"></script> -    <script src="../content_scripts/vomnibar.js"></script> -    <script src="../content_scripts/scroller.js"></script> -    <script src="../content_scripts/marks.js"></script> -    <script src="../content_scripts/mode_insert.js"></script> -    <script src="../content_scripts/mode_find.js"></script> -    <script src="../content_scripts/mode_key_handler.js"></script> -    <script src="../content_scripts/mode_visual.js"></script> -    <script src="../content_scripts/hud.js"></script> -    <script src="../content_scripts/vimium_frontend.js"></script> -    <link rel="stylesheet" type="text/css" href="../content_scripts/vimium.css" /> - +    <link rel="import" href="vimium_resources.html">      <script type="text/javascript" src="ui_component_server.js"></script>      <script type="text/javascript" src="help_dialog.js"></script>    </head> diff --git a/pages/logging.html b/pages/logging.html index dd05e819..bc4ffb80 100644 --- a/pages/logging.html +++ b/pages/logging.html @@ -1,30 +1,7 @@  <html>    <head>      <title>Vimium Logging</title> -    <!-- <script src="content_script_loader.js"></script> --> -    <!-- NOTE(smblott) Temporarily, do not use the content-script loader (2016-09-27).  It appears no longer -      to be loading scripts synchronously, and so all dependent pages fail. --> -    <script src="../lib/utils.js"></script> -    <script src="../lib/keyboard_utils.js"></script> -    <script src="../lib/dom_utils.js"></script> -    <script src="../lib/rect.js"></script> -    <script src="../lib/handler_stack.js"></script> -    <script src="../lib/settings.js"></script> -    <script src="../lib/find_mode_history.js"></script> -    <script src="../content_scripts/mode.js"></script> -    <script src="../content_scripts/ui_component.js"></script> -    <script src="../content_scripts/link_hints.js"></script> -    <script src="../content_scripts/vomnibar.js"></script> -    <script src="../content_scripts/scroller.js"></script> -    <script src="../content_scripts/marks.js"></script> -    <script src="../content_scripts/mode_insert.js"></script> -    <script src="../content_scripts/mode_find.js"></script> -    <script src="../content_scripts/mode_key_handler.js"></script> -    <script src="../content_scripts/mode_visual.js"></script> -    <script src="../content_scripts/hud.js"></script> -    <script src="../content_scripts/vimium_frontend.js"></script> -    <link rel="stylesheet" type="text/css" href="../content_scripts/vimium.css" /> - +    <link rel="import" href="vimium_resources.html">      <script src="logging.js"></script>      <style type="text/css">        body { diff --git a/pages/options.html b/pages/options.html index b24bdec2..92bed6f0 100644 --- a/pages/options.html +++ b/pages/options.html @@ -2,30 +2,7 @@    <head>      <title>Vimium Options</title>      <link rel="stylesheet" type="text/css" href="options.css"> -    <!-- <script src="content_script_loader.js"></script> --> -    <!-- NOTE(smblott) Temporarily, do not use the content-script loader (2016-09-27).  It appears no longer -      to be loading scripts synchronously, and so all dependent pages fail. --> -    <script src="../lib/utils.js"></script> -    <script src="../lib/keyboard_utils.js"></script> -    <script src="../lib/dom_utils.js"></script> -    <script src="../lib/rect.js"></script> -    <script src="../lib/handler_stack.js"></script> -    <script src="../lib/settings.js"></script> -    <script src="../lib/find_mode_history.js"></script> -    <script src="../content_scripts/mode.js"></script> -    <script src="../content_scripts/ui_component.js"></script> -    <script src="../content_scripts/link_hints.js"></script> -    <script src="../content_scripts/vomnibar.js"></script> -    <script src="../content_scripts/scroller.js"></script> -    <script src="../content_scripts/marks.js"></script> -    <script src="../content_scripts/mode_insert.js"></script> -    <script src="../content_scripts/mode_find.js"></script> -    <script src="../content_scripts/mode_key_handler.js"></script> -    <script src="../content_scripts/mode_visual.js"></script> -    <script src="../content_scripts/hud.js"></script> -    <script src="../content_scripts/vimium_frontend.js"></script> -    <link rel="stylesheet" type="text/css" href="../content_scripts/vimium.css" /> - +    <link rel="import" href="vimium_resources.html">      <script type="text/javascript" src="options.js"></script>    </head> diff --git a/pages/vimium_resources.html b/pages/vimium_resources.html new file mode 100644 index 00000000..2fad22a2 --- /dev/null +++ b/pages/vimium_resources.html @@ -0,0 +1,24 @@ +<!-- All content scripts (and CSS) listed in the manifest must be listed here too. +     These load Vimium on Vimium's internal pages (such as the options page).  --> + +<script src="/lib/utils.js"></script> +<script src="/lib/keyboard_utils.js"></script> +<script src="/lib/dom_utils.js"></script> +<script src="/lib/rect.js"></script> +<script src="/lib/handler_stack.js"></script> +<script src="/lib/settings.js"></script> +<script src="/lib/find_mode_history.js"></script> +<script src="/content_scripts/mode.js"></script> +<script src="/content_scripts/ui_component.js"></script> +<script src="/content_scripts/link_hints.js"></script> +<script src="/content_scripts/vomnibar.js"></script> +<script src="/content_scripts/scroller.js"></script> +<script src="/content_scripts/marks.js"></script> +<script src="/content_scripts/mode_insert.js"></script> +<script src="/content_scripts/mode_find.js"></script> +<script src="/content_scripts/mode_key_handler.js"></script> +<script src="/content_scripts/mode_visual.js"></script> +<script src="/content_scripts/hud.js"></script> +<script src="/content_scripts/vimium_frontend.js"></script> + +<link rel="stylesheet" type="text/css" href="/content_scripts/vimium.css" /> diff --git a/tests/unit_tests/commands_test.coffee b/tests/unit_tests/commands_test.coffee index f501a960..c8ded6a9 100644 --- a/tests/unit_tests/commands_test.coffee +++ b/tests/unit_tests/commands_test.coffee @@ -4,12 +4,46 @@ global.Settings = {postUpdateHooks: {}, get: (-> ""), set: ->}  {Commands} = require "../../background_scripts/commands.js"  context "Key mappings", +  setup -> +    @testKeySequence = (key, expectedKeyText, expectedKeyLength) -> +      keySequence = Commands.parseKeySequence key +      assert.equal expectedKeyText, keySequence.join "/" +      assert.equal expectedKeyLength, keySequence.length +    should "lowercase keys correctly", -> -    assert.equal (Commands.normalizeKey '<c-a>'), '<c-a>' -    assert.equal (Commands.normalizeKey '<C-a>'), '<c-a>' -    assert.equal (Commands.normalizeKey '<C-A>'), '<c-A>' -    assert.equal (Commands.normalizeKey '<F12>'), '<f12>' -    assert.equal (Commands.normalizeKey '<C-F12>'), '<c-f12>' +    @testKeySequence "a", "a", 1 +    @testKeySequence "A", "A", 1 +    @testKeySequence "ab", "a/b", 2 + +  should "parse keys with modifiers", -> +    @testKeySequence "<c-a>", "<c-a>", 1 +    @testKeySequence "<c-A>", "<c-A>", 1 +    @testKeySequence "<c-a><a-b>", "<c-a>/<a-b>", 2 +    @testKeySequence "<m-a>", "<m-a>", 1 + +  should "normalize with modifiers", -> +    # Modifiers should be in alphabetical order. +    @testKeySequence "<m-c-a-A>", "<a-c-m-A>", 1 + +  should "parse and normalize named keys", -> +    @testKeySequence "<space>", "<space>", 1 +    @testKeySequence "<Space>", "<space>", 1 +    @testKeySequence "<C-Space>", "<c-space>", 1 +    @testKeySequence "<f12>", "<f12>", 1 +    @testKeySequence "<F12>", "<f12>", 1 + +  should "handle angle brackets", -> +    @testKeySequence "<", "<", 1 +    @testKeySequence ">", ">", 1 + +    @testKeySequence "<<", "</<", 2 +    @testKeySequence ">>", ">/>", 2 + +    @testKeySequence "<>", "</>", 2 +    @testKeySequence "<>", "</>", 2 + +    @testKeySequence "<<space>", "</<space>", 2 +    @testKeySequence "<C->>", "<c->>", 1  context "Validate commands and options",    should "have either noRepeat or repeatLimit, but not both", -> | 
