mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
406 lines
14 KiB
JavaScript
406 lines
14 KiB
JavaScript
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
let gFxAccounts = {
|
|
|
|
PREF_SYNC_START_DOORHANGER: "services.sync.ui.showSyncStartDoorhanger",
|
|
DOORHANGER_ACTIVATE_DELAY_MS: 5000,
|
|
SYNC_MIGRATION_NOTIFICATION_TITLE: "fxa-migration",
|
|
|
|
_initialized: false,
|
|
_inCustomizationMode: false,
|
|
// _expectingNotifyClose is a hack that helps us determine if the
|
|
// migration notification was closed due to being "dismissed" vs closed
|
|
// due to one of the migration buttons being clicked. It's ugly and somewhat
|
|
// fragile, so bug 1119020 exists to help us do this better.
|
|
_expectingNotifyClose: false,
|
|
|
|
get weave() {
|
|
delete this.weave;
|
|
return this.weave = Cc["@mozilla.org/weave/service;1"]
|
|
.getService(Ci.nsISupports)
|
|
.wrappedJSObject;
|
|
},
|
|
|
|
get topics() {
|
|
// Do all this dance to lazy-load FxAccountsCommon.
|
|
delete this.topics;
|
|
return this.topics = [
|
|
"weave:service:ready",
|
|
"weave:service:sync:start",
|
|
"weave:service:login:error",
|
|
"weave:service:setup-complete",
|
|
"fxa-migration:state-changed",
|
|
this.FxAccountsCommon.ONVERIFIED_NOTIFICATION,
|
|
this.FxAccountsCommon.ONLOGOUT_NOTIFICATION,
|
|
"weave:notification:removed",
|
|
];
|
|
},
|
|
|
|
get button() {
|
|
delete this.button;
|
|
return this.button = document.getElementById("PanelUI-fxa-status");
|
|
},
|
|
|
|
get strings() {
|
|
delete this.strings;
|
|
return this.strings = Services.strings.createBundle(
|
|
"chrome://browser/locale/accounts.properties"
|
|
);
|
|
},
|
|
|
|
get loginFailed() {
|
|
// Referencing Weave.Service will implicitly initialize sync, and we don't
|
|
// want to force that - so first check if it is ready.
|
|
let service = Cc["@mozilla.org/weave/service;1"]
|
|
.getService(Components.interfaces.nsISupports)
|
|
.wrappedJSObject;
|
|
if (!service.ready) {
|
|
return false;
|
|
}
|
|
// LOGIN_FAILED_LOGIN_REJECTED explicitly means "you must log back in".
|
|
// All other login failures are assumed to be transient and should go
|
|
// away by themselves, so aren't reflected here.
|
|
return Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED;
|
|
},
|
|
|
|
get isActiveWindow() {
|
|
let fm = Services.focus;
|
|
return fm.activeWindow == window;
|
|
},
|
|
|
|
init: function () {
|
|
// Bail out if we're already initialized and for pop-up windows.
|
|
if (this._initialized || !window.toolbar.visible) {
|
|
return;
|
|
}
|
|
|
|
for (let topic of this.topics) {
|
|
Services.obs.addObserver(this, topic, false);
|
|
}
|
|
|
|
addEventListener("activate", this);
|
|
gNavToolbox.addEventListener("customizationstarting", this);
|
|
gNavToolbox.addEventListener("customizationending", this);
|
|
|
|
// Request the current Legacy-Sync-to-FxA migration status. We'll be
|
|
// notified of fxa-migration:state-changed in response if necessary.
|
|
Services.obs.notifyObservers(null, "fxa-migration:state-request", null);
|
|
|
|
this._initialized = true;
|
|
|
|
this.updateUI();
|
|
},
|
|
|
|
uninit: function () {
|
|
if (!this._initialized) {
|
|
return;
|
|
}
|
|
|
|
for (let topic of this.topics) {
|
|
Services.obs.removeObserver(this, topic);
|
|
}
|
|
|
|
this._initialized = false;
|
|
},
|
|
|
|
observe: function (subject, topic, data) {
|
|
switch (topic) {
|
|
case this.FxAccountsCommon.ONVERIFIED_NOTIFICATION:
|
|
Services.prefs.setBoolPref(this.PREF_SYNC_START_DOORHANGER, true);
|
|
break;
|
|
case "weave:service:sync:start":
|
|
this.onSyncStart();
|
|
break;
|
|
case "fxa-migration:state-changed":
|
|
this.onMigrationStateChanged(data, subject);
|
|
break;
|
|
case "weave:notification:removed":
|
|
// this exists just so we can tell the difference between "box was
|
|
// closed due to button press" vs "was closed due to click on [x]"
|
|
let notif = subject.wrappedJSObject.object;
|
|
if (notif.title == this.SYNC_MIGRATION_NOTIFICATION_TITLE &&
|
|
!this._expectingNotifyClose) {
|
|
// it's an [x] on our notification, so record telemetry.
|
|
this.fxaMigrator.recordTelemetry(this.fxaMigrator.TELEMETRY_DECLINED);
|
|
}
|
|
break;
|
|
default:
|
|
this.updateUI();
|
|
break;
|
|
}
|
|
},
|
|
|
|
onSyncStart: function () {
|
|
if (!this.isActiveWindow) {
|
|
return;
|
|
}
|
|
|
|
let showDoorhanger = false;
|
|
|
|
try {
|
|
showDoorhanger = Services.prefs.getBoolPref(this.PREF_SYNC_START_DOORHANGER);
|
|
} catch (e) { /* The pref might not exist. */ }
|
|
|
|
if (showDoorhanger) {
|
|
Services.prefs.clearUserPref(this.PREF_SYNC_START_DOORHANGER);
|
|
this.showSyncStartedDoorhanger();
|
|
}
|
|
},
|
|
|
|
onMigrationStateChanged: function (newState, email) {
|
|
this._migrationInfo = !newState ? null : {
|
|
state: newState,
|
|
email: email ? email.QueryInterface(Ci.nsISupportsString).data : null,
|
|
};
|
|
this.updateUI();
|
|
},
|
|
|
|
handleEvent: function (event) {
|
|
if (event.type == "activate") {
|
|
// Our window might have been in the background while we received the
|
|
// sync:start notification. If still needed, show the doorhanger after
|
|
// a short delay. Without this delay the doorhanger would not show up
|
|
// or with a too small delay show up while we're still animating the
|
|
// window.
|
|
setTimeout(() => this.onSyncStart(), this.DOORHANGER_ACTIVATE_DELAY_MS);
|
|
} else {
|
|
this._inCustomizationMode = event.type == "customizationstarting";
|
|
this.updateAppMenuItem();
|
|
}
|
|
},
|
|
|
|
showDoorhanger: function (id) {
|
|
let panel = document.getElementById(id);
|
|
let anchor = document.getElementById("PanelUI-menu-button");
|
|
|
|
let iconAnchor =
|
|
document.getAnonymousElementByAttribute(anchor, "class",
|
|
"toolbarbutton-icon");
|
|
|
|
panel.hidden = false;
|
|
panel.openPopup(iconAnchor || anchor, "bottomcenter topright");
|
|
},
|
|
|
|
showSyncStartedDoorhanger: function () {
|
|
this.showDoorhanger("sync-start-panel");
|
|
},
|
|
|
|
showSyncFailedDoorhanger: function () {
|
|
this.showDoorhanger("sync-error-panel");
|
|
},
|
|
|
|
updateUI: function () {
|
|
this.updateAppMenuItem();
|
|
this.updateMigrationNotification();
|
|
},
|
|
|
|
updateAppMenuItem: function () {
|
|
if (this._migrationInfo) {
|
|
this.updateAppMenuItemForMigration();
|
|
return;
|
|
}
|
|
|
|
// Bail out if FxA is disabled.
|
|
if (!this.weave.fxAccountsEnabled) {
|
|
// When migration transitions from needs-verification to the null state,
|
|
// fxAccountsEnabled is false because migration has not yet finished. In
|
|
// that case, hide the button. We'll get another notification with a null
|
|
// state once migration is complete.
|
|
this.button.hidden = true;
|
|
this.button.removeAttribute("fxastatus");
|
|
return;
|
|
}
|
|
|
|
// FxA is enabled, show the widget.
|
|
this.button.hidden = false;
|
|
|
|
// Make sure the button is disabled in customization mode.
|
|
if (this._inCustomizationMode) {
|
|
this.button.setAttribute("disabled", "true");
|
|
} else {
|
|
this.button.removeAttribute("disabled");
|
|
}
|
|
|
|
let defaultLabel = this.button.getAttribute("defaultlabel");
|
|
let errorLabel = this.button.getAttribute("errorlabel");
|
|
|
|
// If the user is signed into their Firefox account and we are not
|
|
// currently in customization mode, show their email address.
|
|
let doUpdate = userData => {
|
|
// Reset the button to its original state.
|
|
this.button.setAttribute("label", defaultLabel);
|
|
this.button.removeAttribute("tooltiptext");
|
|
this.button.removeAttribute("fxastatus");
|
|
|
|
if (!this._inCustomizationMode) {
|
|
if (this.loginFailed) {
|
|
this.button.setAttribute("fxastatus", "error");
|
|
this.button.setAttribute("label", errorLabel);
|
|
} else if (userData) {
|
|
this.button.setAttribute("fxastatus", "signedin");
|
|
this.button.setAttribute("label", userData.email);
|
|
this.button.setAttribute("tooltiptext", userData.email);
|
|
}
|
|
}
|
|
}
|
|
fxAccounts.getSignedInUser().then(userData => {
|
|
doUpdate(userData);
|
|
}).then(null, error => {
|
|
// This is most likely in tests, were we quickly log users in and out.
|
|
// The most likely scenario is a user logged out, so reflect that.
|
|
// Bug 995134 calls for better errors so we could retry if we were
|
|
// sure this was the failure reason.
|
|
doUpdate(null);
|
|
});
|
|
},
|
|
|
|
updateAppMenuItemForMigration: Task.async(function* () {
|
|
let status = null;
|
|
let label = null;
|
|
switch (this._migrationInfo.state) {
|
|
case this.fxaMigrator.STATE_USER_FXA:
|
|
status = "migrate-signup";
|
|
label = this.strings.formatStringFromName("needUserShort",
|
|
[this.button.getAttribute("fxabrandname")], 1);
|
|
break;
|
|
case this.fxaMigrator.STATE_USER_FXA_VERIFIED:
|
|
status = "migrate-verify";
|
|
label = this.strings.formatStringFromName("needVerifiedUserShort",
|
|
[this._migrationInfo.email],
|
|
1);
|
|
break;
|
|
}
|
|
this.button.label = label;
|
|
this.button.hidden = false;
|
|
this.button.setAttribute("fxastatus", status);
|
|
}),
|
|
|
|
updateMigrationNotification: Task.async(function* () {
|
|
if (!this._migrationInfo) {
|
|
this._expectingNotifyClose = true;
|
|
Weave.Notifications.removeAll(this.SYNC_MIGRATION_NOTIFICATION_TITLE);
|
|
// because this is called even when there is no such notification, we
|
|
// set _expectingNotifyClose back to false as we may yet create a new
|
|
// notification (but in general, once we've created a migration
|
|
// notification once in a session, we don't create one again)
|
|
this._expectingNotifyClose = false;
|
|
return;
|
|
}
|
|
let note = null;
|
|
switch (this._migrationInfo.state) {
|
|
case this.fxaMigrator.STATE_USER_FXA: {
|
|
// There are 2 cases here - no email address means it is an offer on
|
|
// the first device (so the user is prompted to create an account).
|
|
// If there is an email address it is the "join the party" flow, so the
|
|
// user is prompted to sign in with the address they previously used.
|
|
let msg, upgradeLabel, upgradeAccessKey, learnMoreLink;
|
|
if (this._migrationInfo.email) {
|
|
msg = this.strings.formatStringFromName("signInAfterUpgradeOnOtherDevice.description",
|
|
[this._migrationInfo.email],
|
|
1);
|
|
upgradeLabel = this.strings.GetStringFromName("signInAfterUpgradeOnOtherDevice.label");
|
|
upgradeAccessKey = this.strings.GetStringFromName("signInAfterUpgradeOnOtherDevice.accessKey");
|
|
} else {
|
|
msg = this.strings.GetStringFromName("needUserLong");
|
|
upgradeLabel = this.strings.GetStringFromName("upgradeToFxA.label");
|
|
upgradeAccessKey = this.strings.GetStringFromName("upgradeToFxA.accessKey");
|
|
learnMoreLink = this.fxaMigrator.learnMoreLink;
|
|
}
|
|
note = new Weave.Notification(
|
|
undefined, msg, undefined, Weave.Notifications.PRIORITY_WARNING, [
|
|
new Weave.NotificationButton(upgradeLabel, upgradeAccessKey, () => {
|
|
this._expectingNotifyClose = true;
|
|
this.fxaMigrator.createFxAccount(window);
|
|
}),
|
|
], learnMoreLink
|
|
);
|
|
break;
|
|
}
|
|
case this.fxaMigrator.STATE_USER_FXA_VERIFIED: {
|
|
let msg =
|
|
this.strings.formatStringFromName("needVerifiedUserLong",
|
|
[this._migrationInfo.email], 1);
|
|
let resendLabel =
|
|
this.strings.GetStringFromName("resendVerificationEmail.label");
|
|
let resendAccessKey =
|
|
this.strings.GetStringFromName("resendVerificationEmail.accessKey");
|
|
note = new Weave.Notification(
|
|
undefined, msg, undefined, Weave.Notifications.PRIORITY_INFO, [
|
|
new Weave.NotificationButton(resendLabel, resendAccessKey, () => {
|
|
this._expectingNotifyClose = true;
|
|
this.fxaMigrator.resendVerificationMail();
|
|
}),
|
|
]
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
note.title = this.SYNC_MIGRATION_NOTIFICATION_TITLE;
|
|
Weave.Notifications.replaceTitle(note);
|
|
}),
|
|
|
|
onMenuPanelCommand: function (event) {
|
|
let button = event.originalTarget;
|
|
|
|
switch (button.getAttribute("fxastatus")) {
|
|
case "signedin":
|
|
this.openPreferences();
|
|
break;
|
|
case "error":
|
|
this.openSignInAgainPage("menupanel");
|
|
break;
|
|
case "migrate-signup":
|
|
case "migrate-verify":
|
|
// The migration flow calls for the menu item to open sync prefs rather
|
|
// than requesting migration start immediately.
|
|
this.openPreferences();
|
|
break;
|
|
default:
|
|
this.openAccountsPage(null, { entryPoint: "menupanel" });
|
|
break;
|
|
}
|
|
|
|
PanelUI.hide();
|
|
},
|
|
|
|
openPreferences: function () {
|
|
openPreferences("paneSync");
|
|
},
|
|
|
|
openAccountsPage: function (action, urlParams={}) {
|
|
// An entryPoint param is used for server-side metrics. If the current tab
|
|
// is UITour, assume that it initiated the call to this method and override
|
|
// the entryPoint accordingly.
|
|
if (UITour.tourBrowsersByWindow.get(window) &&
|
|
UITour.tourBrowsersByWindow.get(window).has(gBrowser.selectedBrowser)) {
|
|
urlParams.entryPoint = "uitour";
|
|
}
|
|
let params = new URLSearchParams();
|
|
if (action) {
|
|
params.set("action", action);
|
|
}
|
|
for (let name in urlParams) {
|
|
if (urlParams[name] !== undefined) {
|
|
params.set(name, urlParams[name]);
|
|
}
|
|
}
|
|
let url = "about:accounts?" + params;
|
|
switchToTabHavingURI(url, true, {
|
|
replaceQueryString: true
|
|
});
|
|
},
|
|
|
|
openSignInAgainPage: function (entryPoint) {
|
|
this.openAccountsPage("reauth", { entryPoint: entryPoint });
|
|
},
|
|
};
|
|
|
|
XPCOMUtils.defineLazyGetter(gFxAccounts, "FxAccountsCommon", function () {
|
|
return Cu.import("resource://gre/modules/FxAccountsCommon.js", {});
|
|
});
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(gFxAccounts, "fxaMigrator",
|
|
"resource://services-sync/FxaMigrator.jsm");
|