| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| var chrome = chrome || {}; |
| // TODO(akalin): Add mocking code for e.g. chrome.send() so that we |
| // can test this without rebuilding chrome. |
| chrome.sync = chrome.sync || {}; |
| (function () { |
| |
| // This Event class is a simplified version of the one from |
| // event_bindings.js. |
| function Event() { |
| this.listeners_ = []; |
| } |
| |
| Event.prototype.addListener = function(listener) { |
| this.listeners_.push(listener); |
| }; |
| |
| Event.prototype.removeListener = function(listener) { |
| var i = this.findListener_(listener); |
| if (i == -1) { |
| return; |
| } |
| this.listeners_.splice(i, 1); |
| }; |
| |
| Event.prototype.hasListener = function(listener) { |
| return this.findListener_(listener) > -1; |
| }; |
| |
| Event.prototype.hasListeners = function(listener) { |
| return this.listeners_.length > 0; |
| }; |
| |
| // Returns the index of the given listener, or -1 if not found. |
| Event.prototype.findListener_ = function(listener) { |
| for (var i = 0; i < this.listeners_.length; i++) { |
| if (this.listeners_[i] == listener) { |
| return i; |
| } |
| } |
| return -1; |
| }; |
| |
| // Fires the event. Called by the actual event callback. Any |
| // exceptions thrown by a listener are caught and logged. |
| Event.prototype.dispatch_ = function() { |
| var args = Array.prototype.slice.call(arguments); |
| for (var i = 0; i < this.listeners_.length; i++) { |
| try { |
| this.listeners_[i].apply(null, args); |
| } catch (e) { |
| if (e instanceof Error) { |
| // Non-standard, but useful. |
| console.error(e.stack); |
| } else { |
| console.error(e); |
| } |
| } |
| } |
| }; |
| |
| // Service events. |
| chrome.sync.onSyncServiceStateChanged = new Event(); |
| |
| // Notifier events. |
| chrome.sync.onSyncNotificationStateChange = new Event(); |
| chrome.sync.onSyncIncomingNotification = new Event(); |
| |
| // Manager events. |
| chrome.sync.onChangesApplied = new Event(); |
| chrome.sync.onChangesComplete = new Event(); |
| chrome.sync.onSyncCycleCompleted = new Event(); |
| chrome.sync.onAuthError = new Event(); |
| chrome.sync.onUpdatedToken = new Event(); |
| chrome.sync.onPassphraseRequired = new Event(); |
| chrome.sync.onPassphraseAccepted = new Event(); |
| chrome.sync.onEncryptionComplete = new Event(); |
| chrome.sync.onMigrationNeededForTypes = new Event(); |
| chrome.sync.onInitializationComplete = new Event(); |
| chrome.sync.onPaused = new Event(); |
| chrome.sync.onResumed = new Event(); |
| chrome.sync.onStopSyncingPermanently = new Event(); |
| chrome.sync.onClearServerDataSucceeded = new Event(); |
| chrome.sync.onClearServerDataFailed = new Event(); |
| |
| function AsyncFunction(name) { |
| this.name_ = name; |
| this.callbacks_ = []; |
| } |
| |
| // Calls the function, assuming the last argument is a callback to be |
| // called with the return value. |
| AsyncFunction.prototype.call = function() { |
| var args = Array.prototype.slice.call(arguments); |
| this.callbacks_.push(args.pop()); |
| chrome.send(this.name_, args); |
| } |
| |
| // Handle a reply, assuming that messages are processed in FIFO order. |
| AsyncFunction.prototype.handleReply = function() { |
| var args = Array.prototype.slice.call(arguments); |
| // Remove the callback before we call it since the callback may |
| // throw. |
| var callback = this.callbacks_.shift(); |
| callback.apply(null, args); |
| } |
| |
| // Sync service functions. |
| chrome.sync.getAboutInfo_ = new AsyncFunction('getAboutInfo'); |
| chrome.sync.getAboutInfo = function(callback) { |
| chrome.sync.getAboutInfo_.call(callback); |
| } |
| |
| // Notification functions. |
| chrome.sync.getNotificationState_ = |
| new AsyncFunction('getNotificationState'); |
| chrome.sync.getNotificationState = function(callback) { |
| chrome.sync.getNotificationState_.call(callback); |
| } |
| |
| chrome.sync.getNotificationInfo_ = |
| new AsyncFunction('getNotificationInfo'); |
| chrome.sync.getNotificationInfo = function(callback) { |
| chrome.sync.getNotificationInfo_.call(callback); |
| } |
| |
| // Node lookup functions. |
| chrome.sync.getRootNode_ = new AsyncFunction('getRootNode'); |
| chrome.sync.getRootNode = function(callback) { |
| chrome.sync.getRootNode_.call(callback); |
| } |
| |
| chrome.sync.getNodeById_ = new AsyncFunction('getNodeById'); |
| chrome.sync.getNodeById = function(id, callback) { |
| chrome.sync.getNodeById_.call(id, callback); |
| } |
| |
| })(); |
| |
| // TODO(akalin): Rewrite the C++ side to not need the handlers below. |
| |
| // Sync service event handlers. |
| |
| function onSyncServiceStateChanged() { |
| chrome.sync.onSyncServiceStateChanged.dispatch_(); |
| } |
| |
| // Notification event handlers. |
| |
| function onSyncNotificationStateChange(notificationsEnabled) { |
| chrome.sync.onSyncNotificationStateChange.dispatch_(notificationsEnabled); |
| } |
| |
| function onSyncIncomingNotification(changedTypes) { |
| chrome.sync.onSyncIncomingNotification.dispatch_(changedTypes); |
| } |
| |
| // Sync manager event handlers. |
| |
| function onChangesApplied(modelType, changes) { |
| chrome.sync.onChangesApplied.dispatch_(modelType, changes); |
| } |
| |
| function onChangesComplete(modelType) { |
| chrome.sync.onChangesComplete.dispatch_(modelType); |
| } |
| |
| function onSyncCycleCompleted(snapshot) { |
| chrome.sync.onSyncCycleCompleted.dispatch_(snapshot); |
| } |
| |
| function onAuthError(authError) { |
| chrome.sync.onAuthError.dispatch_(authError); |
| } |
| |
| function onUpdatedToken(token) { |
| chrome.sync.onUpdatedToken.dispatch_(token); |
| } |
| |
| function onPassphraseRequired(forDecryption) { |
| chrome.sync.onPassphraseRequired.dispatch_(forDecryption); |
| } |
| |
| function onPassphraseAccepted(bootstrapToken) { |
| chrome.sync.onPassphraseAccepted.dispatch_(bootstrapToken); |
| } |
| |
| function onEncryptionComplete(encrypted_types) { |
| chrome.sync.onEncryptionComplete.dispatch_(encrypted_types); |
| } |
| |
| function onMigrationNeededForTypes(model_types) { |
| chrome.sync.onMigrationNeededForTypes.dispatch_(model_types); |
| } |
| |
| function onInitializationComplete() { |
| chrome.sync.onInitializationComplete.dispatch_(); |
| } |
| |
| function onPaused() { |
| chrome.sync.onPaused.dispatch_(); |
| } |
| |
| function onResumed() { |
| chrome.sync.onResumed.dispatch_(); |
| } |
| |
| function onStopSyncingPermanently() { |
| chrome.sync.onStopSyncingPermanently.dispatch_(); |
| } |
| |
| function onClearServerDataSucceeded() { |
| chrome.sync.onClearServerDataSucceeded(); |
| } |
| |
| function onClearServerDataFailed() { |
| chrome.sync.onClearServerDataFailed(); |
| } |
| |
| // Function reply handlers. |
| |
| function onGetAboutInfoFinished(aboutInfo) { |
| chrome.sync.getAboutInfo_.handleReply(aboutInfo); |
| } |
| |
| function onGetNotificationStateFinished(notificationState) { |
| chrome.sync.getNotificationState_.handleReply(notificationState); |
| } |
| |
| function onGetRootNodeFinished(rootNode) { |
| chrome.sync.getRootNode_.handleReply(rootNode); |
| } |
| |
| function onGetNodeByIdFinished(node) { |
| chrome.sync.getNodeById_.handleReply(node); |
| } |
| |
| function onGetNotificationInfoFinished(notificationInfo) { |
| chrome.sync.getNotificationInfo_.handleReply(notificationInfo); |
| } |