michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () { michael@0: return Cu.import("resource://gre/modules/FxAccountsCommon.js", {}); michael@0: }); michael@0: michael@0: const PREF_SYNC_START_DOORHANGER = "services.sync.ui.showSyncStartDoorhanger"; michael@0: const DOORHANGER_ACTIVATE_DELAY_MS = 5000; michael@0: michael@0: let gFxAccounts = { michael@0: michael@0: _initialized: false, michael@0: _inCustomizationMode: false, michael@0: michael@0: get weave() { michael@0: delete this.weave; michael@0: return this.weave = Cc["@mozilla.org/weave/service;1"] michael@0: .getService(Ci.nsISupports) michael@0: .wrappedJSObject; michael@0: }, michael@0: michael@0: get topics() { michael@0: // Do all this dance to lazy-load FxAccountsCommon. michael@0: delete this.topics; michael@0: return this.topics = [ michael@0: "weave:service:ready", michael@0: "weave:service:sync:start", michael@0: "weave:service:login:error", michael@0: "weave:service:setup-complete", michael@0: FxAccountsCommon.ONVERIFIED_NOTIFICATION, michael@0: FxAccountsCommon.ONLOGOUT_NOTIFICATION michael@0: ]; michael@0: }, michael@0: michael@0: get button() { michael@0: delete this.button; michael@0: return this.button = document.getElementById("PanelUI-fxa-status"); michael@0: }, michael@0: michael@0: get loginFailed() { michael@0: // Referencing Weave.Service will implicitly initialize sync, and we don't michael@0: // want to force that - so first check if it is ready. michael@0: let service = Cc["@mozilla.org/weave/service;1"] michael@0: .getService(Components.interfaces.nsISupports) michael@0: .wrappedJSObject; michael@0: if (!service.ready) { michael@0: return false; michael@0: } michael@0: // LOGIN_FAILED_LOGIN_REJECTED explicitly means "you must log back in". michael@0: // All other login failures are assumed to be transient and should go michael@0: // away by themselves, so aren't reflected here. michael@0: return Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED; michael@0: }, michael@0: michael@0: get isActiveWindow() { michael@0: let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); michael@0: return fm.activeWindow == window; michael@0: }, michael@0: michael@0: init: function () { michael@0: // Bail out if we're already initialized and for pop-up windows. michael@0: if (this._initialized || !window.toolbar.visible) { michael@0: return; michael@0: } michael@0: michael@0: for (let topic of this.topics) { michael@0: Services.obs.addObserver(this, topic, false); michael@0: } michael@0: michael@0: addEventListener("activate", this); michael@0: gNavToolbox.addEventListener("customizationstarting", this); michael@0: gNavToolbox.addEventListener("customizationending", this); michael@0: michael@0: this._initialized = true; michael@0: michael@0: this.updateUI(); michael@0: }, michael@0: michael@0: uninit: function () { michael@0: if (!this._initialized) { michael@0: return; michael@0: } michael@0: michael@0: for (let topic of this.topics) { michael@0: Services.obs.removeObserver(this, topic); michael@0: } michael@0: michael@0: this._initialized = false; michael@0: }, michael@0: michael@0: observe: function (subject, topic) { michael@0: switch (topic) { michael@0: case FxAccountsCommon.ONVERIFIED_NOTIFICATION: michael@0: Services.prefs.setBoolPref(PREF_SYNC_START_DOORHANGER, true); michael@0: break; michael@0: case "weave:service:sync:start": michael@0: this.onSyncStart(); michael@0: break; michael@0: default: michael@0: this.updateUI(); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: onSyncStart: function () { michael@0: if (!this.isActiveWindow) { michael@0: return; michael@0: } michael@0: michael@0: let showDoorhanger = false; michael@0: michael@0: try { michael@0: showDoorhanger = Services.prefs.getBoolPref(PREF_SYNC_START_DOORHANGER); michael@0: } catch (e) { /* The pref might not exist. */ } michael@0: michael@0: if (showDoorhanger) { michael@0: Services.prefs.clearUserPref(PREF_SYNC_START_DOORHANGER); michael@0: this.showSyncStartedDoorhanger(); michael@0: } michael@0: }, michael@0: michael@0: handleEvent: function (event) { michael@0: if (event.type == "activate") { michael@0: // Our window might have been in the background while we received the michael@0: // sync:start notification. If still needed, show the doorhanger after michael@0: // a short delay. Without this delay the doorhanger would not show up michael@0: // or with a too small delay show up while we're still animating the michael@0: // window. michael@0: setTimeout(() => this.onSyncStart(), DOORHANGER_ACTIVATE_DELAY_MS); michael@0: } else { michael@0: this._inCustomizationMode = event.type == "customizationstarting"; michael@0: this.updateUI(); michael@0: } michael@0: }, michael@0: michael@0: showDoorhanger: function (id) { michael@0: let panel = document.getElementById(id); michael@0: let anchor = document.getElementById("PanelUI-menu-button"); michael@0: michael@0: let iconAnchor = michael@0: document.getAnonymousElementByAttribute(anchor, "class", michael@0: "toolbarbutton-icon"); michael@0: michael@0: panel.hidden = false; michael@0: panel.openPopup(iconAnchor || anchor, "bottomcenter topright"); michael@0: }, michael@0: michael@0: showSyncStartedDoorhanger: function () { michael@0: this.showDoorhanger("sync-start-panel"); michael@0: }, michael@0: michael@0: showSyncFailedDoorhanger: function () { michael@0: this.showDoorhanger("sync-error-panel"); michael@0: }, michael@0: michael@0: updateUI: function () { michael@0: // Bail out if FxA is disabled. michael@0: if (!this.weave.fxAccountsEnabled) { michael@0: return; michael@0: } michael@0: michael@0: // FxA is enabled, show the widget. michael@0: this.button.removeAttribute("hidden"); michael@0: michael@0: // Make sure the button is disabled in customization mode. michael@0: if (this._inCustomizationMode) { michael@0: this.button.setAttribute("disabled", "true"); michael@0: } else { michael@0: this.button.removeAttribute("disabled"); michael@0: } michael@0: michael@0: let defaultLabel = this.button.getAttribute("defaultlabel"); michael@0: let errorLabel = this.button.getAttribute("errorlabel"); michael@0: michael@0: // If the user is signed into their Firefox account and we are not michael@0: // currently in customization mode, show their email address. michael@0: let doUpdate = userData => { michael@0: // Reset the button to its original state. michael@0: this.button.setAttribute("label", defaultLabel); michael@0: this.button.removeAttribute("tooltiptext"); michael@0: this.button.removeAttribute("signedin"); michael@0: this.button.removeAttribute("failed"); michael@0: michael@0: if (!this._inCustomizationMode) { michael@0: if (this.loginFailed) { michael@0: this.button.setAttribute("failed", "true"); michael@0: this.button.setAttribute("label", errorLabel); michael@0: } else if (userData) { michael@0: this.button.setAttribute("signedin", "true"); michael@0: this.button.setAttribute("label", userData.email); michael@0: this.button.setAttribute("tooltiptext", userData.email); michael@0: } michael@0: } michael@0: } michael@0: fxAccounts.getSignedInUser().then(userData => { michael@0: doUpdate(userData); michael@0: }).then(null, error => { michael@0: // This is most likely in tests, were we quickly log users in and out. michael@0: // The most likely scenario is a user logged out, so reflect that. michael@0: // Bug 995134 calls for better errors so we could retry if we were michael@0: // sure this was the failure reason. michael@0: doUpdate(null); michael@0: }); michael@0: }, michael@0: michael@0: onMenuPanelCommand: function (event) { michael@0: let button = event.originalTarget; michael@0: michael@0: if (button.hasAttribute("signedin")) { michael@0: this.openPreferences(); michael@0: } else if (button.hasAttribute("failed")) { michael@0: this.openSignInAgainPage(); michael@0: } else { michael@0: this.openAccountsPage(); michael@0: } michael@0: michael@0: PanelUI.hide(); michael@0: }, michael@0: michael@0: openPreferences: function () { michael@0: openPreferences("paneSync"); michael@0: }, michael@0: michael@0: openAccountsPage: function () { michael@0: switchToTabHavingURI("about:accounts", true); michael@0: }, michael@0: michael@0: openSignInAgainPage: function () { michael@0: switchToTabHavingURI("about:accounts?action=reauth", true); michael@0: } michael@0: };