diff options
Diffstat (limited to 'background_scripts')
| -rw-r--r-- | background_scripts/completion.coffee | 26 | ||||
| -rw-r--r-- | background_scripts/main.coffee | 129 | ||||
| -rw-r--r-- | background_scripts/settings.coffee | 23 | 
3 files changed, 72 insertions, 106 deletions
| diff --git a/background_scripts/completion.coffee b/background_scripts/completion.coffee index 177892fb..6a1c0d30 100644 --- a/background_scripts/completion.coffee +++ b/background_scripts/completion.coffee @@ -204,7 +204,7 @@ class DomainCompleter    domains: null    filter: (queryTerms, onComplete) -> -    return onComplete([]) if queryTerms.length > 1 +    return onComplete([]) unless queryTerms.length == 1      if @domains        @performSearch(queryTerms, onComplete)      else @@ -344,11 +344,33 @@ class SearchEngineCompleter    computeRelevancy: -> 1    refresh: -> -    this.searchEngines = root.Settings.getSearchEngines() +    @searchEngines = SearchEngineCompleter.getSearchEngines()    getSearchEngineMatches: (queryTerms) ->      (1 < queryTerms.length and @searchEngines[queryTerms[0]]) or {} +  # Static data and methods for parsing the configured search engines.  We keep a cache of the search-engine +  # mapping in @searchEnginesMap. +  @searchEnginesMap: null + +  # Parse the custom search engines setting and cache it in SearchEngineCompleter.searchEnginesMap. +  @parseSearchEngines: (searchEnginesText) -> +    searchEnginesMap = SearchEngineCompleter.searchEnginesMap = {} +    for line in searchEnginesText.split /\n/ +      tokens = line.trim().split /\s+/ +      continue if tokens.length < 2 or tokens[0].startsWith('"') or tokens[0].startsWith("#") +      keywords = tokens[0].split ":" +      continue unless keywords.length == 2 and not keywords[1] # So, like: [ "w", "" ]. +      searchEnginesMap[keywords[0]] = +        url: tokens[1] +        description: tokens[2..].join(" ") + +  # Fetch the search-engine map, building it if necessary. +  @getSearchEngines: -> +    unless SearchEngineCompleter.searchEnginesMap? +      SearchEngineCompleter.parseSearchEngines Settings.get "searchEngines" +    SearchEngineCompleter.searchEnginesMap +  # A completer which calls filter() on many completers, aggregates the results, ranks them, and returns the top  # 10. Queries from the vomnibar frontend script come through a multi completer.  class MultiCompleter diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index 0c7d9343..a26fd8a8 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -26,6 +26,7 @@ validFirstKeys = {}  singleKeyCommands = []  focusedFrame = null  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 @@ -57,7 +58,7 @@ completers =    bookmarks: new MultiCompleter([completionSources.bookmarks])    tabs: new MultiCompleter([completionSources.tabs]) -chrome.runtime.onConnect.addListener((port, name) -> +chrome.runtime.onConnect.addListener (port, name) ->    senderTabId = if port.sender.tab then port.sender.tab.id else null    # If this is a tab we've been waiting to open, execute any "tab loaded" handlers, e.g. to restore    # the tab's scroll position. Wait until domReady before doing this; otherwise operations like restoring @@ -69,14 +70,8 @@ chrome.runtime.onConnect.addListener((port, name) ->        delete tabLoadedHandlers[senderTabId]        toCall.call() -    # domReady is the appropriate time to show the "vimium has been upgraded" message. -    # TODO: This might be broken on pages with frames. -    if (shouldShowUpgradeMessage()) -      chrome.tabs.sendMessage(senderTabId, { name: "showUpgradeNotification", version: currentVersion }) -    if (portHandlers[port.name])      port.onMessage.addListener(portHandlers[port.name]) -)  chrome.runtime.onMessage.addListener((request, sender, sendResponse) ->    if (sendRequestHandlers[request.handler]) @@ -183,14 +178,6 @@ openUrlInIncognito = (request) ->    chrome.windows.create({ url: Utils.convertToUrl(request.url), incognito: true})  # -# Called when the user has clicked the close icon on the "Vimium has been updated" message. -# We should now dismiss that message in all tabs. -# -upgradeNotificationClosed = (request) -> -  Settings.set("previousVersion", currentVersion) -  sendRequestToAllTabs({ name: "hideUpgradeNotification" }) - -#  # Copies or pastes some data (request.data) to/from the clipboard.  # We return null to avoid the return value from the copy operations being passed to sendResponse.  # @@ -368,56 +355,23 @@ updateOpenTabs = (tab, deleteFrames = false) ->    # Frames are recreated on refresh    delete frameIdsForTab[tab.id] if deleteFrames -setBrowserActionIcon = (tabId,path) -> -  chrome.browserAction.setIcon({ tabId: tabId, path: path }) - -chrome.browserAction.setBadgeBackgroundColor -  # This is Vimium blue (from the icon). -  # color: [102, 176, 226, 255] -  # This is a slightly darker blue. It makes the badge more striking in the corner of the eye, and the symbol -  # easier to read. -  color: [82, 156, 206, 255] - -setBadge = do -> -  current = null -  timer = null -  updateBadge = (badge, tabId) -> -> chrome.browserAction.setBadgeText text: badge, tabId: tabId -  (request, sender) -> -    badge = request.badge -    if badge? and badge != current -      current = badge -      clearTimeout timer if timer -      # We wait a few moments. This avoids badge flicker when there are rapid changes. -      timer = setTimeout updateBadge(badge, sender.tab.id), 50 - -# 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. -# Exported via root because it's called from the page popup. -root.updateActiveState = updateActiveState = (tabId) -> -  enabledIcon = "icons/browser_action_enabled.png" -  disabledIcon = "icons/browser_action_disabled.png" -  partialIcon = "icons/browser_action_partial.png" -  chrome.tabs.get tabId, (tab) -> -    setBadge { badge: "" }, tab: { id: tabId } -    chrome.tabs.sendMessage tabId, { name: "getActiveState" }, (response) -> -      if response -        isCurrentlyEnabled = response.enabled -        currentPasskeys = response.passKeys -        config = isEnabledForUrl { url: tab.url }, { tab: tab } -        enabled = config.isEnabledForUrl -        passKeys = config.passKeys -        if (enabled and passKeys) -          setBrowserActionIcon(tabId,partialIcon) -        else if (enabled) -          setBrowserActionIcon(tabId,enabledIcon) -        else -          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, incognito: tab.incognito }) -      else -        setBrowserActionIcon tabId, disabledIcon +# Here's how we set the page icon.  The default is "disabled", so if we do nothing else, then we get the +# grey-out disabled icon.  Thereafter, we only set tab-specific icons, so there's no need to update the icon +# when we visit a tab on which Vimium isn't running. +# +# For active tabs, when a frame starts, it requests its active state via isEnabledForUrl.  We also check the +# state every time a frame gets the focus.  In both cases, the frame then updates the tab's icon accordingly. +# +# Exclusion rule changes (from either the options page or the page popup) propagate via the subsequent focus +# change.  In particular, whenever a frame next gets the focus, it requests its new state and sets the icon +# accordingly. +# +setIcon = (request, sender) -> +  path = switch request.icon +    when "enabled" then "icons/browser_action_enabled.png" +    when "partial" then "icons/browser_action_partial.png" +    when "disabled" then "icons/browser_action_disabled.png" +  chrome.browserAction.setIcon tabId: sender.tab.id, path: path  handleUpdateScrollPosition = (request, sender) ->    updateScrollPosition(sender.tab, request.scrollX, request.scrollY) @@ -434,7 +388,6 @@ chrome.tabs.onUpdated.addListener (tabId, changeInfo, tab) ->      runAt: "document_start"    chrome.tabs.insertCSS tabId, cssConf, -> chrome.runtime.lastError    updateOpenTabs(tab) if changeInfo.url? -  updateActiveState(tabId)  chrome.tabs.onAttached.addListener (tabId, attachedInfo) ->    # We should update all the tabs in the old window and the new window. @@ -469,8 +422,7 @@ chrome.tabs.onRemoved.addListener (tabId) ->    tabInfoMap.deletor = -> delete tabInfoMap[tabId]    setTimeout tabInfoMap.deletor, 1000    delete frameIdsForTab[tabId] - -chrome.tabs.onActiveChanged.addListener (tabId, selectInfo) -> updateActiveState(tabId) +  delete urlForTab[tabId]  unless chrome.sessions    chrome.windows.onRemoved.addListener (windowId) -> delete tabQueue[windowId] @@ -627,16 +579,6 @@ sendRequestToAllTabs = (args) ->        for tab in window.tabs          chrome.tabs.sendMessage(tab.id, args, null)) -# -# Returns true if the current extension version is greater than the previously recorded version in -# localStorage, and false otherwise. -# -shouldShowUpgradeMessage = -> -  # Avoid showing the upgrade notification when previousVersion is undefined, which is the case for new -  # installs. -  Settings.set("previousVersion", currentVersion) unless Settings.get("previousVersion") -  Utils.compareVersions(currentVersion, Settings.get("previousVersion")) == 1 -  openOptionsPageInNewTab = ->    chrome.tabs.getSelected(null, (tab) ->      chrome.tabs.create({ url: chrome.runtime.getURL("pages/options.html"), index: tab.index + 1 })) @@ -654,6 +596,7 @@ unregisterFrame = (request, sender) ->  handleFrameFocused = (request, sender) ->    tabId = sender.tab.id +  urlForTab[tabId] = request.url    if frameIdsForTab[tabId]?      frameIdsForTab[tabId] =        [request.frameId, (frameIdsForTab[tabId].filter (id) -> id != request.frameId)...] @@ -687,7 +630,6 @@ sendRequestHandlers =    unregisterFrame: unregisterFrame    frameFocused: handleFrameFocused    nextFrame: (request) -> BackgroundCommands.nextFrame 1, request.frameId -  upgradeNotificationClosed: upgradeNotificationClosed    updateScrollPosition: handleUpdateScrollPosition    copyToClipboard: copyToClipboard    pasteFromClipboard: pasteFromClipboard @@ -696,7 +638,7 @@ sendRequestHandlers =    refreshCompleter: refreshCompleter    createMark: Marks.create.bind(Marks)    gotoMark: Marks.goto.bind(Marks) -  setBadge: setBadge +  setIcon: setIcon    sendMessageToFrames: sendMessageToFrames    log: bgLog @@ -727,8 +669,30 @@ if Settings.has("keyMappings")  populateValidFirstKeys()  populateSingleKeyCommands() -if shouldShowUpgradeMessage() -  sendRequestToAllTabs({ name: "showUpgradeNotification", version: currentVersion }) + +# Show notification on upgrade. +showUpgradeMessage = -> +  # Avoid showing the upgrade notification when previousVersion is undefined, which is the case for new +  # installs. +  Settings.set "previousVersion", currentVersion  unless Settings.get "previousVersion" +  if Utils.compareVersions(currentVersion, Settings.get "previousVersion" ) == 1 +    notificationId = "VimiumUpgradeNotification" +    notification = +      type: "basic" +      iconUrl: chrome.runtime.getURL "icons/vimium.png" +      title: "Vimium Upgrade" +      message: "Vimium has been upgraded to version #{currentVersion}. Click here for more information." +      isClickable: true +    if chrome.notifications?.create? +      chrome.notifications.create notificationId, notification, -> +        unless chrome.runtime.lastError +          Settings.set "previousVersion", currentVersion +          chrome.notifications.onClicked.addListener (id) -> +            if id == notificationId +              openUrlInNewTab url: "https://github.com/philc/vimium#release-notes" +    else +      # We need to wait for the user to accept the "notifications" permission. +      chrome.permissions.onAdded.addListener showUpgradeMessage  # Ensure that tabInfoMap is populated when Vimium is installed.  chrome.windows.getAll { populate: true }, (windows) -> @@ -741,3 +705,4 @@ chrome.windows.getAll { populate: true }, (windows) ->  # Start pulling changes from synchronized storage.  Sync.init() +showUpgradeMessage() diff --git a/background_scripts/settings.coffee b/background_scripts/settings.coffee index 3528e8a9..a4d95c81 100644 --- a/background_scripts/settings.coffee +++ b/background_scripts/settings.coffee @@ -33,7 +33,7 @@ root.Settings = Settings =        root.refreshCompletionKeysAfterMappingSave()      searchEngines: (value) -> -      root.Settings.parseSearchEngines value +      root.SearchEngineCompleter.parseSearchEngines value      exclusionRules: (value) ->        root.Exclusions.postUpdateHook value @@ -42,27 +42,6 @@ root.Settings = Settings =    performPostUpdateHook: (key, value) ->      @postUpdateHooks[key] value if @postUpdateHooks[key] -  # Here we have our functions that parse the search engines -  # this is a map that we use to store our search engines for use. -  searchEnginesMap: {} - -  # Parse the custom search engines setting and cache it. -  parseSearchEngines: (searchEnginesText) -> -    @searchEnginesMap = {} -    for line in searchEnginesText.split /\n/ -      tokens = line.trim().split /\s+/ -      continue if tokens.length < 2 or tokens[0].startsWith('"') or tokens[0].startsWith("#") -      keywords = tokens[0].split ":" -      continue unless keywords.length == 2 and not keywords[1] # So, like: [ "w", "" ]. -      @searchEnginesMap[keywords[0]] = -        url: tokens[1] -        description: tokens[2..].join(" ") - -  # Fetch the search-engine map, building it if necessary. -  getSearchEngines: -> -    this.parseSearchEngines(@get("searchEngines") || "") if Object.keys(@searchEnginesMap).length == 0 -    @searchEnginesMap -    # options.coffee and options.html only handle booleans and strings; therefore all defaults must be booleans    # or strings    defaults: | 
