aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md7
-rw-r--r--background_scripts/commands.coffee49
-rw-r--r--lib/keyboard_utils.coffee5
-rw-r--r--lib/settings.coffee32
-rw-r--r--manifest.json4
-rw-r--r--pages/blank.html25
-rw-r--r--pages/completion_engines.html25
-rw-r--r--pages/content_script_loader.coffee28
-rw-r--r--pages/help_dialog.html25
-rw-r--r--pages/logging.html25
-rw-r--r--pages/options.html25
-rw-r--r--pages/vimium_resources.html24
-rw-r--r--tests/unit_tests/commands_test.coffee44
13 files changed, 116 insertions, 202 deletions
diff --git a/README.md b/README.md
index 6613254c..ddc12677 100644
--- a/README.md
+++ b/README.md
@@ -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", ->