From c7ada0369f5f49180246eec655249a85643d5df2 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 8 Feb 2015 08:54:12 +0000 Subject: Refactor migration code for find-mode history. Doing the migration in a content script is dumb. Now we do it on the background page. --- background_scripts/settings.coffee | 8 ++++++++ content_scripts/vimium_frontend.coffee | 16 +++------------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/background_scripts/settings.coffee b/background_scripts/settings.coffee index 2fc3b43d..70b94429 100644 --- a/background_scripts/settings.coffee +++ b/background_scripts/settings.coffee @@ -121,3 +121,11 @@ root.Settings = Settings = if Utils.compareVersions("1.42", Settings.get("settingsVersion")) != -1 Settings.set("scrollStepSize", parseFloat Settings.get("scrollStepSize")) Settings.set("settingsVersion", Utils.getCurrentVersion()) + +# Migration (after 1.49, 2015/2/1). +# Legacy setting: findModeRawQuery (a string). +# New setting: findModeRawQueryList (a list of strings). +unless Settings.has "findModeRawQueryList" + rawQuery = Settings.get "findModeRawQuery" + Settings.set "findModeRawQueryList", (if rawQuery then [ rawQuery ] else []) + diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index f6499353..76c654a6 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -41,9 +41,9 @@ settings = port: null values: {} loadedValues: 0 - valuesToLoad: ["scrollStepSize", "linkHintCharacters", "linkHintNumbers", "filterLinkHints", "hideHud", - "previousPatterns", "nextPatterns", "findModeRawQuery", "findModeRawQueryList", "regexFindMode", "userDefinedLinkHintCss", - "helpDialog_showAdvancedCommands", "smoothScroll"] + valuesToLoad: [ "scrollStepSize", "linkHintCharacters", "linkHintNumbers", "filterLinkHints", "hideHud", + "previousPatterns", "nextPatterns", "findModeRawQuery", "findModeRawQueryList", "regexFindMode", + "userDefinedLinkHintCss", "helpDialog_showAdvancedCommands", "smoothScroll" ] isLoaded: false eventListeners: {} @@ -537,24 +537,14 @@ isValidFirstKey = (keyChar) -> # queries, most recent first. FindModeHistory = getQuery: (index = 0) -> - @migration() recentQueries = settings.get "findModeRawQueryList" if index < recentQueries.length then recentQueries[index] else "" recordQuery: (query) -> - @migration() if 0 < query.length recentQueries = settings.get "findModeRawQueryList" settings.set "findModeRawQueryList", ([ query ].concat recentQueries.filter (q) -> q != query)[0..50] - # Migration (from 1.49, 2015/2/1). - # Legacy setting: findModeRawQuery (a string). - # New setting: findModeRawQueryList (a list of strings). - migration: -> - unless settings.get "findModeRawQueryList" - rawQuery = settings.get "findModeRawQuery" - settings.set "findModeRawQueryList", (if rawQuery then [ rawQuery ] else []) - # should be called whenever rawQuery is modified. updateFindModeQuery = -> # the query can be treated differently (e.g. as a plain string versus regex depending on the presence of -- cgit v1.2.3 From e7e88b10afe4329034db7a2320bc16235f25f081 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 8 Feb 2015 09:11:54 +0000 Subject: Fix typo/bug initialising passkeys. --- content_scripts/vimium_frontend.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 76c654a6..004a5f96 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -511,7 +511,7 @@ checkIfEnabledForUrl = -> chrome.runtime.sendMessage { handler: "isEnabledForUrl", url: url }, (response) -> isEnabledForUrl = response.isEnabledForUrl - passKeys = request.passKeys + passKeys = response.passKeys initializeWhenEnabled() if isEnabledForUrl else if (HUD.isReady()) # Quickly hide any HUD we might already be showing, e.g. if we entered insert mode on page load. -- cgit v1.2.3 From 534e460f437ade1016ddff6d7ffa2c2e6b254b17 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 8 Feb 2015 09:18:50 +0000 Subject: Incognito mode for find history. - This commit is incomplete because, to progress, we need bc7db7473456713c8c84f324e71da93145ffa2a0. --- background_scripts/main.coffee | 2 +- content_scripts/vimium_frontend.coffee | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index c1c8dfc8..07127af9 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -382,7 +382,7 @@ root.updateActiveState = updateActiveState = (tabId) -> 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 }) + chrome.tabs.sendMessage(tabId, { name: "setState", enabled: enabled, passKeys: passKeys, incognito: tab.incognito }) else # We didn't get a response from the front end, so Vimium isn't running. setBrowserActionIcon(tabId,disabledIcon) diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 004a5f96..584b7cbb 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -12,6 +12,7 @@ findModeInitialRange = null isShowingHelpDialog = false keyPort = null isEnabledForUrl = true +isIncognitoMode = false passKeys = null keyQueue = null # The user's operating system. @@ -186,6 +187,8 @@ window.initializeWhenEnabled = -> setState = (request) -> isEnabledForUrl = request.enabled passKeys = request.passKeys + isIncognitoMode = request.incognito + console.log "isIncognitoMode", isIncognitoMode initializeWhenEnabled() if isEnabledForUrl handlerStack.bubbleEvent "registerStateChange", enabled: isEnabledForUrl @@ -536,14 +539,16 @@ isValidFirstKey = (keyChar) -> # This implements a find-mode query history (using the "findModeRawQueryList" setting) as a list of raw # queries, most recent first. FindModeHistory = + rawQueryList: null + getQuery: (index = 0) -> - recentQueries = settings.get "findModeRawQueryList" - if index < recentQueries.length then recentQueries[index] else "" + @rawQueryList = settings.get "findModeRawQueryList" unless @rawQueryList + if index < @rawQueryList.length then @rawQueryList[index] else "" - recordQuery: (query) -> + saveQuery: (query) -> + @rawQueryList = settings.get "findModeRawQueryList" unless @rawQueryList if 0 < query.length - recentQueries = settings.get "findModeRawQueryList" - settings.set "findModeRawQueryList", ([ query ].concat recentQueries.filter (q) -> q != query)[0..50] + @rawQueryList = ([ query ].concat @rawQueryList.filter (q) -> q != query)[0..50] # should be called whenever rawQuery is modified. updateFindModeQuery = -> @@ -637,7 +642,7 @@ handleEnterForFindMode = -> exitFindMode() focusFoundLink() document.body.classList.add("vimiumFindMode") - FindModeHistory.recordQuery findModeQuery.rawQuery + FindModeHistory.saveQuery findModeQuery.rawQuery class FindMode extends Mode constructor: -> -- cgit v1.2.3 From b071067a0036a4bd3ce6d2bba8e00fadfd372e21 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 8 Feb 2015 09:23:11 +0000 Subject: Fix error introduced in 5c155d5eab6632fda9b71713e11af299726d5204. --- content_scripts/vimium_frontend.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 584b7cbb..cf7aadca 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -515,7 +515,8 @@ checkIfEnabledForUrl = -> chrome.runtime.sendMessage { handler: "isEnabledForUrl", url: url }, (response) -> isEnabledForUrl = response.isEnabledForUrl passKeys = response.passKeys - initializeWhenEnabled() if isEnabledForUrl + if isEnabledForUrl + initializeWhenEnabled() else if (HUD.isReady()) # Quickly hide any HUD we might already be showing, e.g. if we entered insert mode on page load. HUD.hide() -- cgit v1.2.3 From d27136549f24f65ec0429dc5d845de1f609ff559 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 8 Feb 2015 10:45:42 +0000 Subject: Handle incognito mode for find-mode history. The approach is to maintain the "current" history in every tab, adding queries from other normal tabs in all tabs, but only saving queries from non-incognito mode tabs. So, queries from non-incognito mode tabs propagate everywhere, whereas those from incognito tabs never leave the tab. --- content_scripts/vimium_frontend.coffee | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index cf7aadca..2824a09d 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -47,6 +47,7 @@ settings = "userDefinedLinkHintCss", "helpDialog_showAdvancedCommands", "smoothScroll" ] isLoaded: false eventListeners: {} + postUpdateHooks: {} init: -> @port = chrome.runtime.connect({ name: "settings" }) @@ -77,7 +78,11 @@ settings = receiveMessage: (args) -> # not using 'this' due to issues with binding on callback + settingChanged = settings.values[args.key] != args.value settings.values[args.key] = args.value + # Settings values are refreshed every time the tab/focus changes. We only call any post-update hook if + # the setting's value has in fact changed. + settings.postUpdateHooks[args.key]? args.value if settingChanged # since load() can be called more than once, loadedValues can be greater than valuesToLoad, but we test # for equality so initializeOnReady only runs once if (++settings.loadedValues == settings.valuesToLoad.length) @@ -188,7 +193,6 @@ setState = (request) -> isEnabledForUrl = request.enabled passKeys = request.passKeys isIncognitoMode = request.incognito - console.log "isIncognitoMode", isIncognitoMode initializeWhenEnabled() if isEnabledForUrl handlerStack.bubbleEvent "registerStateChange", enabled: isEnabledForUrl @@ -537,19 +541,27 @@ window.refreshCompletionKeys = (response) -> isValidFirstKey = (keyChar) -> validFirstKeys[keyChar] || /^[1-9]/.test(keyChar) -# This implements a find-mode query history (using the "findModeRawQueryList" setting) as a list of raw -# queries, most recent first. +# This implements find-mode query history (using the "findModeRawQueryList" setting) as a list of raw queries, +# most recent first. FindModeHistory = + max: 50 rawQueryList: null + postUpdateHook: do -> + settings.postUpdateHooks.findModeRawQueryList = ( rawQueryList ) -> FindModeHistory.postUpdateHook rawQueryList + (rawQueryList) -> + @rawQueryList ||= rawQueryList + @updateRawQueryList rawQueryList[0] if rawQueryList[0]? + + updateRawQueryList: (query) -> + @rawQueryList = ([ query ].concat @rawQueryList.filter (q) => q != query)[0..@max] + getQuery: (index = 0) -> - @rawQueryList = settings.get "findModeRawQueryList" unless @rawQueryList - if index < @rawQueryList.length then @rawQueryList[index] else "" + if @rawQueryList and index < @rawQueryList.length then @rawQueryList[index] else "" saveQuery: (query) -> - @rawQueryList = settings.get "findModeRawQueryList" unless @rawQueryList - if 0 < query.length - @rawQueryList = ([ query ].concat @rawQueryList.filter (q) -> q != query)[0..50] + @updateRawQueryList query if 0 < query.length + settings.set "findModeRawQueryList", @rawQueryList unless isIncognitoMode # should be called whenever rawQuery is modified. updateFindModeQuery = -> -- cgit v1.2.3 From 1df1b9bdcd7155631d048a3645541db525cd4443 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 8 Feb 2015 12:17:42 +0000 Subject: Fix background-page error on "yy". The return value from copyToClipboard is passed to sendResponse by the chrome.runtime.onMessage.addListener listener. This was using the (somewhat arbitrary) value returned by Clipboard.copy, which turns out to be circular, causing an error. This fixes that. --- background_scripts/main.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index 07127af9..06df8988 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -170,7 +170,7 @@ upgradeNotificationClosed = (request) -> # # Copies some data (request.data) to the clipboard. # -copyToClipboard = (request) -> Clipboard.copy(request.data) +copyToClipboard = (request) -> Clipboard.copy(request.data); null # # Selects the tab with the ID specified in request.id -- cgit v1.2.3 From 3af220b4b26d10e87db2a3caf734dd3a4139a378 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 8 Feb 2015 12:39:16 +0000 Subject: Find-mode history now incorporates ingognito mode. --- background_scripts/main.coffee | 4 ++++ content_scripts/vimium_frontend.coffee | 40 +++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index 06df8988..65b97aff 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -189,6 +189,10 @@ handleSettings = (args, port) -> port.postMessage({ key: args.key, value: value }) else # operation == "set" Settings.set(args.key, args.value) + # For some settings, we propagate changes to all tabs immediately. + # In the case of findModeRawQueryList, this allows each tab to accurately track the find-mode history. + if args.key in [ "findModeRawQueryList" ] + sendRequestToAllTabs extend args, name: "updateSettings" refreshCompleter = (request) -> completers[request.name].refresh() diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 2824a09d..218869e9 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -64,6 +64,12 @@ settings = get: (key) -> @values[key] + # This is used when an updated value is received from the background page. + update: (key, value) -> + @values[key] = value + @postUpdateHooks[key]? value + + # This is used when the current tab sets a new value for a setting. set: (key, value) -> @init() unless @port @@ -78,11 +84,7 @@ settings = receiveMessage: (args) -> # not using 'this' due to issues with binding on callback - settingChanged = settings.values[args.key] != args.value - settings.values[args.key] = args.value - # Settings values are refreshed every time the tab/focus changes. We only call any post-update hook if - # the setting's value has in fact changed. - settings.postUpdateHooks[args.key]? args.value if settingChanged + settings.update args.key, args.value # since load() can be called more than once, loadedValues can be greater than valuesToLoad, but we test # for equality so initializeOnReady only runs once if (++settings.loadedValues == settings.valuesToLoad.length) @@ -156,6 +158,9 @@ initializePreDomReady = -> currentKeyQueue: (request) -> keyQueue = request.keyQueue handlerStack.bubbleEvent "registerKeyQueue", { keyQueue: keyQueue } + updateSettings: (request) -> + settings.update request.key, request.value + FindModeHistory.updateFindModeHistory request.value if request.key = "findModeRawQueryList" chrome.runtime.onMessage.addListener (request, sender, sendResponse) -> # In the options page, we will receive requests from both content and background scripts. ignore those @@ -548,20 +553,29 @@ FindModeHistory = rawQueryList: null postUpdateHook: do -> - settings.postUpdateHooks.findModeRawQueryList = ( rawQueryList ) -> FindModeHistory.postUpdateHook rawQueryList - (rawQueryList) -> - @rawQueryList ||= rawQueryList - @updateRawQueryList rawQueryList[0] if rawQueryList[0]? - + # This update path is only used to initialize @rawQueryList. Thereafter, we use updateFindModeHistory to + # track the history. + settings.postUpdateHooks.findModeRawQueryList = (args...) -> FindModeHistory.postUpdateHook args... + (rawQueryList) -> @rawQueryList ||= rawQueryList + + # This is called when we receive an updateSettings message from the background page. It is called + # synchronously with the update from another tab. Therefore, we know that only the most-recent query can + # have changed. + updateFindModeHistory: (rawQueryList) -> + @updateRawQueryList rawQueryList[0] if rawQueryList[0]? + + # Register query as the most-recent query, removing any existing occurrences. Note: this is idempotent when + # called repeatedly with the same argument. updateRawQueryList: (query) -> @rawQueryList = ([ query ].concat @rawQueryList.filter (q) => q != query)[0..@max] getQuery: (index = 0) -> - if @rawQueryList and index < @rawQueryList.length then @rawQueryList[index] else "" + @rawQueryList?[index] or "" saveQuery: (query) -> - @updateRawQueryList query if 0 < query.length - settings.set "findModeRawQueryList", @rawQueryList unless isIncognitoMode + if 0 < query.length + @updateRawQueryList query + settings.set "findModeRawQueryList", @rawQueryList unless isIncognitoMode # should be called whenever rawQuery is modified. updateFindModeQuery = -> -- cgit v1.2.3 From 7b451aaca8d8c84aab77ac262753c6239b466791 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 8 Feb 2015 14:13:38 +0000 Subject: Push fond-mode queries from incognito-mode tabs to other incognito tabs. --- background_scripts/main.coffee | 7 +++++-- content_scripts/vimium_frontend.coffee | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index 65b97aff..54e0491b 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -188,7 +188,7 @@ handleSettings = (args, port) -> value = Settings.get(args.key) port.postMessage({ key: args.key, value: value }) else # operation == "set" - Settings.set(args.key, args.value) + Settings.set(args.key, args.value) unless args.incognito and args.key in [ "findModeRawQueryList" ] # For some settings, we propagate changes to all tabs immediately. # In the case of findModeRawQueryList, this allows each tab to accurately track the find-mode history. if args.key in [ "findModeRawQueryList" ] @@ -593,12 +593,15 @@ checkKeyQueue = (keysToCheck, tabId, frameId) -> # # Message all tabs. Args should be the arguments hash used by the Chrome sendRequest API. +# Normally, the request is sent to all tabs. However, if args.incognito is set, then the request is only sent +# to incognito tabs. # sendRequestToAllTabs = (args) -> chrome.windows.getAll({ populate: true }, (windows) -> for window in windows for tab in window.tabs - chrome.tabs.sendMessage(tab.id, args, null)) + if not args.incognito or tab.incognito + chrome.tabs.sendMessage(tab.id, args, null)) # # Returns true if the current extension version is greater than the previously recorded version in diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 218869e9..b9737ffd 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -74,7 +74,7 @@ settings = @init() unless @port @values[key] = value - @port.postMessage({ operation: "set", key: key, value: value }) + @port.postMessage({ operation: "set", key: key, value: value, incognito: isIncognitoMode }) load: -> @init() unless @port @@ -575,7 +575,7 @@ FindModeHistory = saveQuery: (query) -> if 0 < query.length @updateRawQueryList query - settings.set "findModeRawQueryList", @rawQueryList unless isIncognitoMode + settings.set "findModeRawQueryList", @rawQueryList # should be called whenever rawQuery is modified. updateFindModeQuery = -> -- cgit v1.2.3 From 11609b918485ee4c3a659bee9dc0c420fb04ddcc Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sun, 8 Feb 2015 15:30:04 +0000 Subject: Proper find-mode history for incognito mode. Approach: - We never save the find mode history from an incognito tab in the settings, instead they are saved in the tabMapInfo for each currently-active incognito tab. - When a new incognito tab (or page, after navigation) starts, we scan the tabMapInfo looking for the find-mode history of any active tab. In this way, the history is shared between incognito tabs, but discarded once the last incognito tab closes. --- background_scripts/main.coffee | 12 ++++++++++++ content_scripts/vimium_frontend.coffee | 14 +++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index 54e0491b..b4eac4f1 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -193,6 +193,15 @@ handleSettings = (args, port) -> # In the case of findModeRawQueryList, this allows each tab to accurately track the find-mode history. if args.key in [ "findModeRawQueryList" ] sendRequestToAllTabs extend args, name: "updateSettings" + # We also track the incognito find-mode history setting in the tabInfoMap for all incognito tabs. + if args.incognito and args.key == "findModeRawQueryList" + for own _, map of tabInfoMap + map.findModeRawQueryList = args.value if map.incognito + +# Search through the active tab map for an up-to-date find-mode history for an incognito-mode tab. +getIncognitoRawQueryList = -> + for own id, map of tabInfoMap + return map.findModeRawQueryList if map.findModeRawQueryList refreshCompleter = (request) -> completers[request.name].refresh() @@ -337,6 +346,8 @@ updateOpenTabs = (tab) -> scrollX: null scrollY: null deletor: null + incognito: tab.incognito + findModeRawQueryList: null # Frames are recreated on refresh delete frameIdsForTab[tab.id] @@ -661,6 +672,7 @@ sendRequestHandlers = createMark: Marks.create.bind(Marks) gotoMark: Marks.goto.bind(Marks) setBadge: setBadge + getIncognitoRawQueryList: getIncognitoRawQueryList # Convenience function for development use. window.runTests = -> open(chrome.runtime.getURL('tests/dom_tests/dom_tests.html')) diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index b9737ffd..3d40e307 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -122,6 +122,12 @@ window.initializeModes = -> new PassKeysMode new InsertMode permanent: true +# +# Called if we learn that this frame is in incognito mode. +# +goIncognito = -> + FindModeHistory.goIncognito() + # # Complete initialization work that sould be done prior to DOMReady. # @@ -197,6 +203,7 @@ window.initializeWhenEnabled = -> setState = (request) -> isEnabledForUrl = request.enabled passKeys = request.passKeys + goIncognito() if request.incognito and not isIncognitoMode isIncognitoMode = request.incognito initializeWhenEnabled() if isEnabledForUrl handlerStack.bubbleEvent "registerStateChange", @@ -556,7 +563,7 @@ FindModeHistory = # This update path is only used to initialize @rawQueryList. Thereafter, we use updateFindModeHistory to # track the history. settings.postUpdateHooks.findModeRawQueryList = (args...) -> FindModeHistory.postUpdateHook args... - (rawQueryList) -> @rawQueryList ||= rawQueryList + (rawQueryList) -> @rawQueryList = rawQueryList unless @rawQueryList? # This is called when we receive an updateSettings message from the background page. It is called # synchronously with the update from another tab. Therefore, we know that only the most-recent query can @@ -577,6 +584,11 @@ FindModeHistory = @updateRawQueryList query settings.set "findModeRawQueryList", @rawQueryList + goIncognito: -> + # In incognito mode, we try to fetch the query history from another incognito tab. See #1465. + chrome.runtime.sendMessage { handler: "getIncognitoRawQueryList" }, (response) => + @rawQueryList = response if response + # should be called whenever rawQuery is modified. updateFindModeQuery = -> # the query can be treated differently (e.g. as a plain string versus regex depending on the presence of -- cgit v1.2.3 From b4f0645075ca79f8b2eb5ad942fb51f5076c6a40 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Mon, 9 Feb 2015 08:29:10 +0000 Subject: Initial find-mode history via chrome.storage. --- background_scripts/main.coffee | 38 +++++++++--------- background_scripts/settings.coffee | 10 ++--- background_scripts/sync.coffee | 2 +- content_scripts/vimium_frontend.coffee | 70 +++++++++++++--------------------- 4 files changed, 49 insertions(+), 71 deletions(-) diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee index b4eac4f1..286781b4 100644 --- a/background_scripts/main.coffee +++ b/background_scripts/main.coffee @@ -188,20 +188,7 @@ handleSettings = (args, port) -> value = Settings.get(args.key) port.postMessage({ key: args.key, value: value }) else # operation == "set" - Settings.set(args.key, args.value) unless args.incognito and args.key in [ "findModeRawQueryList" ] - # For some settings, we propagate changes to all tabs immediately. - # In the case of findModeRawQueryList, this allows each tab to accurately track the find-mode history. - if args.key in [ "findModeRawQueryList" ] - sendRequestToAllTabs extend args, name: "updateSettings" - # We also track the incognito find-mode history setting in the tabInfoMap for all incognito tabs. - if args.incognito and args.key == "findModeRawQueryList" - for own _, map of tabInfoMap - map.findModeRawQueryList = args.value if map.incognito - -# Search through the active tab map for an up-to-date find-mode history for an incognito-mode tab. -getIncognitoRawQueryList = -> - for own id, map of tabInfoMap - return map.findModeRawQueryList if map.findModeRawQueryList + Settings.set(args.key, args.value) refreshCompleter = (request) -> completers[request.name].refresh() @@ -346,8 +333,6 @@ updateOpenTabs = (tab) -> scrollX: null scrollY: null deletor: null - incognito: tab.incognito - findModeRawQueryList: null # Frames are recreated on refresh delete frameIdsForTab[tab.id] @@ -604,15 +589,12 @@ checkKeyQueue = (keysToCheck, tabId, frameId) -> # # Message all tabs. Args should be the arguments hash used by the Chrome sendRequest API. -# Normally, the request is sent to all tabs. However, if args.incognito is set, then the request is only sent -# to incognito tabs. # sendRequestToAllTabs = (args) -> chrome.windows.getAll({ populate: true }, (windows) -> for window in windows for tab in window.tabs - if not args.incognito or tab.incognito - chrome.tabs.sendMessage(tab.id, args, null)) + chrome.tabs.sendMessage(tab.id, args, null)) # # Returns true if the current extension version is greater than the previously recorded version in @@ -672,7 +654,21 @@ sendRequestHandlers = createMark: Marks.create.bind(Marks) gotoMark: Marks.goto.bind(Marks) setBadge: setBadge - getIncognitoRawQueryList: getIncognitoRawQueryList + +# We always remove chrome.storage.local/findModeRawQueryListIncognito on startup. +chrome.storage.local.remove "findModeRawQueryListIncognito" + +# Remove chrome.storage.local/findModeRawQueryListIncognito if there are no remaining incognito-mode tabs. +# Since the common case is that there are none to begin with, we first check whether the key is set at all. +chrome.tabs.onRemoved.addListener (tabId) -> + chrome.storage.local.get "findModeRawQueryListIncognito", (items) -> + if items.findModeRawQueryListIncognito + chrome.windows.getAll { populate: true }, (windows) -> + for window in windows + for tab in window.tabs + return if tab.incognito and tab.id != tabId + # There are no remaining incognito-mode tabs, and findModeRawQueryListIncognito is set. + chrome.storage.local.remove "findModeRawQueryListIncognito" # Convenience function for development use. window.runTests = -> open(chrome.runtime.getURL('tests/dom_tests/dom_tests.html')) diff --git a/background_scripts/settings.coffee b/background_scripts/settings.coffee index 70b94429..7430145c 100644 --- a/background_scripts/settings.coffee +++ b/background_scripts/settings.coffee @@ -116,7 +116,6 @@ root.Settings = Settings = settingsVersion: Utils.getCurrentVersion() - # We use settingsVersion to coordinate any necessary schema changes. if Utils.compareVersions("1.42", Settings.get("settingsVersion")) != -1 Settings.set("scrollStepSize", parseFloat Settings.get("scrollStepSize")) @@ -124,8 +123,9 @@ Settings.set("settingsVersion", Utils.getCurrentVersion()) # Migration (after 1.49, 2015/2/1). # Legacy setting: findModeRawQuery (a string). -# New setting: findModeRawQueryList (a list of strings). -unless Settings.has "findModeRawQueryList" - rawQuery = Settings.get "findModeRawQuery" - Settings.set "findModeRawQueryList", (if rawQuery then [ rawQuery ] else []) +# New setting: findModeRawQueryList (a list of strings), now stored in chrome.storage.local (not localStorage). +chrome.storage.local.get "findModeRawQueryList", (items) -> + unless chrome.runtime.lastError or items.findModeRawQueryList + rawQuery = Settings.get "findModeRawQuery" + chrome.storage.local.set findModeRawQueryList: (if rawQuery then [ rawQuery ] else []) diff --git a/background_scripts/sync.coffee b/background_scripts/sync.coffee index f1850438..866faca1 100644 --- a/background_scripts/sync.coffee +++ b/background_scripts/sync.coffee @@ -42,7 +42,7 @@ root.Sync = Sync = # Only ever called from asynchronous synced-storage callbacks (fetchAsync and handleStorageUpdate). storeAndPropagate: (key, value) -> - return if not key of Settings.defaults + return unless key of Settings.defaults return if not @shouldSyncKey key return if value and key of localStorage and localStorage[key] is value defaultValue = Settings.defaults[key] diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 3d40e307..9a50d373 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -43,11 +43,10 @@ settings = values: {} loadedValues: 0 valuesToLoad: [ "scrollStepSize", "linkHintCharacters", "linkHintNumbers", "filterLinkHints", "hideHud", - "previousPatterns", "nextPatterns", "findModeRawQuery", "findModeRawQueryList", "regexFindMode", - "userDefinedLinkHintCss", "helpDialog_showAdvancedCommands", "smoothScroll" ] + "previousPatterns", "nextPatterns", "regexFindMode", "userDefinedLinkHintCss", + "helpDialog_showAdvancedCommands", "smoothScroll" ] isLoaded: false eventListeners: {} - postUpdateHooks: {} init: -> @port = chrome.runtime.connect({ name: "settings" }) @@ -64,17 +63,11 @@ settings = get: (key) -> @values[key] - # This is used when an updated value is received from the background page. - update: (key, value) -> - @values[key] = value - @postUpdateHooks[key]? value - - # This is used when the current tab sets a new value for a setting. set: (key, value) -> @init() unless @port @values[key] = value - @port.postMessage({ operation: "set", key: key, value: value, incognito: isIncognitoMode }) + @port.postMessage({ operation: "set", key: key, value: value }) load: -> @init() unless @port @@ -84,7 +77,7 @@ settings = receiveMessage: (args) -> # not using 'this' due to issues with binding on callback - settings.update args.key, args.value + settings.values[args.key] = args.value # since load() can be called more than once, loadedValues can be greater than valuesToLoad, but we test # for equality so initializeOnReady only runs once if (++settings.loadedValues == settings.valuesToLoad.length) @@ -122,12 +115,6 @@ window.initializeModes = -> new PassKeysMode new InsertMode permanent: true -# -# Called if we learn that this frame is in incognito mode. -# -goIncognito = -> - FindModeHistory.goIncognito() - # # Complete initialization work that sould be done prior to DOMReady. # @@ -164,9 +151,6 @@ initializePreDomReady = -> currentKeyQueue: (request) -> keyQueue = request.keyQueue handlerStack.bubbleEvent "registerKeyQueue", { keyQueue: keyQueue } - updateSettings: (request) -> - settings.update request.key, request.value - FindModeHistory.updateFindModeHistory request.value if request.key = "findModeRawQueryList" chrome.runtime.onMessage.addListener (request, sender, sendResponse) -> # In the options page, we will receive requests from both content and background scripts. ignore those @@ -203,9 +187,9 @@ window.initializeWhenEnabled = -> setState = (request) -> isEnabledForUrl = request.enabled passKeys = request.passKeys - goIncognito() if request.incognito and not isIncognitoMode isIncognitoMode = request.incognito initializeWhenEnabled() if isEnabledForUrl + FindModeHistory.init() handlerStack.bubbleEvent "registerStateChange", enabled: isEnabledForUrl passKeys: passKeys @@ -556,38 +540,36 @@ isValidFirstKey = (keyChar) -> # This implements find-mode query history (using the "findModeRawQueryList" setting) as a list of raw queries, # most recent first. FindModeHistory = + storage: chrome.storage.local + key: "findModeRawQueryList" max: 50 rawQueryList: null - postUpdateHook: do -> - # This update path is only used to initialize @rawQueryList. Thereafter, we use updateFindModeHistory to - # track the history. - settings.postUpdateHooks.findModeRawQueryList = (args...) -> FindModeHistory.postUpdateHook args... - (rawQueryList) -> @rawQueryList = rawQueryList unless @rawQueryList? - - # This is called when we receive an updateSettings message from the background page. It is called - # synchronously with the update from another tab. Therefore, we know that only the most-recent query can - # have changed. - updateFindModeHistory: (rawQueryList) -> - @updateRawQueryList rawQueryList[0] if rawQueryList[0]? - - # Register query as the most-recent query, removing any existing occurrences. Note: this is idempotent when - # called repeatedly with the same argument. - updateRawQueryList: (query) -> - @rawQueryList = ([ query ].concat @rawQueryList.filter (q) => q != query)[0..@max] + init: -> + unless @rawQueryList + @rawQueryList = [] # Prevent repeated initialization. + @key = "findModeRawQueryListIncognito" if isIncognitoMode + @storage.get @key, (items) => + unless chrome.runtime.lastError + @rawQueryList = items[@key] + if isIncognitoMode and not @rawQueryList + # This is the first incognito tab, we need to initialize the incognito-mode query history. + @storage.get "findModeRawQueryList", (items) => + unless chrome.runtime.lastError + @rawQueryList = items.findModeRawQueryList + @storage.set findModeRawQueryListIncognito: @rawQueryList + + chrome.storage.onChanged.addListener (changes, area) => + @rawQueryList = changes[@key].newValue if changes[@key]?.newValue? getQuery: (index = 0) -> @rawQueryList?[index] or "" saveQuery: (query) -> if 0 < query.length - @updateRawQueryList query - settings.set "findModeRawQueryList", @rawQueryList - - goIncognito: -> - # In incognito mode, we try to fetch the query history from another incognito tab. See #1465. - chrome.runtime.sendMessage { handler: "getIncognitoRawQueryList" }, (response) => - @rawQueryList = response if response + @rawQueryList = ([ query ].concat @rawQueryList.filter (q) => q != query)[0..@max] + newSetting = {}; newSetting[@key] = @rawQueryList + @storage.set newSetting # should be called whenever rawQuery is modified. updateFindModeQuery = -> -- cgit v1.2.3 From 8991e7b16bdee88195851db8832707fc256e53fc Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Mon, 9 Feb 2015 08:39:15 +0000 Subject: Include get and remove in test chrome stub for chrome.storage.local --- tests/unit_tests/test_chrome_stubs.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit_tests/test_chrome_stubs.coffee b/tests/unit_tests/test_chrome_stubs.coffee index 7f666068..c61d7246 100644 --- a/tests/unit_tests/test_chrome_stubs.coffee +++ b/tests/unit_tests/test_chrome_stubs.coffee @@ -46,7 +46,9 @@ exports.chrome = storage: # chrome.storage.local local: + get: -> set: -> + remove: -> # chrome.storage.onChanged onChanged: -- cgit v1.2.3 From 88f6eab0908ee05e67f4883ca3419681e7de39ef Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Mon, 9 Feb 2015 08:55:47 +0000 Subject: Propagate queries to incognito-mode tabs. --- background_scripts/settings.coffee | 1 + content_scripts/vimium_frontend.coffee | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/background_scripts/settings.coffee b/background_scripts/settings.coffee index 7430145c..f43bd4bc 100644 --- a/background_scripts/settings.coffee +++ b/background_scripts/settings.coffee @@ -116,6 +116,7 @@ root.Settings = Settings = settingsVersion: Utils.getCurrentVersion() + # We use settingsVersion to coordinate any necessary schema changes. if Utils.compareVersions("1.42", Settings.get("settingsVersion")) != -1 Settings.set("scrollStepSize", parseFloat Settings.get("scrollStepSize")) diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 9a50d373..06eaf334 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -551,16 +551,16 @@ FindModeHistory = @key = "findModeRawQueryListIncognito" if isIncognitoMode @storage.get @key, (items) => unless chrome.runtime.lastError - @rawQueryList = items[@key] - if isIncognitoMode and not @rawQueryList - # This is the first incognito tab, we need to initialize the incognito-mode query history. + @rawQueryList = items[@key] if items[@key] + if isIncognitoMode and not items[@key] + # This is the first incognito tab, so we need to initialize the incognito-mode query history. @storage.get "findModeRawQueryList", (items) => unless chrome.runtime.lastError @rawQueryList = items.findModeRawQueryList @storage.set findModeRawQueryListIncognito: @rawQueryList chrome.storage.onChanged.addListener (changes, area) => - @rawQueryList = changes[@key].newValue if changes[@key]?.newValue? + @rawQueryList = changes[@key].newValue if changes[@key]? getQuery: (index = 0) -> @rawQueryList?[index] or "" @@ -570,6 +570,12 @@ FindModeHistory = @rawQueryList = ([ query ].concat @rawQueryList.filter (q) => q != query)[0..@max] newSetting = {}; newSetting[@key] = @rawQueryList @storage.set newSetting + # Now, check whether we need to propagte this query to incognito mode too. + unless isIncognitoMode + @storage.get "findModeRawQueryListIncognito", (items) => + if not chrome.runtime.lastError and items.findModeRawQueryListIncognito + rawQueryList = ([ query ].concat items.findModeRawQueryListIncognito.filter (q) => q != query)[0..@max] + @storage.set findModeRawQueryListIncognito: rawQueryList # should be called whenever rawQuery is modified. updateFindModeQuery = -> -- cgit v1.2.3 From b0ffde36732eee6a6b114927d45ae4d1e7ab0107 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Mon, 9 Feb 2015 14:13:44 +0000 Subject: Minor refactoring for find-mode history. --- content_scripts/vimium_frontend.coffee | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee index 06eaf334..d51683d5 100644 --- a/content_scripts/vimium_frontend.coffee +++ b/content_scripts/vimium_frontend.coffee @@ -560,22 +560,25 @@ FindModeHistory = @storage.set findModeRawQueryListIncognito: @rawQueryList chrome.storage.onChanged.addListener (changes, area) => - @rawQueryList = changes[@key].newValue if changes[@key]? + @rawQueryList = changes[@key].newValue if changes[@key] getQuery: (index = 0) -> - @rawQueryList?[index] or "" + @rawQueryList[index] or "" saveQuery: (query) -> if 0 < query.length - @rawQueryList = ([ query ].concat @rawQueryList.filter (q) => q != query)[0..@max] + @rawQueryList = @refreshRawQueryList query, @rawQueryList newSetting = {}; newSetting[@key] = @rawQueryList @storage.set newSetting - # Now, check whether we need to propagte this query to incognito mode too. + # If there are any active incognito-mode tabs, then propagte this query to those tabs too. unless isIncognitoMode @storage.get "findModeRawQueryListIncognito", (items) => if not chrome.runtime.lastError and items.findModeRawQueryListIncognito - rawQueryList = ([ query ].concat items.findModeRawQueryListIncognito.filter (q) => q != query)[0..@max] - @storage.set findModeRawQueryListIncognito: rawQueryList + @storage.set + findModeRawQueryListIncognito: @refreshRawQueryList query, items.findModeRawQueryListIncognito + + refreshRawQueryList: (query, rawQueryList) -> + ([ query ].concat rawQueryList.filter (q) => q != query)[0..@max] # should be called whenever rawQuery is modified. updateFindModeQuery = -> -- cgit v1.2.3