зеркало из https://github.com/mozilla/gecko-dev.git
Bug 571897 (Sync UI) - Part 8: Tools Menu & Status Bar [r=dolske]
This commit is contained in:
Родитель
397f02fadf
Коммит
16507b0173
|
@ -606,6 +606,35 @@
|
|||
label="&addons.label;"
|
||||
accesskey="&addons.accesskey;"
|
||||
command="Tools:Addons"/>
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
<!-- only one of sync-setup or sync-menu will be showing at once -->
|
||||
<menuitem id="sync-setup"
|
||||
label="&syncSetup.label;"
|
||||
accesskey="&syncSetup.accesskey;"
|
||||
oncommand="gSyncUI.openSetup()"/>
|
||||
<menu id="sync-menu"
|
||||
label="&syncMenu.label;"
|
||||
accesskey="&syncMenu.accesskey;">
|
||||
<menupopup id="sync-menu-popup"
|
||||
onpopupshowing="if (event.target == this) gSyncUI.doUpdateMenu(event);">
|
||||
<menuitem id="sync-loginitem"
|
||||
label="&syncLogInItem.label;"
|
||||
accesskey="&syncLogInItem.accesskey;"
|
||||
oncommand="gSyncUI.doLogin();"/>
|
||||
<menuitem id="sync-logoutitem"
|
||||
label="&syncLogOutItem.label;"
|
||||
accesskey="&syncLogOutItem.accesskey;"
|
||||
oncommand="gSyncUI.doLogout();"/>
|
||||
<menuitem id="sync-syncnowitem"
|
||||
label="&syncSyncNowItem.label;"
|
||||
accesskey="&syncSyncNowItem.accesskey;"
|
||||
oncommand="gSyncUI.doSync(event);"/>
|
||||
<menuseparator id="sync-lastsyncsep" hidden="true"/>
|
||||
<menuitem id="sync-lastsyncitem"
|
||||
disabled="true" hidden="true"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
#endif
|
||||
<menuseparator id="devToolsSeparator"/>
|
||||
<menuitem id="menu_pageinspect"
|
||||
type="checkbox"
|
||||
|
|
|
@ -0,0 +1,382 @@
|
|||
# ***** 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 the Bookmarks Sync.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Dan Mills <thunder@mozilla.com>
|
||||
# Chris Beard <cbeard@mozilla.com>
|
||||
# Dan Mosedale <dmose@mozilla.org>
|
||||
# Paul O’Shannessy <paul@oshannessy.com>
|
||||
#
|
||||
# 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 *****
|
||||
|
||||
// gSyncUI handles updating the tools menu
|
||||
let gSyncUI = {
|
||||
init: function SUI_init() {
|
||||
let obs = [["weave:service:sync:start", "onActivityStart"],
|
||||
["weave:service:sync:finish", "onSyncFinish"],
|
||||
["weave:service:sync:error", "onSyncError"],
|
||||
["weave:service:sync:delayed", "onSyncDelay"],
|
||||
["weave:service:setup-complete", "onLoginFinish"],
|
||||
["weave:service:login:start", "onActivityStart"],
|
||||
["weave:service:login:finish", "onLoginFinish"],
|
||||
["weave:service:login:error", "onLoginError"],
|
||||
["weave:service:logout:finish", "onLogout"],
|
||||
["weave:service:start-over", "onStartOver"]];
|
||||
|
||||
// If this is a browser window?
|
||||
if (gBrowser) {
|
||||
obs.push(["weave:notification:added", "onNotificationAdded"],
|
||||
["weave:notification:removed", "onNotificationRemoved"]);
|
||||
}
|
||||
|
||||
// Add the observers now and remove them on unload
|
||||
let self = this;
|
||||
let addRem = function(add) {
|
||||
obs.forEach(function([topic, func]) {
|
||||
//XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
|
||||
// of `this`. Fix in a followup. (bug 583347)
|
||||
if (add)
|
||||
Weave.Svc.Obs.add(topic, self[func], self);
|
||||
else
|
||||
Weave.Svc.Obs.remove(topic, self[func], self);
|
||||
});
|
||||
};
|
||||
addRem(true);
|
||||
window.addEventListener("unload", function() addRem(false), false);
|
||||
|
||||
// Find the alltabs-popup, only if there is a gBrowser
|
||||
if (gBrowser) {
|
||||
let popup = document.getElementById("alltabs-popup");
|
||||
let self = this;
|
||||
popup.addEventListener("popupshowing", function() {
|
||||
self.alltabsPopupShowing();
|
||||
}, true);
|
||||
}
|
||||
|
||||
this.updateUI();
|
||||
},
|
||||
|
||||
_wasDelayed: false,
|
||||
|
||||
_needsSetup: function SUI__needsSetup() {
|
||||
let firstSync = "";
|
||||
try {
|
||||
firstSync = Services.prefs.getCharPref("services.sync.firstSync");
|
||||
} catch (e) { }
|
||||
return Weave.Status.service == Weave.CLIENT_NOT_CONFIGURED ||
|
||||
firstSync == "notReady";
|
||||
},
|
||||
|
||||
updateUI: function SUI_updateUI() {
|
||||
let needsSetup = this._needsSetup();
|
||||
document.getElementById("sync-setup").hidden = !needsSetup;
|
||||
document.getElementById("sync-menu").hidden = needsSetup;
|
||||
|
||||
if (gBrowser) {
|
||||
let showLabel = !Weave.Service.isLoggedIn && !needsSetup;
|
||||
let button = document.getElementById("sync-status-button");
|
||||
button.setAttribute("class", showLabel ? "statusbarpanel-iconic-text"
|
||||
: "statusbarpanel-iconic");
|
||||
button.image = "chrome://browser/skin/sync-16.png";
|
||||
|
||||
if (!Weave.Service.isLoggedIn) {
|
||||
//XXXzpao When we move the string bundle, we can add more and make this
|
||||
// say "needs setup" or something similar. (bug 583381)
|
||||
button.removeAttribute("tooltiptext");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
alltabsPopupShowing: function(event) {
|
||||
// Should we show the menu item?
|
||||
if (!Weave.Service.isLoggedIn || !Weave.Engines.get("tabs").enabled)
|
||||
return;
|
||||
|
||||
let label = this._stringBundle.GetStringFromName("tabs.fromOtherComputers.label");
|
||||
|
||||
let popup = document.getElementById("alltabs-popup");
|
||||
let menuitem = document.createElement("menuitem");
|
||||
menuitem.setAttribute("id", "sync-tabs-menuitem");
|
||||
menuitem.setAttribute("label", label);
|
||||
menuitem.setAttribute("class", "alltabs-item");
|
||||
menuitem.setAttribute("oncommand", "BrowserOpenSyncTabs();");
|
||||
|
||||
let sep = document.createElement("menuseparator");
|
||||
sep.setAttribute("id", "sync-tabs-sep");
|
||||
|
||||
// Fake the tab object on the menu entries, so that we don't have to worry
|
||||
// about removing them ourselves. They will just get cleaned up by popup
|
||||
// binding. This also makes sure the statusbar updates with the URL.
|
||||
menuitem.tab = { "linkedBrowser": { "currentURI": { "spec": label } } };
|
||||
sep.tab = { "linkedBrowser": { "currentURI": { "spec": " " } } };
|
||||
|
||||
popup.insertBefore(sep, popup.firstChild);
|
||||
popup.insertBefore(menuitem, sep);
|
||||
},
|
||||
|
||||
|
||||
// Functions called by observers
|
||||
onActivityStart: function SUI_onActivityStart() {
|
||||
//XXXzpao Followup: Do this with a class. (bug 583384)
|
||||
if (gBrowser)
|
||||
document.getElementById("sync-status-button").image =
|
||||
"chrome://browser/skin/sync-16-throbber.png";
|
||||
},
|
||||
|
||||
onSyncFinish: function SUI_onSyncFinish() {
|
||||
this._onSyncEnd(true);
|
||||
},
|
||||
|
||||
onSyncError: function SUI_onSyncError() {
|
||||
this._onSyncEnd(false);
|
||||
},
|
||||
|
||||
onSyncDelay: function SUI_onSyncDelay() {
|
||||
// basically, we want to just inform users that stuff is going to take a while
|
||||
let title = this._stringBundle.GetStringFromName("error.sync.no_node_found.title");
|
||||
let description = this._stringBundle.GetStringFromName("error.sync.no_node_found");
|
||||
let notification = new Weave.Notification(title, description, null, Weave.Notifications.PRIORITY_INFO);
|
||||
Weave.Notifications.replaceTitle(notification);
|
||||
this._wasDelayed = true;
|
||||
},
|
||||
|
||||
onLoginFinish: function SUI_onLoginFinish() {
|
||||
// Clear out any login failure notifications
|
||||
let title = this._stringBundle.GetStringFromName("error.login.title");
|
||||
Weave.Notifications.removeAll(title);
|
||||
|
||||
this.updateUI();
|
||||
this._updateLastSyncItem();
|
||||
},
|
||||
|
||||
onLoginError: function SUI_onLoginError() {
|
||||
// if login fails, any other notifications are essentially moot
|
||||
Weave.Notifications.removeAll();
|
||||
|
||||
// if we haven't set up the client, don't show errors
|
||||
if (this._needsSetup()) {
|
||||
this.updateUI();
|
||||
return;
|
||||
}
|
||||
|
||||
let title = this._stringBundle.GetStringFromName("error.login.title");
|
||||
let reason = Weave.Utils.getErrorString(Weave.Status.login);
|
||||
let description =
|
||||
this._stringBundle.formatStringFromName("error.login.description", [reason], 1);
|
||||
let buttons = [];
|
||||
buttons.push(new Weave.NotificationButton(
|
||||
this._stringBundle.GetStringFromName("error.login.prefs.label"),
|
||||
this._stringBundle.GetStringFromName("error.login.prefs.accesskey"),
|
||||
function() { gSyncUI.openPrefs(); return true; }
|
||||
));
|
||||
|
||||
let notification = new Weave.Notification(title, description, null,
|
||||
Weave.Notifications.PRIORITY_WARNING, buttons);
|
||||
Weave.Notifications.replaceTitle(notification);
|
||||
this.updateUI();
|
||||
},
|
||||
|
||||
onLogout: function SUI_onLogout() {
|
||||
this.updateUI();
|
||||
},
|
||||
|
||||
onStartOver: function SUI_onStartOver() {
|
||||
this.updateUI();
|
||||
},
|
||||
|
||||
onNotificationAdded: function SUI_onNotificationAdded() {
|
||||
if (!gBrowser)
|
||||
return;
|
||||
|
||||
let notificationsButton = document.getElementById("sync-notifications-button");
|
||||
notificationsButton.hidden = false;
|
||||
let notification = Weave.Notifications.notifications.reduce(function(prev, cur) {
|
||||
return prev.priority > cur.priority ? prev : cur;
|
||||
});
|
||||
|
||||
let image = notification.priority >= Weave.Notifications.PRIORITY_WARNING ?
|
||||
"chrome://global/skin/icons/warning-16.png" :
|
||||
"chrome://global/skin/icons/information-16.png";
|
||||
notificationsButton.image = image;
|
||||
notificationsButton.label = notification.title;
|
||||
},
|
||||
|
||||
onNotificationRemoved: function SUI_onNotificationRemoved() {
|
||||
if (!gBrowser)
|
||||
return;
|
||||
|
||||
if (Weave.Notifications.notifications.length == 0) {
|
||||
document.getElementById("sync-notifications-button").hidden = true;
|
||||
}
|
||||
else {
|
||||
// Display remaining notifications
|
||||
this.onNotificationAdded();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Commands
|
||||
doUpdateMenu: function SUI_doUpdateMenu(event) {
|
||||
this._updateLastSyncItem();
|
||||
|
||||
let loginItem = document.getElementById("sync-loginitem");
|
||||
let logoutItem = document.getElementById("sync-logoutitem");
|
||||
let syncItem = document.getElementById("sync-syncnowitem");
|
||||
|
||||
// Don't allow "login" to be selected in some cases
|
||||
let offline = Services.io.offline;
|
||||
let locked = Weave.Service.locked;
|
||||
let noUser = Weave.Service.username == "";
|
||||
let notReady = offline || locked || noUser;
|
||||
loginItem.setAttribute("disabled", notReady);
|
||||
logoutItem.setAttribute("disabled", notReady);
|
||||
|
||||
// Don't allow "sync now" to be selected in some cases
|
||||
let loggedIn = Weave.Service.isLoggedIn;
|
||||
let noNode = Weave.Status.sync == Weave.NO_SYNC_NODE_FOUND;
|
||||
let disableSync = notReady || !loggedIn || noNode;
|
||||
syncItem.setAttribute("disabled", disableSync);
|
||||
|
||||
// Only show one of login/logout
|
||||
loginItem.setAttribute("hidden", loggedIn);
|
||||
logoutItem.setAttribute("hidden", !loggedIn);
|
||||
},
|
||||
|
||||
doLogin: function SUI_doLogin() {
|
||||
Weave.Service.login();
|
||||
},
|
||||
|
||||
doLogout: function SUI_doLogout() {
|
||||
Weave.Service.logout();
|
||||
},
|
||||
|
||||
doSync: function SUI_doSync() {
|
||||
Weave.Service.sync();
|
||||
},
|
||||
|
||||
handleStatusbarButton: function SUI_handleStatusbarButton() {
|
||||
if (Weave.Service.isLoggedIn)
|
||||
Weave.Service.sync();
|
||||
else if (this._needsSetup())
|
||||
this.openSetup();
|
||||
else
|
||||
Weave.Service.login();
|
||||
},
|
||||
|
||||
//XXXzpao should be part of syncCommon.js - which we might want to make a module...
|
||||
// To be fixed in a followup (bug 583366)
|
||||
openSetup: function SUI_openSetup() {
|
||||
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
|
||||
if (win)
|
||||
win.focus();
|
||||
else {
|
||||
window.openDialog("chrome://browser/content/syncSetup.xul",
|
||||
"weaveSetup", "centerscreen,chrome,resizable=no");
|
||||
}
|
||||
},
|
||||
|
||||
openPrefs: function SUI_openPrefs() {
|
||||
openPreferences("paneSync");
|
||||
},
|
||||
|
||||
|
||||
// Helpers
|
||||
_updateLastSyncItem: function SUI__updateLastSyncItem() {
|
||||
let lastSync;
|
||||
try {
|
||||
Services.prefs.getCharPref("services.sync.lastSync");
|
||||
}
|
||||
catch (e) { };
|
||||
if (!lastSync)
|
||||
return;
|
||||
|
||||
let lastSyncItem = document.getElementById("sync-lastsyncitem");
|
||||
|
||||
// Show the day-of-week and time (HH:MM) of last sync
|
||||
let lastSyncDate = new Date(lastSync).toLocaleFormat("%a %H:%M");
|
||||
let lastSyncLabel =
|
||||
this._stringBundle.formatStringFromName("lastSync.label", [lastSyncDate], 1);
|
||||
lastSyncItem.setAttribute("label", lastSyncLabel);
|
||||
lastSyncItem.setAttribute("hidden", "false");
|
||||
document.getElementById("sync-lastsyncsep").hidden = false;
|
||||
|
||||
if (gBrowser)
|
||||
document.getElementById("sync-status-button").
|
||||
setAttribute("tooltiptext", lastSyncLabel);
|
||||
},
|
||||
|
||||
_onSyncEnd: function SUI__onSyncEnd(success) {
|
||||
let title = this._stringBundle.GetStringFromName("error.sync.title");
|
||||
if (!success) {
|
||||
let error = Weave.Utils.getErrorString(Weave.Status.sync);
|
||||
let description =
|
||||
this._stringBundle.formatStringFromName("error.sync.description", [error], 1);
|
||||
|
||||
let priority = Weave.Notifications.PRIORITY_WARNING;
|
||||
let buttons = [];
|
||||
|
||||
if (!Weave.Status.enforceBackoff) {
|
||||
priority = Weave.Notifications.PRIORITY_INFO;
|
||||
buttons.push(new Weave.NotificationButton(
|
||||
this._stringBundle.GetStringFromName("error.sync.tryAgainButton.label"),
|
||||
this._stringBundle.GetStringFromName("error.sync.tryAgainButton.accesskey"),
|
||||
function() { gSyncUI.doSync(); return true; }
|
||||
));
|
||||
}
|
||||
|
||||
let notification =
|
||||
new Weave.Notification(title, description, null, priority, buttons);
|
||||
Weave.Notifications.replaceTitle(notification);
|
||||
}
|
||||
else {
|
||||
// Clear out sync failures on a successful sync
|
||||
Weave.Notifications.removeAll(title);
|
||||
}
|
||||
|
||||
if (this._wasDelayed && Weave.Status.sync != Weave.NO_SYNC_NODE_FOUND) {
|
||||
title = this._stringBundle.GetStringFromName("error.sync.no_node_found.title");
|
||||
Weave.Notifications.removeAll(title);
|
||||
this._wasDelayed = false;
|
||||
}
|
||||
|
||||
this.updateUI();
|
||||
this._updateLastSyncItem();
|
||||
}
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(gSyncUI, "_stringBundle", function() {
|
||||
//XXXzpao these strings should probably be moved from /services to /browser... (bug 583381)
|
||||
// but for now just make it work
|
||||
return Cc["@mozilla.org/intl/stringbundle;1"].
|
||||
getService(Ci.nsIStringBundleService).
|
||||
createBundle("chrome://weave/locale/services/sync.properties");
|
||||
});
|
||||
|
|
@ -175,6 +175,10 @@ let gInitialPages = [
|
|||
#include browser-places.js
|
||||
#include browser-tabPreviews.js
|
||||
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
#include browser-syncui.js
|
||||
#endif
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "Win7Features", function () {
|
||||
#ifdef XP_WIN
|
||||
#ifndef WINCE
|
||||
|
@ -1511,6 +1515,11 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
|||
if (Win7Features)
|
||||
Win7Features.onOpenWindow();
|
||||
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
// initialize the sync UI
|
||||
gSyncUI.init();
|
||||
#endif
|
||||
|
||||
Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "");
|
||||
}
|
||||
|
||||
|
@ -1651,6 +1660,11 @@ function nonBrowserWindowDelayedStartup()
|
|||
|
||||
// initialize the private browsing UI
|
||||
gPrivateBrowsingUI.init();
|
||||
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
// initialize the sync UI
|
||||
gSyncUI.init();
|
||||
#endif
|
||||
}
|
||||
|
||||
function nonBrowserWindowShutdown()
|
||||
|
|
|
@ -1021,6 +1021,24 @@
|
|||
<statusbarpanel id="security-button" class="statusbarpanel-iconic"
|
||||
hidden="true"
|
||||
onclick="if (event.button == 0 && event.detail == 1) displaySecurityInfo();"/>
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
<statusbarpanel id="sync-status-button"
|
||||
class="statusbarpanel-iconic-text"
|
||||
image="chrome://browser/skin/sync-16.png"
|
||||
label="&syncLogInItem.label;"
|
||||
oncommand="gSyncUI.handleStatusbarButton();"
|
||||
onmousedown="event.preventDefault();">
|
||||
</statusbarpanel>
|
||||
<separator class="thin"/>
|
||||
<statusbarpanel id="sync-notifications-button"
|
||||
class="statusbarpanel-iconic-text"
|
||||
hidden="true"
|
||||
popup="sync-notifications-panel">
|
||||
</statusbarpanel>
|
||||
<panel id="sync-notifications-panel" position="before_end">
|
||||
<notificationbox id="sync-notifications-box"/>
|
||||
</panel>
|
||||
#endif
|
||||
<statusbarpanel id="page-report-button" type="menu"
|
||||
class="statusbarpanel-menu-iconic"
|
||||
hidden="true"
|
||||
|
|
|
@ -512,3 +512,18 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
|||
|
||||
<!-- LOCALIZATION NOTE (syncTabsMenu.label): This appears in the history menu -->
|
||||
<!ENTITY syncTabsMenu.label "Tabs From Other Computers">
|
||||
|
||||
<!ENTITY syncBrand.shortName.label "Sync">
|
||||
|
||||
<!ENTITY syncMenu.label "&syncBrand.shortName.label;">
|
||||
<!-- LOCALIZATION NOTE (sync.menu.accesskey): This is part of the tools menu, so
|
||||
don't use a conflicting access key -->
|
||||
<!ENTITY syncMenu.accesskey "Y">
|
||||
<!ENTITY syncSetup.label "Set Up &syncBrand.shortName.label;…">
|
||||
<!ENTITY syncSetup.accesskey "Y">
|
||||
<!ENTITY syncLogInItem.label "Connect">
|
||||
<!ENTITY syncLogInItem.accesskey "C">
|
||||
<!ENTITY syncLogOutItem.label "Disconnect">
|
||||
<!ENTITY syncLogOutItem.accesskey "D">
|
||||
<!ENTITY syncSyncNowItem.label "Sync Now">
|
||||
<!ENTITY syncSyncNowItem.accesskey "S">
|
||||
|
|
Загрузка…
Ссылка в новой задаче