aboutsummaryrefslogtreecommitdiffstats
path: root/background_scripts
diff options
context:
space:
mode:
authorPhil Crosby2014-04-30 00:42:42 -0700
committerPhil Crosby2014-04-30 00:42:42 -0700
commitfc23be221270dc11914244f5c93d900ad8e9225c (patch)
tree9d676401ce359a28ef76a552e514db590cee3ecd /background_scripts
parentfa16722613cd60933258edac2c0aa1908fe387bd (diff)
parentdb65721aa67b2de75b1e279f01e721676e83b448 (diff)
downloadvimium-fc23be221270dc11914244f5c93d900ad8e9225c.tar.bz2
Merge branch 'smblott-github-sync-chrome-instances'
Conflicts: tests/unit_tests/utils_test.coffee
Diffstat (limited to 'background_scripts')
-rw-r--r--background_scripts/main.coffee3
-rw-r--r--background_scripts/settings.coffee22
-rw-r--r--background_scripts/sync.coffee105
3 files changed, 128 insertions, 2 deletions
diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee
index 207cbccb..b2b4669c 100644
--- a/background_scripts/main.coffee
+++ b/background_scripts/main.coffee
@@ -599,3 +599,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()
diff --git a/background_scripts/settings.coffee b/background_scripts/settings.coffee
index 0fe1e1bb..73a7a04b 100644
--- a/background_scripts/settings.coffee
+++ b/background_scripts/settings.coffee
@@ -12,12 +12,30 @@ root.Settings = Settings =
if (value == @defaults[key])
@clear(key)
else
- localStorage[key] = JSON.stringify(value)
+ jsonValue = JSON.stringify value
+ localStorage[key] = jsonValue
+ Sync.set key, jsonValue
- clear: (key) -> delete localStorage[key]
+ clear: (key) ->
+ if @has key
+ delete localStorage[key]
+ Sync.clear key
has: (key) -> key of localStorage
+ # for settings which require action when their value changes, add hooks here
+ # called from options/options.coffee (when the options page is saved), and from background_scripts/sync.coffee (when
+ # an update propagates from chrome.storage.sync).
+ postUpdateHooks:
+ keyMappings: (value) ->
+ root.Commands.clearKeyMappingsAndSetDefaults()
+ root.Commands.parseCustomKeyMappings value
+ root.refreshCompletionKeysAfterMappingSave()
+
+ # postUpdateHooks convenience wrapper
+ performPostUpdateHook: (key, value) ->
+ @postUpdateHooks[key] value if @postUpdateHooks[key]
+
# options/options.(coffee|html) only handle booleans and strings; therefore
# all defaults must be booleans or strings
defaults:
diff --git a/background_scripts/sync.coffee b/background_scripts/sync.coffee
new file mode 100644
index 00000000..56c74b81
--- /dev/null
+++ b/background_scripts/sync.coffee
@@ -0,0 +1,105 @@
+#
+# * Sync.set() and Sync.clear() propagate local changes to chrome.storage.sync.
+# * Sync.handleStorageUpdate() listens for changes to chrome.storage.sync and propagates those
+# changes to localStorage and into vimium's internal state.
+# * Sync.fetchAsync() polls chrome.storage.sync at startup, similarly propagating
+# changes to localStorage and into vimium's internal state.
+#
+# Changes are propagated into vimium's state using the same mechanism
+# (Settings.performPostUpdateHook) that is used when options are changed on
+# the options page.
+#
+# The effect is best-effort synchronization of vimium options/settings between
+# chrome/vimium instances.
+#
+# NOTE:
+# Values handled within this module are ALWAYS already JSON.stringifed, so
+# they're always non-empty strings.
+#
+
+root = exports ? window
+root.Sync = Sync =
+
+ # 19/4/14:
+ # Leave logging statements in, but disable debugging.
+ # We may need to come back to this, so removing logging now would be premature.
+ # However, if users have problems, they are unlikely to notice and make sense of console logs on
+ # background pages. So disable it, by default.
+ # For genuine errors, we call console.log directly.
+ debug: true
+ storage: chrome.storage.sync
+ doNotSync: [ "settingsVersion", "previousVersion" ]
+
+ # This is called in main.coffee.
+ init: ->
+ chrome.storage.onChanged.addListener (changes, area) -> Sync.handleStorageUpdate changes, area
+ @fetchAsync()
+
+ # Asynchronous fetch from synced storage, called only at startup.
+ fetchAsync: ->
+ @storage.get null, (items) =>
+ # Chrome sets chrome.runtime.lastError if there is an error.
+ if chrome.runtime.lastError is undefined
+ for own key, value of items
+ @log "fetchAsync: #{key} <- #{value}"
+ @storeAndPropagate key, value
+ else
+ console.log "callback for Sync.fetchAsync() indicates error"
+ console.log chrome.runtime.lastError
+
+ # Asynchronous message from synced storage.
+ handleStorageUpdate: (changes, area) ->
+ for own key, change of changes
+ @log "handleStorageUpdate: #{key} <- #{change.newValue}"
+ @storeAndPropagate key, change?.newValue
+
+ # Only ever called from asynchronous synced-storage callbacks (fetchAsync and handleStorageUpdate).
+ storeAndPropagate: (key, value) ->
+ return if not 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]
+ defaultValueJSON = JSON.stringify(defaultValue)
+
+ if value and value != defaultValueJSON
+ # Key/value has been changed to non-default value at remote instance.
+ @log "storeAndPropagate update: #{key}=#{value}"
+ localStorage[key] = value
+ Settings.performPostUpdateHook key, JSON.parse(value)
+ else
+ # Key has been reset to default value at remote instance.
+ @log "storeAndPropagate clear: #{key}"
+ if key of localStorage
+ delete localStorage[key]
+ Settings.performPostUpdateHook key, defaultValue
+
+ # Only called synchronously from within vimium, never on a callback.
+ # No need to propagate updates to the rest of vimium, that's already been done.
+ set: (key, value) ->
+ if @shouldSyncKey key
+ @log "set scheduled: #{key}=#{value}"
+ key_value = {}
+ key_value[key] = value
+ @storage.set key_value, =>
+ # Chrome sets chrome.runtime.lastError if there is an error.
+ if chrome.runtime.lastError
+ console.log "callback for Sync.set() indicates error: #{key} <- #{value}"
+ console.log chrome.runtime.lastError
+
+ # Only called synchronously from within vimium, never on a callback.
+ clear: (key) ->
+ if @shouldSyncKey key
+ @log "clear scheduled: #{key}"
+ @storage.remove key, =>
+ # Chrome sets chrome.runtime.lastError if there is an error.
+ if chrome.runtime.lastError
+ console.log "for Sync.clear() indicates error: #{key}"
+ console.log chrome.runtime.lastError
+
+ # Should we synchronize this key?
+ shouldSyncKey: (key) ->
+ key not in @doNotSync
+
+ log: (msg) ->
+ console.log "Sync: #{msg}" if @debug
+