diff --git a/browser/base/content/aboutHome.css b/browser/base/content/aboutHome.css index d52b628c53d1..e96bf05a671c 100644 --- a/browser/base/content/aboutHome.css +++ b/browser/base/content/aboutHome.css @@ -369,6 +369,14 @@ body[dir=rtl] #restorePreviousSession::before { bottom: 2%; } +#syncLinksContainer { + padding-top: 1em; +} + +.sync-link { + padding: 1em; +} + @media all and (max-height: 370px) { #bottomSection { visibility: hidden; diff --git a/browser/base/content/aboutHome.xhtml b/browser/base/content/aboutHome.xhtml index fcc80878a10c..b6fb4ea7c4bb 100644 --- a/browser/base/content/aboutHome.xhtml +++ b/browser/base/content/aboutHome.xhtml @@ -102,6 +102,10 @@
&abouthome.aboutMozilla;
+ diff --git a/browser/base/content/browser-syncui.js b/browser/base/content/browser-syncui.js index bb43750e93da..132a4a718a8e 100644 --- a/browser/base/content/browser-syncui.js +++ b/browser/base/content/browser-syncui.js @@ -211,6 +211,24 @@ let gSyncUI = { this.clearError(title); }, + // Set visibility of "Setup Sync" link + showSetupSyncAboutHome: function SUI_showSetupSyncAboutHome(toShow) { + let browsers = gBrowser.browsers; + for (let i = 0; i < browsers.length; i++) { + let b = browsers[i]; + if ("about:home" == b.currentURI.spec) { + b.contentDocument.getElementById("setupSyncLink").hidden = !toShow; + } + } + }, + + onSetupComplete: function SUI_onSetupComplete() { + // Remove "setup sync" link in about:home if it is open. + this.showSetupSyncAboutHome(false); + + onLoginFinish(); + }, + onLoginError: function SUI_onLoginError() { // if login fails, any other notifications are essentially moot Weave.Notifications.removeAll(); @@ -255,6 +273,8 @@ let gSyncUI = { onStartOver: function SUI_onStartOver() { this.clearError(); + // Make "setup sync" link visible in about:home if it is open. + this.showSetupSyncAboutHome(true); }, onQuotaNotice: function onQuotaNotice(subject, data) { @@ -291,16 +311,40 @@ let gSyncUI = { //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() { + + /** + * Invoke the Sync setup wizard. + * + * @param wizardType + * Indicates type of wizard to launch: + * null -- regular set up wizard + * "pair" -- pair a device first + * "reset" -- reset sync + */ + + openSetup: function SUI_openSetup(wizardType) { let win = Services.wm.getMostRecentWindow("Weave:AccountSetup"); if (win) win.focus(); else { window.openDialog("chrome://browser/content/syncSetup.xul", - "weaveSetup", "centerscreen,chrome,resizable=no"); + "weaveSetup", "centerscreen,chrome,resizable=no", + wizardType); } }, + openAddDevice: function () { + if (!Weave.Utils.ensureMPUnlocked()) + return; + + let win = Services.wm.getMostRecentWindow("Sync:AddDevice"); + if (win) + win.focus(); + else + window.openDialog("chrome://browser/content/syncAddDevice.xul", + "syncAddDevice", "centerscreen,chrome,resizable=no"); + }, + openQuotaDialog: function SUI_openQuotaDialog() { let win = Services.wm.getMostRecentWindow("Sync:ViewQuota"); if (win) @@ -462,7 +506,7 @@ let gSyncUI = { this.onQuotaNotice(); break; case "weave:service:setup-complete": - this.onLoginFinish(); + this.onSetupComplete(); break; case "weave:service:login:start": this.onActivityStart(); diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 555804b59d90..828c94f86183 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -2675,6 +2675,10 @@ function BrowserOnAboutPageLoad(document) { getService(Components.interfaces.nsISessionStore); if (!ss.canRestoreLastSession) document.getElementById("sessionRestoreContainer").hidden = true; + // Sync-related links + if (Services.prefs.prefHasUserValue("services.sync.username")) { + document.getElementById("setupSyncLink").hidden = true; + } } } @@ -2683,7 +2687,9 @@ function BrowserOnAboutPageLoad(document) { */ function BrowserOnClick(event) { // Don't trust synthetic events - if (!event.isTrusted || event.target.localName != "button") + if (!event.isTrusted || + (event.target.localName != "button" && + event.target.className != "sync-link")) return; var ot = event.originalTarget; @@ -2813,6 +2819,16 @@ function BrowserOnClick(event) { ss.restoreLastSession(); errorDoc.getElementById("sessionRestoreContainer").hidden = true; } + else if (ot == errorDoc.getElementById("pairDeviceLink")) { + if (Services.prefs.prefHasUserValue("services.sync.username")) { + gSyncUI.openAddDevice(); + } else { + gSyncUI.openSetup("pair"); + } + } + else if (ot == errorDoc.getElementById("setupSyncLink")) { + gSyncUI.openSetup(null); + } } } diff --git a/browser/base/content/syncProgress.js b/browser/base/content/syncProgress.js index 3a89f54f844f..49ccfb45e93b 100644 --- a/browser/base/content/syncProgress.js +++ b/browser/base/content/syncProgress.js @@ -44,12 +44,14 @@ let gProgressBar; let gCounter = 0; function onLoad(event) { - Services.obs.addObserver(increaseProgressBar, "weave:engine:sync:finish", false); - Services.obs.addObserver(increaseProgressBar, "weave:engine:sync:error", false); + Services.obs.addObserver(onEngineSync, "weave:engine:sync:finish", false); + Services.obs.addObserver(onEngineSync, "weave:engine:sync:error", false); + Services.obs.addObserver(onServiceSync, "weave:service:sync:finish", false); + Services.obs.addObserver(onServiceSync, "weave:service:sync:error", false); + gProgressBar = document.getElementById('uploadProgressBar'); if (Services.prefs.getPrefType("services.sync.firstSync") != Ci.nsIPrefBranch.PREF_INVALID) { - gProgressBar.max = Weave.Engines.getEnabled().length; gProgressBar.style.display = "inline"; } else { @@ -58,15 +60,46 @@ function onLoad(event) { } function onUnload(event) { - Services.obs.removeObserver(increaseProgressBar, "weave:engine:sync:finish"); - Services.obs.removeObserver(increaseProgressBar, "weave:engine:sync:error"); + cleanUpObservers(); } -function increaseProgressBar(){ +function cleanUpObservers() { + try { + Services.obs.removeObserver(onEngineSync, "weave:engine:sync:finish", false); + Services.obs.removeObserver(onEngineSync, "weave:engine:sync:error", false); + Services.obs.removeObserver(onServiceSync, "weave:service:sync:finish", false); + Services.obs.removeObserver(onServiceSync, "weave:service:sync:error", false); + } + catch (e) { + // may be double called by unload & exit. Ignore. + } +} + +function onEngineSync(subject, topic, data) { + // The Clients engine syncs first. At this point we don't necessarily know + // yet how many engines will be enabled, so we'll ignore the Clients engine + // and evaluate how many engines are enabled when the first "real" engine + // syncs. + if (data == "clients") { + return; + } + + if (!gCounter && + Services.prefs.getPrefType("services.sync.firstSync") != Ci.nsIPrefBranch.PREF_INVALID) { + gProgressBar.max = Weave.Engines.getEnabled().length; + } + gCounter += 1; gProgressBar.setAttribute("value", gCounter); } +function onServiceSync(subject, topic, data) { + // To address the case where 0 engines are synced, we will fill the + // progress bar so the user knows that the sync has finished. + gProgressBar.setAttribute("value", gProgressBar.max); + cleanUpObservers(); +} + function closeTab() { window.close(); } diff --git a/browser/base/content/test/browser_aboutHome.js b/browser/base/content/test/browser_aboutHome.js index 72f20cd45768..6ecb364ecbf9 100644 --- a/browser/base/content/test/browser_aboutHome.js +++ b/browser/base/content/test/browser_aboutHome.js @@ -10,6 +10,9 @@ registerCleanupFunction(function() { try { Services.prefs.clearUserPref("network.cookie.lifetimePolicy"); } catch (ex) {} + try { + Services.prefs.clearUserPref("services.sync.username"); + } catch (ex) {} }); let gTests = [ @@ -114,6 +117,116 @@ let gTests = [ } }, +{ + desc: "Check sync links visibility before and after Sync setup", + setup: function () + { + try { + Services.prefs.clearUserPref("services.sync.username"); + } catch (ex) {} + Services.obs.notifyObservers(null, "weave:service:ready", null); + }, + run: function () + { + let doc = gBrowser.selectedTab.linkedBrowser.contentDocument; + let pairLink = doc.getElementById("pairDeviceLink"); + let setupLink = doc.getElementById("setupSyncLink"); + + ok(pairLink, "Found 'Pair Device' link"); + ok(setupLink, "Found 'Set Up Sync' link"); + ok(!pairLink.hidden, "'Pair' link is visible before setup"); + ok(!setupLink.hidden, "'Set Up' link is visible before setup"); + + Services.obs.notifyObservers(null, "weave:service:setup-complete", null); + + executeSoon(function () { + setupLink = doc.getElementById("setupSyncLink"); + ok(setupLink.hidden, "'Set Up' link is hidden after setup"); + ok(!pairLink.hidden, "'Pair' link is visible after setup"); + + executeSoon(runNextTest); + }); + } +}, + +{ + desc: "Check sync links visibility before and after Sync unlink", + setup: function () + { + Services.prefs.setCharPref("services.sync.username", "someuser@domain.com"); + Services.obs.notifyObservers(null, "weave:service:ready", null); + }, + run: function () + { + let doc = gBrowser.selectedTab.linkedBrowser.contentDocument; + let pairLink = doc.getElementById("pairDeviceLink"); + let setupLink = doc.getElementById("setupSyncLink"); + + ok(!pairLink.hidden, "'Pair' link is visible before unlink"); + ok(setupLink.hidden, "'Set Up' link is hidden before unlink"); + + Services.obs.notifyObservers(null, "weave:service:start-over", null); + + executeSoon(function () { + setupLink = doc.getElementById("setupSyncLink"); + ok(!setupLink.hidden, "'Set Up' link is visible after unlink"); + ok(!pairLink.hidden, "'Pair' link is visible after unlink"); + executeSoon(runNextTest); + }); + } +}, + +{ + desc: "Check Pair Device link opens correct dialog with Sync account ", + setup: function () + { + Services.prefs.setCharPref("services.sync.username", "someuser@domain.com"); + Services.obs.notifyObservers(null, "weave:service:ready", null); + }, + run: function () + { + expectDialogWindow("Sync:AddDevice"); + let browser = gBrowser.selectedTab.linkedBrowser; + let button = browser.contentDocument.getElementById("pairDeviceLink"); + EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow); + } +}, + +{ + desc: "Check Pair Device link opens correct dialog without Sync account", + setup: function () + { + try { + Services.prefs.clearUserPref("services.sync.username"); + } catch (ex) {} + Services.obs.notifyObservers(null, "weave:service:ready", null); + }, + run: function () + { + expectDialogWindow("Weave:AccountSetup"); + let browser = gBrowser.selectedTab.linkedBrowser; + let button = browser.contentDocument.getElementById("pairDeviceLink"); + EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow); + } +}, + +{ + desc: "Check Sync Setup link opens correct dialog (without Sync account)", + setup: function () + { + try { + Services.prefs.clearUserPref("services.sync.username"); + } catch (ex) {} + Services.obs.notifyObservers(null, "weave:service:ready", null); + }, + run: function () + { + expectDialogWindow("Weave:AccountSetup"); + let browser = gBrowser.selectedTab.linkedBrowser; + let button = browser.contentDocument.getElementById("setupSyncLink"); + EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow); + } +}, ]; function test() @@ -159,6 +272,22 @@ function runNextTest() } } +function expectDialogWindow(expectedDialog) { + Services.ww.registerNotification(function onWindow(subject, topic) { + let win = subject.QueryInterface(Components.interfaces.nsIDOMWindow); + win.addEventListener("load", function onLoad() { + win.removeEventListener("load", onLoad, false); + let wintype = win.document.documentElement.getAttribute("windowtype"); + if (topic == "domwindowopened" && wintype == expectedDialog) { + Services.ww.unregisterNotification(onWindow); + // Clean up dialog. + win.close(); + executeSoon(runNextTest); + } + }, false); + }); +} + function getStorage() { let aboutHomeURI = Services.io.newURI("moz-safe-about:home", null, null); diff --git a/browser/locales/en-US/chrome/browser/aboutHome.dtd b/browser/locales/en-US/chrome/browser/aboutHome.dtd index 1fc59a5913c4..f41846a0d480 100644 --- a/browser/locales/en-US/chrome/browser/aboutHome.dtd +++ b/browser/locales/en-US/chrome/browser/aboutHome.dtd @@ -18,3 +18,6 @@ text in will be linked to the featured add-ons on addons.mozilla.org --> Choose from thousands of add-ons."> + + + diff --git a/mobile/chrome/content/aboutHome.xhtml b/mobile/chrome/content/aboutHome.xhtml index 1212a6ef3edc..c355e3d308d5 100644 --- a/mobile/chrome/content/aboutHome.xhtml +++ b/mobile/chrome/content/aboutHome.xhtml @@ -96,6 +96,7 @@
&aboutHome.setupSync; + &aboutHome.syncPairDevice;
@@ -433,8 +434,10 @@ function initSetupSync() { let services = getChromeWin().Services; if (services.prefs.prefHasUserValue("services.sync.username")) { - document.getElementById("syncSetupSync").style.display = "none"; - } + syncConnected(); + } else { + syncDisconnected(); + } services.obs.addObserver(syncConnected, "weave:service:setup-complete", false); services.obs.addObserver(syncDisconnected, "weave:service:start-over", false); } @@ -447,10 +450,12 @@ function syncConnected() { document.getElementById("syncSetupSync").style.display = "none"; + document.getElementById("syncPairDevice").style.display = "inline"; } function syncDisconnected() { document.getElementById("syncSetupSync").style.display = "inline"; + document.getElementById("syncPairDevice").style.display = "none"; } function openSetupSyncWizard() { @@ -458,6 +463,11 @@ chromeWin.WeaveGlue.open(); } + function openPairDeviceWizard() { + let chromeWin = getChromeWin(); + chromeWin.SyncPairDevice.open(); + } + function initLightbox() { let prefs = getChromeWin().Services.prefs; let channel = prefs.getCharPref("app.update.channel"); diff --git a/mobile/chrome/content/browser-scripts.js b/mobile/chrome/content/browser-scripts.js index 1209fddc9d47..aa4ed082d362 100644 --- a/mobile/chrome/content/browser-scripts.js +++ b/mobile/chrome/content/browser-scripts.js @@ -113,6 +113,7 @@ XPCOMUtils.defineLazyGetter(this, "CommonUI", function() { ["MasterPasswordUI", "chrome://browser/content/MasterPasswordUI.js"], #ifdef MOZ_SERVICES_SYNC ["WeaveGlue", "chrome://browser/content/sync.js"], + ["SyncPairDevice", "chrome://browser/content/sync.js"], #endif ["WebappsUI", "chrome://browser/content/WebappsUI.js"], ["SSLExceptions", "chrome://browser/content/exceptions.js"], diff --git a/mobile/chrome/content/browser.xul b/mobile/chrome/content/browser.xul index 33bfb385abd7..ad35df46ccbb 100644 --- a/mobile/chrome/content/browser.xul +++ b/mobile/chrome/content/browser.xul @@ -24,6 +24,7 @@ - Brad Lassey - Mark Finkle - Matt Brubeck + - Allison Naaktgeboren - - 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 @@ -487,6 +488,7 @@ + + + + #endif