aboutsummaryrefslogtreecommitdiffstats
path: root/background_scripts
diff options
context:
space:
mode:
Diffstat (limited to 'background_scripts')
-rw-r--r--background_scripts/exclusions.coffee70
-rw-r--r--background_scripts/main.coffee89
-rw-r--r--background_scripts/settings.coffee17
3 files changed, 108 insertions, 68 deletions
diff --git a/background_scripts/exclusions.coffee b/background_scripts/exclusions.coffee
new file mode 100644
index 00000000..3a8ef1e7
--- /dev/null
+++ b/background_scripts/exclusions.coffee
@@ -0,0 +1,70 @@
+root = exports ? window
+
+RegexpCache =
+ cache: {}
+ get: (pattern) ->
+ if regexp = @cache[pattern]
+ regexp
+ else
+ @cache[pattern] = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$")
+
+# The Exclusions class manages the exclusion rule setting.
+# An exclusion is an object with two attributes: pattern and passKeys.
+# The exclusions are an array of such objects (because the order matters).
+
+root.Exclusions = Exclusions =
+
+ rules: Settings.get("exclusionRules")
+
+ # Return the first exclusion rule matching the URL, or null.
+ getRule: (url) ->
+ for rule in @rules
+ return rule if url.match(RegexpCache.get(rule.pattern))
+ return null
+
+ setRules: (rules) ->
+ # Callers map a rule to null to have it deleted, and rules without a pattern are useless.
+ @rules = rules.filter (rule) -> rule and rule.pattern
+ Settings.set("exclusionRules", @rules)
+
+ postUpdateHook: (rules) ->
+ @rules = rules
+
+ # Update an existing rule or add a new rule.
+ updateOrAdd: (newRule) ->
+ seen = false
+ @rules.push(newRule)
+ @setRules @rules.map (rule) ->
+ if rule.pattern == newRule.pattern
+ if seen then null else seen = newRule
+ else
+ rule
+
+ remove: (pattern) ->
+ @setRules(@rules.filter((rule) -> rule and rule.pattern != pattern))
+
+# Development and debug only.
+# Enable this (temporarily) to restore legacy exclusion rules from backup.
+if false and Settings.has("excludedUrlsBackup")
+ Settings.clear("exclusionRules")
+ Settings.set("excludedUrls", Settings.get("excludedUrlsBackup"))
+
+if not Settings.has("exclusionRules") and Settings.has("excludedUrls")
+ # Migration from the legacy representation of exclusion rules.
+ #
+ # In Vimium 1.45 and in github/master on 27 August, 2014, exclusion rules are represented by the setting:
+ # excludedUrls: "http*://www.google.com/reader/*\nhttp*://mail.google.com/* jk"
+ #
+ # The new (equivalent) settings is:
+ # exclusionRules: [ { pattern: "http*://www.google.com/reader/*", passKeys: "" }, { pattern: "http*://mail.google.com/*", passKeys: "jk" } ]
+
+ parseLegacyRules = (lines) ->
+ for line in lines.trim().split("\n").map((line) -> line.trim())
+ if line.length and line.indexOf("#") != 0 and line.indexOf('"') != 0
+ parse = line.split(/\s+/)
+ { pattern: parse[0], passKeys: parse[1..].join("") }
+
+ Exclusions.setRules(parseLegacyRules(Settings.get("excludedUrls")))
+ # We'll keep a backup of the "excludedUrls" setting, just in case.
+ Settings.set("excludedUrlsBackup", Settings.get("excludedUrls")) if not Settings.has("excludedUrlsBackup")
+ Settings.clear("excludedUrls")
diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee
index dda1beae..352cfa48 100644
--- a/background_scripts/main.coffee
+++ b/background_scripts/main.coffee
@@ -73,57 +73,27 @@ getCurrentTabUrl = (request, sender) -> sender.tab.url
# whether any keys should be passed through to the underlying page.
#
root.isEnabledForUrl = isEnabledForUrl = (request) ->
- # Excluded URLs are stored as a series of URL expressions and optional passKeys, separated by newlines.
- # Lines for which the first non-blank character is "#" or '"' are comments.
- excludedLines = (line.trim() for line in Settings.get("excludedUrls").split("\n"))
- excludedSpecs = (line.split(/\s+/) for line in excludedLines when line and line.indexOf("#") != 0 and line.indexOf('"') != 0)
- for spec in excludedSpecs
- url = spec[0]
- # The user can add "*" to the URL which means ".*"
- regexp = new RegExp("^" + url.replace(/\*/g, ".*") + "$")
- if request.url.match(regexp)
- passKeys = spec[1..].join("")
- if passKeys
- # Enabled, but not for these keys.
- return { isEnabledForUrl: true, passKeys: passKeys, matchingUrl: url }
- # Wholly disabled.
- return { isEnabledForUrl: false, passKeys: "", matchingUrl: url }
- # Enabled (the default).
- { isEnabledForUrl: true, passKeys: undefined, matchingUrl: undefined }
-
-# Called by the popup UI. Strips leading/trailing whitespace and ignores new empty strings. If an existing
-# exclusion rule has been changed, then the existing rule is updated. Otherwise, the new rule is added.
-root.addExcludedUrl = (url) ->
- return unless url = url.trim()
-
- parse = url.split(/\s+/)
- url = parse[0]
- passKeys = parse[1..].join(" ")
- newSpec = (if passKeys then url + " " + passKeys else url)
-
- excludedUrls = Settings.get("excludedUrls").split("\n")
- excludedUrls.push(newSpec)
-
- # Update excludedUrls.
- # Try to keep the list as unchanged as possible: same order, same comments, same blank lines.
- seenNew = false
- newExcludedUrls = []
- for spec in excludedUrls
- spec = spec.trim()
- parse = spec.split(/\s+/)
- # Keep just one copy of the new exclusion rule.
- if parse.length and parse[0] == url
- if !seenNew
- newExcludedUrls.push(newSpec)
- seenNew = true
- continue
- # And just keep everything else.
- newExcludedUrls.push(spec)
-
- Settings.set("excludedUrls", newExcludedUrls.join("\n"))
-
- chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT, active: true },
- (tabs) -> updateActiveState(tabs[0].id))
+ rule = Exclusions.getRule(request.url)
+ {
+ rule: rule
+ isEnabledForUrl: not rule or rule.passKeys
+ passKeys: rule?.passKeys or ""
+ }
+
+# Called by the popup UI.
+# If the URL pattern matches an existing rule, then the existing rule is updated. Otherwise, a new rule is created.
+root.addExclusionRule = (pattern,passKeys) ->
+ if pattern = pattern.trim()
+ Exclusions.updateOrAdd({ pattern: pattern, passKeys: passKeys })
+ chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT, active: true },
+ (tabs) -> updateActiveState(tabs[0].id))
+
+# Called by the popup UI. Remove all existing exclusion rules with this pattern.
+root.removeExclusionRule = (pattern) ->
+ if pattern = pattern.trim()
+ Exclusions.remove(pattern)
+ chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT, active: true },
+ (tabs) -> updateActiveState(tabs[0].id))
saveHelpDialogSettings = (request) ->
Settings.set("helpDialog_showAdvancedCommands", request.showAdvancedCommands)
@@ -389,24 +359,21 @@ updateActiveState = (tabId) ->
partialIcon = "icons/browser_action_partial.png"
chrome.tabs.get tabId, (tab) ->
chrome.tabs.sendMessage tabId, { name: "getActiveState" }, (response) ->
- console.log response
if response
isCurrentlyEnabled = response.enabled
currentPasskeys = response.passKeys
- # TODO:
- # isEnabledForUrl is quite expensive to run each time we change tab. Perhaps memoize it?
- shouldHaveConfig = isEnabledForUrl({url: tab.url})
- shouldBeEnabled = shouldHaveConfig.isEnabledForUrl
- shouldHavePassKeys = shouldHaveConfig.passKeys
- if (shouldBeEnabled and shouldHavePassKeys)
+ config = isEnabledForUrl({url: tab.url})
+ enabled = config.isEnabledForUrl
+ passKeys = config.passKeys
+ if (enabled and passKeys)
setBrowserActionIcon(tabId,partialIcon)
- else if (shouldBeEnabled)
+ else if (enabled)
setBrowserActionIcon(tabId,enabledIcon)
else
setBrowserActionIcon(tabId,disabledIcon)
# Propagate the new state only if it has changed.
- if (isCurrentlyEnabled != shouldBeEnabled || currentPasskeys != shouldHavePassKeys)
- chrome.tabs.sendMessage(tabId, { name: "setState", enabled: shouldBeEnabled, passKeys: shouldHavePassKeys })
+ if (isCurrentlyEnabled != enabled || currentPasskeys != passKeys)
+ chrome.tabs.sendMessage(tabId, { name: "setState", enabled: enabled, passKeys: passKeys })
else
# We didn't get a response from the front end, so Vimium isn't running.
setBrowserActionIcon(tabId,disabledIcon)
diff --git a/background_scripts/settings.coffee b/background_scripts/settings.coffee
index 34d6e879..7150fcba 100644
--- a/background_scripts/settings.coffee
+++ b/background_scripts/settings.coffee
@@ -35,6 +35,9 @@ root.Settings = Settings =
searchEngines: (value) ->
root.Settings.parseSearchEngines value
+ exclusionRules: (value) ->
+ root.Exclusions.postUpdateHook value
+
# postUpdateHooks convenience wrapper
performPostUpdateHook: (key, value) ->
@postUpdateHooks[key] value if @postUpdateHooks[key]
@@ -58,6 +61,7 @@ root.Settings = Settings =
# or strings
defaults:
scrollStepSize: 60
+ keyMappings: "# Insert your prefered key mappings here."
linkHintCharacters: "sadfjklewcmpgh"
linkHintNumbers: "0123456789"
filterLinkHints: false
@@ -81,14 +85,13 @@ root.Settings = Settings =
div > .vimiumHintMarker > .matchingCharacter {
}
"""
- excludedUrls:
- """
- # Disable Vimium on Gmail:
- http*://mail.google.com/*
+ # Default exclusion rules.
+ exclusionRules:
+ [
+ # Disable Vimium on Gmail.
+ { pattern: "http*://mail.google.com/*", passKeys: "" }
+ ]
- # Use Facebook's own j/k bindings:
- http*://www.facebook.com/* jk
- """
# NOTE: If a page contains both a single angle-bracket link and a double angle-bracket link, then in
# most cases the single bracket link will be "prev/next page" and the double bracket link will be
# "first/last page", so we put the single bracket first in the pattern string so that it gets searched