diff options
Diffstat (limited to 'background_scripts/main.coffee')
| -rw-r--r-- | background_scripts/main.coffee | 182 |
1 files changed, 120 insertions, 62 deletions
diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index f564f477..352cfa48 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -24,9 +24,11 @@ completionSources = history: new HistoryCompleter() domains: new DomainCompleter() tabs: new TabCompleter() + seachEngines: new SearchEngineCompleter() completers = omni: new MultiCompleter([ + completionSources.seachEngines, completionSources.bookmarks, completionSources.history, completionSources.domains]) @@ -67,30 +69,31 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) -> getCurrentTabUrl = (request, sender) -> sender.tab.url # -# Checks the user's preferences in local storage to determine if Vimium is enabled for the given URL. +# Checks the user's preferences in local storage to determine if Vimium is enabled for the given URL, and +# whether any keys should be passed through to the underlying page. # -isEnabledForUrl = (request) -> - # excludedUrls are stored as a series of URL expressions separated by newlines. - excludedUrls = Settings.get("excludedUrls").split("\n") - isEnabled = true - for url in excludedUrls - # The user can add "*" to the URL which means ".*" - regexp = new RegExp("^" + url.replace(/\*/g, ".*") + "$") - isEnabled = false if request.url.match(regexp) - { isEnabledForUrl: isEnabled } - -# Called by the popup UI. Strips leading/trailing whitespace and ignores empty strings. -root.addExcludedUrl = (url) -> - return unless url = url.trim() - - excludedUrls = Settings.get("excludedUrls") - return if excludedUrls.indexOf(url) >= 0 - - excludedUrls += "\n" + url - Settings.set("excludedUrls", excludedUrls) - - chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT, active: true }, - (tabs) -> updateActiveState(tabs[0].id)) +root.isEnabledForUrl = isEnabledForUrl = (request) -> + 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) @@ -217,6 +220,12 @@ repeatFunction = (func, totalCount, currentCount, frameId) -> -> repeatFunction(func, totalCount, currentCount + 1, frameId), frameId) +moveTab = (callback, direction) -> + chrome.tabs.getSelected(null, (tab) -> + # Use Math.max to prevent -1 as the new index, otherwise the tab of index n will wrap to the far RHS when + # moved left by exactly (n+1) places. + chrome.tabs.move(tab.id, {index: Math.max(0, tab.index + direction) }, callback)) + # Start action functions # These are commands which are bound to keystroke which must be handled by the background page. They are @@ -228,8 +237,9 @@ BackgroundCommands = chrome.tabs.duplicate(tab.id) selectionChangedHandlers.push(callback)) moveTabToNewWindow: (callback) -> - chrome.tabs.getSelected(null, (tab) -> - chrome.windows.create({tabId: tab.id})) + chrome.tabs.query {active: true, currentWindow: true}, (tabs) -> + tab = tabs[0] + chrome.windows.create {tabId: tab.id, incognito: tab.incognito} nextTab: (callback) -> selectTab(callback, "next") previousTab: (callback) -> selectTab(callback, "previous") firstTab: (callback) -> selectTab(callback, "first") @@ -238,29 +248,38 @@ BackgroundCommands = chrome.tabs.getSelected(null, (tab) -> chrome.tabs.remove(tab.id)) restoreTab: (callback) -> - # TODO(ilya): Should this be getLastFocused instead? - chrome.windows.getCurrent((window) -> - return unless (tabQueue[window.id] && tabQueue[window.id].length > 0) - tabQueueEntry = tabQueue[window.id].pop() - # Clean out the tabQueue so we don't have unused windows laying about. - delete tabQueue[window.id] if (tabQueue[window.id].length == 0) - - # We have to chain a few callbacks to set the appropriate scroll position. We can't just wait until the - # tab is created because the content script is not available during the "loading" state. We need to - # wait until that's over before we can call setScrollPosition. - chrome.tabs.create({ url: tabQueueEntry.url, index: tabQueueEntry.positionIndex }, (tab) -> - tabLoadedHandlers[tab.id] = -> - chrome.tabs.sendMessage(tab.id, - name: "setScrollPosition", - scrollX: tabQueueEntry.scrollX, - scrollY: tabQueueEntry.scrollY) - callback())) + # TODO: remove if-else -block when adopted into stable + if chrome.sessions + chrome.sessions.restore(null, (restoredSession) -> callback()) + else + # TODO(ilya): Should this be getLastFocused instead? + chrome.windows.getCurrent((window) -> + return unless (tabQueue[window.id] && tabQueue[window.id].length > 0) + tabQueueEntry = tabQueue[window.id].pop() + # Clean out the tabQueue so we don't have unused windows laying about. + delete tabQueue[window.id] if (tabQueue[window.id].length == 0) + + # We have to chain a few callbacks to set the appropriate scroll position. We can't just wait until the + # tab is created because the content script is not available during the "loading" state. We need to + # wait until that's over before we can call setScrollPosition. + chrome.tabs.create({ url: tabQueueEntry.url, index: tabQueueEntry.positionIndex }, (tab) -> + tabLoadedHandlers[tab.id] = -> + chrome.tabs.sendRequest(tab.id, + name: "setScrollPosition", + scrollX: tabQueueEntry.scrollX, + scrollY: tabQueueEntry.scrollY) + callback())) openCopiedUrlInCurrentTab: (request) -> openUrlInCurrentTab({ url: Clipboard.paste() }) openCopiedUrlInNewTab: (request) -> openUrlInNewTab({ url: Clipboard.paste() }) + togglePinTab: (request) -> + chrome.tabs.getSelected(null, (tab) -> + chrome.tabs.update(tab.id, { pinned: !tab.pinned })) showHelp: (callback, frameId) -> chrome.tabs.getSelected(null, (tab) -> chrome.tabs.sendMessage(tab.id, { name: "toggleHelpDialog", dialogHtml: helpDialogHtml(), frameId:frameId })) + moveTabLeft: (count) -> moveTab(null, -count) + moveTabRight: (count) -> moveTab(null, count) nextFrame: (count) -> chrome.tabs.getSelected(null, (tab) -> frames = framesForTab[tab.id].frames @@ -272,6 +291,30 @@ BackgroundCommands = chrome.tabs.sendMessage(tab.id, { name: "focusFrame", frameId: frames[newIndex].id, highlight: true })) + closeTabsOnLeft: -> removeTabsRelative "before" + closeTabsOnRight: -> removeTabsRelative "after" + closeOtherTabs: -> removeTabsRelative "both" + +# Remove tabs before, after, or either side of the currently active tab +removeTabsRelative = (direction) -> + chrome.tabs.query {currentWindow: true}, (tabs) -> + chrome.tabs.query {currentWindow: true, active: true}, (activeTabs) -> + activeTabIndex = activeTabs[0].index + + shouldDelete = switch direction + when "before" + (index) -> index < activeTabIndex + when "after" + (index) -> index > activeTabIndex + when "both" + (index) -> index != activeTabIndex + + toRemove = [] + for tab in tabs + if not tab.pinned and shouldDelete tab.index + toRemove.push tab.id + chrome.tabs.remove toRemove + # Selects a tab before or after the currently selected tab. # - direction: "next", "previous", "first" or "last". selectTab = (callback, direction) -> @@ -304,32 +347,36 @@ updateOpenTabs = (tab) -> # Frames are recreated on refresh delete framesForTab[tab.id] -# Updates the browserAction icon to indicated whether Vimium is enabled or disabled on the current page. -# Also disables Vimium if it is currently enabled but should be disabled according to the url blacklist. +setBrowserActionIcon = (tabId,path) -> + chrome.browserAction.setIcon({ tabId: tabId, path: path }) + +# Updates the browserAction icon to indicate whether Vimium is enabled or disabled on the current page. +# Also propagates new enabled/disabled/passkeys state to active window, if necessary. # This lets you disable Vimium on a page without needing to reload. -# -# Three situations are considered: -# 1. Active tab is disabled -> disable icon -# 2. Active tab is enabled and should be enabled -> enable icon -# 3. Active tab is enabled but should be disabled -> disable icon and disable vimium updateActiveState = (tabId) -> enabledIcon = "icons/browser_action_enabled.png" disabledIcon = "icons/browser_action_disabled.png" - chrome.tabs.get(tabId, (tab) -> - # Default to disabled state in case we can't connect to Vimium, primarily for the "New Tab" page. - chrome.browserAction.setIcon({ path: disabledIcon }) - chrome.tabs.sendMessage(tabId, { name: "getActiveState" }, (response) -> - isCurrentlyEnabled = (response? && response.enabled) - shouldBeEnabled = isEnabledForUrl({url: tab.url}).isEnabledForUrl - - if (isCurrentlyEnabled) - if (shouldBeEnabled) - chrome.browserAction.setIcon({ path: enabledIcon }) + partialIcon = "icons/browser_action_partial.png" + chrome.tabs.get tabId, (tab) -> + chrome.tabs.sendMessage tabId, { name: "getActiveState" }, (response) -> + if response + isCurrentlyEnabled = response.enabled + currentPasskeys = response.passKeys + config = isEnabledForUrl({url: tab.url}) + enabled = config.isEnabledForUrl + passKeys = config.passKeys + if (enabled and passKeys) + setBrowserActionIcon(tabId,partialIcon) + else if (enabled) + setBrowserActionIcon(tabId,enabledIcon) else - chrome.browserAction.setIcon({ path: disabledIcon }) - chrome.tabs.sendMessage(tabId, { name: "disableVimium" }) + setBrowserActionIcon(tabId,disabledIcon) + # Propagate the new state only if it has changed. + if (isCurrentlyEnabled != enabled || currentPasskeys != passKeys) + chrome.tabs.sendMessage(tabId, { name: "setState", enabled: enabled, passKeys: passKeys }) else - chrome.browserAction.setIcon({ path: disabledIcon }))) + # We didn't get a response from the front end, so Vimium isn't running. + setBrowserActionIcon(tabId,disabledIcon) handleUpdateScrollPosition = (request, sender) -> updateScrollPosition(sender.tab, request.scrollX, request.scrollY) @@ -458,6 +505,14 @@ handleKeyDown = (request, port) -> console.log("checking keyQueue: [", keyQueue + key, "]") keyQueue = checkKeyQueue(keyQueue + key, port.sender.tab.id, request.frameId) console.log("new KeyQueue: " + keyQueue) + # 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 @@ -596,3 +651,6 @@ chrome.windows.getAll { populate: true }, (windows) -> createScrollPositionHandler = -> (response) -> updateScrollPosition(tab, response.scrollX, response.scrollY) if response? chrome.tabs.sendMessage(tab.id, { name: "getScrollPosition" }, createScrollPositionHandler()) + +# Start pulling changes from synchronized storage. +Sync.init() |
