diff options
Diffstat (limited to 'background_scripts')
| -rw-r--r-- | background_scripts/commands.coffee | 32 | ||||
| -rw-r--r-- | background_scripts/main.coffee | 173 |
2 files changed, 33 insertions, 172 deletions
diff --git a/background_scripts/commands.coffee b/background_scripts/commands.coffee index ab9992b3..7429b6f0 100644 --- a/background_scripts/commands.coffee +++ b/background_scripts/commands.coffee @@ -2,6 +2,13 @@ Commands = init: -> for own command, description of commandDescriptions @addCommand(command, description[0], description[1]) + @loadKeyMappings Settings.get "keyMappings" + Settings.postUpdateHooks["keyMappings"] = @loadKeyMappings.bind this + + loadKeyMappings: (customKeyMappings) -> + @clearKeyMappingsAndSetDefaults() + @parseCustomKeyMappings customKeyMappings + @generateKeyStateMapping() availableCommands: {} keyToCommandRegistry: {} @@ -94,6 +101,25 @@ Commands = @keyToCommandRegistry = {} @mapKeyToCommand { key, command } for own key, command of defaultKeyMappings + # 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,5})>)(.*)$/ + 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..]] + if currentMapping[key]?.command + break # Do not overwrite existing command bindings, they take priority. + else if 0 < keys.length + currentMapping = currentMapping[key] ?= {} + else + currentMapping[key] = registryEntry + chrome.storage.local.set normalModeKeyStateMapping: keyStateMapping + # An ordered listing of all available commands, grouped by type. This is the order they will # be shown in the help page. commandGroups: @@ -371,11 +397,5 @@ commandDescriptions = Commands.init() -# Register postUpdateHook for keyMappings setting. -Settings.postUpdateHooks["keyMappings"] = (value) -> - Commands.clearKeyMappingsAndSetDefaults() - Commands.parseCustomKeyMappings value - refreshCompletionKeysAfterMappingSave() - root = exports ? window root.Commands = Commands diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index 7c970866..49199cae 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -19,17 +19,9 @@ chrome.runtime.onInstalled.addListener ({ reason }) -> func tab.id, { file: file, allFrames: contentScripts.all_frames }, checkLastRuntimeError currentVersion = Utils.getCurrentVersion() -keyQueue = "" # Queue of keys typed -validFirstKeys = {} -singleKeyCommands = [] frameIdsForTab = {} root.urlForTab = {} -# 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,5})>)(.*)$/ - # This is exported for use by "marks.coffee". root.tabLoadedHandlers = {} # tabId -> function() @@ -189,14 +181,6 @@ fetchFileContents = (extensionFileName) -> req.send() req.responseText -# -# Returns the keys that can complete a valid command given the current key queue. -# -getCompletionKeysRequest = (request, keysToCheck = "") -> - name: "refreshCompletionKeys" - completionKeys: generateCompletionKeys(keysToCheck) - validFirstKeys: validFirstKeys - TabOperations = # Opens the url in the current tab. openUrlInCurrentTab: (request, callback = (->)) -> @@ -385,148 +369,13 @@ chrome.tabs.onUpdated.addListener (tabId, changeInfo, tab) -> # End action functions -splitKeyIntoFirstAndSecond = (key) -> - if (key.search(namedKeyRegex) == 0) - { first: RegExp.$1, second: RegExp.$2 } +runBackgroundCommand = ({frameId, registryEntry, count}, sender) -> + if registryEntry.passCountToFunction + BackgroundCommands[registryEntry.command] count, frameId + else if registryEntry.noRepeat + BackgroundCommands[registryEntry.command] frameId else - { first: key[0], second: key.slice(1) } - -getActualKeyStrokeLength = (key) -> - if (key.search(namedKeyRegex) == 0) - 1 + getActualKeyStrokeLength(RegExp.$2) - else - key.length - -populateValidFirstKeys = -> - for own key of Commands.keyToCommandRegistry - if (getActualKeyStrokeLength(key) == 2) - validFirstKeys[splitKeyIntoFirstAndSecond(key).first] = true - -populateSingleKeyCommands = -> - for own key of Commands.keyToCommandRegistry - if (getActualKeyStrokeLength(key) == 1) - singleKeyCommands.push(key) - -# Invoked by options.coffee. -root.refreshCompletionKeysAfterMappingSave = -> - validFirstKeys = {} - singleKeyCommands = [] - - populateValidFirstKeys() - populateSingleKeyCommands() - - sendRequestToAllTabs(getCompletionKeysRequest()) - -# Generates a list of keys that can complete a valid command given the current key queue or the one passed in -generateCompletionKeys = (keysToCheck) -> - splitHash = splitKeyQueue(keysToCheck || keyQueue) - command = splitHash.command - count = splitHash.count - - completionKeys = singleKeyCommands.slice(0) - - if (getActualKeyStrokeLength(command) == 1) - for own key of Commands.keyToCommandRegistry - splitKey = splitKeyIntoFirstAndSecond(key) - if (splitKey.first == command) - completionKeys.push(splitKey.second) - - completionKeys - -splitKeyQueue = (queue) -> - match = /([1-9][0-9]*)?(.*)/.exec(queue) - count = parseInt(match[1], 10) - command = match[2] - - { count: count, command: command } - -handleKeyDown = (sender) -> (request, port) -> - key = request.keyChar - if (key == "<ESC>") - logMessage "clearing keyQueue", sender - keyQueue = "" - else - logMessage "checking keyQueue: [#{keyQueue + key}]", sender - keyQueue = checkKeyQueue(keyQueue + key, port.sender.tab.id, request.frameId) - logMessage "new KeyQueue: #{keyQueue}", sender - # Tell the content script whether there are keys in the queue. - # FIXME: There is a race condition here. The behaviour in the content script depends upon whether this message gets - # back there before or after the next keystroke. - # That being said, I suspect there are other similar race conditions here, for example in checkKeyQueue(). - # Steve (23 Aug, 14). - chrome.tabs.sendMessage(port.sender.tab.id, - name: "currentKeyQueue", - keyQueue: keyQueue) - -checkKeyQueue = (keysToCheck, tabId, frameId) -> - refreshedCompletionKeys = false - splitHash = splitKeyQueue(keysToCheck) - command = splitHash.command - count = splitHash.count - - return keysToCheck if command.length == 0 - count = 1 if isNaN(count) - - if (Commands.keyToCommandRegistry[command]) - registryEntry = Commands.keyToCommandRegistry[command] - runCommand = true - count *= registryEntry.options.count ? 1 - - if registryEntry.noRepeat - count = 1 - else if registryEntry.repeatLimit and count > registryEntry.repeatLimit - runCommand = confirm """ - You have asked Vimium to perform #{count} repeats of the command: - #{Commands.availableCommands[registryEntry.command].description} - - Are you sure you want to continue? - """ - - if runCommand - if not registryEntry.isBackgroundCommand - chrome.tabs.sendMessage tabId, - name: "executePageCommand" - command: registryEntry.command - frameId: frameId - count: count - completionKeys: generateCompletionKeys "" - registryEntry: registryEntry - refreshedCompletionKeys = true - else - if registryEntry.passCountToFunction - BackgroundCommands[registryEntry.command](count, frameId) - else if registryEntry.noRepeat - BackgroundCommands[registryEntry.command](frameId) - else - repeatFunction(BackgroundCommands[registryEntry.command], count, 0, frameId) - - newKeyQueue = "" - else if (getActualKeyStrokeLength(command) > 1) - splitKey = splitKeyIntoFirstAndSecond(command) - - # The second key might be a valid command by its self. - if (Commands.keyToCommandRegistry[splitKey.second]) - newKeyQueue = checkKeyQueue(splitKey.second, tabId, frameId) - else - newKeyQueue = (if validFirstKeys[splitKey.second] then splitKey.second else "") - else - newKeyQueue = (if validFirstKeys[command] then count.toString() + command else "") - - # If we haven't sent the completion keys piggybacked on executePageCommand, - # send them by themselves. - unless refreshedCompletionKeys - chrome.tabs.sendMessage(tabId, getCompletionKeysRequest(null, newKeyQueue), null) - - newKeyQueue - -# -# Message all tabs. Args should be the arguments hash used by the Chrome sendRequest API. -# -sendRequestToAllTabs = (args) -> - chrome.windows.getAll({ populate: true }, (windows) -> - for window in windows - for tab in window.tabs - chrome.tabs.sendMessage(tab.id, args, null)) + repeatFunction BackgroundCommands[registryEntry.command], count, 0, frameId openOptionsPageInNewTab = -> chrome.tabs.getSelected(null, (tab) -> @@ -574,11 +423,10 @@ bgLog = (request, sender) -> # Port handler mapping portHandlers = - keyDown: handleKeyDown, completions: handleCompletions sendRequestHandlers = - getCompletionKeys: getCompletionKeysRequest + runBackgroundCommand: runBackgroundCommand getCurrentTabUrl: getCurrentTabUrl openUrlInNewTab: TabOperations.openUrlInNewTab openUrlInIncognito: TabOperations.openUrlInIncognito @@ -624,13 +472,6 @@ window.runTests = -> open(chrome.runtime.getURL('tests/dom_tests/dom_tests.html' # # Begin initialization. # -Commands.clearKeyMappingsAndSetDefaults() - -if Settings.has("keyMappings") - Commands.parseCustomKeyMappings(Settings.get("keyMappings")) - -populateValidFirstKeys() -populateSingleKeyCommands() # Show notification on upgrade. showUpgradeMessage = -> |
