diff options
Diffstat (limited to 'application/basilisk/base/content')
34 files changed, 280 insertions, 5400 deletions
diff --git a/application/basilisk/base/content/aboutaccounts/aboutaccounts.css b/application/basilisk/base/content/aboutaccounts/aboutaccounts.css deleted file mode 100644 index a2c5cb8f0..000000000 --- a/application/basilisk/base/content/aboutaccounts/aboutaccounts.css +++ /dev/null @@ -1,24 +0,0 @@ -html, body { - height: 100%; -} - -#remote { - width: 100%; - height: 100%; - border: 0; - display: none; -} - -#networkError, #manage, #intro, #stage, #configError { - display: none; -} - -#oldsync { - background: none; - border: 0; - color: #0095dd; -} - -#oldsync:focus { - outline: 1px dotted #0095dd; -} diff --git a/application/basilisk/base/content/aboutaccounts/aboutaccounts.js b/application/basilisk/base/content/aboutaccounts/aboutaccounts.js deleted file mode 100644 index a05c1ea75..000000000 --- a/application/basilisk/base/content/aboutaccounts/aboutaccounts.js +++ /dev/null @@ -1,543 +0,0 @@ -/* 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/. */ - -"use strict"; - -var {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/FxAccounts.jsm"); - -var fxAccountsCommon = {}; -Cu.import("resource://gre/modules/FxAccountsCommon.js", fxAccountsCommon); - -// for master-password utilities -Cu.import("resource://services-sync/util.js"); - -const PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash"; -const PREF_SYNC_SHOW_CUSTOMIZATION = "services.sync-setup.ui.showCustomizationDialog"; - -const ACTION_URL_PARAM = "action"; - -const OBSERVER_TOPICS = [ - fxAccountsCommon.ONVERIFIED_NOTIFICATION, - fxAccountsCommon.ONLOGOUT_NOTIFICATION, -]; - -function log(msg) { - // dump("FXA: " + msg + "\n"); -} - -function error(msg) { - console.log("Firefox Account Error: " + msg + "\n"); -} - -function getPreviousAccountNameHash() { - try { - return Services.prefs.getComplexValue(PREF_LAST_FXA_USER, Ci.nsISupportsString).data; - } catch (_) { - return ""; - } -} - -function setPreviousAccountNameHash(acctName) { - let string = Cc["@mozilla.org/supports-string;1"] - .createInstance(Ci.nsISupportsString); - string.data = sha256(acctName); - Services.prefs.setComplexValue(PREF_LAST_FXA_USER, Ci.nsISupportsString, string); -} - -function needRelinkWarning(acctName) { - let prevAcctHash = getPreviousAccountNameHash(); - return prevAcctHash && prevAcctHash != sha256(acctName); -} - -// Given a string, returns the SHA265 hash in base64 -function sha256(str) { - let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] - .createInstance(Ci.nsIScriptableUnicodeConverter); - converter.charset = "UTF-8"; - // Data is an array of bytes. - let data = converter.convertToByteArray(str, {}); - let hasher = Cc["@mozilla.org/security/hash;1"] - .createInstance(Ci.nsICryptoHash); - hasher.init(hasher.SHA256); - hasher.update(data, data.length); - - return hasher.finish(true); -} - -function promptForRelink(acctName) { - let sb = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties"); - let continueLabel = sb.GetStringFromName("continue.label"); - let title = sb.GetStringFromName("relinkVerify.title"); - let description = sb.formatStringFromName("relinkVerify.description", - [acctName], 1); - let body = sb.GetStringFromName("relinkVerify.heading") + - "\n\n" + description; - let ps = Services.prompt; - let buttonFlags = (ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING) + - (ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL) + - ps.BUTTON_POS_1_DEFAULT; - let pressed = Services.prompt.confirmEx(window, title, body, buttonFlags, - continueLabel, null, null, null, - {}); - return pressed == 0; // 0 is the "continue" button -} - -// If the last fxa account used for sync isn't this account, we display -// a modal dialog checking they really really want to do this... -// (This is sync-specific, so ideally would be in sync's identity module, -// but it's a little more seamless to do here, and sync is currently the -// only fxa consumer, so... -function shouldAllowRelink(acctName) { - return !needRelinkWarning(acctName) || promptForRelink(acctName); -} - -function updateDisplayedEmail(user) { - let emailDiv = document.getElementById("email"); - if (emailDiv && user) { - emailDiv.textContent = user.email; - } -} - -var wrapper = { - iframe: null, - - init: function (url, urlParams) { - // If a master-password is enabled, we want to encourage the user to - // unlock it. Things still work if not, but the user will probably need - // to re-auth next startup (in which case we will get here again and - // re-prompt) - Utils.ensureMPUnlocked(); - - let iframe = document.getElementById("remote"); - this.iframe = iframe; - this.iframe.QueryInterface(Ci.nsIFrameLoaderOwner); - let docShell = this.iframe.frameLoader.docShell; - docShell.QueryInterface(Ci.nsIWebProgress); - docShell.addProgressListener(this.iframeListener, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT); - iframe.addEventListener("load", this); - - // Ideally we'd just merge urlParams with new URL(url).searchParams, but our - // URLSearchParams implementation doesn't support iteration (bug 1085284). - let urlParamStr = urlParams.toString(); - if (urlParamStr) { - url += (url.includes("?") ? "&" : "?") + urlParamStr; - } - this.url = url; - // Set the iframe's location with loadURI/LOAD_FLAGS_REPLACE_HISTORY to - // avoid having a new history entry being added. REPLACE_HISTORY is used - // to replace the current entry, which is `about:blank`. - let webNav = iframe.frameLoader.docShell.QueryInterface(Ci.nsIWebNavigation); - webNav.loadURI(url, Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY, null, null, null); - }, - - retry: function () { - let webNav = this.iframe.frameLoader.docShell.QueryInterface(Ci.nsIWebNavigation); - webNav.loadURI(this.url, Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY, null, null, null); - }, - - iframeListener: { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, - Ci.nsISupportsWeakReference, - Ci.nsISupports]), - - onStateChange: function(aWebProgress, aRequest, aState, aStatus) { - let failure = false; - - // Captive portals sometimes redirect users - if ((aState & Ci.nsIWebProgressListener.STATE_REDIRECTING)) { - failure = true; - } else if ((aState & Ci.nsIWebProgressListener.STATE_STOP)) { - if (aRequest instanceof Ci.nsIHttpChannel) { - try { - failure = aRequest.responseStatus != 200; - } catch (e) { - failure = aStatus != Components.results.NS_OK; - } - } - } - - // Calling cancel() will raise some OnStateChange notifications by itself, - // so avoid doing that more than once - if (failure && aStatus != Components.results.NS_BINDING_ABORTED) { - aRequest.cancel(Components.results.NS_BINDING_ABORTED); - setErrorPage("networkError"); - } - }, - - onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) { - if (aRequest && aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) { - aRequest.cancel(Components.results.NS_BINDING_ABORTED); - setErrorPage("networkError"); - } - }, - - onProgressChange: function() {}, - onStatusChange: function() {}, - onSecurityChange: function() {}, - }, - - handleEvent: function (evt) { - switch (evt.type) { - case "load": - this.iframe.contentWindow.addEventListener("FirefoxAccountsCommand", this); - this.iframe.removeEventListener("load", this); - break; - case "FirefoxAccountsCommand": - this.handleRemoteCommand(evt); - break; - } - }, - - /** - * onLogin handler receives user credentials from the jelly after a - * sucessful login and stores it in the fxaccounts service - * - * @param accountData the user's account data and credentials - */ - onLogin: function (accountData) { - log("Received: 'login'. Data:" + JSON.stringify(accountData)); - - if (accountData.customizeSync) { - Services.prefs.setBoolPref(PREF_SYNC_SHOW_CUSTOMIZATION, true); - } - delete accountData.customizeSync; - // sessionTokenContext is erroneously sent by the content server. - // https://github.com/mozilla/fxa-content-server/issues/2766 - // To avoid having the FxA storage manager not knowing what to do with - // it we delete it here. - delete accountData.sessionTokenContext; - - // We need to confirm a relink - see shouldAllowRelink for more - let newAccountEmail = accountData.email; - // The hosted code may have already checked for the relink situation - // by sending the can_link_account command. If it did, then - // it will indicate we don't need to ask twice. - if (!accountData.verifiedCanLinkAccount && !shouldAllowRelink(newAccountEmail)) { - // we need to tell the page we successfully received the message, but - // then bail without telling fxAccounts - this.injectData("message", { status: "login" }); - // after a successful login we return to preferences - openPrefs(); - return; - } - delete accountData.verifiedCanLinkAccount; - - // Remember who it was so we can log out next time. - setPreviousAccountNameHash(newAccountEmail); - - // A sync-specific hack - we want to ensure sync has been initialized - // before we set the signed-in user. - let xps = Cc["@mozilla.org/weave/service;1"] - .getService(Ci.nsISupports) - .wrappedJSObject; - xps.whenLoaded().then(() => { - updateDisplayedEmail(accountData); - return fxAccounts.setSignedInUser(accountData); - }).then(() => { - // If the user data is verified, we want it to immediately look like - // they are signed in without waiting for messages to bounce around. - if (accountData.verified) { - openPrefs(); - } - this.injectData("message", { status: "login" }); - // until we sort out a better UX, just leave the jelly page in place. - // If the account email is not yet verified, it will tell the user to - // go check their email, but then it will *not* change state after - // the verification completes (the browser will begin syncing, but - // won't notify the user). If the email has already been verified, - // the jelly will say "Welcome! You are successfully signed in as - // EMAIL", but it won't then say "syncing started". - }, (err) => this.injectData("message", { status: "error", error: err }) - ); - }, - - onCanLinkAccount: function(accountData) { - // We need to confirm a relink - see shouldAllowRelink for more - let ok = shouldAllowRelink(accountData.email); - this.injectData("message", { status: "can_link_account", data: { ok: ok } }); - }, - - /** - * onSignOut handler erases the current user's session from the fxaccounts service - */ - onSignOut: function () { - log("Received: 'sign_out'."); - - fxAccounts.signOut().then( - () => this.injectData("message", { status: "sign_out" }), - (err) => this.injectData("message", { status: "error", error: err }) - ); - }, - - handleRemoteCommand: function (evt) { - log('command: ' + evt.detail.command); - let data = evt.detail.data; - - switch (evt.detail.command) { - case "login": - this.onLogin(data); - break; - case "can_link_account": - this.onCanLinkAccount(data); - break; - case "sign_out": - this.onSignOut(data); - break; - default: - log("Unexpected remote command received: " + evt.detail.command + ". Ignoring command."); - break; - } - }, - - injectData: function (type, content) { - return fxAccounts.promiseAccountsSignUpURI().then(authUrl => { - let data = { - type: type, - content: content - }; - this.iframe.contentWindow.postMessage(data, authUrl); - }) - .catch(e => { - console.log("Failed to inject data", e); - setErrorPage("configError"); - }); - }, -}; - - -// Button onclick handlers -function handleOldSync() { - let chromeWin = window - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem) - .rootTreeItem - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow) - .QueryInterface(Ci.nsIDOMChromeWindow); - let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "old-sync"; - chromeWin.switchToTabHavingURI(url, true); -} - -function getStarted() { - show("remote"); -} - -function retry() { - show("remote"); - wrapper.retry(); -} - -function openPrefs() { - // Bug 1199303 calls for this tab to always be replaced with Preferences - // rather than it opening in a different tab. - window.location = "about:preferences#sync"; -} - -function init() { - fxAccounts.getSignedInUser().then(user => { - // tests in particular might cause the window to start closing before - // getSignedInUser has returned. - if (window.closed) { - return Promise.resolve(); - } - - updateDisplayedEmail(user); - - // Ideally we'd use new URL(document.URL).searchParams, but for about: URIs, - // searchParams is empty. - let urlParams = new URLSearchParams(document.URL.split("?")[1] || ""); - let action = urlParams.get(ACTION_URL_PARAM); - urlParams.delete(ACTION_URL_PARAM); - - switch (action) { - case "signin": - if (user) { - // asking to sign-in when already signed in just shows manage. - show("stage", "manage"); - } else { - return fxAccounts.promiseAccountsSignInURI().then(url => { - show("remote"); - wrapper.init(url, urlParams); - }); - } - break; - case "signup": - if (user) { - // asking to sign-up when already signed in just shows manage. - show("stage", "manage"); - } else { - return fxAccounts.promiseAccountsSignUpURI().then(url => { - show("remote"); - wrapper.init(url, urlParams); - }); - } - break; - case "reauth": - // ideally we would only show this when we know the user is in a - // "must reauthenticate" state - but we don't. - // As the email address will be included in the URL returned from - // promiseAccountsForceSigninURI, just always show it. - return fxAccounts.promiseAccountsForceSigninURI().then(url => { - show("remote"); - wrapper.init(url, urlParams); - }); - default: - // No action specified. - if (user) { - show("stage", "manage"); - } else { - // Attempt a migration if enabled or show the introductory page - // otherwise. - return migrateToDevEdition(urlParams).then(migrated => { - if (!migrated) { - show("stage", "intro"); - // load the remote frame in the background - return fxAccounts.promiseAccountsSignUpURI().then(uri => - wrapper.init(uri, urlParams)); - } - return Promise.resolve(); - }); - } - break; - } - return Promise.resolve(); - }).catch(err => { - console.log("Configuration or sign in error", err); - setErrorPage("configError"); - }); -} - -function setErrorPage(errorType) { - show("stage", errorType); -} - -// Causes the "top-level" element with |id| to be shown - all other top-level -// elements are hidden. Optionally, ensures that only 1 "second-level" element -// inside the top-level one is shown. -function show(id, childId) { - // top-level items are either <div> or <iframe> - let allTop = document.querySelectorAll("body > div, iframe"); - for (let elt of allTop) { - if (elt.getAttribute("id") == id) { - elt.style.display = 'block'; - } else { - elt.style.display = 'none'; - } - } - if (childId) { - // child items are all <div> - let allSecond = document.querySelectorAll("#" + id + " > div"); - for (let elt of allSecond) { - if (elt.getAttribute("id") == childId) { - elt.style.display = 'block'; - } else { - elt.style.display = 'none'; - } - } - } -} - -// Migrate sync data from the default profile to the dev-edition profile. -// Returns a promise of a true value if migration succeeded, or false if it -// failed. -function migrateToDevEdition(urlParams) { - let defaultProfilePath; - try { - defaultProfilePath = window.getDefaultProfilePath(); - } catch (e) {} // no default profile. - let migrateSyncCreds = false; - if (defaultProfilePath) { - try { - migrateSyncCreds = Services.prefs.getBoolPref("identity.fxaccounts.migrateToDevEdition"); - } catch (e) {} - } - - if (!migrateSyncCreds) { - return Promise.resolve(false); - } - - Cu.import("resource://gre/modules/osfile.jsm"); - let fxAccountsStorage = OS.Path.join(defaultProfilePath, fxAccountsCommon.DEFAULT_STORAGE_FILENAME); - return OS.File.read(fxAccountsStorage, { encoding: "utf-8" }).then(text => { - let accountData = JSON.parse(text).accountData; - updateDisplayedEmail(accountData); - return fxAccounts.setSignedInUser(accountData); - }).then(() => { - return fxAccounts.promiseAccountsForceSigninURI().then(url => { - show("remote"); - wrapper.init(url, urlParams); - }); - }).then(null, error => { - log("Failed to migrate FX Account: " + error); - show("stage", "intro"); - // load the remote frame in the background - fxAccounts.promiseAccountsSignUpURI().then(uri => { - wrapper.init(uri, urlParams) - }).catch(e => { - console.log("Failed to load signup page", e); - setErrorPage("configError"); - }); - }).then(() => { - // Reset the pref after migration. - Services.prefs.setBoolPref("identity.fxaccounts.migrateToDevEdition", false); - return true; - }).then(null, err => { - Cu.reportError("Failed to reset the migrateToDevEdition pref: " + err); - return false; - }); -} - -// Helper function that returns the path of the default profile on disk. Will be -// overridden in tests. -function getDefaultProfilePath() { - let defaultProfile = Cc["@mozilla.org/toolkit/profile-service;1"] - .getService(Ci.nsIToolkitProfileService) - .defaultProfile; - return defaultProfile.rootDir.path; -} - -document.addEventListener("DOMContentLoaded", function onload() { - document.removeEventListener("DOMContentLoaded", onload, true); - init(); - var buttonGetStarted = document.getElementById('buttonGetStarted'); - buttonGetStarted.addEventListener('click', getStarted); - - var buttonRetry = document.getElementById('buttonRetry'); - buttonRetry.addEventListener('click', retry); - - var oldsync = document.getElementById('oldsync'); - oldsync.addEventListener('click', handleOldSync); - - var buttonOpenPrefs = document.getElementById('buttonOpenPrefs') - buttonOpenPrefs.addEventListener('click', openPrefs); -}, true); - -function initObservers() { - function observe(subject, topic, data) { - log("about:accounts observed " + topic); - if (topic == fxAccountsCommon.ONLOGOUT_NOTIFICATION) { - // All about:account windows get changed to action=signin on logout. - window.location = "about:accounts?action=signin"; - return; - } - - // must be onverified - we want to open preferences. - openPrefs(); - } - - for (let topic of OBSERVER_TOPICS) { - Services.obs.addObserver(observe, topic, false); - } - window.addEventListener("unload", function(event) { - log("about:accounts unloading") - for (let topic of OBSERVER_TOPICS) { - Services.obs.removeObserver(observe, topic); - } - }); -} -initObservers(); diff --git a/application/basilisk/base/content/aboutaccounts/aboutaccounts.xhtml b/application/basilisk/base/content/aboutaccounts/aboutaccounts.xhtml deleted file mode 100644 index 475f0e86f..000000000 --- a/application/basilisk/base/content/aboutaccounts/aboutaccounts.xhtml +++ /dev/null @@ -1,112 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- 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/. --> -<!DOCTYPE html [ - <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> - %htmlDTD; - <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> - %brandDTD; - <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> - %globalDTD; - <!ENTITY % aboutAccountsDTD SYSTEM "chrome://browser/locale/aboutAccounts.dtd"> - %aboutAccountsDTD; - <!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd"> - %syncBrandDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml" dir="&locale.dir;"> - <head> - <title>&syncBrand.fullName.label;</title> - <meta name="viewport" content="width=device-width"/> - - - <link rel="icon" type="image/png" id="favicon" - href="chrome://branding/content/icon32.png"/> - <link rel="stylesheet" - href="chrome://browser/content/aboutaccounts/normalize.css" - type="text/css" /> - <link rel="stylesheet" - href="chrome://browser/content/aboutaccounts/main.css" - type="text/css" /> - <link rel="stylesheet" - href="chrome://browser/content/aboutaccounts/aboutaccounts.css" - type="text/css" /> - </head> - <body> - <div id="stage"> - - <div id="manage"> - <header> - <h1>&aboutAccounts.connected;</h1> - <div id="email"></div> - </header> - - <section> - <div class="graphic graphic-sync-intro"> </div> - - <div class="button-row"> - <button id="buttonOpenPrefs" class="button" href="#" tabindex="0">&aboutAccountsConfig.syncPreferences.label;</button> - </div> - </section> - </div> - - <div id="intro"> - <header> - <h1>&aboutAccounts.welcome;</h1> - </header> - - <section> - <div class="graphic graphic-sync-intro"> </div> - - <div class="description">&aboutAccountsConfig.description;</div> - - <div class="button-row"> - <button id="buttonGetStarted" class="button" tabindex="1">&aboutAccountsConfig.startButton.label;</button> - </div> - - <div class="links"> - <button id="oldsync" tabindex="2">&aboutAccountsConfig.useOldSync.label;</button> - </div> - </section> - </div> - - <div id="networkError"> - <header> - <h1>&aboutAccounts.noConnection.title;</h1> - </header> - - <section> - <div class="graphic graphic-sync-intro"> </div> - - <div class="description">&aboutAccounts.noConnection.description;</div> - - <div class="button-row"> - <button id="buttonRetry" class="button" tabindex="3">&aboutAccounts.noConnection.retry;</button> - </div> - </section> - </div> - - <div id="configError"> - <header> - <h1>&aboutAccounts.badConfig.title;</h1> - </header> - - <section> - <div class="graphic graphic-sync-intro"> </div> - - <div class="description">&aboutAccounts.badConfig.description;</div> - - </section> - </div> - - </div> - - <iframe mozframetype="content" id="remote" /> - - <script type="application/javascript;version=1.8" - src="chrome://browser/content/utilityOverlay.js"/> - <script type="text/javascript;version=1.8" - src="chrome://browser/content/aboutaccounts/aboutaccounts.js" /> - </body> -</html> diff --git a/application/basilisk/base/content/aboutaccounts/images/fox.png b/application/basilisk/base/content/aboutaccounts/images/fox.png Binary files differdeleted file mode 100644 index 83af78d6c..000000000 --- a/application/basilisk/base/content/aboutaccounts/images/fox.png +++ /dev/null diff --git a/application/basilisk/base/content/aboutaccounts/images/graphic_sync_intro.png b/application/basilisk/base/content/aboutaccounts/images/graphic_sync_intro.png Binary files differdeleted file mode 100644 index ff5f482f0..000000000 --- a/application/basilisk/base/content/aboutaccounts/images/graphic_sync_intro.png +++ /dev/null diff --git a/application/basilisk/base/content/aboutaccounts/images/graphic_sync_intro@2x.png b/application/basilisk/base/content/aboutaccounts/images/graphic_sync_intro@2x.png Binary files differdeleted file mode 100644 index 89fda0681..000000000 --- a/application/basilisk/base/content/aboutaccounts/images/graphic_sync_intro@2x.png +++ /dev/null diff --git a/application/basilisk/base/content/aboutaccounts/main.css b/application/basilisk/base/content/aboutaccounts/main.css deleted file mode 100644 index 8f4c3b34e..000000000 --- a/application/basilisk/base/content/aboutaccounts/main.css +++ /dev/null @@ -1,166 +0,0 @@ -*, -*:before, -*:after { - box-sizing: border-box; -} - -html { - background-color: #F2F2F2; - height: 100%; -} - -body { - color: #424f59; - font: message-box; - font-size: 14px; - height: 100%; -} - -a { - color: #0095dd; - cursor: pointer; /* Use the correct cursor for anchors without an href */ -} - -a:active { - outline: none; -} - -a:focus { - outline: 1px dotted #0095dd; -} - - -a.no-underline { - text-decoration: none; -} - -#stage { - background:#fff; - border-radius: 5px; - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.25); - margin: 0 auto; - min-height: 300px; - padding: 60px 40px 40px 40px; - position: relative; - text-align: center; - top: 80px; - width: 420px; -} - -header h1 -{ - font-size: 24px; - font-weight: 200; - line-height: 1em; -} - -#intro header h1 { - margin: 0 0 32px 0; -} - -#manage header h1 { - margin: 0 0 12px 0; -} - -#manage header #email { - margin-bottom: 23px; - color: rgb(138, 155, 168); - font-size: 19px; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; -} - -.description { - font-size: 18px; -} - -.button-row { - margin-top: 45px; - margin-bottom:20px; -} - -.button-row button, -.button-row a.button { - background: #0095dd; - border: none; - border-radius: 5px; - color: #FFFFFF; - cursor: pointer; - font-size: 24px; - padding: 15px 0; - transition-duration: 150ms; - transition-property: background-color; - width: 100%; -} - -.button-row a.button { - display: inline-block; - text-decoration: none; -} - -.button-row a.button:active, -.button-row a.button:hover, -.button-row a.button:focus, -.button-row button:active, -.button-row button:hover, -.button-row button:focus { - background: #08c; -} - - -.graphic-sync-intro { - background-image: url(images/graphic_sync_intro.png); - background-repeat: no-repeat; - background-size: 150px 195px; - height: 195px; - margin: 0 auto; - overflow: hidden; - text-indent: 100%; - white-space: nowrap; - width: 150px; -} - -.description, -.button-row { - margin-top: 30px; -} - -.links { - margin: 20px 0; -} - -@media only screen and (max-width: 500px) { - html { - background: #fff; - } - - #stage { - box-shadow: none; - margin: 30px auto 0 auto; - min-height: none; - min-width: 320px; - padding: 0 10px; - width: 100%; - } - - .button-row { - margin-top: 20px; - } - - .button-row button, - .button-row a.button { - padding: 10px 0; - } - -} - -/* Retina */ -@media -only screen and (min-device-pixel-ratio: 2), -only screen and ( min-resolution: 192dpi), -only screen and ( min-resolution: 2dppx) { - .graphic-sync-intro { - background-image: url(images/graphic_sync_intro@2x.png); - } -} diff --git a/application/basilisk/base/content/aboutaccounts/normalize.css b/application/basilisk/base/content/aboutaccounts/normalize.css deleted file mode 100644 index c02ab25de..000000000 --- a/application/basilisk/base/content/aboutaccounts/normalize.css +++ /dev/null @@ -1,402 +0,0 @@ -/*! normalize.css v2.1.3 | MIT License | git.io/normalize */
-
-/* ==========================================================================
- HTML5 display definitions
- ========================================================================== */
-
-/**
- * Correct `block` display not defined in IE 8/9.
- */
-
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-nav,
-section,
-summary {
- display: block;
-}
-
-/**
- * Correct `inline-block` display not defined in IE 8/9.
- */
-
-audio,
-canvas,
-video {
- display: inline-block;
-}
-
-/**
- * Prevent modern browsers from displaying `audio` without controls.
- * Remove excess height in iOS 5 devices.
- */
-
-audio:not([controls]) {
- display: none;
- height: 0;
-}
-
-/**
- * Address `[hidden]` styling not present in IE 8/9.
- * Hide the `template` element in IE, Safari, and Firefox < 22.
- */
-
-[hidden],
-template {
- display: none;
-}
-
-/* ==========================================================================
- Base
- ========================================================================== */
-
-/**
- * 1. Set default font family to sans-serif.
- * 2. Prevent iOS text size adjust after orientation change, without disabling
- * user zoom.
- */
-
-html {
- font-family: sans-serif; /* 1 */
- -ms-text-size-adjust: 100%; /* 2 */
- -webkit-text-size-adjust: 100%; /* 2 */
-}
-
-/**
- * Remove default margin.
- */
-
-body {
- margin: 0;
-}
-
-/* ==========================================================================
- Links
- ========================================================================== */
-
-/**
- * Remove the gray background color from active links in IE 10.
- */
-
-a {
- background: transparent;
-}
-
-/**
- * Address `outline` inconsistency between Chrome and other browsers.
- */
-
-a:focus {
- outline: thin dotted;
-}
-
-/**
- * Improve readability when focused and also mouse hovered in all browsers.
- */
-
-a:active,
-a:hover {
- outline: 0;
-}
-
-/* ==========================================================================
- Typography
- ========================================================================== */
-
-/**
- * Address variable `h1` font-size and margin within `section` and `article`
- * contexts in Firefox 4+, Safari 5, and Chrome.
- */
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-/**
- * Address styling not present in IE 8/9, Safari 5, and Chrome.
- */
-
-abbr[title] {
- border-bottom: 1px dotted;
-}
-
-/**
- * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
- */
-
-b,
-strong {
- font-weight: bold;
-}
-
-/**
- * Address styling not present in Safari 5 and Chrome.
- */
-
-dfn {
- font-style: italic;
-}
-
-/**
- * Address differences between Firefox and other browsers.
- */
-
-hr {
- box-sizing: content-box;
- height: 0;
-}
-
-/**
- * Address styling not present in IE 8/9.
- */
-
-mark {
- background: #ff0;
- color: #000;
-}
-
-/**
- * Correct font family set oddly in Safari 5 and Chrome.
- */
-
-code,
-kbd,
-pre,
-samp {
- font-family: monospace, serif;
- font-size: 1em;
-}
-
-/**
- * Improve readability of pre-formatted text in all browsers.
- */
-
-pre {
- white-space: pre-wrap;
-}
-
-/**
- * Set consistent quote types.
- */
-
-q {
- quotes: "\201C" "\201D" "\2018" "\2019";
-}
-
-/**
- * Address inconsistent and variable font size in all browsers.
- */
-
-small {
- font-size: 80%;
-}
-
-/**
- * Prevent `sub` and `sup` affecting `line-height` in all browsers.
- */
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sup {
- top: -0.5em;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-/* ==========================================================================
- Embedded content
- ========================================================================== */
-
-/**
- * Remove border when inside `a` element in IE 8/9.
- */
-
-img {
- border: 0;
-}
-
-/**
- * Correct overflow displayed oddly in IE 9.
- */
-
-svg:not(:root) {
- overflow: hidden;
-}
-
-/* ==========================================================================
- Figures
- ========================================================================== */
-
-/**
- * Address margin not present in IE 8/9 and Safari 5.
- */
-
-figure {
- margin: 0;
-}
-
-/* ==========================================================================
- Forms
- ========================================================================== */
-
-/**
- * Define consistent border, margin, and padding.
- */
-
-fieldset {
- border: 1px solid #c0c0c0;
- margin: 0 2px;
- padding: 0.35em 0.625em 0.75em;
-}
-
-/**
- * 1. Correct `color` not being inherited in IE 8/9.
- * 2. Remove padding so people aren't caught out if they zero out fieldsets.
- */
-
-legend {
- border: 0; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * 1. Correct font family not being inherited in all browsers.
- * 2. Correct font size not being inherited in all browsers.
- * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
- */
-
-button,
-input,
-select,
-textarea {
- font-family: inherit; /* 1 */
- font-size: 100%; /* 2 */
- margin: 0; /* 3 */
-}
-
-/**
- * Address Firefox 4+ setting `line-height` on `input` using `!important` in
- * the UA stylesheet.
- */
-
-button,
-input {
- line-height: normal;
-}
-
-/**
- * Address inconsistent `text-transform` inheritance for `button` and `select`.
- * All other form control elements do not inherit `text-transform` values.
- * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
- * Correct `select` style inheritance in Firefox 4+ and Opera.
- */
-
-button,
-select {
- text-transform: none;
-}
-
-/**
- * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
- * and `video` controls.
- * 2. Correct inability to style clickable `input` types in iOS.
- * 3. Improve usability and consistency of cursor style between image-type
- * `input` and others.
- */
-
-button,
-html input[type="button"], /* 1 */
-input[type="reset"],
-input[type="submit"] {
- -webkit-appearance: button; /* 2 */
- cursor: pointer; /* 3 */
-}
-
-/**
- * Re-set default cursor for disabled elements.
- */
-
-button[disabled],
-html input[disabled] {
- cursor: default;
-}
-
-/**
- * 1. Address box sizing set to `content-box` in IE 8/9/10.
- * 2. Remove excess padding in IE 8/9/10.
- */
-
-input[type="checkbox"],
-input[type="radio"] {
- box-sizing: border-box; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
- * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome.
- */
-
-input[type="search"] {
- -webkit-appearance: textfield; /* 1 */
- box-sizing: content-box; /* 2 */
-}
-
-/**
- * Remove inner padding and search cancel button in Safari 5 and Chrome
- * on OS X.
- */
-
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-/**
- * Remove inner padding and border in Firefox 4+.
- */
-
-button::-moz-focus-inner,
-input::-moz-focus-inner {
- border: 0;
- padding: 0;
-}
-
-/**
- * 1. Remove default vertical scrollbar in IE 8/9.
- * 2. Improve readability and alignment in all browsers.
- */
-
-textarea {
- overflow: auto; /* 1 */
- vertical-align: top; /* 2 */
-}
-
-/* ==========================================================================
- Tables
- ========================================================================== */
-
-/**
- * Remove most spacing between table cells.
- */
-
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
diff --git a/application/basilisk/base/content/browser-fxaccounts.js b/application/basilisk/base/content/browser-fxaccounts.js deleted file mode 100644 index e1d556bff..000000000 --- a/application/basilisk/base/content/browser-fxaccounts.js +++ /dev/null @@ -1,314 +0,0 @@ -/* 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/. */ - -var gFxAccounts = { - - _initialized: false, - _inCustomizationMode: false, - _cachedProfile: null, - - 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:login:change", - "weave:service:setup-complete", - "weave:service:sync:error", - "weave:ui:login:error", - this.FxAccountsCommon.ONLOGIN_NOTIFICATION, - this.FxAccountsCommon.ONLOGOUT_NOTIFICATION, - this.FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION, - ]; - }, - - get panelUIFooter() { - delete this.panelUIFooter; - return this.panelUIFooter = document.getElementById("PanelUI-footer-fxa"); - }, - - get panelUIStatus() { - delete this.panelUIStatus; - return this.panelUIStatus = document.getElementById("PanelUI-fxa-status"); - }, - - get panelUIAvatar() { - delete this.panelUIAvatar; - return this.panelUIAvatar = document.getElementById("PanelUI-fxa-avatar"); - }, - - get panelUILabel() { - delete this.panelUILabel; - return this.panelUILabel = document.getElementById("PanelUI-fxa-label"); - }, - - get panelUIIcon() { - delete this.panelUIIcon; - return this.panelUIIcon = document.getElementById("PanelUI-fxa-icon"); - }, - - 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; - }, - - 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); - } - - gNavToolbox.addEventListener("customizationstarting", this); - gNavToolbox.addEventListener("customizationending", this); - - EnsureFxAccountsWebChannel(); - 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.ON_PROFILE_CHANGE_NOTIFICATION: - this._cachedProfile = null; - // Fallthrough intended - default: - this.updateUI(); - break; - } - }, - - handleEvent: function (event) { - this._inCustomizationMode = event.type == "customizationstarting"; - this.updateAppMenuItem(); - }, - - updateUI: function () { - // It's possible someone signed in to FxA after seeing our notification - // about "Legacy Sync migration" (which now is actually "Legacy Sync - // auto-disconnect") so kill that notification if it still exists. - let nb = window.document.getElementById("global-notificationbox"); - let n = nb.getNotificationWithValue(this.SYNC_MIGRATION_NOTIFICATION_TITLE); - if (n) { - nb.removeNotification(n, true); - } - - this.updateAppMenuItem(); - }, - - // Note that updateAppMenuItem() returns a Promise that's only used by tests. - updateAppMenuItem: function () { - let profileInfoEnabled = false; - try { - profileInfoEnabled = Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled"); - } catch (e) { } - - this.panelUIFooter.hidden = false; - - // Make sure the button is disabled in customization mode. - if (this._inCustomizationMode) { - this.panelUIStatus.setAttribute("disabled", "true"); - this.panelUILabel.setAttribute("disabled", "true"); - this.panelUIAvatar.setAttribute("disabled", "true"); - this.panelUIIcon.setAttribute("disabled", "true"); - } else { - this.panelUIStatus.removeAttribute("disabled"); - this.panelUILabel.removeAttribute("disabled"); - this.panelUIAvatar.removeAttribute("disabled"); - this.panelUIIcon.removeAttribute("disabled"); - } - - let defaultLabel = this.panelUIStatus.getAttribute("defaultlabel"); - let errorLabel = this.panelUIStatus.getAttribute("errorlabel"); - let unverifiedLabel = this.panelUIStatus.getAttribute("unverifiedlabel"); - let settingslabel = this.panelUIStatus.getAttribute("settingslabel"); - // The localization string is for the signed in text, but it's the default text as well - let defaultTooltiptext = this.panelUIStatus.getAttribute("signedinTooltiptext"); - - let updateWithUserData = (userData) => { - // Window might have been closed while fetching data. - if (window.closed) { - return; - } - - // Reset the button to its original state. - this.panelUILabel.setAttribute("label", defaultLabel); - this.panelUIStatus.setAttribute("tooltiptext", defaultTooltiptext); - this.panelUIFooter.removeAttribute("fxastatus"); - this.panelUIFooter.removeAttribute("fxaprofileimage"); - this.panelUIAvatar.style.removeProperty("list-style-image"); - - if (Weave.Status.service == Weave.CLIENT_NOT_CONFIGURED) { - // Leave the default state - return; - } - - if (this.loginFailed) { - this.panelUIFooter.setAttribute("fxastatus", "error"); - this.panelUILabel.setAttribute("label", errorLabel); - } else { - this.panelUIFooter.setAttribute("fxastatus", "signedin"); - this.panelUILabel.setAttribute("label", settingslabel); - this.panelUIStatus.setAttribute("tooltiptext", ""); - } - } - - let updateWithProfile = (profile) => { - if (profileInfoEnabled) { - if (profile.displayName) { - this.panelUILabel.setAttribute("label", profile.displayName); - } - if (profile.avatar) { - this.panelUIFooter.setAttribute("fxaprofileimage", "set"); - let bgImage = "url(\"" + profile.avatar + "\")"; - this.panelUIAvatar.style.listStyleImage = bgImage; - - let img = new Image(); - img.onerror = () => { - // Clear the image if it has trouble loading. Since this callback is asynchronous - // we check to make sure the image is still the same before we clear it. - if (this.panelUIAvatar.style.listStyleImage === bgImage) { - this.panelUIFooter.removeAttribute("fxaprofileimage"); - this.panelUIAvatar.style.removeProperty("list-style-image"); - } - }; - img.src = profile.avatar; - } - } - } - - return fxAccounts.getSignedInUser().then(userData => { - // userData may be null here when the user is not signed-in, but that's expected - updateWithUserData(userData); - // unverified users cause us to spew log errors fetching an OAuth token - // to fetch the profile, so don't even try in that case. - if (!userData || !userData.verified || !profileInfoEnabled) { - return null; // don't even try to grab the profile. - } - if (this._cachedProfile) { - return this._cachedProfile; - } - return fxAccounts.getSignedInUserProfile().catch(err => { - // Not fetching the profile is sad but the FxA logs will already have noise. - return null; - }); - }).then(profile => { - if (!profile) { - return; - } - updateWithProfile(profile); - this._cachedProfile = profile; // Try to avoid fetching the profile on every UI update - }).catch(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. - this.FxAccountsCommon.log.error("Error updating FxA account info", error); - updateWithUserData(null); - }); - }, - - onMenuPanelCommand: function () { - - switch (this.panelUIFooter.getAttribute("fxastatus")) { - case "signedin": - this.openPreferences(); - break; - case "error": - if (this.panelUIFooter.getAttribute("unverified")) { - this.openPreferences(); - } else { - this.openSignInAgainPage("menupanel"); - } - break; - default: - this.openPreferences(); - break; - } - - PanelUI.hide(); - }, - - openPreferences: function () { - openPreferences("paneSync", { urlParams: { entrypoint: "menupanel" } }); - }, - - openAccountsPage: function (action, urlParams={}) { - 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 }); - }, - - updateTabContextMenu: function (aPopupMenu) { - // STUB - }, - - initPageContextMenu: function (contextMenu) { - // STUB - } -}; - -XPCOMUtils.defineLazyGetter(gFxAccounts, "FxAccountsCommon", function () { - return Cu.import("resource://gre/modules/FxAccountsCommon.js", {}); -}); - -XPCOMUtils.defineLazyModuleGetter(gFxAccounts, "fxaMigrator", - "resource://services-sync/FxaMigrator.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "EnsureFxAccountsWebChannel", - "resource://gre/modules/FxAccountsWebChannel.jsm"); diff --git a/application/basilisk/base/content/browser-menubar.inc b/application/basilisk/base/content/browser-menubar.inc index 0549ad915..0af0cc1c7 100644 --- a/application/basilisk/base/content/browser-menubar.inc +++ b/application/basilisk/base/content/browser-menubar.inc @@ -195,9 +195,6 @@ key="key_gotoHistory" observes="viewHistorySidebar" label="&historyButton.label;"/> - <menuitem id="menu_tabsSidebar" - observes="viewTabsSidebar" - label="&syncedTabs.sidebar.label;"/> </menupopup> </menu> <menuseparator/> @@ -439,12 +436,7 @@ label="&toolsMenu.label;" accesskey="&toolsMenu.accesskey;" onpopupshowing="mirrorShow(this)"> - <menupopup id="menu_ToolsPopup" -# We have to use setTimeout() here to avoid a flickering menu bar when opening -# the Tools menu, see bug 970769. This can be removed once we got rid of the -# event loop spinning in Weave.Status._authManager. - onpopupshowing="setTimeout(() => gSyncUI.updateUI());" - > + <menupopup id="menu_ToolsPopup"> <menuitem id="menu_openDownloads" label="&downloads.label;" accesskey="&downloads.accesskey;" @@ -455,23 +447,6 @@ accesskey="&addons.accesskey;" key="key_openAddons" command="Tools:Addons"/> - - <!-- only one of sync-setup, sync-syncnowitem or sync-reauthitem will be showing at once --> - <menuitem id="sync-setup" - label="&syncSignIn.label;" - accesskey="&syncSignIn.accesskey;" - observes="sync-setup-state" - oncommand="gSyncUI.openSetup(null, 'menubar')"/> - <menuitem id="sync-syncnowitem" - label="&syncSyncNowItem.label;" - accesskey="&syncSyncNowItem.accesskey;" - observes="sync-syncnow-state" - oncommand="gSyncUI.doSync(event);"/> - <menuitem id="sync-reauthitem" - label="&syncReAuthItem.label;" - accesskey="&syncReAuthItem.accesskey;" - observes="sync-reauth-state" - oncommand="gSyncUI.openSignInAgainPage('menubar');"/> <menuseparator id="devToolsSeparator"/> <menu id="webDeveloperMenu" label="&webDeveloperMenu.label;" diff --git a/application/basilisk/base/content/browser-sets.inc b/application/basilisk/base/content/browser-sets.inc index 6ea057d93..47fd1547c 100644 --- a/application/basilisk/base/content/browser-sets.inc +++ b/application/basilisk/base/content/browser-sets.inc @@ -169,10 +169,6 @@ <broadcaster id="sync-setup-state"/> <broadcaster id="sync-syncnow-state" hidden="true"/> <broadcaster id="sync-reauth-state" hidden="true"/> - <broadcaster id="viewTabsSidebar" autoCheck="false" sidebartitle="&syncedTabs.sidebar.label;" - type="checkbox" group="sidebar" - sidebarurl="chrome://browser/content/syncedtabs/sidebar.xhtml" - oncommand="SidebarUI.toggle('viewTabsSidebar');"/> <broadcaster id="workOfflineMenuitemState"/> <broadcaster id="devtoolsMenuBroadcaster_ErrorConsole" diff --git a/application/basilisk/base/content/browser-syncui.js b/application/basilisk/base/content/browser-syncui.js index 3a57140f2..67056e221 100644 --- a/application/basilisk/base/content/browser-syncui.js +++ b/application/basilisk/base/content/browser-syncui.js @@ -1,63 +1,37 @@ -/* 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/. */ +# 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/. -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -#ifdef MOZ_SERVICES_CLOUDSYNC -XPCOMUtils.defineLazyModuleGetter(this, "CloudSync", - "resource://gre/modules/CloudSync.jsm"); -#endif - -XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts", - "resource://gre/modules/FxAccounts.jsm"); - -const MIN_STATUS_ANIMATION_DURATION = 1600; - -// gSyncUI handles updating the tools menu and displaying notifications. +// gSyncUI handles updating the tools menu var gSyncUI = { _obs: ["weave:service:sync:start", - "weave:service:sync:finish", - "weave:service:sync:error", + "weave:service:sync:delayed", "weave:service:quota:remaining", "weave:service:setup-complete", "weave:service:login:start", "weave:service:login:finish", - "weave:service:login:error", "weave:service:logout:finish", "weave:service:start-over", - "weave:service:start-over:finish", "weave:ui:login:error", "weave:ui:sync:error", "weave:ui:sync:finish", "weave:ui:clear-error", - "weave:engine:sync:finish" ], _unloaded: false, - // The last sync start time. Used to calculate the leftover animation time - // once syncing completes (bug 1239042). - _syncStartTime: 0, - _syncAnimationTimer: 0, - - init: function () { - Cu.import("resource://services-common/stringbundle.js"); + init: function SUI_init() { // Proceed to set up the UI if Sync has already started up. // Otherwise we'll do it when Sync is firing up. - if (this.weaveService.ready) { + let xps = Components.classes["@mozilla.org/weave/service;1"] + .getService(Components.interfaces.nsISupports) + .wrappedJSObject; + if (xps.ready) { this.initUI(); return; } - // Sync isn't ready yet, but we can still update the UI with an initial - // state - we haven't called initUI() yet, but that's OK - that's more - // about observers for state changes, and will be called once Sync is - // ready to start sending notifications. - this.updateUI(); - Services.obs.addObserver(this, "weave:service:ready", true); - Services.obs.addObserver(this, "quit-application", true); // Remove the observer if the window is closed before the observer // was triggered. @@ -65,7 +39,6 @@ var gSyncUI = { gSyncUI._unloaded = true; window.removeEventListener("unload", onUnload, false); Services.obs.removeObserver(gSyncUI, "weave:service:ready"); - Services.obs.removeObserver(gSyncUI, "quit-application"); if (Weave.Status.ready) { gSyncUI._obs.forEach(function(topic) { @@ -85,161 +58,130 @@ var gSyncUI = { Services.obs.addObserver(this, topic, true); }, this); - // initial label for the sync buttons. - let broadcaster = document.getElementById("sync-status"); - broadcaster.setAttribute("label", this._stringBundle.GetStringFromName("syncnow.label")); + if (gBrowser && Weave.Notifications.notifications.length) { + this.initNotifications(); + } + this.updateUI(); + }, + + initNotifications: function SUI_initNotifications() { + const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + let notificationbox = document.createElementNS(XULNS, "notificationbox"); + notificationbox.id = "sync-notifications"; + notificationbox.setAttribute("flex", "1"); - this.maybeMoveSyncedTabsButton(); + let bottombox = document.getElementById("browser-bottombox"); + bottombox.insertBefore(notificationbox, bottombox.firstChild); - this.updateUI(); + // Force a style flush to ensure that our binding is attached. + notificationbox.clientTop; + + // notificationbox will listen to observers from now on. + Services.obs.removeObserver(this, "weave:notification:added"); }, + _wasDelayed: false, - // Returns a promise that resolves with true if Sync needs to be configured, - // false otherwise. - _needsSetup() { - // If Sync is configured for FxAccounts then we do that promise-dance. - if (this.weaveService.fxAccountsEnabled) { - return fxAccounts.getSignedInUser().then(user => { - // We want to treat "account needs verification" as "needs setup". - return !(user && user.verified); - }); - } - // We are using legacy sync - check that. + _needsSetup: function SUI__needsSetup() { let firstSync = ""; try { firstSync = Services.prefs.getCharPref("services.sync.firstSync"); } catch (e) { } - - return Promise.resolve(Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED || - firstSync == "notReady"); + return Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED || + firstSync == "notReady"; }, - // Returns a promise that resolves with true if the user currently signed in - // to Sync needs to be verified, false otherwise. - _needsVerification() { - // For callers who care about the distinction between "needs setup" and - // "needs verification" - if (this.weaveService.fxAccountsEnabled) { - return fxAccounts.getSignedInUser().then(user => { - // If there is no user, they can't be in a "needs verification" state. - if (!user) { - return false; - } - return !user.verified; - }); - } + updateUI: function SUI_updateUI() { + let needsSetup = this._needsSetup(); + document.getElementById("sync-setup-state").hidden = !needsSetup; + document.getElementById("sync-syncnow-state").hidden = needsSetup; - // Otherwise we are configured for legacy Sync, which has no verification - // concept. - return Promise.resolve(false); - }, + if (!gBrowser) + return; - // Note that we don't show login errors in a notification bar here, but do - // still need to track a login-failed state so the "Tools" menu updates - // with the correct state. - _loginFailed: function () { - // If Sync isn't already ready, we don't want to force it to initialize - // by referencing Weave.Status - and it isn't going to be accurate before - // Sync is ready anyway. - if (!this.weaveService.ready) { - this.log.debug("_loginFailed has sync not ready, so returning false"); - return false; - } - this.log.debug("_loginFailed has sync state=${sync}", - { sync: Weave.Status.login}); - return Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED; - }, + let button = document.getElementById("sync-button"); + if (!button) + return; - // Kick off an update of the UI - does *not* return a promise. - updateUI() { - this._promiseUpdateUI().catch(err => { - this.log.error("updateUI failed", err); - }) + button.removeAttribute("status"); + this._updateLastSyncTime(); + if (needsSetup) + button.removeAttribute("tooltiptext"); }, - // Updates the UI - returns a promise. - _promiseUpdateUI() { - return this._needsSetup().then(needsSetup => { - if (!gBrowser) - return Promise.resolve(); - - let loginFailed = this._loginFailed(); - - // Start off with a clean slate - document.getElementById("sync-reauth-state").hidden = true; - document.getElementById("sync-setup-state").hidden = true; - document.getElementById("sync-syncnow-state").hidden = true; - -#ifdef MOZ_SERVICES_CLOUDSYNC - if (CloudSync && CloudSync.ready && CloudSync().adapters.count) { - document.getElementById("sync-syncnow-state").hidden = false; - } else if (loginFailed) { -#else - if (loginFailed) { -#endif - // unhiding this element makes the menubar show the login failure state. - document.getElementById("sync-reauth-state").hidden = false; - } else if (needsSetup) { - document.getElementById("sync-setup-state").hidden = false; - } else { - document.getElementById("sync-syncnow-state").hidden = false; - } - - return this._updateSyncButtonsTooltip(); - }); - }, // Functions called by observers - onActivityStart() { + onActivityStart: function SUI_onActivityStart() { if (!gBrowser) return; - this.log.debug("onActivityStart"); + let button = document.getElementById("sync-button"); + if (!button) + return; - clearTimeout(this._syncAnimationTimer); - this._syncStartTime = Date.now(); + button.setAttribute("status", "active"); + }, - let broadcaster = document.getElementById("sync-status"); - broadcaster.setAttribute("syncstatus", "active"); - broadcaster.setAttribute("label", this._stringBundle.GetStringFromName("syncing2.label")); - broadcaster.setAttribute("disabled", "true"); + 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 buttons = [new Weave.NotificationButton( + this._stringBundle.GetStringFromName("error.sync.serverStatusButton.label"), + this._stringBundle.GetStringFromName("error.sync.serverStatusButton.accesskey"), + function() { gSyncUI.openServerStatus(); return true; } + )]; + let notification = new Weave.Notification( + title, description, null, Weave.Notifications.PRIORITY_INFO, buttons); + Weave.Notifications.replaceTitle(notification); + this._wasDelayed = true; + }, - this.updateUI(); + onLoginFinish: function SUI_onLoginFinish() { + // Clear out any login failure notifications + let title = this._stringBundle.GetStringFromName("error.login.title"); + this.clearError(title); }, - _updateSyncStatus() { - if (!gBrowser) - return; - let broadcaster = document.getElementById("sync-status"); - broadcaster.removeAttribute("syncstatus"); - broadcaster.removeAttribute("disabled"); - broadcaster.setAttribute("label", this._stringBundle.GetStringFromName("syncnow.label")); - this.updateUI(); + onSetupComplete: function SUI_onSetupComplete() { + this.onLoginFinish(); }, - onActivityStop() { - if (!gBrowser) + 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; - this.log.debug("onActivityStop"); + } - let now = Date.now(); - let syncDuration = now - this._syncStartTime; + let title = this._stringBundle.GetStringFromName("error.login.title"); - if (syncDuration < MIN_STATUS_ANIMATION_DURATION) { - let animationTime = MIN_STATUS_ANIMATION_DURATION - syncDuration; - clearTimeout(this._syncAnimationTimer); - this._syncAnimationTimer = setTimeout(() => this._updateSyncStatus(), animationTime); + let description; + if (Weave.Status.sync == Weave.PROLONGED_SYNC_FAILURE) { + // Convert to days + let lastSync = + Services.prefs.getIntPref("services.sync.errorhandler.networkFailureReportTimeout") / 86400; + description = + this._stringBundle.formatStringFromName("error.sync.prolonged_failure", [lastSync], 1); } else { - this._updateSyncStatus(); + let reason = Weave.Utils.getErrorString(Weave.Status.login); + description = + this._stringBundle.formatStringFromName("error.sync.description", [reason], 1); } - }, - onLoginError: function SUI_onLoginError() { - this.log.debug("onLoginError: login=${login}, sync=${sync}", Weave.Status); + 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; } + )); - // We don't show any login errors here; browser-fxaccounts shows them in - // the hamburger menu. + let notification = new Weave.Notification(title, description, null, + Weave.Notifications.PRIORITY_WARNING, buttons); + Weave.Notifications.replaceTitle(notification); this.updateUI(); }, @@ -247,6 +189,10 @@ var gSyncUI = { this.updateUI(); }, + onStartOver: function SUI_onStartOver() { + this.clearError(); + }, + onQuotaNotice: function onQuotaNotice(subject, data) { let title = this._stringBundle.GetStringFromName("warning.sync.quota.label"); let description = this._stringBundle.GetStringFromName("warning.sync.quota.description"); @@ -262,40 +208,26 @@ var gSyncUI = { Weave.Notifications.replaceTitle(notification); }, - _getAppName: function () { - let brand = new StringBundle("chrome://branding/locale/brand.properties"); - return brand.get("brandShortName"); + openServerStatus: function () { + let statusURL = Services.prefs.getCharPref("services.sync.statusURL"); + window.openUILinkIn(statusURL, "tab"); }, // Commands - // doSync forces a sync - it *does not* return a promise as it is called - // via the various UI components. - doSync() { - this._needsSetup().then(needsSetup => { - if (!needsSetup) { - setTimeout(() => Weave.Service.errorHandler.syncAndReportErrors(), 0); - } - Services.obs.notifyObservers(null, "cloudsync:user-sync", null); - }).catch(err => { - this.log.error("Failed to force a sync", err); - }); + doSync: function SUI_doSync() { + setTimeout(function() Weave.Service.errorHandler.syncAndReportErrors(), 0); }, - // Handle clicking the toolbar button - which either opens the Sync setup - // pages or forces a sync now. Does *not* return a promise as it is called - // via the UI. - handleToolbarButton() { - this._needsSetup().then(needsSetup => { - if (needsSetup || this._loginFailed()) { - this.openSetup(); - } else { - this.doSync(); - } - }).catch(err => { - this.log.error("Failed to handle toolbar button command", err); - }); + handleToolbarButton: function SUI_handleStatusbarButton() { + if (this._needsSetup()) + this.openSetup(); + else + this.doSync(); }, + //XXXzpao should be part of syncCommon.js - which we might want to make a module... + // To be fixed in a followup (bug 583366) + /** * Invoke the Sync setup wizard. * @@ -304,11 +236,9 @@ var gSyncUI = { * null -- regular set up wizard * "pair" -- pair a device first * "reset" -- reset sync - * @param entryPoint - * Indicates the entrypoint from where this method was called. */ - openSetup: function SUI_openSetup(wizardType, entryPoint = "syncbutton") { + openSetup: function SUI_openSetup(wizardType) { let win = Services.wm.getMostRecentWindow("Weave:AccountSetup"); if (win) win.focus(); @@ -319,7 +249,6 @@ var gSyncUI = { } }, - // Open the legacy-sync device pairing UI. Note used for FxA Sync. openAddDevice: function () { if (!Weave.Utils.ensureMPUnlocked()) return; @@ -332,202 +261,186 @@ var gSyncUI = { "syncAddDevice", "centerscreen,chrome,resizable=no"); }, - openPrefs: function (entryPoint) { - openPreferences("paneSync", { urlParams: { entrypoint: entryPoint } }); + openQuotaDialog: function SUI_openQuotaDialog() { + let win = Services.wm.getMostRecentWindow("Sync:ViewQuota"); + if (win) + win.focus(); + else + Services.ww.activeWindow.openDialog( + "chrome://browser/content/sync/quota.xul", "", + "centerscreen,chrome,dialog,modal"); }, - openSignInAgainPage: function (entryPoint = "syncbutton") { - gFxAccounts.openSignInAgainPage(entryPoint); + openPrefs: function SUI_openPrefs() { + openPreferences("paneSync"); }, - /* After Sync is initialized we perform a once-only check for the sync - button being in "customize purgatory" and if so, move it to the panel. - This is done primarily for profiles created before SyncedTabs landed, - where the button defaulted to being in that purgatory. - We use a preference to ensure we only do it once, so people can still - customize it away and have it stick. - */ - maybeMoveSyncedTabsButton() { - const prefName = "browser.migrated-sync-button"; - let migrated = false; - try { - migrated = Services.prefs.getBoolPref(prefName); - } catch (_) {} - if (migrated) { - return; - } - if (!CustomizableUI.getPlacementOfWidget("sync-button")) { - CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL); - } - Services.prefs.setBoolPref(prefName, true); - }, - /* Update the tooltip for the sync-status broadcaster (which will update the - Sync Toolbar button and the Sync spinner in the FxA hamburger area.) - If Sync is configured, the tooltip is when the last sync occurred, - otherwise the tooltip reflects the fact that Sync needs to be - (re-)configured. - */ - _updateSyncButtonsTooltip: Task.async(function* () { + // Helpers + _updateLastSyncTime: function SUI__updateLastSyncTime() { if (!gBrowser) return; - let email; - try { - email = Services.prefs.getCharPref("services.sync.username"); - } catch (ex) {} - - let needsSetup = yield this._needsSetup(); - let needsVerification = yield this._needsVerification(); - let loginFailed = this._loginFailed(); - // This is a little messy as the Sync buttons are 1/2 Sync related and - // 1/2 FxA related - so for some strings we use Sync strings, but for - // others we reach into gFxAccounts for strings. - let tooltiptext; - if (needsVerification) { - // "needs verification" - tooltiptext = gFxAccounts.strings.formatStringFromName("verifyDescription", [email], 1); - } else if (needsSetup) { - // "needs setup". - tooltiptext = this._stringBundle.GetStringFromName("signInToSync.description"); - } else if (loginFailed) { - // "need to reconnect/re-enter your password" - tooltiptext = gFxAccounts.strings.formatStringFromName("reconnectDescription", [email], 1); - } else { - // Sync appears configured - format the "last synced at" time. - try { - let lastSync = new Date(Services.prefs.getCharPref("services.sync.lastSync")); - tooltiptext = this.formatLastSyncDate(lastSync); - } - catch (e) { - // pref doesn't exist (which will be the case until we've seen the - // first successful sync) or is invalid (which should be impossible!) - // Just leave tooltiptext as the empty string in these cases, which - // will cause the tooltip to be removed below. - } - } - - // We've done all our promise-y work and ready to update the UI - make - // sure it hasn't been torn down since we started. - if (!gBrowser) + let syncButton = document.getElementById("sync-button"); + if (!syncButton) return; - let broadcaster = document.getElementById("sync-status"); - if (broadcaster) { - if (tooltiptext) { - broadcaster.setAttribute("tooltiptext", tooltiptext); - } else { - broadcaster.removeAttribute("tooltiptext"); - } + let lastSync; + try { + lastSync = Services.prefs.getCharPref("services.sync.lastSync"); } - }), - - formatLastSyncDate: function(date) { - let dateFormat; - let sixDaysAgo = (() => { - let date = new Date(); - date.setDate(date.getDate() - 6); - date.setHours(0, 0, 0, 0); - return date; - })(); - // It may be confusing for the user to see "Last Sync: Monday" when the last sync was a indeed a Monday but 3 weeks ago - if (date < sixDaysAgo) { - dateFormat = {month: 'long', day: 'numeric'}; - } else { - dateFormat = {weekday: 'long', hour: 'numeric', minute: 'numeric'}; + catch (e) { }; + if (!lastSync || this._needsSetup()) { + syncButton.removeAttribute("tooltiptext"); + return; } - let lastSyncDateString = date.toLocaleDateString(undefined, dateFormat); - return this._stringBundle.formatStringFromName("lastSync2.label", [lastSyncDateString], 1); + + // 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("lastSync2.label", [lastSyncDate], 1); + + syncButton.setAttribute("tooltiptext", lastSyncLabel); }, - onClientsSynced: function() { - let broadcaster = document.getElementById("sync-syncnow-state"); - if (broadcaster) { - if (Weave.Service.clientsEngine.stats.numClients > 1) { - broadcaster.setAttribute("devices-status", "multi"); - } else { - broadcaster.setAttribute("devices-status", "single"); - } + clearError: function SUI_clearError(errorString) { + Weave.Notifications.removeAll(errorString); + this.updateUI(); + }, + + onSyncFinish: function SUI_onSyncFinish() { + let title = this._stringBundle.GetStringFromName("error.sync.title"); + + // Clear out sync failures on a successful sync + this.clearError(title); + + if (this._wasDelayed && Weave.Status.sync != Weave.NO_SYNC_NODE_FOUND) { + title = this._stringBundle.GetStringFromName("error.sync.no_node_found.title"); + this.clearError(title); + this._wasDelayed = false; } }, onSyncError: function SUI_onSyncError() { - this.log.debug("onSyncError: login=${login}, sync=${sync}", Weave.Status); let title = this._stringBundle.GetStringFromName("error.sync.title"); - let error = Weave.Utils.getErrorString(Weave.Status.sync); - let description = + + if (Weave.Status.login != Weave.LOGIN_SUCCEEDED) { + this.onLoginError(); + return; + } + + let description; + if (Weave.Status.sync == Weave.PROLONGED_SYNC_FAILURE) { + // Convert to days + let lastSync = + Services.prefs.getIntPref("services.sync.errorhandler.networkFailureReportTimeout") / 86400; + description = + this._stringBundle.formatStringFromName("error.sync.prolonged_failure", [lastSync], 1); + } else { + let error = Weave.Utils.getErrorString(Weave.Status.sync); + description = this._stringBundle.formatStringFromName("error.sync.description", [error], 1); + } let priority = Weave.Notifications.PRIORITY_WARNING; let buttons = []; - if (Weave.Status.sync == Weave.OVER_QUOTA) { - description = this._stringBundle.GetStringFromName("error.sync.quota.description"); + // Check if the client is outdated in some way + let outdated = Weave.Status.sync == Weave.VERSION_OUT_OF_DATE; + for (let [engine, reason] in Iterator(Weave.Status.engines)) + outdated = outdated || reason == Weave.VERSION_OUT_OF_DATE; + + if (outdated) { + description = this._stringBundle.GetStringFromName( + "error.sync.needUpdate.description"); buttons.push(new Weave.NotificationButton( - this._stringBundle.GetStringFromName("error.sync.viewQuotaButton.label"), - this._stringBundle.GetStringFromName("error.sync.viewQuotaButton.accesskey"), + this._stringBundle.GetStringFromName("error.sync.needUpdate.label"), + this._stringBundle.GetStringFromName("error.sync.needUpdate.accesskey"), + function() { + window.openUILinkIn(Services.prefs.getCharPref("services.sync.outdated.url"), "tab"); + return true; + } + )); + } + else if (Weave.Status.sync == Weave.OVER_QUOTA) { + description = this._stringBundle.GetStringFromName( + "error.sync.quota.description"); + buttons.push(new Weave.NotificationButton( + this._stringBundle.GetStringFromName( + "error.sync.viewQuotaButton.label"), + this._stringBundle.GetStringFromName( + "error.sync.viewQuotaButton.accesskey"), function() { gSyncUI.openQuotaDialog(); return true; } ) ); - // Only show the notification bar on Quota error. the panel will show the rest. - let notification = - new Weave.Notification(title, description, null, priority, buttons); - Weave.Notifications.replaceTitle(notification); + } + else if (Weave.Status.enforceBackoff) { + priority = Weave.Notifications.PRIORITY_INFO; + buttons.push(new Weave.NotificationButton( + this._stringBundle.GetStringFromName("error.sync.serverStatusButton.label"), + this._stringBundle.GetStringFromName("error.sync.serverStatusButton.accesskey"), + function() { gSyncUI.openServerStatus(); return true; } + )); + } + else { + 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); + + 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(); }, - observe: function SUI_observe(subject, topic, data) { - this.log.debug("observed", topic); if (this._unloaded) { Cu.reportError("SyncUI observer called after unload: " + topic); return; } - // Unwrap, just like Svc.Obs, but without pulling in that dependency. - if (subject && typeof subject == "object" && - ("wrappedJSObject" in subject) && - ("observersModuleSubjectWrapper" in subject.wrappedJSObject)) { - subject = subject.wrappedJSObject.object; - } - - // First handle "activity" only. switch (topic) { case "weave:service:sync:start": this.onActivityStart(); break; - case "weave:service:sync:finish": - case "weave:service:sync:error": - this.onActivityStop(); - break; - } - // Now non-activity state (eg, enabled, errors, etc) - // Note that sync uses the ":ui:" notifications for errors because sync. - switch (topic) { case "weave:ui:sync:finish": - // Do nothing. + this.onSyncFinish(); break; case "weave:ui:sync:error": this.onSyncError(); break; - case "weave:service:setup-complete": - case "weave:service:login:finish": - case "weave:service:login:start": - case "weave:service:start-over": - this.updateUI(); + case "weave:service:sync:delayed": + this.onSyncDelay(); break; case "weave:service:quota:remaining": this.onQuotaNotice(); break; + case "weave:service:setup-complete": + this.onSetupComplete(); + break; + case "weave:service:login:start": + this.onActivityStart(); + break; + case "weave:service:login:finish": + this.onLoginFinish(); + break; case "weave:ui:login:error": - case "weave:service:login:error": this.onLoginError(); break; case "weave:service:logout:finish": this.onLogout(); break; - case "weave:service:start-over:finish": - this.updateUI(); + case "weave:service:start-over": + this.onStartOver(); break; case "weave:service:ready": this.initUI(); @@ -535,16 +448,8 @@ var gSyncUI = { case "weave:notification:added": this.initNotifications(); break; - case "weave:engine:sync:finish": - if (data != "clients") { - return; - } - this.onClientsSynced(); - break; - case "quit-application": - // Stop the animation timer on shutdown, since we can't update the UI - // after this. - clearTimeout(this._syncAnimationTimer); + case "weave:ui:clear-error": + this.clearError(); break; } }, @@ -556,19 +461,10 @@ var gSyncUI = { }; XPCOMUtils.defineLazyGetter(gSyncUI, "_stringBundle", function() { - // XXXzpao these strings should probably be moved from /services to /browser... (bug 583381) + //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"); }); -XPCOMUtils.defineLazyGetter(gSyncUI, "log", function() { - return Log.repository.getLogger("browserwindow.syncui"); -}); - -XPCOMUtils.defineLazyGetter(gSyncUI, "weaveService", function() { - return Components.classes["@mozilla.org/weave/service;1"] - .getService(Components.interfaces.nsISupports) - .wrappedJSObject; -}); diff --git a/application/basilisk/base/content/browser.css b/application/basilisk/base/content/browser.css index 517c1c5eb..a2c2559d6 100644 --- a/application/basilisk/base/content/browser.css +++ b/application/basilisk/base/content/browser.css @@ -687,6 +687,18 @@ window[chromehidden~="toolbar"] toolbar:not(#nav-bar):not(#TabsToolbar):not(#pri min-width: 1px; } +%ifdef MOZ_SERVICES_SYNC +/* Sync notification UI */ +#sync-notifications { + -moz-binding: url("chrome://browser/content/sync/notification.xml#notificationbox"); + overflow-y: visible !important; +} + +#sync-notifications notification { + -moz-binding: url("chrome://browser/content/sync/notification.xml#notification"); +} +%endif + /* History Swipe Animation */ #historySwipeAnimationContainer { diff --git a/application/basilisk/base/content/browser.js b/application/basilisk/base/content/browser.js index ddbe11a9d..49ee14848 100644 --- a/application/basilisk/base/content/browser.js +++ b/application/basilisk/base/content/browser.js @@ -46,7 +46,6 @@ Cu.import("resource://gre/modules/NotificationDB.jsm"); ["Task", "resource://gre/modules/Task.jsm"], ["UpdateUtils", "resource://gre/modules/UpdateUtils.jsm"], ["Weave", "resource://services-sync/main.js"], - ["fxAccounts", "resource://gre/modules/FxAccounts.jsm"], #ifdef MOZ_DEVTOOLS // Note: Do not delete! It is used for: base/content/nsContextMenu.js ["gDevTools", "resource://devtools/client/framework/gDevTools.jsm"], @@ -103,6 +102,12 @@ XPCOMUtils.defineLazyGetter(this, "PageMenuParent", function() { return new tmp.PageMenuParent(); }); +#ifdef MOZ_SERVICES_SYNC +XPCOMUtils.defineLazyModuleGetter(this, "Weave", + "resource://services-sync/main.js"); +#endif + + XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () { let tmp = {}; Cu.import("resource://gre/modules/PopupNotifications.jsm", tmp); @@ -208,6 +213,10 @@ var gInitialPages = [ "about:logopage" ]; +#ifdef MOZ_SERVICES_SYNC +#include browser-syncui.js +#endif + function* browserWindows() { let windows = Services.wm.getEnumerator("navigator:browser"); while (windows.hasMoreElements()) @@ -1305,13 +1314,14 @@ var gBrowserInit = { FullScreen.init(); PointerLock.init(); - // initialize the sync UI - gSyncUI.init(); - gFxAccounts.init(); - if (AppConstants.MOZ_DATA_REPORTING) gDataNotificationInfoBar.init(); +#ifdef MOZ_SERVICES_SYNC + // initialize the sync UI + gSyncUI.init(); +#endif + gBrowserThumbnails.init(); gMenuButtonBadgeManager.init(); @@ -1445,8 +1455,6 @@ var gBrowserInit = { FullScreen.uninit(); - gFxAccounts.uninit(); - Services.obs.removeObserver(gPluginHandler.NPAPIPluginCrashed, "plugin-crashed"); try { @@ -1607,8 +1615,10 @@ if (AppConstants.platform == "macosx") { // initialize the private browsing UI gPrivateBrowsingUI.init(); +#ifdef MOZ_SERVICES_SYNC // initialize the sync UI gSyncUI.init(); +#endif }; gBrowserInit.nonBrowserWindowShutdown = function() { @@ -3181,12 +3191,14 @@ var PrintPreviewListener = { this._chromeState.globalNotificationsOpen = !globalNotificationBox.notificationsHidden; globalNotificationBox.notificationsHidden = true; +#ifdef MOZ_SERVICES_SYNC this._chromeState.syncNotificationsOpen = false; var syncNotifications = document.getElementById("sync-notifications"); if (syncNotifications) { this._chromeState.syncNotificationsOpen = !syncNotifications.notificationsHidden; syncNotifications.notificationsHidden = true; } +#endif }, _showChrome: function () { if (this._chromeState.notificationsOpen) @@ -3198,8 +3210,10 @@ var PrintPreviewListener = { if (this._chromeState.globalNotificationsOpen) document.getElementById("global-notificationbox").notificationsHidden = false; +#ifdef MOZ_SERVICES_SYNC if (this._chromeState.syncNotificationsOpen) document.getElementById("sync-notifications").notificationsHidden = false; +#endif if (this._chromeState.sidebarOpen) SidebarUI.show(this._sidebarCommand); @@ -6238,9 +6252,11 @@ function checkEmptyPageOrigin(browser = gBrowser.selectedBrowser, return ssm.isSystemPrincipal(contentPrincipal); } +#ifdef MOZ_SERVICES_SYNC function BrowserOpenSyncTabs() { switchToTabHavingURI("about:sync-tabs", true); } +#endif /** * Format a URL @@ -7540,8 +7556,6 @@ var TabContextMenu = { this.contextTab.addEventListener("TabAttrModified", this, false); aPopupMenu.addEventListener("popuphiding", this, false); - - gFxAccounts.updateTabContextMenu(aPopupMenu); }, handleEvent(aEvent) { switch (aEvent.type) { diff --git a/application/basilisk/base/content/browser.xul b/application/basilisk/base/content/browser.xul index 0cc4c982a..d50a5c773 100644 --- a/application/basilisk/base/content/browser.xul +++ b/application/basilisk/base/content/browser.xul @@ -390,59 +390,6 @@ <tooltip id="dynamic-shortcut-tooltip" onpopupshowing="UpdateDynamicShortcutTooltipText(this);"/> - - <menupopup id="SyncedTabsSidebarContext"> - <menuitem label="&syncedTabs.context.open.label;" - accesskey="&syncedTabs.context.open.accesskey;" - id="syncedTabsOpenSelected" where="current"/> - <menuitem label="&syncedTabs.context.openInNewTab.label;" - accesskey="&syncedTabs.context.openInNewTab.accesskey;" - id="syncedTabsOpenSelectedInTab" where="tab"/> - <menuitem label="&syncedTabs.context.openInNewWindow.label;" - accesskey="&syncedTabs.context.openInNewWindow.accesskey;" - id="syncedTabsOpenSelectedInWindow" where="window"/> - <menuitem label="&syncedTabs.context.openInNewPrivateWindow.label;" - accesskey="&syncedTabs.context.openInNewPrivateWindow.accesskey;" - id="syncedTabsOpenSelectedInPrivateWindow" where="window" private="true"/> - <menuseparator/> - <menuitem label="&syncedTabs.context.bookmarkSingleTab.label;" - accesskey="&syncedTabs.context.bookmarkSingleTab.accesskey;" - id="syncedTabsBookmarkSelected"/> - <menuitem label="&syncedTabs.context.copy.label;" - accesskey="&syncedTabs.context.copy.accesskey;" - id="syncedTabsCopySelected"/> - <menuseparator/> - <menuitem label="&syncSyncNowItem.label;" - accesskey="&syncSyncNowItem.accesskey;" - id="syncedTabsRefresh"/> - </menupopup> - <menupopup id="SyncedTabsSidebarTabsFilterContext" - class="textbox-contextmenu"> - <menuitem label="&undoCmd.label;" - accesskey="&undoCmd.accesskey;" - cmd="cmd_undo"/> - <menuseparator/> - <menuitem label="&cutCmd.label;" - accesskey="&cutCmd.accesskey;" - cmd="cmd_cut"/> - <menuitem label="©Cmd.label;" - accesskey="©Cmd.accesskey;" - cmd="cmd_copy"/> - <menuitem label="&pasteCmd.label;" - accesskey="&pasteCmd.accesskey;" - cmd="cmd_paste"/> - <menuitem label="&deleteCmd.label;" - accesskey="&deleteCmd.accesskey;" - cmd="cmd_delete"/> - <menuseparator/> - <menuitem label="&selectAllCmd.label;" - accesskey="&selectAllCmd.accesskey;" - cmd="cmd_selectAll"/> - <menuseparator/> - <menuitem label="&syncSyncNowItem.label;" - accesskey="&syncSyncNowItem.accesskey;" - id="syncedTabsRefreshFilter"/> - </menupopup> </popupset> #ifdef CAN_DRAW_IN_TITLEBAR diff --git a/application/basilisk/base/content/global-scripts.inc b/application/basilisk/base/content/global-scripts.inc index eef21e15e..6417a1d95 100644 --- a/application/basilisk/base/content/global-scripts.inc +++ b/application/basilisk/base/content/global-scripts.inc @@ -27,7 +27,6 @@ <script type="application/javascript" src="chrome://browser/content/browser-safebrowsing.js"/> #endif <script type="application/javascript" src="chrome://browser/content/browser-sidebar.js"/> -<script type="application/javascript" src="chrome://browser/content/browser-syncui.js"/> <script type="application/javascript" src="chrome://browser/content/browser-tabsintitlebar.js"/> <script type="application/javascript" src="chrome://browser/content/browser-thumbnails.js"/> <script type="application/javascript" src="chrome://browser/content/browser-trackingprotection.js"/> diff --git a/application/basilisk/base/content/nsContextMenu.js b/application/basilisk/base/content/nsContextMenu.js index 74a2e7a8e..370e5ba60 100644 --- a/application/basilisk/base/content/nsContextMenu.js +++ b/application/basilisk/base/content/nsContextMenu.js @@ -112,7 +112,6 @@ nsContextMenu.prototype = { this.initLeaveDOMFullScreenItems(); this.initClickToPlayItems(); this.initPasswordManagerItems(); - this.initSyncItems(); }, initPageMenuSeparator: function CM_initPageMenuSeparator() { @@ -522,10 +521,6 @@ nsContextMenu.prototype = { popup.insertBefore(fragment, insertBeforeElement); }, - initSyncItems: function() { - gFxAccounts.initPageContextMenu(this); - }, - openPasswordManager: function() { LoginHelper.openPasswordManager(window, gContextMenuContentData.documentURIObject.host); }, diff --git a/application/basilisk/base/content/sync/aboutSyncTabs-bindings.xml b/application/basilisk/base/content/sync/aboutSyncTabs-bindings.xml deleted file mode 100644 index e6108209a..000000000 --- a/application/basilisk/base/content/sync/aboutSyncTabs-bindings.xml +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0"?> - -<!-- 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/. --> - -<bindings id="tabBindings" - xmlns="http://www.mozilla.org/xbl" - xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - xmlns:xbl="http://www.mozilla.org/xbl"> - - <binding id="tab-listing" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem"> - <content> - <xul:hbox flex="1"> - <xul:vbox pack="start"> - <xul:image class="tabIcon" - xbl:inherits="src=icon"/> - </xul:vbox> - <xul:vbox pack="start" flex="1"> - <xul:label xbl:inherits="value=title,selected" - crop="end" flex="1" class="title"/> - <xul:label xbl:inherits="value=url,selected" - crop="end" flex="1" class="url"/> - </xul:vbox> - </xul:hbox> - </content> - <handlers> - <handler event="dblclick" button="0"> - <![CDATA[ - RemoteTabViewer.openSelected(); - ]]> - </handler> - </handlers> - </binding> - - <binding id="client-listing" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem"> - <content> - <xul:hbox pack="start" align="center" onfocus="event.target.blur()" onselect="return false;"> - <xul:image/> - <xul:label xbl:inherits="value=clientName" - class="clientName" - crop="center" flex="1"/> - </xul:hbox> - </content> - </binding> -</bindings> diff --git a/application/basilisk/base/content/sync/aboutSyncTabs.css b/application/basilisk/base/content/sync/aboutSyncTabs.css deleted file mode 100644 index 5a353175b..000000000 --- a/application/basilisk/base/content/sync/aboutSyncTabs.css +++ /dev/null @@ -1,11 +0,0 @@ -/* 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/. */ - -richlistitem[type="tab"] { - -moz-binding: url(chrome://browser/content/sync/aboutSyncTabs-bindings.xml#tab-listing); -} - -richlistitem[type="client"] { - -moz-binding: url(chrome://browser/content/sync/aboutSyncTabs-bindings.xml#client-listing); -} diff --git a/application/basilisk/base/content/sync/aboutSyncTabs.js b/application/basilisk/base/content/sync/aboutSyncTabs.js deleted file mode 100644 index f4bb607ea..000000000 --- a/application/basilisk/base/content/sync/aboutSyncTabs.js +++ /dev/null @@ -1,364 +0,0 @@ -/* 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/. */ - -var Cu = Components.utils; - -Cu.import("resource://services-common/utils.js"); -Cu.import("resource://services-sync/main.js"); -Cu.import("resource:///modules/PlacesUIUtils.jsm"); -Cu.import("resource://gre/modules/PlacesUtils.jsm", this); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Promise", - "resource://gre/modules/Promise.jsm"); - -#ifdef MOZ_SERVICES_CLOUDSYNC -XPCOMUtils.defineLazyModuleGetter(this, "CloudSync", - "resource://gre/modules/CloudSync.jsm"); -#endif - -var RemoteTabViewer = { - _tabsList: null, - - init: function () { - Services.obs.addObserver(this, "weave:service:login:finish", false); - Services.obs.addObserver(this, "weave:engine:sync:finish", false); - - Services.obs.addObserver(this, "cloudsync:tabs:update", false); - - this._tabsList = document.getElementById("tabsList"); - - this.buildList(true); - }, - - uninit: function () { - Services.obs.removeObserver(this, "weave:service:login:finish"); - Services.obs.removeObserver(this, "weave:engine:sync:finish"); - - Services.obs.removeObserver(this, "cloudsync:tabs:update"); - }, - - createItem: function (attrs) { - let item = document.createElement("richlistitem"); - - // Copy the attributes from the argument into the item. - for (let attr in attrs) { - item.setAttribute(attr, attrs[attr]); - } - - if (attrs["type"] == "tab") { - item.label = attrs.title != "" ? attrs.title : attrs.url; - } - - return item; - }, - - filterTabs: function (event) { - let val = event.target.value.toLowerCase(); - let numTabs = this._tabsList.getRowCount(); - let clientTabs = 0; - let currentClient = null; - - for (let i = 0; i < numTabs; i++) { - let item = this._tabsList.getItemAtIndex(i); - let hide = false; - if (item.getAttribute("type") == "tab") { - if (!item.getAttribute("url").toLowerCase().includes(val) && - !item.getAttribute("title").toLowerCase().includes(val)) { - hide = true; - } else { - clientTabs++; - } - } - else if (item.getAttribute("type") == "client") { - if (currentClient) { - if (clientTabs == 0) { - currentClient.hidden = true; - } - } - currentClient = item; - clientTabs = 0; - } - item.hidden = hide; - } - if (clientTabs == 0) { - currentClient.hidden = true; - } - }, - - openSelected: function () { - let items = this._tabsList.selectedItems; - let urls = []; - for (let i = 0; i < items.length; i++) { - if (items[i].getAttribute("type") == "tab") { - urls.push(items[i].getAttribute("url")); - let index = this._tabsList.getIndexOfItem(items[i]); - this._tabsList.removeItemAt(index); - } - } - if (urls.length) { - getTopWin().gBrowser.loadTabs(urls); - this._tabsList.clearSelection(); - } - }, - - bookmarkSingleTab: function () { - let item = this._tabsList.selectedItems[0]; - let uri = Weave.Utils.makeURI(item.getAttribute("url")); - let title = item.getAttribute("title"); - PlacesUIUtils.showBookmarkDialog({ action: "add" - , type: "bookmark" - , uri: uri - , title: title - , hiddenRows: [ "description" - , "location" - , "loadInSidebar" - , "keyword" ] - }, window.top); - }, - - bookmarkSelectedTabs: function () { - let items = this._tabsList.selectedItems; - let URIs = []; - for (let i = 0; i < items.length; i++) { - if (items[i].getAttribute("type") == "tab") { - let uri = Weave.Utils.makeURI(items[i].getAttribute("url")); - if (!uri) { - continue; - } - - URIs.push(uri); - } - } - if (URIs.length) { - PlacesUIUtils.showBookmarkDialog({ action: "add" - , type: "folder" - , URIList: URIs - , hiddenRows: [ "description" ] - }, window.top); - } - }, - - getIcon: function (iconUri, defaultIcon) { - try { - let iconURI = Weave.Utils.makeURI(iconUri); - return PlacesUtils.favicons.getFaviconLinkForIcon(iconURI).spec; - } catch (ex) { - // Do nothing. - } - - // Just give the provided default icon or the system's default. - return defaultIcon || PlacesUtils.favicons.defaultFavicon.spec; - }, - - _waitingForBuildList: false, - - _buildListRequested: false, - - buildList: function (forceSync) { - if (this._waitingForBuildList) { - this._buildListRequested = true; - return; - } - - this._waitingForBuildList = true; - this._buildListRequested = false; - - this._clearTabList(); - - if (Weave.Service.isLoggedIn) { - this._refetchTabs(forceSync); - this._generateWeaveTabList(); - } else { - // XXXzpao We should say something about not being logged in & not having data - // or tell the appropriate condition. (bug 583344) - } - - let complete = () => { - this._waitingForBuildList = false; - if (this._buildListRequested) { - CommonUtils.nextTick(this.buildList, this); - } - } - -#ifdef MOZ_SERVICES_CLOUDSYNC - if (CloudSync && CloudSync.ready && CloudSync().tabsReady && CloudSync().tabs.hasRemoteTabs()) { - this._generateCloudSyncTabList() - .then(complete, complete); - } else { - complete(); - } -#else - complete(); -#endif - }, - - _clearTabList: function () { - let list = this._tabsList; - - // Clear out existing richlistitems. - let count = list.getRowCount(); - if (count > 0) { - for (let i = count - 1; i >= 0; i--) { - list.removeItemAt(i); - } - } - }, - - _generateWeaveTabList: function () { - let engine = Weave.Service.engineManager.get("tabs"); - let list = this._tabsList; - - let seenURLs = new Set(); - let localURLs = engine.getOpenURLs(); - - for (let [, client] of Object.entries(engine.getAllClients())) { - // Create the client node, but don't add it in-case we don't show any tabs - let appendClient = true; - - client.tabs.forEach(function({title, urlHistory, icon}) { - let url = urlHistory[0]; - if (!url || localURLs.has(url) || seenURLs.has(url)) { - return; - } - seenURLs.add(url); - - if (appendClient) { - let attrs = { - type: "client", - clientName: client.clientName, - class: Weave.Service.clientsEngine.isMobile(client.id) ? "mobile" : "desktop" - }; - let clientEnt = this.createItem(attrs); - list.appendChild(clientEnt); - appendClient = false; - clientEnt.disabled = true; - } - let attrs = { - type: "tab", - title: title || url, - url: url, - icon: this.getIcon(icon), - } - let tab = this.createItem(attrs); - list.appendChild(tab); - }, this); - } - }, - - _generateCloudSyncTabList: function () { - let updateTabList = function (remoteTabs) { - let list = this._tabsList; - - for (let client of remoteTabs) { - let clientAttrs = { - type: "client", - clientName: client.name, - }; - - let clientEnt = this.createItem(clientAttrs); - list.appendChild(clientEnt); - - for (let tab of client.tabs) { - let tabAttrs = { - type: "tab", - title: tab.title, - url: tab.url, - icon: this.getIcon(tab.icon), - }; - let tabEnt = this.createItem(tabAttrs); - list.appendChild(tabEnt); - } - } - }.bind(this); - - return CloudSync().tabs.getRemoteTabs() - .then(updateTabList, Promise.reject.bind(Promise)); - }, - - adjustContextMenu: function (event) { - let mode = "all"; - switch (this._tabsList.selectedItems.length) { - case 0: - break; - case 1: - mode = "single" - break; - default: - mode = "multiple"; - break; - } - - let menu = document.getElementById("tabListContext"); - let el = menu.firstChild; - while (el) { - let showFor = el.getAttribute("showFor"); - if (showFor) { - el.hidden = showFor != mode && showFor != "all"; - } - - el = el.nextSibling; - } - }, - - _refetchTabs: function (force) { - if (!force) { - // Don't bother refetching tabs if we already did so recently - let lastFetch = 0; - try { - lastFetch = Services.prefs.getIntPref("services.sync.lastTabFetch"); - } - catch (e) { - /* Just use the default value of 0 */ - } - - let now = Math.floor(Date.now() / 1000); - if (now - lastFetch < 30) { - return false; - } - } - - // Ask Sync to just do the tabs engine if it can. - Weave.Service.sync(["tabs"]); - Services.prefs.setIntPref("services.sync.lastTabFetch", - Math.floor(Date.now() / 1000)); - - return true; - }, - - observe: function (subject, topic, data) { - switch (topic) { - case "weave:service:login:finish": - // A login has finished, which means that a Sync is about to start and - // we will eventually get to the "tabs" engine - but try and force the - // tab engine to sync first by passing |true| for the forceSync param. - this.buildList(true); - break; - case "weave:engine:sync:finish": - if (data == "tabs") { - // The tabs engine just finished, so re-build the list without - // forcing a new sync of the tabs engine. - this.buildList(false); - } - break; - case "cloudsync:tabs:update": - this.buildList(false); - break; - } - }, - - handleClick: function (event) { - if (event.target.getAttribute("type") != "tab") { - return; - } - - if (event.button == 1) { - let url = event.target.getAttribute("url"); - openUILink(url, event); - let index = this._tabsList.getIndexOfItem(event.target); - this._tabsList.removeItemAt(index); - } - } -} diff --git a/application/basilisk/base/content/sync/aboutSyncTabs.xul b/application/basilisk/base/content/sync/aboutSyncTabs.xul deleted file mode 100644 index a4aa0032f..000000000 --- a/application/basilisk/base/content/sync/aboutSyncTabs.xul +++ /dev/null @@ -1,68 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?> -<?xml-stylesheet href="chrome://browser/skin/aboutSyncTabs.css" type="text/css"?> -<?xml-stylesheet href="chrome://browser/content/sync/aboutSyncTabs.css" type="text/css"?> - -<!DOCTYPE window [ - <!ENTITY % aboutSyncTabsDTD SYSTEM "chrome://browser/locale/aboutSyncTabs.dtd"> - %aboutSyncTabsDTD; -]> - -<window id="tabs-display" - onload="RemoteTabViewer.init()" - onunload="RemoteTabViewer.uninit()" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - xmlns:html="http://www.w3.org/1999/xhtml" - title="&tabs.otherDevices.label;"> - <script type="application/javascript;version=1.8" src="chrome://browser/content/sync/aboutSyncTabs.js"/> - <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/> - <html:head> - <html:link rel="icon" href="chrome://browser/skin/sync-16.png"/> - </html:head> - - <popupset id="contextmenus"> - <menupopup id="tabListContext"> - <menuitem label="&tabs.context.openTab.label;" - accesskey="&tabs.context.openTab.accesskey;" - oncommand="RemoteTabViewer.openSelected()" - showFor="single"/> - <menuitem label="&tabs.context.bookmarkSingleTab.label;" - accesskey="&tabs.context.bookmarkSingleTab.accesskey;" - oncommand="RemoteTabViewer.bookmarkSingleTab(event)" - showFor="single"/> - <menuitem label="&tabs.context.openMultipleTabs.label;" - accesskey="&tabs.context.openMultipleTabs.accesskey;" - oncommand="RemoteTabViewer.openSelected()" - showFor="multiple"/> - <menuitem label="&tabs.context.bookmarkMultipleTabs.label;" - accesskey="&tabs.context.bookmarkMultipleTabs.accesskey;" - oncommand="RemoteTabViewer.bookmarkSelectedTabs()" - showFor="multiple"/> - <menuseparator/> - <menuitem label="&tabs.context.refreshList.label;" - accesskey="&tabs.context.refreshList.accesskey;" - oncommand="RemoteTabViewer.buildList()" - showFor="all"/> - </menupopup> - </popupset> - <richlistbox context="tabListContext" id="tabsList" seltype="multiple" - align="center" flex="1" - onclick="RemoteTabViewer.handleClick(event)" - oncontextmenu="RemoteTabViewer.adjustContextMenu(event)"> - <hbox id="headers" align="center"> - <label id="tabsListHeading" - value="&tabs.otherDevices.label;"/> - <spacer flex="1"/> - <textbox type="search" - emptytext="&tabs.searchText.label;" - oncommand="RemoteTabViewer.filterTabs(event)"/> - </hbox> - - </richlistbox> -</window> - diff --git a/application/basilisk/base/content/sync/addDevice.js b/application/basilisk/base/content/sync/addDevice.js deleted file mode 100644 index 0390d4397..000000000 --- a/application/basilisk/base/content/sync/addDevice.js +++ /dev/null @@ -1,157 +0,0 @@ -/* 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/. */ - -var Ci = Components.interfaces; -var Cc = Components.classes; -var Cu = Components.utils; - -Cu.import("resource://services-sync/main.js"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -const PIN_PART_LENGTH = 4; - -const ADD_DEVICE_PAGE = 0; -const SYNC_KEY_PAGE = 1; -const DEVICE_CONNECTED_PAGE = 2; - -var gSyncAddDevice = { - - init: function init() { - this.pin1.setAttribute("maxlength", PIN_PART_LENGTH); - this.pin2.setAttribute("maxlength", PIN_PART_LENGTH); - this.pin3.setAttribute("maxlength", PIN_PART_LENGTH); - - this.nextFocusEl = {pin1: this.pin2, - pin2: this.pin3, - pin3: this.wizard.getButton("next")}; - - this.throbber = document.getElementById("pairDeviceThrobber"); - this.errorRow = document.getElementById("errorRow"); - - // Kick off a sync. That way the server will have the most recent data from - // this computer and it will show up immediately on the new device. - Weave.Service.scheduler.scheduleNextSync(0); - }, - - onPageShow: function onPageShow() { - this.wizard.getButton("back").hidden = true; - - switch (this.wizard.pageIndex) { - case ADD_DEVICE_PAGE: - this.onTextBoxInput(); - this.wizard.canRewind = false; - this.wizard.getButton("next").hidden = false; - this.pin1.focus(); - break; - case SYNC_KEY_PAGE: - this.wizard.canAdvance = false; - this.wizard.canRewind = true; - this.wizard.getButton("back").hidden = false; - this.wizard.getButton("next").hidden = true; - document.getElementById("weavePassphrase").value = - Weave.Utils.hyphenatePassphrase(Weave.Service.identity.syncKey); - break; - case DEVICE_CONNECTED_PAGE: - this.wizard.canAdvance = true; - this.wizard.canRewind = false; - this.wizard.getButton("cancel").hidden = true; - break; - } - }, - - onWizardAdvance: function onWizardAdvance() { - switch (this.wizard.pageIndex) { - case ADD_DEVICE_PAGE: - this.startTransfer(); - return false; - case DEVICE_CONNECTED_PAGE: - window.close(); - return false; - } - return true; - }, - - startTransfer: function startTransfer() { - this.errorRow.hidden = true; - // When onAbort is called, Weave may already be gone. - const JPAKE_ERROR_USERABORT = Weave.JPAKE_ERROR_USERABORT; - - let self = this; - let jpakeclient = this._jpakeclient = new Weave.JPAKEClient({ - onPaired: function onPaired() { - let credentials = {account: Weave.Service.identity.account, - password: Weave.Service.identity.basicPassword, - synckey: Weave.Service.identity.syncKey, - serverURL: Weave.Service.serverURL}; - jpakeclient.sendAndComplete(credentials); - }, - onComplete: function onComplete() { - delete self._jpakeclient; - self.wizard.pageIndex = DEVICE_CONNECTED_PAGE; - - // Schedule a Sync for soonish to fetch the data uploaded by the - // device with which we just paired. - Weave.Service.scheduler.scheduleNextSync(Weave.Service.scheduler.activeInterval); - }, - onAbort: function onAbort(error) { - delete self._jpakeclient; - - // Aborted by user, ignore. - if (error == JPAKE_ERROR_USERABORT) { - return; - } - - self.errorRow.hidden = false; - self.throbber.hidden = true; - self.pin1.value = self.pin2.value = self.pin3.value = ""; - self.pin1.disabled = self.pin2.disabled = self.pin3.disabled = false; - self.pin1.focus(); - } - }); - this.throbber.hidden = false; - this.pin1.disabled = this.pin2.disabled = this.pin3.disabled = true; - this.wizard.canAdvance = false; - - let pin = this.pin1.value + this.pin2.value + this.pin3.value; - let expectDelay = false; - jpakeclient.pairWithPIN(pin, expectDelay); - }, - - onWizardBack: function onWizardBack() { - if (this.wizard.pageIndex != SYNC_KEY_PAGE) - return true; - - this.wizard.pageIndex = ADD_DEVICE_PAGE; - return false; - }, - - onWizardCancel: function onWizardCancel() { - if (this._jpakeclient) { - this._jpakeclient.abort(); - delete this._jpakeclient; - } - return true; - }, - - onTextBoxInput: function onTextBoxInput(textbox) { - if (textbox && textbox.value.length == PIN_PART_LENGTH) - this.nextFocusEl[textbox.id].focus(); - - this.wizard.canAdvance = (this.pin1.value.length == PIN_PART_LENGTH - && this.pin2.value.length == PIN_PART_LENGTH - && this.pin3.value.length == PIN_PART_LENGTH); - }, - - goToSyncKeyPage: function goToSyncKeyPage() { - this.wizard.pageIndex = SYNC_KEY_PAGE; - } - -}; -// onWizardAdvance() and onPageShow() are run before init() so we'll set -// these up as lazy getters. -["wizard", "pin1", "pin2", "pin3"].forEach(function (id) { - XPCOMUtils.defineLazyGetter(gSyncAddDevice, id, function() { - return document.getElementById(id); - }); -}); diff --git a/application/basilisk/base/content/sync/addDevice.xul b/application/basilisk/base/content/sync/addDevice.xul deleted file mode 100644 index 83c3b7b3c..000000000 --- a/application/basilisk/base/content/sync/addDevice.xul +++ /dev/null @@ -1,129 +0,0 @@ -<?xml version="1.0"?> - -<!-- 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/. --> - -<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> -<?xml-stylesheet href="chrome://browser/skin/syncSetup.css" type="text/css"?> -<?xml-stylesheet href="chrome://browser/skin/syncCommon.css" type="text/css"?> - -<!DOCTYPE window [ -<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> -<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd"> -<!ENTITY % syncSetupDTD SYSTEM "chrome://browser/locale/syncSetup.dtd"> -%brandDTD; -%syncBrandDTD; -%syncSetupDTD; -]> -<wizard xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - xmlns:html="http://www.w3.org/1999/xhtml" - id="wizard" - title="&pairDevice.title.label;" - windowtype="Sync:AddDevice" - persist="screenX screenY" - onwizardnext="return gSyncAddDevice.onWizardAdvance();" - onwizardback="return gSyncAddDevice.onWizardBack();" - onwizardcancel="gSyncAddDevice.onWizardCancel();" - onload="gSyncAddDevice.init();"> - - <script type="application/javascript" - src="chrome://browser/content/sync/addDevice.js"/> - <script type="application/javascript" - src="chrome://browser/content/sync/utils.js"/> - <script type="application/javascript" - src="chrome://browser/content/utilityOverlay.js"/> - <script type="application/javascript" - src="chrome://global/content/printUtils.js"/> - - <wizardpage id="addDevicePage" - label="&pairDevice.title.label;" - onpageshow="gSyncAddDevice.onPageShow();"> - <description> - &pairDevice.dialog.description.label; - <label class="text-link" - value="&addDevice.showMeHow.label;" - href="https://services.mozilla.com/sync/help/add-device"/> - </description> - <separator class="groove-thin"/> - <description> - &addDevice.dialog.enterCode.label; - </description> - <separator class="groove-thin"/> - <vbox align="center"> - <textbox id="pin1" - class="pin" - oninput="gSyncAddDevice.onTextBoxInput(this);" - onfocus="this.select();" - /> - <textbox id="pin2" - class="pin" - oninput="gSyncAddDevice.onTextBoxInput(this);" - onfocus="this.select();" - /> - <textbox id="pin3" - class="pin" - oninput="gSyncAddDevice.onTextBoxInput(this);" - onfocus="this.select();" - /> - </vbox> - <separator class="groove-thin"/> - <vbox id="pairDeviceThrobber" align="center" hidden="true"> - <image/> - </vbox> - <hbox id="errorRow" pack="center" hidden="true"> - <image class="statusIcon" status="error"/> - <label class="status" - value="&addDevice.dialog.tryAgain.label;"/> - </hbox> - <spacer flex="3"/> - <label class="text-link" - value="&addDevice.dontHaveDevice.label;" - onclick="gSyncAddDevice.goToSyncKeyPage();"/> - </wizardpage> - - <!-- Need a non-empty label here, otherwise we get a default label on Mac --> - <wizardpage id="syncKeyPage" - label=" " - onpageshow="gSyncAddDevice.onPageShow();"> - <description> - &addDevice.dialog.recoveryKey.label; - </description> - <spacer/> - - <groupbox> - <label value="&recoveryKeyEntry.label;" - accesskey="&recoveryKeyEntry.accesskey;" - control="weavePassphrase"/> - <textbox id="weavePassphrase" - readonly="true"/> - </groupbox> - - <groupbox align="center"> - <description>&recoveryKeyBackup.description;</description> - <hbox> - <button id="printSyncKeyButton" - label="&button.syncKeyBackup.print.label;" - accesskey="&button.syncKeyBackup.print.accesskey;" - oncommand="gSyncUtils.passphrasePrint('weavePassphrase');"/> - <button id="saveSyncKeyButton" - label="&button.syncKeyBackup.save.label;" - accesskey="&button.syncKeyBackup.save.accesskey;" - oncommand="gSyncUtils.passphraseSave('weavePassphrase');"/> - </hbox> - </groupbox> - </wizardpage> - - <wizardpage id="deviceConnectedPage" - label="&addDevice.dialog.connected.label;" - onpageshow="gSyncAddDevice.onPageShow();"> - <vbox align="center"> - <image id="successPageIcon"/> - </vbox> - <separator/> - <description class="normal"> - &addDevice.dialog.successful.label; - </description> - </wizardpage> - -</wizard> diff --git a/application/basilisk/base/content/sync/customize.css b/application/basilisk/base/content/sync/customize.css deleted file mode 100644 index 2bb62595d..000000000 --- a/application/basilisk/base/content/sync/customize.css +++ /dev/null @@ -1,28 +0,0 @@ -/* 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/. */ - -:root { - font-size: 80%; -} - -#sync-customize-pane { - padding-inline-start: 74px; - background: top left url(chrome://browser/skin/sync-128.png) no-repeat; - background-size: 64px; -} - -#sync-customize-title { - margin-inline-start: 0; - padding-bottom: 0.5em; - font-weight: bold; -} - -#sync-customize-subtitle { - font-size: 90%; -} - -checkbox { - margin: 0; - padding: 0.5em 0 0; -} diff --git a/application/basilisk/base/content/sync/customize.js b/application/basilisk/base/content/sync/customize.js deleted file mode 100644 index f431ac58c..000000000 --- a/application/basilisk/base/content/sync/customize.js +++ /dev/null @@ -1,25 +0,0 @@ -/* 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/. */ - -"use strict"; - -Components.utils.import("resource://gre/modules/Services.jsm"); - -addEventListener("dialogaccept", function () { - let pane = document.getElementById("sync-customize-pane"); - // First determine what the preference for the "global" sync enabled pref - // should be based on the engines selected. - let prefElts = pane.querySelectorAll("preferences > preference"); - let syncEnabled = false; - for (let elt of prefElts) { - if (elt.name.startsWith("services.sync.") && elt.value) { - syncEnabled = true; - break; - } - } - Services.prefs.setBoolPref("services.sync.enabled", syncEnabled); - // and write the individual prefs. - pane.writePreferences(true); - window.arguments[0].accepted = true; -}); diff --git a/application/basilisk/base/content/sync/customize.xul b/application/basilisk/base/content/sync/customize.xul deleted file mode 100644 index 827edf565..000000000 --- a/application/basilisk/base/content/sync/customize.xul +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0"?> - -<!-- 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/. --> - -<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> -<?xml-stylesheet href="chrome://browser/content/sync/customize.css" type="text/css"?> - -<!DOCTYPE dialog [ -<!ENTITY % syncCustomizeDTD SYSTEM "chrome://browser/locale/syncCustomize.dtd"> -%syncCustomizeDTD; -]> -<dialog id="sync-customize" - windowtype="Sync:Customize" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - xmlns:html="http://www.w3.org/1999/xhtml" - title="&syncCustomize.dialog.title;" - buttonlabelaccept="&syncCustomize.acceptButton.label;" - buttons="accept"> - - <prefpane id="sync-customize-pane"> - <preferences> - <preference id="engine.bookmarks" name="services.sync.engine.bookmarks" type="bool"/> - <preference id="engine.history" name="services.sync.engine.history" type="bool"/> - <preference id="engine.tabs" name="services.sync.engine.tabs" type="bool"/> - <preference id="engine.passwords" name="services.sync.engine.passwords" type="bool"/> - <preference id="engine.addons" name="services.sync.engine.addons" type="bool"/> - <preference id="engine.prefs" name="services.sync.engine.prefs" type="bool"/> - </preferences> - - <label id="sync-customize-title" value="&syncCustomize.title;"/> - <description id="sync-customize-subtitle" - value="&syncCustomize.description;"/> - - <vbox align="start"> - <checkbox label="&engine.tabs.label;" - accesskey="&engine.tabs.accesskey;" - preference="engine.tabs"/> - <checkbox label="&engine.bookmarks.label;" - accesskey="&engine.bookmarks.accesskey;" - preference="engine.bookmarks"/> - <checkbox label="&engine.passwords.label;" - accesskey="&engine.passwords.accesskey;" - preference="engine.passwords"/> - <checkbox label="&engine.history.label;" - accesskey="&engine.history.accesskey;" - preference="engine.history"/> - <checkbox label="&engine.addons.label;" - accesskey="&engine.addons.accesskey;" - preference="engine.addons"/> - <checkbox label="&engine.prefs.label;" - accesskey="&engine.prefs.accesskey;" - preference="engine.prefs"/> - </vbox> - - </prefpane> - - <script type="application/javascript" - src="chrome://browser/content/sync/customize.js" /> - -</dialog> diff --git a/application/basilisk/base/content/sync/genericChange.js b/application/basilisk/base/content/sync/genericChange.js deleted file mode 100644 index 51a74f1b1..000000000 --- a/application/basilisk/base/content/sync/genericChange.js +++ /dev/null @@ -1,233 +0,0 @@ -/* 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/. */ - -var Ci = Components.interfaces; -var Cc = Components.classes; - -Components.utils.import("resource://services-sync/main.js"); -Components.utils.import("resource://gre/modules/Services.jsm"); - -var Change = { - _dialog: null, - _dialogType: null, - _status: null, - _statusIcon: null, - _firstBox: null, - _secondBox: null, - - get _passphraseBox() { - delete this._passphraseBox; - return this._passphraseBox = document.getElementById("passphraseBox"); - }, - - get _currentPasswordInvalid() { - return Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED; - }, - - get _updatingPassphrase() { - return this._dialogType == "UpdatePassphrase"; - }, - - onLoad: function Change_onLoad() { - /* Load labels */ - let introText = document.getElementById("introText"); - let warningText = document.getElementById("warningText"); - - // load some other elements & info from the window - this._dialog = document.getElementById("change-dialog"); - this._dialogType = window.arguments[0]; - this._duringSetup = window.arguments[1]; - this._status = document.getElementById("status"); - this._statusIcon = document.getElementById("statusIcon"); - this._statusRow = document.getElementById("statusRow"); - this._firstBox = document.getElementById("textBox1"); - this._secondBox = document.getElementById("textBox2"); - - this._dialog.getButton("finish").disabled = true; - this._dialog.getButton("back").hidden = true; - - this._stringBundle = - Services.strings.createBundle("chrome://browser/locale/syncGenericChange.properties"); - - switch (this._dialogType) { - case "UpdatePassphrase": - case "ResetPassphrase": - document.getElementById("textBox1Row").hidden = true; - document.getElementById("textBox2Row").hidden = true; - document.getElementById("passphraseLabel").value - = this._str("new.recoverykey.label"); - document.getElementById("passphraseSpacer").hidden = false; - - if (this._updatingPassphrase) { - document.getElementById("passphraseHelpBox").hidden = false; - document.title = this._str("new.recoverykey.title"); - introText.textContent = this._str("new.recoverykey.introText"); - this._dialog.getButton("finish").label - = this._str("new.recoverykey.acceptButton"); - } - else { - document.getElementById("generatePassphraseButton").hidden = false; - document.getElementById("passphraseBackupButtons").hidden = false; - this._passphraseBox.setAttribute("readonly", "true"); - let pp = Weave.Service.identity.syncKey; - if (Weave.Utils.isPassphrase(pp)) - pp = Weave.Utils.hyphenatePassphrase(pp); - this._passphraseBox.value = pp; - this._passphraseBox.focus(); - document.title = this._str("change.recoverykey.title"); - introText.textContent = this._str("change.synckey.introText2"); - warningText.textContent = this._str("change.recoverykey.warningText"); - this._dialog.getButton("finish").label - = this._str("change.recoverykey.acceptButton"); - if (this._duringSetup) { - this._dialog.getButton("finish").disabled = false; - } - } - break; - case "ChangePassword": - document.getElementById("passphraseRow").hidden = true; - let box1label = document.getElementById("textBox1Label"); - let box2label = document.getElementById("textBox2Label"); - box1label.value = this._str("new.password.label"); - - if (this._currentPasswordInvalid) { - document.title = this._str("new.password.title"); - introText.textContent = this._str("new.password.introText"); - this._dialog.getButton("finish").label - = this._str("new.password.acceptButton"); - document.getElementById("textBox2Row").hidden = true; - } - else { - document.title = this._str("change.password.title"); - box2label.value = this._str("new.password.confirm"); - introText.textContent = this._str("change.password3.introText"); - warningText.textContent = this._str("change.password.warningText"); - this._dialog.getButton("finish").label - = this._str("change.password.acceptButton"); - } - break; - } - document.getElementById("change-page") - .setAttribute("label", document.title); - }, - - _clearStatus: function _clearStatus() { - this._status.value = ""; - this._statusIcon.removeAttribute("status"); - }, - - _updateStatus: function Change__updateStatus(str, state) { - this._updateStatusWithString(this._str(str), state); - }, - - _updateStatusWithString: function Change__updateStatusWithString(string, state) { - this._statusRow.hidden = false; - this._status.value = string; - this._statusIcon.setAttribute("status", state); - - let error = state == "error"; - this._dialog.getButton("cancel").disabled = !error; - this._dialog.getButton("finish").disabled = !error; - document.getElementById("printSyncKeyButton").disabled = !error; - document.getElementById("saveSyncKeyButton").disabled = !error; - - if (state == "success") - window.setTimeout(window.close, 1500); - }, - - onDialogAccept: function() { - switch (this._dialogType) { - case "UpdatePassphrase": - case "ResetPassphrase": - return this.doChangePassphrase(); - case "ChangePassword": - return this.doChangePassword(); - } - return undefined; - }, - - doGeneratePassphrase: function () { - let passphrase = Weave.Utils.generatePassphrase(); - this._passphraseBox.value = Weave.Utils.hyphenatePassphrase(passphrase); - this._dialog.getButton("finish").disabled = false; - }, - - doChangePassphrase: function Change_doChangePassphrase() { - let pp = Weave.Utils.normalizePassphrase(this._passphraseBox.value); - if (this._updatingPassphrase) { - Weave.Service.identity.syncKey = pp; - if (Weave.Service.login()) { - this._updateStatus("change.recoverykey.success", "success"); - Weave.Service.persistLogin(); - Weave.Service.scheduler.delayedAutoConnect(0); - } - else { - this._updateStatus("new.passphrase.status.incorrect", "error"); - } - } - else { - this._updateStatus("change.recoverykey.label", "active"); - - if (Weave.Service.changePassphrase(pp)) - this._updateStatus("change.recoverykey.success", "success"); - else - this._updateStatus("change.recoverykey.error", "error"); - } - - return false; - }, - - doChangePassword: function Change_doChangePassword() { - if (this._currentPasswordInvalid) { - Weave.Service.identity.basicPassword = this._firstBox.value; - if (Weave.Service.login()) { - this._updateStatus("change.password.status.success", "success"); - Weave.Service.persistLogin(); - } - else { - this._updateStatus("new.password.status.incorrect", "error"); - } - } - else { - this._updateStatus("change.password.status.active", "active"); - - if (Weave.Service.changePassword(this._firstBox.value)) - this._updateStatus("change.password.status.success", "success"); - else - this._updateStatus("change.password.status.error", "error"); - } - - return false; - }, - - validate: function (event) { - let valid = false; - let errorString = ""; - - if (this._dialogType == "ChangePassword") { - if (this._currentPasswordInvalid) - [valid, errorString] = gSyncUtils.validatePassword(this._firstBox); - else - [valid, errorString] = gSyncUtils.validatePassword(this._firstBox, this._secondBox); - } - else { - if (!this._updatingPassphrase) - return; - - valid = this._passphraseBox.value != ""; - } - - if (errorString == "") - this._clearStatus(); - else - this._updateStatusWithString(errorString, "error"); - - this._statusRow.hidden = valid; - this._dialog.getButton("finish").disabled = !valid; - }, - - _str: function Change__string(str) { - return this._stringBundle.GetStringFromName(str); - } -}; diff --git a/application/basilisk/base/content/sync/genericChange.xul b/application/basilisk/base/content/sync/genericChange.xul deleted file mode 100644 index db74a1b31..000000000 --- a/application/basilisk/base/content/sync/genericChange.xul +++ /dev/null @@ -1,123 +0,0 @@ -<?xml version="1.0"?> - -<!-- 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/. --> - -<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> -<?xml-stylesheet href="chrome://browser/skin/syncSetup.css" type="text/css"?> -<?xml-stylesheet href="chrome://browser/skin/syncCommon.css" type="text/css"?> - -<!DOCTYPE window [ -<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> -<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd"> -<!ENTITY % syncSetupDTD SYSTEM "chrome://browser/locale/syncSetup.dtd"> -%brandDTD; -%syncBrandDTD; -%syncSetupDTD; -]> -<wizard xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - xmlns:html="http://www.w3.org/1999/xhtml" - id="change-dialog" - windowtype="Weave:ChangeSomething" - persist="screenX screenY" - onwizardnext="Change.onLoad()" - onwizardfinish="return Change.onDialogAccept();"> - - <script type="application/javascript" - src="chrome://browser/content/sync/genericChange.js"/> - <script type="application/javascript" - src="chrome://browser/content/sync/utils.js"/> - <script type="application/javascript" - src="chrome://global/content/printUtils.js"/> - - <wizardpage id="change-page" - label=""> - - <description id="introText"> - </description> - - <separator class="thin"/> - - <groupbox> - <grid> - <columns> - <column align="right"/> - <column flex="3"/> - <column flex="1"/> - </columns> - <rows> - <row id="textBox1Row" align="center"> - <label id="textBox1Label" control="textBox1"/> - <textbox id="textBox1" type="password" oninput="Change.validate()"/> - <spacer/> - </row> - <row id="textBox2Row" align="center"> - <label id="textBox2Label" control="textBox2"/> - <textbox id="textBox2" type="password" oninput="Change.validate()"/> - <spacer/> - </row> - </rows> - </grid> - - <vbox id="passphraseRow"> - <hbox flex="1"> - <label id="passphraseLabel" control="passphraseBox"/> - <spacer flex="1"/> - <label id="generatePassphraseButton" - hidden="true" - value="&syncGenerateNewKey.label;" - class="text-link" - onclick="event.stopPropagation(); - Change.doGeneratePassphrase();"/> - </hbox> - <textbox id="passphraseBox" - flex="1" - onfocus="this.select()" - oninput="Change.validate()"/> - </vbox> - - <vbox id="feedback" pack="center"> - <hbox id="statusRow" align="center"> - <image id="statusIcon" class="statusIcon"/> - <label id="status" class="status" value=" "/> - </hbox> - </vbox> - </groupbox> - - <separator class="thin"/> - - <hbox id="passphraseBackupButtons" - hidden="true" - pack="center"> - <button id="printSyncKeyButton" - label="&button.syncKeyBackup.print.label;" - accesskey="&button.syncKeyBackup.print.accesskey;" - oncommand="gSyncUtils.passphrasePrint('passphraseBox');"/> - <button id="saveSyncKeyButton" - label="&button.syncKeyBackup.save.label;" - accesskey="&button.syncKeyBackup.save.accesskey;" - oncommand="gSyncUtils.passphraseSave('passphraseBox');"/> - </hbox> - - <vbox id="passphraseHelpBox" - hidden="true"> - <description> - &existingRecoveryKey.description; - <label class="text-link" - href="https://services.mozilla.com/sync/help/manual-setup"> - &addDevice.showMeHow.label; - </label> - </description> - </vbox> - - <spacer id="passphraseSpacer" - flex="1" - hidden="true"/> - - <description id="warningText" class="data"> - </description> - - <spacer flex="1"/> - </wizardpage> -</wizard> diff --git a/application/basilisk/base/content/sync/key.xhtml b/application/basilisk/base/content/sync/key.xhtml deleted file mode 100644 index 1363132e7..000000000 --- a/application/basilisk/base/content/sync/key.xhtml +++ /dev/null @@ -1,54 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> - %htmlDTD; - <!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd"> - %syncBrandDTD; - <!ENTITY % syncKeyDTD SYSTEM "chrome://browser/locale/syncKey.dtd"> - %syncKeyDTD; - <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd" > - %globalDTD; -]> -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> - <title>&syncKey.page.title;</title> - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> - <meta name="robots" content="noindex"/> - <style type="text/css"> - #synckey { font-size: 150% } - footer { font-size: 70% } - /* Bug 575675: Need to have an a:visited rule in a chrome document. */ - a:visited { color: purple; } - </style> -</head> - -<body dir="&locale.dir;"> -<h1>&syncKey.page.title;</h1> - -<p id="synckey" dir="ltr">SYNCKEY</p> - -<p>&syncKey.page.description2;</p> - -<div id="column1"> - <h2>&syncKey.keepItSecret.heading;</h2> - <p>&syncKey.keepItSecret.description;</p> -</div> - -<div id="column2"> - <h2>&syncKey.keepItSafe.heading;</h2> - <p><em>&syncKey.keepItSafe1.description;</em>&syncKey.keepItSafe2.description;<em>&syncKey.keepItSafe3.description;</em>&syncKey.keepItSafe4a.description;</p> -</div> - -<p>&syncKey.findOutMore1.label;<a href="https://services.mozilla.com">https://services.mozilla.com</a>&syncKey.findOutMore2.label;</p> - -<footer> - &syncKey.footer1.label;<a id="tosLink" href="termsURL">termsURL</a>&syncKey.footer2.label;<a id="ppLink" href="privacyURL">privacyURL</a>&syncKey.footer3.label; -</footer> - -</body> -</html> diff --git a/application/basilisk/base/content/sync/quota.js b/application/basilisk/base/content/sync/quota.js deleted file mode 100644 index b416a44cc..000000000 --- a/application/basilisk/base/content/sync/quota.js +++ /dev/null @@ -1,247 +0,0 @@ -/* 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/. */ - -const Ci = Components.interfaces; -const Cc = Components.classes; -const Cr = Components.results; -const Cu = Components.utils; - -Cu.import("resource://services-sync/main.js"); -Cu.import("resource://gre/modules/DownloadUtils.jsm"); - -var gSyncQuota = { - - init: function init() { - this.bundle = document.getElementById("quotaStrings"); - let caption = document.getElementById("treeCaption"); - caption.firstChild.nodeValue = this.bundle.getString("quota.treeCaption.label"); - - gUsageTreeView.init(); - this.tree = document.getElementById("usageTree"); - this.tree.view = gUsageTreeView; - - this.loadData(); - }, - - loadData: function loadData() { - this._usage_req = Weave.Service.getStorageInfo(Weave.INFO_COLLECTION_USAGE, - function (error, usage) { - delete gSyncQuota._usage_req; - // displayUsageData handles null values, so no need to check 'error'. - gUsageTreeView.displayUsageData(usage); - }); - - let usageLabel = document.getElementById("usageLabel"); - let bundle = this.bundle; - - this._quota_req = Weave.Service.getStorageInfo(Weave.INFO_QUOTA, - function (error, quota) { - delete gSyncQuota._quota_req; - - if (error) { - usageLabel.value = bundle.getString("quota.usageError.label"); - return; - } - let used = gSyncQuota.convertKB(quota[0]); - if (!quota[1]) { - // No quota on the server. - usageLabel.value = bundle.getFormattedString( - "quota.usageNoQuota.label", used); - return; - } - let percent = Math.round(100 * quota[0] / quota[1]); - let total = gSyncQuota.convertKB(quota[1]); - usageLabel.value = bundle.getFormattedString( - "quota.usagePercentage.label", [percent].concat(used).concat(total)); - }); - }, - - onCancel: function onCancel() { - if (this._usage_req) { - this._usage_req.abort(); - } - if (this._quota_req) { - this._quota_req.abort(); - } - return true; - }, - - onAccept: function onAccept() { - let engines = gUsageTreeView.getEnginesToDisable(); - for each (let engine in engines) { - Weave.Service.engineManager.get(engine).enabled = false; - } - if (engines.length) { - // The 'Weave' object will disappear once the window closes. - let Service = Weave.Service; - Weave.Utils.nextTick(function() { Service.sync(); }); - } - return this.onCancel(); - }, - - convertKB: function convertKB(value) { - return DownloadUtils.convertByteUnits(value * 1024); - } - -}; - -var gUsageTreeView = { - - _ignored: {keys: true, - meta: true, - clients: true}, - - /* - * Internal data structures underlaying the tree. - */ - _collections: [], - _byname: {}, - - init: function init() { - let retrievingLabel = gSyncQuota.bundle.getString("quota.retrieving.label"); - for each (let engine in Weave.Service.engineManager.getEnabled()) { - if (this._ignored[engine.name]) - continue; - - // Some engines use the same pref, which means they can only be turned on - // and off together. We need to combine them here as well. - let existing = this._byname[engine.prefName]; - if (existing) { - existing.engines.push(engine.name); - continue; - } - - let obj = {name: engine.prefName, - title: this._collectionTitle(engine), - engines: [engine.name], - enabled: true, - sizeLabel: retrievingLabel}; - this._collections.push(obj); - this._byname[engine.prefName] = obj; - } - }, - - _collectionTitle: function _collectionTitle(engine) { - try { - return gSyncQuota.bundle.getString( - "collection." + engine.prefName + ".label"); - } catch (ex) { - return engine.Name; - } - }, - - /* - * Process the quota information as returned by info/collection_usage. - */ - displayUsageData: function displayUsageData(data) { - for each (let coll in this._collections) { - coll.size = 0; - // If we couldn't retrieve any data, just blank out the label. - if (!data) { - coll.sizeLabel = ""; - continue; - } - - for each (let engineName in coll.engines) - coll.size += data[engineName] || 0; - let sizeLabel = ""; - sizeLabel = gSyncQuota.bundle.getFormattedString( - "quota.sizeValueUnit.label", gSyncQuota.convertKB(coll.size)); - coll.sizeLabel = sizeLabel; - } - let sizeColumn = this.treeBox.columns.getNamedColumn("size"); - this.treeBox.invalidateColumn(sizeColumn); - }, - - /* - * Handle click events on the tree. - */ - onTreeClick: function onTreeClick(event) { - if (event.button == 2) - return; - - let cell = this.treeBox.getCellAt(event.clientX, event.clientY); - if (cell.col && cell.col.id == "enabled") - this.toggle(cell.row); - }, - - /* - * Toggle enabled state of an engine. - */ - toggle: function toggle(row) { - // Update the tree - let collection = this._collections[row]; - collection.enabled = !collection.enabled; - this.treeBox.invalidateRow(row); - }, - - /* - * Return a list of engines (or rather their pref names) that should be - * disabled. - */ - getEnginesToDisable: function getEnginesToDisable() { - // Tycho: return [coll.name for each (coll in this._collections) if (!coll.enabled)]; - let engines = []; - for each (let coll in this._collections) { - if (!coll.enabled) { - engines.push(coll.name); - } - } - return engines; - }, - - // nsITreeView - - get rowCount() { - return this._collections.length; - }, - - getRowProperties: function(index) { return ""; }, - getCellProperties: function(row, col) { return ""; }, - getColumnProperties: function(col) { return ""; }, - isContainer: function(index) { return false; }, - isContainerOpen: function(index) { return false; }, - isContainerEmpty: function(index) { return false; }, - isSeparator: function(index) { return false; }, - isSorted: function() { return false; }, - canDrop: function(index, orientation, dataTransfer) { return false; }, - drop: function(row, orientation, dataTransfer) {}, - getParentIndex: function(rowIndex) {}, - hasNextSibling: function(rowIndex, afterIndex) { return false; }, - getLevel: function(index) { return 0; }, - getImageSrc: function(row, col) {}, - - getCellValue: function(row, col) { - return this._collections[row].enabled; - }, - - getCellText: function getCellText(row, col) { - let collection = this._collections[row]; - switch (col.id) { - case "collection": - return collection.title; - case "size": - return collection.sizeLabel; - default: - return ""; - } - }, - - setTree: function setTree(tree) { - this.treeBox = tree; - }, - - toggleOpenState: function(index) {}, - cycleHeader: function(col) {}, - selectionChanged: function() {}, - cycleCell: function(row, col) {}, - isEditable: function(row, col) { return false; }, - isSelectable: function (row, col) { return false; }, - setCellValue: function(row, col, value) {}, - setCellText: function(row, col, value) {}, - performAction: function(action) {}, - performActionOnRow: function(action, row) {}, - performActionOnCell: function(action, row, col) {} - -}; diff --git a/application/basilisk/base/content/sync/quota.xul b/application/basilisk/base/content/sync/quota.xul deleted file mode 100644 index 99e6ed78b..000000000 --- a/application/basilisk/base/content/sync/quota.xul +++ /dev/null @@ -1,65 +0,0 @@ -<?xml version="1.0"?> - -<!-- 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/. --> - -<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> -<?xml-stylesheet href="chrome://browser/skin/syncQuota.css"?> - -<!DOCTYPE dialog [ -<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> -<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd"> -<!ENTITY % syncQuotaDTD SYSTEM "chrome://browser/locale/syncQuota.dtd"> -%brandDTD; -%syncBrandDTD; -%syncQuotaDTD; -]> -<dialog id="quotaDialog" - windowtype="Sync:ViewQuota" - persist="screenX screenY width height" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - xmlns:html="http://www.w3.org/1999/xhtml" - onload="gSyncQuota.init()" - buttons="accept,cancel" - title=""a.dialogTitle.label;" - ondialogcancel="return gSyncQuota.onCancel();" - ondialogaccept="return gSyncQuota.onAccept();"> - - <script type="application/javascript" - src="chrome://browser/content/sync/quota.js"/> - - <stringbundleset id="stringbundleset"> - <stringbundle id="quotaStrings" - src="chrome://browser/locale/syncQuota.properties"/> - </stringbundleset> - - <vbox flex="1"> - <label id="usageLabel" - value=""a.retrievingInfo.label;"/> - <separator/> - <tree id="usageTree" - seltype="single" - hidecolumnpicker="true" - onclick="gUsageTreeView.onTreeClick(event);" - flex="1"> - <treecols> - <treecol id="enabled" - type="checkbox" - fixed="true"/> - <splitter class="tree-splitter"/> - <treecol id="collection" - label=""a.typeColumn.label;" - flex="1"/> - <splitter class="tree-splitter"/> - <treecol id="size" - label=""a.sizeColumn.label;" - flex="1"/> - </treecols> - <treechildren flex="1"/> - </tree> - <separator/> - <description id="treeCaption"> </description> - </vbox> - -</dialog> diff --git a/application/basilisk/base/content/sync/setup.js b/application/basilisk/base/content/sync/setup.js deleted file mode 100644 index f9dae1bd4..000000000 --- a/application/basilisk/base/content/sync/setup.js +++ /dev/null @@ -1,1060 +0,0 @@ -// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- -/* 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/. */ - -var Ci = Components.interfaces; -var Cc = Components.classes; -var Cr = Components.results; -var Cu = Components.utils; - -// page consts - -const PAIR_PAGE = 0; -const INTRO_PAGE = 1; -const NEW_ACCOUNT_START_PAGE = 2; -const EXISTING_ACCOUNT_CONNECT_PAGE = 3; -const EXISTING_ACCOUNT_LOGIN_PAGE = 4; -const OPTIONS_PAGE = 5; -const OPTIONS_CONFIRM_PAGE = 6; - -// Broader than we'd like, but after this changed from api-secure.recaptcha.net -// we had no choice. At least we only do this for the duration of setup. -// See discussion in Bugs 508112 and 653307. -const RECAPTCHA_DOMAIN = "https://www.google.com"; - -const PIN_PART_LENGTH = 4; - -Cu.import("resource://services-sync/main.js"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/PlacesUtils.jsm"); -Cu.import("resource://gre/modules/PluralForm.jsm"); - - -function setVisibility(element, visible) { - element.style.visibility = visible ? "visible" : "hidden"; -} - -var gSyncSetup = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, - Ci.nsIWebProgressListener, - Ci.nsISupportsWeakReference]), - - captchaBrowser: null, - wizard: null, - _disabledSites: [], - - status: { - password: false, - email: false, - server: false - }, - - get _remoteSites() { - return [Weave.Service.serverURL, RECAPTCHA_DOMAIN]; - }, - - get _usingMainServers() { - if (this._settingUpNew) - return document.getElementById("server").selectedIndex == 0; - return document.getElementById("existingServer").selectedIndex == 0; - }, - - init: function () { - let obs = [ - ["weave:service:change-passphrase", "onResetPassphrase"], - ["weave:service:login:start", "onLoginStart"], - ["weave:service:login:error", "onLoginEnd"], - ["weave:service:login:finish", "onLoginEnd"]]; - - // 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", () => addRem(false), false); - - window.setTimeout(function () { - // Force Service to be loaded so that engines are registered. - // See Bug 670082. - Weave.Service; - }, 0); - - this.captchaBrowser = document.getElementById("captcha"); - - this.wizardType = null; - if (window.arguments && window.arguments[0]) { - this.wizardType = window.arguments[0]; - } - switch (this.wizardType) { - case null: - this.wizard.pageIndex = INTRO_PAGE; - // Fall through! - case "pair": - this.captchaBrowser.addProgressListener(this); - Weave.Svc.Prefs.set("firstSync", "notReady"); - break; - case "reset": - this._resettingSync = true; - this.wizard.pageIndex = OPTIONS_PAGE; - break; - } - - this.wizard.getButton("extra1").label = - this._stringBundle.GetStringFromName("button.syncOptions.label"); - - // Remember these values because the options pages change them temporarily. - this._nextButtonLabel = this.wizard.getButton("next").label; - this._nextButtonAccesskey = this.wizard.getButton("next") - .getAttribute("accesskey"); - this._backButtonLabel = this.wizard.getButton("back").label; - this._backButtonAccesskey = this.wizard.getButton("back") - .getAttribute("accesskey"); - }, - - startNewAccountSetup: function () { - if (!Weave.Utils.ensureMPUnlocked()) - return; - this._settingUpNew = true; - this.wizard.pageIndex = NEW_ACCOUNT_START_PAGE; - }, - - useExistingAccount: function () { - if (!Weave.Utils.ensureMPUnlocked()) - return; - this._settingUpNew = false; - if (this.wizardType == "pair") { - // We're already pairing, so there's no point in pairing again. - // Go straight to the manual login page. - this.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE; - } else { - this.wizard.pageIndex = EXISTING_ACCOUNT_CONNECT_PAGE; - } - }, - - resetPassphrase: function resetPassphrase() { - // Apply the existing form fields so that - // Weave.Service.changePassphrase() has the necessary credentials. - Weave.Service.identity.account = document.getElementById("existingAccountName").value; - Weave.Service.identity.basicPassword = document.getElementById("existingPassword").value; - - // Generate a new passphrase so that Weave.Service.login() will - // actually do something. - let passphrase = Weave.Utils.generatePassphrase(); - Weave.Service.identity.syncKey = passphrase; - - // Only open the dialog if username + password are actually correct. - Weave.Service.login(); - if ([Weave.LOGIN_FAILED_INVALID_PASSPHRASE, - Weave.LOGIN_FAILED_NO_PASSPHRASE, - Weave.LOGIN_SUCCEEDED].indexOf(Weave.Status.login) == -1) { - return; - } - - // Hide any errors about the passphrase, we know it's not right. - let feedback = document.getElementById("existingPassphraseFeedbackRow"); - feedback.hidden = true; - let el = document.getElementById("existingPassphrase"); - el.value = Weave.Utils.hyphenatePassphrase(passphrase); - - // changePassphrase() will sync, make sure we set the "firstSync" pref - // according to the user's pref. - Weave.Svc.Prefs.reset("firstSync"); - this.setupInitialSync(); - gSyncUtils.resetPassphrase(true); - }, - - onResetPassphrase: function () { - document.getElementById("existingPassphrase").value = - Weave.Utils.hyphenatePassphrase(Weave.Service.identity.syncKey); - this.checkFields(); - this.wizard.advance(); - }, - - onLoginStart: function () { - this.toggleLoginFeedback(false); - }, - - onLoginEnd: function () { - this.toggleLoginFeedback(true); - }, - - sendCredentialsAfterSync: function () { - let send = function() { - Services.obs.removeObserver("weave:service:sync:finish", send); - Services.obs.removeObserver("weave:service:sync:error", send); - let credentials = {account: Weave.Service.identity.account, - password: Weave.Service.identity.basicPassword, - synckey: Weave.Service.identity.syncKey, - serverURL: Weave.Service.serverURL}; - this._jpakeclient.sendAndComplete(credentials); - }.bind(this); - Services.obs.addObserver("weave:service:sync:finish", send, false); - Services.obs.addObserver("weave:service:sync:error", send, false); - }, - - toggleLoginFeedback: function (stop) { - document.getElementById("login-throbber").hidden = stop; - let password = document.getElementById("existingPasswordFeedbackRow"); - let server = document.getElementById("existingServerFeedbackRow"); - let passphrase = document.getElementById("existingPassphraseFeedbackRow"); - - if (!stop || (Weave.Status.login == Weave.LOGIN_SUCCEEDED)) { - password.hidden = server.hidden = passphrase.hidden = true; - return; - } - - let feedback; - switch (Weave.Status.login) { - case Weave.LOGIN_FAILED_NETWORK_ERROR: - case Weave.LOGIN_FAILED_SERVER_ERROR: - feedback = server; - break; - case Weave.LOGIN_FAILED_LOGIN_REJECTED: - case Weave.LOGIN_FAILED_NO_USERNAME: - case Weave.LOGIN_FAILED_NO_PASSWORD: - feedback = password; - break; - case Weave.LOGIN_FAILED_INVALID_PASSPHRASE: - feedback = passphrase; - break; - } - this._setFeedbackMessage(feedback, false, Weave.Status.login); - }, - - setupInitialSync: function () { - let action = document.getElementById("mergeChoiceRadio").selectedItem.id; - switch (action) { - case "resetClient": - // if we're not resetting sync, we don't need to explicitly - // call resetClient - if (!this._resettingSync) - return; - // otherwise, fall through - case "wipeClient": - case "wipeRemote": - Weave.Svc.Prefs.set("firstSync", action); - break; - } - }, - - // fun with validation! - checkFields: function () { - this.wizard.canAdvance = this.readyToAdvance(); - }, - - readyToAdvance: function () { - switch (this.wizard.pageIndex) { - case INTRO_PAGE: - return false; - case NEW_ACCOUNT_START_PAGE: - for (let i in this.status) { - if (!this.status[i]) - return false; - } - if (this._usingMainServers) - return document.getElementById("tos").checked; - - return true; - case EXISTING_ACCOUNT_LOGIN_PAGE: - let hasUser = document.getElementById("existingAccountName").value != ""; - let hasPass = document.getElementById("existingPassword").value != ""; - let hasKey = document.getElementById("existingPassphrase").value != ""; - - if (hasUser && hasPass && hasKey) { - if (this._usingMainServers) - return true; - - if (this._validateServer(document.getElementById("existingServer"))) { - return true; - } - } - return false; - } - // Default, e.g. wizard's special page -1 etc. - return true; - }, - - onPINInput: function onPINInput(textbox) { - if (textbox && textbox.value.length == PIN_PART_LENGTH) { - this.nextFocusEl[textbox.id].focus(); - } - this.wizard.canAdvance = (this.pin1.value.length == PIN_PART_LENGTH && - this.pin2.value.length == PIN_PART_LENGTH && - this.pin3.value.length == PIN_PART_LENGTH); - }, - - onEmailInput: function () { - // Check account validity when the user stops typing for 1 second. - if (this._checkAccountTimer) - window.clearTimeout(this._checkAccountTimer); - this._checkAccountTimer = window.setTimeout(function () { - gSyncSetup.checkAccount(); - }, 1000); - }, - - checkAccount: function() { - delete this._checkAccountTimer; - let value = Weave.Utils.normalizeAccount( - document.getElementById("weaveEmail").value); - if (!value) { - this.status.email = false; - this.checkFields(); - return; - } - - let re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - let feedback = document.getElementById("emailFeedbackRow"); - let valid = re.test(value); - - let str = ""; - if (!valid) { - str = "invalidEmail.label"; - } else { - let availCheck = Weave.Service.checkAccount(value); - valid = availCheck == "available"; - if (!valid) { - if (availCheck == "notAvailable") - str = "usernameNotAvailable.label"; - else - str = availCheck; - } - } - - this._setFeedbackMessage(feedback, valid, str); - this.status.email = valid; - if (valid) - Weave.Service.identity.account = value; - this.checkFields(); - }, - - onPasswordChange: function () { - let password = document.getElementById("weavePassword"); - let pwconfirm = document.getElementById("weavePasswordConfirm"); - let [valid, errorString] = gSyncUtils.validatePassword(password, pwconfirm); - - let feedback = document.getElementById("passwordFeedbackRow"); - this._setFeedback(feedback, valid, errorString); - - this.status.password = valid; - this.checkFields(); - }, - - onPageShow: function() { - switch (this.wizard.pageIndex) { - case PAIR_PAGE: - this.wizard.getButton("back").hidden = true; - this.wizard.getButton("extra1").hidden = true; - this.onPINInput(); - this.pin1.focus(); - break; - case INTRO_PAGE: - // We may not need the captcha in the Existing Account branch of the - // wizard. However, we want to preload it to avoid any flickering while - // the Create Account page is shown. - this.loadCaptcha(); - this.wizard.getButton("next").hidden = true; - this.wizard.getButton("back").hidden = true; - this.wizard.getButton("extra1").hidden = true; - this.checkFields(); - break; - case NEW_ACCOUNT_START_PAGE: - this.wizard.getButton("extra1").hidden = false; - this.wizard.getButton("next").hidden = false; - this.wizard.getButton("back").hidden = false; - this.onServerCommand(); - this.wizard.canRewind = true; - this.checkFields(); - break; - case EXISTING_ACCOUNT_CONNECT_PAGE: - Weave.Svc.Prefs.set("firstSync", "existingAccount"); - this.wizard.getButton("next").hidden = false; - this.wizard.getButton("back").hidden = false; - this.wizard.getButton("extra1").hidden = false; - this.wizard.canAdvance = false; - this.wizard.canRewind = true; - this.startEasySetup(); - break; - case EXISTING_ACCOUNT_LOGIN_PAGE: - this.wizard.getButton("next").hidden = false; - this.wizard.getButton("back").hidden = false; - this.wizard.getButton("extra1").hidden = false; - this.wizard.canRewind = true; - this.checkFields(); - break; - case OPTIONS_PAGE: - this.wizard.canRewind = false; - this.wizard.canAdvance = true; - if (!this._resettingSync) { - this.wizard.getButton("next").label = - this._stringBundle.GetStringFromName("button.syncOptionsDone.label"); - this.wizard.getButton("next").removeAttribute("accesskey"); - } - this.wizard.getButton("next").hidden = false; - this.wizard.getButton("back").hidden = true; - this.wizard.getButton("cancel").hidden = !this._resettingSync; - this.wizard.getButton("extra1").hidden = true; - document.getElementById("syncComputerName").value = Weave.Service.clientsEngine.localName; - document.getElementById("syncOptions").collapsed = this._resettingSync; - document.getElementById("mergeOptions").collapsed = this._settingUpNew; - break; - case OPTIONS_CONFIRM_PAGE: - this.wizard.canRewind = true; - this.wizard.canAdvance = true; - this.wizard.getButton("back").label = - this._stringBundle.GetStringFromName("button.syncOptionsCancel.label"); - this.wizard.getButton("back").removeAttribute("accesskey"); - this.wizard.getButton("back").hidden = this._resettingSync; - this.wizard.getButton("next").hidden = false; - this.wizard.getButton("finish").hidden = true; - break; - } - }, - - onWizardAdvance: function () { - // Check pageIndex so we don't prompt before the Sync setup wizard appears. - // This is a fallback in case the Master Password gets locked mid-wizard. - if ((this.wizard.pageIndex >= 0) && - !Weave.Utils.ensureMPUnlocked()) { - return false; - } - - switch (this.wizard.pageIndex) { - case PAIR_PAGE: - this.startPairing(); - return false; - case NEW_ACCOUNT_START_PAGE: - // If the user selects Next (e.g. by hitting enter) when we haven't - // executed the delayed checks yet, execute them immediately. - if (this._checkAccountTimer) { - this.checkAccount(); - } - if (this._checkServerTimer) { - this.checkServer(); - } - if (!this.wizard.canAdvance) { - return false; - } - - let doc = this.captchaBrowser.contentDocument; - let getField = function getField(field) { - let node = doc.getElementById("recaptcha_" + field + "_field"); - return node && node.value; - }; - - // Display throbber - let feedback = document.getElementById("captchaFeedback"); - let image = feedback.firstChild; - let label = image.nextSibling; - image.setAttribute("status", "active"); - label.value = this._stringBundle.GetStringFromName("verifying.label"); - setVisibility(feedback, true); - - let password = document.getElementById("weavePassword").value; - let email = Weave.Utils.normalizeAccount( - document.getElementById("weaveEmail").value); - let challenge = getField("challenge"); - let response = getField("response"); - - let error = Weave.Service.createAccount(email, password, - challenge, response); - - if (error == null) { - Weave.Service.identity.account = email; - Weave.Service.identity.basicPassword = password; - Weave.Service.identity.syncKey = Weave.Utils.generatePassphrase(); - this._handleNoScript(false); - Weave.Svc.Prefs.set("firstSync", "newAccount"); - this.wizardFinish(); - return false; - } - - image.setAttribute("status", "error"); - label.value = Weave.Utils.getErrorString(error); - return false; - case EXISTING_ACCOUNT_LOGIN_PAGE: - Weave.Service.identity.account = Weave.Utils.normalizeAccount( - document.getElementById("existingAccountName").value); - Weave.Service.identity.basicPassword = - document.getElementById("existingPassword").value; - let pp = document.getElementById("existingPassphrase").value; - Weave.Service.identity.syncKey = Weave.Utils.normalizePassphrase(pp); - if (Weave.Service.login()) { - this.wizardFinish(); - } - return false; - case OPTIONS_PAGE: - let desc = document.getElementById("mergeChoiceRadio").selectedIndex; - // No confirmation needed on new account setup or merge option - // with existing account. - if (this._settingUpNew || (!this._resettingSync && desc == 0)) - return this.returnFromOptions(); - return this._handleChoice(); - case OPTIONS_CONFIRM_PAGE: - if (this._resettingSync) { - this.wizardFinish(); - return false; - } - return this.returnFromOptions(); - } - return true; - }, - - onWizardBack: function () { - switch (this.wizard.pageIndex) { - case NEW_ACCOUNT_START_PAGE: - this.wizard.pageIndex = INTRO_PAGE; - return false; - case EXISTING_ACCOUNT_CONNECT_PAGE: - this.abortEasySetup(); - this.wizard.pageIndex = INTRO_PAGE; - return false; - case EXISTING_ACCOUNT_LOGIN_PAGE: - // If we were already pairing on entry, we went straight to the manual - // login page. If subsequently we go back, return to the page that lets - // us choose whether we already have an account. - if (this.wizardType == "pair") { - this.wizard.pageIndex = INTRO_PAGE; - return false; - } - return true; - case OPTIONS_CONFIRM_PAGE: - // Backing up from the confirmation page = resetting first sync to merge. - document.getElementById("mergeChoiceRadio").selectedIndex = 0; - return this.returnFromOptions(); - } - return true; - }, - - wizardFinish: function () { - this.setupInitialSync(); - - if (this.wizardType == "pair") { - this.completePairing(); - } - - if (!this._resettingSync) { - function isChecked(element) { - return document.getElementById(element).hasAttribute("checked"); - } - - let prefs = ["engine.bookmarks", "engine.passwords", "engine.history", - "engine.tabs", "engine.prefs", "engine.addons"]; - for (let i = 0;i < prefs.length;i++) { - Weave.Svc.Prefs.set(prefs[i], isChecked(prefs[i])); - } - this._handleNoScript(false); - if (Weave.Svc.Prefs.get("firstSync", "") == "notReady") - Weave.Svc.Prefs.reset("firstSync"); - - Weave.Service.persistLogin(); - Weave.Svc.Obs.notify("weave:service:setup-complete"); - } - Weave.Utils.nextTick(Weave.Service.sync, Weave.Service); - window.close(); - }, - - onWizardCancel: function () { - if (this._resettingSync) - return; - - this.abortEasySetup(); - this._handleNoScript(false); - Weave.Service.startOver(); - }, - - onSyncOptions: function () { - this._beforeOptionsPage = this.wizard.pageIndex; - this.wizard.pageIndex = OPTIONS_PAGE; - }, - - returnFromOptions: function() { - this.wizard.getButton("next").label = this._nextButtonLabel; - this.wizard.getButton("next").setAttribute("accesskey", - this._nextButtonAccesskey); - this.wizard.getButton("back").label = this._backButtonLabel; - this.wizard.getButton("back").setAttribute("accesskey", - this._backButtonAccesskey); - this.wizard.getButton("cancel").hidden = false; - this.wizard.getButton("extra1").hidden = false; - this.wizard.pageIndex = this._beforeOptionsPage; - return false; - }, - - startPairing: function startPairing() { - this.pairDeviceErrorRow.hidden = true; - // When onAbort is called, Weave may already be gone. - const JPAKE_ERROR_USERABORT = Weave.JPAKE_ERROR_USERABORT; - - let self = this; - let jpakeclient = this._jpakeclient = new Weave.JPAKEClient({ - onPaired: function onPaired() { - self.wizard.pageIndex = INTRO_PAGE; - }, - onComplete: function onComplete() { - // This method will never be called since SendCredentialsController - // will take over after the wizard completes. - }, - onAbort: function onAbort(error) { - delete self._jpakeclient; - - // Aborted by user, ignore. The window is almost certainly going to close - // or is already closed. - if (error == JPAKE_ERROR_USERABORT) { - return; - } - - self.pairDeviceErrorRow.hidden = false; - self.pairDeviceThrobber.hidden = true; - self.pin1.value = self.pin2.value = self.pin3.value = ""; - self.pin1.disabled = self.pin2.disabled = self.pin3.disabled = false; - if (self.wizard.pageIndex == PAIR_PAGE) { - self.pin1.focus(); - } - } - }); - this.pairDeviceThrobber.hidden = false; - this.pin1.disabled = this.pin2.disabled = this.pin3.disabled = true; - this.wizard.canAdvance = false; - - let pin = this.pin1.value + this.pin2.value + this.pin3.value; - let expectDelay = true; - jpakeclient.pairWithPIN(pin, expectDelay); - }, - - completePairing: function completePairing() { - if (!this._jpakeclient) { - // The channel was aborted while we were setting up the account - // locally. XXX TODO should we do anything here, e.g. tell - // the user on the last wizard page that it's ok, they just - // have to pair again? - return; - } - let controller = new Weave.SendCredentialsController(this._jpakeclient, - Weave.Service); - this._jpakeclient.controller = controller; - }, - - startEasySetup: function () { - // Don't do anything if we have a client already (e.g. we went to - // Sync Options and just came back). - if (this._jpakeclient) - return; - - // When onAbort is called, Weave may already be gone - const JPAKE_ERROR_USERABORT = Weave.JPAKE_ERROR_USERABORT; - - let self = this; - this._jpakeclient = new Weave.JPAKEClient({ - displayPIN: function displayPIN(pin) { - document.getElementById("easySetupPIN1").value = pin.slice(0, 4); - document.getElementById("easySetupPIN2").value = pin.slice(4, 8); - document.getElementById("easySetupPIN3").value = pin.slice(8); - }, - - onPairingStart: function onPairingStart() {}, - - onComplete: function onComplete(credentials) { - Weave.Service.identity.account = credentials.account; - Weave.Service.identity.basicPassword = credentials.password; - Weave.Service.identity.syncKey = credentials.synckey; - Weave.Service.serverURL = credentials.serverURL; - gSyncSetup.wizardFinish(); - }, - - onAbort: function onAbort(error) { - delete self._jpakeclient; - - // Ignore if wizard is aborted. - if (error == JPAKE_ERROR_USERABORT) - return; - - // Automatically go to manual setup if we couldn't acquire a channel. - if (error == Weave.JPAKE_ERROR_CHANNEL) { - self.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE; - return; - } - - // Restart on all other errors. - self.startEasySetup(); - } - }); - this._jpakeclient.receiveNoPIN(); - }, - - abortEasySetup: function () { - document.getElementById("easySetupPIN1").value = ""; - document.getElementById("easySetupPIN2").value = ""; - document.getElementById("easySetupPIN3").value = ""; - if (!this._jpakeclient) - return; - - this._jpakeclient.abort(); - delete this._jpakeclient; - }, - - manualSetup: function () { - this.abortEasySetup(); - this.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE; - }, - - // _handleNoScript is needed because it blocks the captcha. So we temporarily - // allow the necessary sites so that we can verify the user is in fact a human. - // This was done with the help of Giorgio (NoScript author). See bug 508112. - _handleNoScript: function (addExceptions) { - // if NoScript isn't installed, or is disabled, bail out. - let ns = Cc["@maone.net/noscript-service;1"]; - if (ns == null) - return; - - ns = ns.getService().wrappedJSObject; - if (addExceptions) { - this._remoteSites.forEach(function(site) { - site = ns.getSite(site); - if (!ns.isJSEnabled(site)) { - this._disabledSites.push(site); // save status - ns.setJSEnabled(site, true); // allow site - } - }, this); - } - else { - this._disabledSites.forEach(function(site) { - ns.setJSEnabled(site, false); - }); - this._disabledSites = []; - } - }, - - onExistingServerCommand: function () { - let control = document.getElementById("existingServer"); - if (control.selectedIndex == 0) { - control.removeAttribute("editable"); - Weave.Svc.Prefs.reset("serverURL"); - } else { - control.setAttribute("editable", "true"); - // Force a style flush to ensure that the binding is attached. - control.clientTop; - control.value = ""; - control.inputField.focus(); - } - document.getElementById("existingServerFeedbackRow").hidden = true; - this.checkFields(); - }, - - onExistingServerInput: function () { - // Check custom server validity when the user stops typing for 1 second. - if (this._existingServerTimer) - window.clearTimeout(this._existingServerTimer); - this._existingServerTimer = window.setTimeout(function () { - gSyncSetup.checkFields(); - }, 1000); - }, - - onServerCommand: function () { - setVisibility(document.getElementById("TOSRow"), this._usingMainServers); - let control = document.getElementById("server"); - if (!this._usingMainServers) { - control.setAttribute("editable", "true"); - // Force a style flush to ensure that the binding is attached. - control.clientTop; - control.value = ""; - control.inputField.focus(); - // checkServer() will call checkAccount() and checkFields(). - this.checkServer(); - return; - } - control.removeAttribute("editable"); - Weave.Svc.Prefs.reset("serverURL"); - if (this._settingUpNew) { - this.loadCaptcha(); - } - this.checkAccount(); - this.status.server = true; - document.getElementById("serverFeedbackRow").hidden = true; - this.checkFields(); - }, - - onServerInput: function () { - // Check custom server validity when the user stops typing for 1 second. - if (this._checkServerTimer) - window.clearTimeout(this._checkServerTimer); - this._checkServerTimer = window.setTimeout(function () { - gSyncSetup.checkServer(); - }, 1000); - }, - - checkServer: function () { - delete this._checkServerTimer; - let el = document.getElementById("server"); - let valid = false; - let feedback = document.getElementById("serverFeedbackRow"); - if (el.value) { - valid = this._validateServer(el); - let str = valid ? "" : "serverInvalid.label"; - this._setFeedbackMessage(feedback, valid, str); - } - else - this._setFeedbackMessage(feedback, true); - - // Recheck account against the new server. - if (valid) - this.checkAccount(); - - this.status.server = valid; - this.checkFields(); - }, - - _validateServer: function (element) { - let valid = false; - let val = element.value; - if (!val) - return false; - - let uri = Weave.Utils.makeURI(val); - - if (!uri) - uri = Weave.Utils.makeURI("https://" + val); - - if (uri && this._settingUpNew) { - function isValid(uri) { - Weave.Service.serverURL = uri.spec; - let check = Weave.Service.checkAccount("a"); - return (check == "available" || check == "notAvailable"); - } - - if (uri.schemeIs("http")) { - uri.scheme = "https"; - if (isValid(uri)) - valid = true; - else - // setting the scheme back to http - uri.scheme = "http"; - } - if (!valid) - valid = isValid(uri); - - if (valid) { - this.loadCaptcha(); - } - } - else if (uri) { - valid = true; - Weave.Service.serverURL = uri.spec; - } - - if (valid) - element.value = Weave.Service.serverURL; - else - Weave.Svc.Prefs.reset("serverURL"); - - return valid; - }, - - _handleChoice: function () { - let desc = document.getElementById("mergeChoiceRadio").selectedIndex; - document.getElementById("chosenActionDeck").selectedIndex = desc; - switch (desc) { - case 1: - if (this._case1Setup) - break; - - let places_db = PlacesUtils.history - .QueryInterface(Ci.nsPIPlacesDatabase) - .DBConnection; - if (Weave.Service.engineManager.get("history").enabled) { - let daysOfHistory = 0; - let stm = places_db.createStatement( - "SELECT ROUND(( " + - "strftime('%s','now','localtime','utc') - " + - "( " + - "SELECT visit_date FROM moz_historyvisits " + - "ORDER BY visit_date ASC LIMIT 1 " + - ")/1000000 " + - ")/86400) AS daysOfHistory "); - - if (stm.step()) - daysOfHistory = stm.getInt32(0); - // Support %S for historical reasons (see bug 600141) - document.getElementById("historyCount").value = - PluralForm.get(daysOfHistory, - this._stringBundle.GetStringFromName("historyDaysCount.label")) - .replace("%S", daysOfHistory) - .replace("#1", daysOfHistory); - } else { - document.getElementById("historyCount").hidden = true; - } - - if (Weave.Service.engineManager.get("bookmarks").enabled) { - let bookmarks = 0; - let stm = places_db.createStatement( - "SELECT count(*) AS bookmarks " + - "FROM moz_bookmarks b " + - "LEFT JOIN moz_bookmarks t ON " + - "b.parent = t.id WHERE b.type = 1 AND t.parent <> :tag"); - stm.params.tag = PlacesUtils.tagsFolderId; - if (stm.executeStep()) - bookmarks = stm.row.bookmarks; - // Support %S for historical reasons (see bug 600141) - document.getElementById("bookmarkCount").value = - PluralForm.get(bookmarks, - this._stringBundle.GetStringFromName("bookmarksCount.label")) - .replace("%S", bookmarks) - .replace("#1", bookmarks); - } else { - document.getElementById("bookmarkCount").hidden = true; - } - - if (Weave.Service.engineManager.get("passwords").enabled) { - let logins = Services.logins.getAllLogins({}); - // Support %S for historical reasons (see bug 600141) - document.getElementById("passwordCount").value = - PluralForm.get(logins.length, - this._stringBundle.GetStringFromName("passwordsCount.label")) - .replace("%S", logins.length) - .replace("#1", logins.length); - } else { - document.getElementById("passwordCount").hidden = true; - } - - if (!Weave.Service.engineManager.get("prefs").enabled) { - document.getElementById("prefsWipe").hidden = true; - } - - let addonsEngine = Weave.Service.engineManager.get("addons"); - if (addonsEngine.enabled) { - let ids = addonsEngine._store.getAllIDs(); - let blessedcount = Object.keys(ids).filter(id => ids[id]).length; - // bug 600141 does not apply, as this does not have to support existing strings - document.getElementById("addonCount").value = - PluralForm.get(blessedcount, - this._stringBundle.GetStringFromName("addonsCount.label")) - .replace("#1", blessedcount); - } else { - document.getElementById("addonCount").hidden = true; - } - - this._case1Setup = true; - break; - case 2: - if (this._case2Setup) - break; - let count = 0; - function appendNode(label) { - let box = document.getElementById("clientList"); - let node = document.createElement("label"); - node.setAttribute("value", label); - node.setAttribute("class", "data indent"); - box.appendChild(node); - } - - for (let name of Weave.Service.clientsEngine.stats.names) { - // Don't list the current client - if (name == Weave.Service.clientsEngine.localName) - continue; - - // Only show the first several client names - if (++count <= 5) - appendNode(name); - } - if (count > 5) { - // Support %S for historical reasons (see bug 600141) - let label = - PluralForm.get(count - 5, - this._stringBundle.GetStringFromName("additionalClientCount.label")) - .replace("%S", count - 5) - .replace("#1", count - 5); - appendNode(label); - } - this._case2Setup = true; - break; - } - - return true; - }, - - // sets class and string on a feedback element - // if no property string is passed in, we clear label/style - _setFeedback: function (element, success, string) { - element.hidden = success || !string; - let classname = success ? "success" : "error"; - let image = element.getElementsByAttribute("class", "statusIcon")[0]; - image.setAttribute("status", classname); - let label = element.getElementsByAttribute("class", "status")[0]; - label.value = string; - }, - - // shim - _setFeedbackMessage: function (element, success, string) { - let str = ""; - if (string) { - try { - str = this._stringBundle.GetStringFromName(string); - } catch (e) {} - - if (!str) - str = Weave.Utils.getErrorString(string); - } - this._setFeedback(element, success, str); - }, - - loadCaptcha: function loadCaptcha() { - let captchaURI = Weave.Service.miscAPI + "captcha_html"; - // First check for NoScript and whitelist the right sites. - this._handleNoScript(true); - if (this.captchaBrowser.currentURI.spec != captchaURI) { - this.captchaBrowser.loadURI(captchaURI); - } - }, - - onStateChange: function(webProgress, request, stateFlags, status) { - // We're only looking for the end of the frame load - if ((stateFlags & Ci.nsIWebProgressListener.STATE_STOP) == 0) - return; - if ((stateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) == 0) - return; - if ((stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) == 0) - return; - - // If we didn't find a captcha, assume it's not needed and don't show it. - let responseStatus = request.QueryInterface(Ci.nsIHttpChannel).responseStatus; - setVisibility(this.captchaBrowser, responseStatus != 404); - // XXX TODO we should really log any responseStatus other than 200 - }, - onProgressChange: function() {}, - onStatusChange: function() {}, - onSecurityChange: function() {}, - onLocationChange: function () {} -}; - -// Define lazy getters for various XUL elements. -// -// onWizardAdvance() and onPageShow() are run before init(), so we'll even -// define things that will almost certainly be used (like 'wizard') as a lazy -// getter here. -["wizard", - "pin1", - "pin2", - "pin3", - "pairDeviceErrorRow", - "pairDeviceThrobber"].forEach(function (id) { - XPCOMUtils.defineLazyGetter(gSyncSetup, id, function() { - return document.getElementById(id); - }); -}); -XPCOMUtils.defineLazyGetter(gSyncSetup, "nextFocusEl", function () { - return {pin1: this.pin2, - pin2: this.pin3, - pin3: this.wizard.getButton("next")}; -}); -XPCOMUtils.defineLazyGetter(gSyncSetup, "_stringBundle", function() { - return Services.strings.createBundle("chrome://browser/locale/syncSetup.properties"); -}); diff --git a/application/basilisk/base/content/sync/setup.xul b/application/basilisk/base/content/sync/setup.xul deleted file mode 100644 index 11c085931..000000000 --- a/application/basilisk/base/content/sync/setup.xul +++ /dev/null @@ -1,490 +0,0 @@ -<?xml version="1.0"?> - -<!-- 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/. --> - -<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> -<?xml-stylesheet href="chrome://browser/skin/syncSetup.css" type="text/css"?> -<?xml-stylesheet href="chrome://browser/skin/syncCommon.css" type="text/css"?> - -<!DOCTYPE window [ -<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> -<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd"> -<!ENTITY % syncSetupDTD SYSTEM "chrome://browser/locale/syncSetup.dtd"> -%brandDTD; -%syncBrandDTD; -%syncSetupDTD; -]> -<wizard id="wizard" - title="&accountSetupTitle.label;" - windowtype="Weave:AccountSetup" - persist="screenX screenY" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - xmlns:html="http://www.w3.org/1999/xhtml" - onwizardnext="return gSyncSetup.onWizardAdvance()" - onwizardback="return gSyncSetup.onWizardBack()" - onwizardcancel="gSyncSetup.onWizardCancel()" - onload="gSyncSetup.init()"> - - <script type="application/javascript" - src="chrome://browser/content/sync/setup.js"/> - <script type="application/javascript" - src="chrome://browser/content/sync/utils.js"/> - <script type="application/javascript" - src="chrome://browser/content/utilityOverlay.js"/> - <script type="application/javascript" - src="chrome://global/content/printUtils.js"/> - - <wizardpage id="addDevicePage" - label="&pairDevice.title.label;" - onpageshow="gSyncSetup.onPageShow()"> - <description> - &pairDevice.dialog.description.label; - <label class="text-link" - value="&addDevice.showMeHow.label;" - href="https://services.mozilla.com/sync/help/add-device"/> - </description> - <separator class="groove-thin"/> - <description> - &addDevice.dialog.enterCode.label; - </description> - <separator class="groove-thin"/> - <vbox align="center"> - <textbox id="pin1" - class="pin" - oninput="gSyncSetup.onPINInput(this);" - onfocus="this.select();" - /> - <textbox id="pin2" - class="pin" - oninput="gSyncSetup.onPINInput(this);" - onfocus="this.select();" - /> - <textbox id="pin3" - class="pin" - oninput="gSyncSetup.onPINInput(this);" - onfocus="this.select();" - /> - </vbox> - <separator class="groove-thin"/> - <vbox id="pairDeviceThrobber" align="center" hidden="true"> - <image/> - </vbox> - <hbox id="pairDeviceErrorRow" pack="center" hidden="true"> - <image class="statusIcon" status="error"/> - <label class="status" - value="&addDevice.dialog.tryAgain.label;"/> - </hbox> - </wizardpage> - - <wizardpage id="pickSetupType" - label="&syncBrand.fullName.label;" - onpageshow="gSyncSetup.onPageShow()"> - <vbox align="center" flex="1"> - <description style="padding: 0 7em;"> - &setup.pickSetupType.description2; - </description> - <spacer flex="3"/> - <button id="newAccount" - class="accountChoiceButton" - label="&button.createNewAccount.label;" - oncommand="gSyncSetup.startNewAccountSetup()" - align="center"/> - <spacer flex="1"/> - </vbox> - <separator class="groove"/> - <vbox align="center" flex="1"> - <spacer flex="1"/> - <button id="existingAccount" - class="accountChoiceButton" - label="&button.haveAccount.label;" - oncommand="gSyncSetup.useExistingAccount()"/> - <spacer flex="3"/> - </vbox> - </wizardpage> - - <wizardpage label="&setup.newAccountDetailsPage.title.label;" - id="newAccountStart" - onextra1="gSyncSetup.onSyncOptions()" - onpageshow="gSyncSetup.onPageShow();"> - <grid> - <columns> - <column/> - <column class="inputColumn" flex="1"/> - </columns> - <rows> - <row id="emailRow" align="center"> - <label value="&setup.emailAddress.label;" - accesskey="&setup.emailAddress.accesskey;" - control="weaveEmail"/> - <textbox id="weaveEmail" - oninput="gSyncSetup.onEmailInput()"/> - </row> - <row id="emailFeedbackRow" align="center" hidden="true"> - <spacer/> - <hbox> - <image class="statusIcon"/> - <label class="status" value=" "/> - </hbox> - </row> - <row id="passwordRow" align="center"> - <label value="&setup.choosePassword.label;" - accesskey="&setup.choosePassword.accesskey;" - control="weavePassword"/> - <textbox id="weavePassword" - type="password" - onchange="gSyncSetup.onPasswordChange()"/> - </row> - <row id="confirmRow" align="center"> - <label value="&setup.confirmPassword.label;" - accesskey="&setup.confirmPassword.accesskey;" - control="weavePasswordConfirm"/> - <textbox id="weavePasswordConfirm" - type="password" - onchange="gSyncSetup.onPasswordChange()"/> - </row> - <row id="passwordFeedbackRow" align="center" hidden="true"> - <spacer/> - <hbox> - <image class="statusIcon"/> - <label class="status" value=" "/> - </hbox> - </row> - <row align="center"> - <label control="server" - value="&server.label;"/> - <menulist id="server" - oncommand="gSyncSetup.onServerCommand()" - oninput="gSyncSetup.onServerInput()"> - <menupopup> - <menuitem label="&serverType.default.label;" - value="main"/> - <menuitem label="&serverType.custom2.label;" - value="custom"/> - </menupopup> - </menulist> - </row> - <row id="serverFeedbackRow" align="center" hidden="true"> - <spacer/> - <hbox> - <image class="statusIcon"/> - <label class="status" value=" "/> - </hbox> - </row> - <row id="TOSRow" align="center"> - <spacer/> - <hbox align="center"> - <checkbox id="tos" - accesskey="&setup.tosAgree1.accesskey;" - oncommand="this.focus(); gSyncSetup.checkFields();"/> - <description id="tosDesc" - flex="1" - onclick="document.getElementById('tos').focus(); - document.getElementById('tos').click()"> - &setup.tosAgree1.label; - <label class="text-link" - onclick="event.stopPropagation();gSyncUtils.openToS();"> - &setup.tosLink.label; - </label> - &setup.tosAgree2.label; - <label class="text-link" - onclick="event.stopPropagation();gSyncUtils.openPrivacyPolicy();"> - &setup.ppLink.label; - </label> - &setup.tosAgree3.label; - </description> - </hbox> - </row> - </rows> - </grid> - <spacer flex="1"/> - <vbox flex="1" align="center"> - <browser height="150" - width="500" - id="captcha" - type="content" - disablehistory="true"/> - <spacer flex="1"/> - <hbox id="captchaFeedback"> - <image class="statusIcon"/> - <label class="status" value=" "/> - </hbox> - </vbox> - </wizardpage> - - <wizardpage id="addDevice" - label="&pairDevice.title.label;" - onextra1="gSyncSetup.onSyncOptions()" - onpageshow="gSyncSetup.onPageShow()"> - <description> - &pairDevice.setup.description.label; - <label class="text-link" - value="&addDevice.showMeHow.label;" - href="https://services.mozilla.com/sync/help/easy-setup"/> - </description> - <label value="&addDevice.setup.enterCode.label;" - control="easySetupPIN1"/> - <spacer flex="1"/> - <vbox align="center" flex="1"> - <textbox id="easySetupPIN1" - class="pin" - value="" - readonly="true" - /> - <textbox id="easySetupPIN2" - class="pin" - value="" - readonly="true" - /> - <textbox id="easySetupPIN3" - class="pin" - value="" - readonly="true" - /> - </vbox> - <spacer flex="3"/> - <label class="text-link" - value="&addDevice.dontHaveDevice.label;" - onclick="gSyncSetup.manualSetup();"/> - </wizardpage> - - <wizardpage id="existingAccount" - label="&setup.signInPage.title.label;" - onextra1="gSyncSetup.onSyncOptions()" - onpageshow="gSyncSetup.onPageShow()"> - <grid> - <columns> - <column/> - <column class="inputColumn" flex="1"/> - </columns> - <rows> - <row id="existingAccountRow" align="center"> - <label id="existingAccountLabel" - value="&signIn.account2.label;" - accesskey="&signIn.account2.accesskey;" - control="existingAccount"/> - <textbox id="existingAccountName" - oninput="gSyncSetup.checkFields(event)" - onchange="gSyncSetup.checkFields(event)"/> - </row> - <row id="existingPasswordRow" align="center"> - <label id="existingPasswordLabel" - value="&signIn.password.label;" - accesskey="&signIn.password.accesskey;" - control="existingPassword"/> - <textbox id="existingPassword" - type="password" - onkeyup="gSyncSetup.checkFields(event)" - onchange="gSyncSetup.checkFields(event)"/> - </row> - <row id="existingPasswordFeedbackRow" align="center" hidden="true"> - <spacer/> - <hbox> - <image class="statusIcon"/> - <label class="status" value=" "/> - </hbox> - </row> - <row align="center"> - <spacer/> - <label class="text-link" - value="&resetPassword.label;" - onclick="gSyncUtils.resetPassword(); return false;"/> - </row> - <row align="center"> - <label control="existingServer" - value="&server.label;"/> - <menulist id="existingServer" - oncommand="gSyncSetup.onExistingServerCommand()" - oninput="gSyncSetup.onExistingServerInput()"> - <menupopup> - <menuitem label="&serverType.default.label;" - value="main"/> - <menuitem label="&serverType.custom2.label;" - value="custom"/> - </menupopup> - </menulist> - </row> - <row id="existingServerFeedbackRow" align="center" hidden="true"> - <spacer/> - <hbox> - <image class="statusIcon"/> - <vbox> - <label class="status" value=" "/> - </vbox> - </hbox> - </row> - </rows> - </grid> - - <groupbox> - <label id="existingPassphraseLabel" - value="&signIn.recoveryKey.label;" - accesskey="&signIn.recoveryKey.accesskey;" - control="existingPassphrase"/> - <textbox id="existingPassphrase" - oninput="gSyncSetup.checkFields()"/> - <hbox id="login-throbber" hidden="true"> - <image/> - <label value="&verifying.label;"/> - </hbox> - <vbox align="left" id="existingPassphraseFeedbackRow" hidden="true"> - <hbox> - <image class="statusIcon"/> - <label class="status" value=" "/> - </hbox> - </vbox> - </groupbox> - - <vbox id="passphraseHelpBox"> - <description> - &existingRecoveryKey.description; - <label class="text-link" - href="https://services.mozilla.com/sync/help/manual-setup"> - &addDevice.showMeHow.label; - </label> - <spacer id="passphraseHelpSpacer"/> - <label class="text-link" - onclick="gSyncSetup.resetPassphrase(); return false;"> - &resetSyncKey.label; - </label> - </description> - </vbox> - </wizardpage> - - <wizardpage id="syncOptionsPage" - label="&setup.optionsPage.title;" - onpageshow="gSyncSetup.onPageShow()"> - <groupbox id="syncOptions"> - <grid> - <columns> - <column/> - <column flex="1" style="margin-inline-end: 2px"/> - </columns> - <rows> - <row align="center"> - <label value="&syncDeviceName.label;" - accesskey="&syncDeviceName.accesskey;" - control="syncComputerName"/> - <textbox id="syncComputerName" flex="1" - onchange="gSyncUtils.changeName(this)"/> - </row> - <row> - <label value="&syncMy.label;" /> - <vbox> - <checkbox label="&engine.addons.label;" - accesskey="&engine.addons.accesskey;" - id="engine.addons" - checked="true"/> - <checkbox label="&engine.bookmarks.label;" - accesskey="&engine.bookmarks.accesskey;" - id="engine.bookmarks" - checked="true"/> - <checkbox label="&engine.passwords.label;" - accesskey="&engine.passwords.accesskey;" - id="engine.passwords" - checked="true"/> - <checkbox label="&engine.prefs.label;" - accesskey="&engine.prefs.accesskey;" - id="engine.prefs" - checked="true"/> - <checkbox label="&engine.history.label;" - accesskey="&engine.history.accesskey;" - id="engine.history" - checked="true"/> - <checkbox label="&engine.tabs.label;" - accesskey="&engine.tabs.accesskey;" - id="engine.tabs" - checked="true"/> - </vbox> - </row> - </rows> - </grid> - </groupbox> - - <groupbox id="mergeOptions"> - <radiogroup id="mergeChoiceRadio" pack="start"> - <grid> - <columns> - <column/> - <column flex="1"/> - </columns> - <rows flex="1"> - <row align="center"> - <radio id="resetClient" - class="mergeChoiceButton" - aria-labelledby="resetClientLabel"/> - <label id="resetClientLabel" control="resetClient"> - <html:strong>&choice2.merge.recommended.label;</html:strong> - &choice2a.merge.main.label; - </label> - </row> - <row align="center"> - <radio id="wipeClient" - class="mergeChoiceButton" - aria-labelledby="wipeClientLabel"/> - <label id="wipeClientLabel" - control="wipeClient"> - &choice2a.client.main.label; - </label> - </row> - <row align="center"> - <radio id="wipeRemote" - class="mergeChoiceButton" - aria-labelledby="wipeRemoteLabel"/> - <label id="wipeRemoteLabel" - control="wipeRemote"> - &choice2a.server.main.label; - </label> - </row> - </rows> - </grid> - </radiogroup> - </groupbox> - </wizardpage> - - <wizardpage id="syncOptionsConfirm" - label="&setup.optionsConfirmPage.title;" - onpageshow="gSyncSetup.onPageShow()"> - <deck id="chosenActionDeck"> - <vbox id="chosenActionMerge" class="confirm"> - <description class="normal"> - &confirm.merge2.label; - </description> - </vbox> - <vbox id="chosenActionWipeClient" class="confirm"> - <description class="normal"> - &confirm.client3.label; - </description> - <separator class="thin"/> - <vbox id="dataList"> - <label class="data indent" id="bookmarkCount"/> - <label class="data indent" id="historyCount"/> - <label class="data indent" id="passwordCount"/> - <label class="data indent" id="addonCount"/> - <label class="data indent" id="prefsWipe" - value="&engine.prefs.label;"/> - </vbox> - <separator class="thin"/> - <description class="normal"> - &confirm.client2.moreinfo.label; - </description> - </vbox> - <vbox id="chosenActionWipeServer" class="confirm"> - <description class="normal"> - &confirm.server2.label; - </description> - <separator class="thin"/> - <vbox id="clientList"> - </vbox> - </vbox> - </deck> - </wizardpage> - <!-- In terms of the wizard flow shown to the user, the 'syncOptionsConfirm' - page above is not the last wizard page. To prevent the wizard binding from - assuming that it is, we're inserting this dummy page here. This also means - that the wizard needs to always be closed manually via wizardFinish(). --> - <wizardpage> - </wizardpage> -</wizard> - diff --git a/application/basilisk/base/content/sync/utils.js b/application/basilisk/base/content/sync/utils.js deleted file mode 100644 index 92981f7b4..000000000 --- a/application/basilisk/base/content/sync/utils.js +++ /dev/null @@ -1,231 +0,0 @@ -/* 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/. */ - -// Equivalent to 0o600 permissions; used for saved Sync Recovery Key. -// This constant can be replaced when the equivalent values are available to -// chrome JS; see Bug 433295 and Bug 757351. -const PERMISSIONS_RWUSR = 0x180; - -// Weave should always exist before before this file gets included. -var gSyncUtils = { - get bundle() { - delete this.bundle; - return this.bundle = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties"); - }, - - get fxAccountsEnabled() { - let service = Components.classes["@mozilla.org/weave/service;1"] - .getService(Components.interfaces.nsISupports) - .wrappedJSObject; - return service.fxAccountsEnabled; - }, - - // opens in a new window if we're in a modal prefwindow world, in a new tab otherwise - _openLink: function (url) { - let thisDocEl = document.documentElement, - openerDocEl = window.opener && window.opener.document.documentElement; - if (thisDocEl.id == "accountSetup" && window.opener && - openerDocEl.id == "BrowserPreferences" && !openerDocEl.instantApply) - openUILinkIn(url, "window"); - else if (thisDocEl.id == "BrowserPreferences" && !thisDocEl.instantApply) - openUILinkIn(url, "window"); - else if (document.documentElement.id == "change-dialog") - Services.wm.getMostRecentWindow("navigator:browser") - .openUILinkIn(url, "tab"); - else - openUILinkIn(url, "tab"); - }, - - changeName: function changeName(input) { - // Make sure to update to a modified name, e.g., empty-string -> default - Weave.Service.clientsEngine.localName = input.value; - input.value = Weave.Service.clientsEngine.localName; - }, - - openChange: function openChange(type, duringSetup) { - // Just re-show the dialog if it's already open - let openedDialog = Services.wm.getMostRecentWindow("Sync:" + type); - if (openedDialog != null) { - openedDialog.focus(); - return; - } - - // Open up the change dialog - let changeXUL = "chrome://browser/content/sync/genericChange.xul"; - let changeOpt = "centerscreen,chrome,resizable=no"; - Services.ww.activeWindow.openDialog(changeXUL, "", changeOpt, - type, duringSetup); - }, - - changePassword: function () { - if (Weave.Utils.ensureMPUnlocked()) - this.openChange("ChangePassword"); - }, - - resetPassphrase: function (duringSetup) { - if (Weave.Utils.ensureMPUnlocked()) - this.openChange("ResetPassphrase", duringSetup); - }, - - updatePassphrase: function () { - if (Weave.Utils.ensureMPUnlocked()) - this.openChange("UpdatePassphrase"); - }, - - resetPassword: function () { - this._openLink(Weave.Service.pwResetURL); - }, - - get tosURL() { - let root = this.fxAccountsEnabled ? "fxa." : ""; - return Weave.Svc.Prefs.get(root + "termsURL"); - }, - - openToS: function () { - this._openLink(this.tosURL); - }, - - get privacyPolicyURL() { - let root = this.fxAccountsEnabled ? "fxa." : ""; - return Weave.Svc.Prefs.get(root + "privacyURL"); - }, - - openPrivacyPolicy: function () { - this._openLink(this.privacyPolicyURL); - }, - - /** - * Prepare an invisible iframe with the passphrase backup document. - * Used by both the print and saving methods. - * - * @param elid : ID of the form element containing the passphrase. - * @param callback : Function called once the iframe has loaded. - */ - _preparePPiframe: function(elid, callback) { - let pp = document.getElementById(elid).value; - - // Create an invisible iframe whose contents we can print. - let iframe = document.createElement("iframe"); - iframe.setAttribute("src", "chrome://browser/content/sync/key.xhtml"); - iframe.collapsed = true; - document.documentElement.appendChild(iframe); - iframe.contentWindow.addEventListener("load", function() { - iframe.contentWindow.removeEventListener("load", arguments.callee, false); - - // Insert the Sync Key into the page. - let el = iframe.contentDocument.getElementById("synckey"); - el.firstChild.nodeValue = pp; - - // Insert the TOS and Privacy Policy URLs into the page. - let termsURL = Weave.Svc.Prefs.get("termsURL"); - el = iframe.contentDocument.getElementById("tosLink"); - el.setAttribute("href", termsURL); - el.firstChild.nodeValue = termsURL; - - let privacyURL = Weave.Svc.Prefs.get("privacyURL"); - el = iframe.contentDocument.getElementById("ppLink"); - el.setAttribute("href", privacyURL); - el.firstChild.nodeValue = privacyURL; - - callback(iframe); - }, false); - }, - - /** - * Print passphrase backup document. - * - * @param elid : ID of the form element containing the passphrase. - */ - passphrasePrint: function(elid) { - this._preparePPiframe(elid, function(iframe) { - let webBrowserPrint = iframe.contentWindow - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebBrowserPrint); - let printSettings = PrintUtils.getPrintSettings(); - - // Display no header/footer decoration except for the date. - printSettings.headerStrLeft - = printSettings.headerStrCenter - = printSettings.headerStrRight - = printSettings.footerStrLeft - = printSettings.footerStrCenter = ""; - printSettings.footerStrRight = "&D"; - - try { - webBrowserPrint.print(printSettings, null); - } catch (ex) { - // print()'s return codes are expressed as exceptions. Ignore. - } - }); - }, - - /** - * Save passphrase backup document to disk as HTML file. - * - * @param elid : ID of the form element containing the passphrase. - */ - passphraseSave: function(elid) { - let dialogTitle = this.bundle.GetStringFromName("save.recoverykey.title"); - let defaultSaveName = this.bundle.GetStringFromName("save.recoverykey.defaultfilename"); - this._preparePPiframe(elid, function(iframe) { - let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); - let fpCallback = function fpCallback_done(aResult) { - if (aResult == Ci.nsIFilePicker.returnOK || - aResult == Ci.nsIFilePicker.returnReplace) { - let stream = Cc["@mozilla.org/network/file-output-stream;1"]. - createInstance(Ci.nsIFileOutputStream); - stream.init(fp.file, -1, PERMISSIONS_RWUSR, 0); - - let serializer = new XMLSerializer(); - let output = serializer.serializeToString(iframe.contentDocument); - output = output.replace(/<!DOCTYPE (.|\n)*?]>/, - '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' + - '"DTD/xhtml1-strict.dtd">'); - output = Weave.Utils.encodeUTF8(output); - stream.write(output, output.length); - } - }; - - fp.init(window, dialogTitle, Ci.nsIFilePicker.modeSave); - fp.appendFilters(Ci.nsIFilePicker.filterHTML); - fp.defaultString = defaultSaveName; - fp.open(fpCallback); - return false; - }); - }, - - /** - * validatePassword - * - * @param el1 : the first textbox element in the form - * @param el2 : the second textbox element, if omitted it's an update form - * - * returns [valid, errorString] - */ - validatePassword: function (el1, el2) { - let valid = false; - let val1 = el1.value; - let val2 = el2 ? el2.value : ""; - let error = ""; - - if (!el2) - valid = val1.length >= Weave.MIN_PASS_LENGTH; - else if (val1 && val1 == Weave.Service.identity.username) - error = "change.password.pwSameAsUsername"; - else if (val1 && val1 == Weave.Service.identity.account) - error = "change.password.pwSameAsEmail"; - else if (val1 && val1 == Weave.Service.identity.basicPassword) - error = "change.password.pwSameAsPassword"; - else if (val1 && val2) { - if (val1 == val2 && val1.length >= Weave.MIN_PASS_LENGTH) - valid = true; - else if (val1.length < Weave.MIN_PASS_LENGTH) - error = "change.password.tooShort"; - else if (val1 != val2) - error = "change.password.mismatch"; - } - let errorString = error ? Weave.Utils.getErrorString(error) : ""; - return [valid, errorString]; - } -}; |