diff --git a/services/sync/locales/en-US/notification.dtd b/services/sync/locales/en-US/notification.dtd new file mode 100644 index 00000000000..5bbdf7793ee --- /dev/null +++ b/services/sync/locales/en-US/notification.dtd @@ -0,0 +1,3 @@ + + + diff --git a/services/sync/locales/en-US/sync.dtd b/services/sync/locales/en-US/sync.dtd index e548bbd19a8..6cdd2cf7f87 100644 --- a/services/sync/locales/en-US/sync.dtd +++ b/services/sync/locales/en-US/sync.dtd @@ -6,10 +6,5 @@ - - - - - diff --git a/services/sync/locales/en-US/sync.properties b/services/sync/locales/en-US/sync.properties index 90dab966f84..016a9f4ba81 100644 --- a/services/sync/locales/en-US/sync.properties +++ b/services/sync/locales/en-US/sync.properties @@ -1,8 +1,22 @@ # %S is the date and time at which the last sync successfully completed lastSync.label = Last Update: %S + +weaveButtonOffline.label = Sign In +weaveButtonOnline.label = Weave +shareBookmark.menuItem = Share This Folder... +unShareBookmark.menuItem = Stop Sharing This Folder + +status.offline = Sign in + +# The next two are not normally used, as we now display the username +# when the user is logged in. But if for some reason we can't get the username, +# we display these. status.idle = Idle status.active = Working... -status.offline = Offline -status.error = Error -shareBookmark.menuItem = Share This Folder... -unShareBookmark.menuItem = Stop Sharing This Folder \ No newline at end of file + +error.logout.title = Error While Signing Out +error.logout.description = Weave encountered an error while signing you out. It's probably ok, and you don't have to do anything about it (then why are we bugging you with this info?). +error.sync.title = Error While Syncing +error.sync.description = Weave encountered an error while syncing. You might want to try syncing manually to make sure you are up-to-date. +error.sync.tryAgainButton.label = Try Again +error.sync.tryAgainButton.accesskey = T diff --git a/services/sync/modules/Observers.js b/services/sync/modules/Observers.js new file mode 100644 index 00000000000..e98281158ad --- /dev/null +++ b/services/sync/modules/Observers.js @@ -0,0 +1,100 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Observers. + * + * The Initial Developer of the Original Code is Daniel Aquino. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Aquino + * Myk Melez + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +let EXPORTED_SYMBOLS = ["Observers"]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +let Observers = { + add: function(callback, topic) { + let observer = new Observer(callback); + if (!(topic in Observers._observers)) + Observers._observers[topic] = {}; + Observers._observers[topic][callback] = observer; + Observers._service.addObserver(observer, topic, true); + return observer; + }, + + remove: function(callback, topic) { + let observer = Observers._observers[topic][callback]; + Observers._service.removeObserver(observer, topic); + delete this._observers[topic][callback]; + }, + + notify: function(subject, topic, data) { + Observers._service.notifyObservers(new Subject(subject), topic, data); + }, + + _service: Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService), + + _observers: {} +}; + + +function Observer(callback) { + this._callback = callback; +} + +Observer.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]), + observe: function(subject, topic, data) { + // Pass the wrappedJSObject for subjects that have one. Otherwise pass + // the subject itself. This way we support both wrapped subjects created + // using this module and those that are real XPCOM components. + if (subject.wrappedJSObject) + this._callback(subject.wrappedJSObject, topic, data); + else + this._callback(subject, topic, data); + } +} + + +function Subject(object) { + this.wrappedJSObject = object; +} + +Subject.prototype = { + QueryInterface: XPCOMUtils.generateQI([]), + getHelperForLanguage: function() {}, + getInterfaces: function() {} +}; diff --git a/services/sync/modules/notifications.js b/services/sync/modules/notifications.js new file mode 100644 index 00000000000..a3f59422887 --- /dev/null +++ b/services/sync/modules/notifications.js @@ -0,0 +1,143 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Bookmarks Sync. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Myk Melez + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const EXPORTED_SYMBOLS = ["Notifications", "Notification", "NotificationButton", + "TabsNotification"]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://weave/Observers.js"); +Cu.import("resource://weave/log4moz.js"); +Cu.import("resource://weave/util.js"); + +let Notifications = { + // Match the referenced values in toolkit/content/widgets/notification.xml. + get PRIORITY_INFO() 1, // PRIORITY_INFO_LOW + get PRIORITY_WARNING() 4, // PRIORITY_WARNING_LOW + get PRIORITY_ERROR() 7, // PRIORITY_CRITICAL_LOW + + // FIXME: instead of making this public, dress the Notifications object + // to behave like an iterator (using generators?) and have callers access + // this array through the Notifications object. + notifications: [], + + _observers: [], + + // XXX Should we have a helper method for adding a simple notification? + // I.e. something like |function notify(title, description, priority)|. + + add: function Notifications_add(notification) { + this.notifications.push(notification); + Observers.notify(notification, "weave:notification:added", null); + }, + + remove: function Notifications_remove(notification) { + let index = this.notifications.indexOf(notification); + + if (index != -1) { + this.notifications.splice(index, 1); + Observers.notify(notification, "weave:notification:removed", null); + } + }, + + /** + * Replace an existing notification. + */ + replace: function Notifications_replace(oldNotification, newNotification) { + let index = this.notifications.indexOf(oldNotification); + + if (index != -1) + this.notifications.splice(index, 1, newNotification); + else { + this.notifications.push(newNotification); + // XXX Should we throw because we didn't find the existing notification? + // XXX Should we notify observers about weave:notification:added? + } + + // XXX Should we notify observers about weave:notification:replaced? + } + +}; + + +/** + * A basic notification. Subclass this to create more complex notifications. + */ +function Notification(title, description, iconURL, priority, buttons) { + this.title = title; + this.description = description; + + if (iconURL) + this.iconURL = iconURL; + + if (priority) + this.priority = priority; + + if (buttons) + this.buttons = buttons; +} + +// We set each prototype property individually instead of redefining +// the entire prototype to avoid blowing away existing properties +// of the prototype like the the "constructor" property, which we use +// to bind notification objects to their XBL representations. +Notification.prototype.priority = Notifications.PRIORITY_INFO; +Notification.prototype.iconURL = null; +Notification.prototype.buttons = []; + +/** + * A button to display in a notification. + */ +function NotificationButton(label, accessKey, callback) { + this.label = label; + this.accessKey = accessKey; + this.callback = callback; +} + +function TabsNotification() { + // Call the base class's constructor to initialize the new instance. + // XXX Can we simply pass null, null for the title, description? + Notification.call(this, "", "", null, Notifications.PRIORITY_INFO, null); +} + +// We set each prototype property individually instead of redefining +// the entire prototype to avoid blowing away existing properties +// of the prototype like the the "constructor" property, which we use +// to bind notification objects to their XBL representations. +TabsNotification.prototype.__proto__ = Notification.prototype; diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index ecd9fb80bd4..2968d4021ab 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -89,6 +89,7 @@ Cu.import("resource://weave/constants.js", Weave); Cu.import("resource://weave/util.js", Weave); Cu.import("resource://weave/async.js", Weave); Cu.import("resource://weave/crypto.js", Weave); +Cu.import("resource://weave/notifications.js", Weave); Cu.import("resource://weave/identity.js", Weave); Cu.import("resource://weave/dav.js", Weave); Cu.import("resource://weave/stores.js", Weave); @@ -260,7 +261,7 @@ WeaveSvc.prototype = { _onSchedule: function WeaveSync__onSchedule() { if (this.enabled) { this._log.info("Running scheduled sync"); - this._notify("sync", this._lock(this._syncAsNeeded)).async(this); + this._notify("syncAsNeeded", this._lock(this._syncAsNeeded)).async(this); } },