diff options
124 files changed, 1128 insertions, 9037 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..b6ab23be5 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/> @@ -317,11 +314,13 @@ key="key_sanitize" command="Tools:Sanitize"/> <menuseparator id="sanitizeSeparator"/> +#ifdef MOZ_SERVICES_SYNC <menuitem id="sync-tabs-menuitem" class="syncTabsMenuItem" - label="&syncTabsMenu3.label;" + label="&syncTabsMenu2.label;" oncommand="BrowserOpenSyncTabs();" - hidden="true"/> + disabled="true"/> +#endif <menuitem id="historyRestoreLastSession" label="&historyRestoreLastSession.label;" command="Browser:RestoreLastSession"/> @@ -440,11 +439,10 @@ 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());" - > +#ifdef MOZ_SERVICES_SYNC + onpopupshowing="gSyncUI.updateUI();" +#endif + > <menuitem id="menu_openDownloads" label="&downloads.label;" accesskey="&downloads.accesskey;" @@ -455,23 +453,19 @@ accesskey="&addons.accesskey;" key="key_openAddons" command="Tools:Addons"/> - - <!-- only one of sync-setup, sync-syncnowitem or sync-reauthitem will be showing at once --> +#ifdef MOZ_SERVICES_SYNC + <!-- only one of sync-setup or sync-menu will be showing at once --> <menuitem id="sync-setup" - label="&syncSignIn.label;" - accesskey="&syncSignIn.accesskey;" + label="&syncSetup.label;" + accesskey="&syncSetup.accesskey;" observes="sync-setup-state" - oncommand="gSyncUI.openSetup(null, 'menubar')"/> + oncommand="gSyncUI.openSetup()"/> <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');"/> +#endif <menuseparator id="devToolsSeparator"/> <menu id="webDeveloperMenu" label="&webDeveloperMenu.label;" diff --git a/application/basilisk/base/content/browser-places.js b/application/basilisk/base/content/browser-places.js index 83c737977..87734140f 100644 --- a/application/basilisk/base/content/browser-places.js +++ b/application/basilisk/base/content/browser-places.js @@ -804,18 +804,29 @@ HistoryMenu.prototype = { }, toggleTabsFromOtherComputers: function PHM_toggleTabsFromOtherComputers() { + // This is a no-op if MOZ_SERVICES_SYNC isn't defined +#ifdef MOZ_SERVICES_SYNC // Enable/disable the Tabs From Other Computers menu. Some of the menus handled // by HistoryMenu do not have this menuitem. let menuitem = this._rootElt.getElementsByClassName("syncTabsMenuItem")[0]; if (!menuitem) return; - if (!PlacesUIUtils.shouldShowTabsFromOtherComputersMenuitem()) { + // If Sync isn't configured yet, then don't show the menuitem. + if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED || + Weave.Svc.Prefs.get("firstSync", "") == "notReady") { menuitem.setAttribute("hidden", true); return; } + // The tabs engine might never be inited (if services.sync.registerEngines + // is modified), so make sure we avoid undefined errors. + let enabled = Weave.Service.isLoggedIn && + Weave.Service.engineManager.get("tabs") && + Weave.Service.engineManager.get("tabs").enabled; + menuitem.setAttribute("disabled", !enabled); menuitem.setAttribute("hidden", false); +#endif }, _onPopupShowing: function HM__onPopupShowing(aEvent) { diff --git a/application/basilisk/base/content/browser-sets.inc b/application/basilisk/base/content/browser-sets.inc index 6ea057d93..d6a9310ed 100644 --- a/application/basilisk/base/content/browser-sets.inc +++ b/application/basilisk/base/content/browser-sets.inc @@ -163,16 +163,13 @@ <!-- A broadcaster of a number of attributes suitable for "sync now" UI - A 'syncstatus' attribute is set while actively syncing, and the label attribute which changes from "sync now" to "syncing" etc. --> +#ifdef MOZ_SERVICES_SYNC <broadcaster id="sync-status"/> <!-- broadcasters of the "hidden" attribute to reflect setup state for menus --> <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');"/> +#endif <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..a752f4cd9 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,14 @@ function checkEmptyPageOrigin(browser = gBrowser.selectedBrowser, return ssm.isSystemPrincipal(contentPrincipal); } +#ifdef MOZ_SERVICES_SYNC function BrowserOpenSyncTabs() { - switchToTabHavingURI("about:sync-tabs", true); + if (gSyncUI._needsSetup()) + gSyncUI.openSetup(); + else + switchToTabHavingURI("about:sync-tabs", true); } +#endif /** * Format a URL @@ -7540,8 +7559,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..d99ac9bc8 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 @@ -964,6 +911,18 @@ type="checkbox" label="&fullScreenCmd.label;" tooltip="dynamic-shortcut-tooltip"/> + +#ifdef MOZ_SERVICES_SYNC + <toolbarbutton id="sync-button" + class="toolbarbutton-1 chromeclass-toolbar-additional" + label="&syncToolbarButton.label;" + oncommand="gSyncUI.handleToolbarButton();"/>> + + <toolbarbutton id="sync-tabs-button" + class="toolbarbutton-1 chromeclass-toolbar-additional" + label="&syncTabsToolbarButton.label;" + oncommand="BrowserOpenSyncTabs();"/> +#endif </toolbarpalette> </toolbox> 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/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/jar.mn b/application/basilisk/base/jar.mn index 3b51e9555..126312cd5 100644 --- a/application/basilisk/base/jar.mn +++ b/application/basilisk/base/jar.mn @@ -48,16 +48,6 @@ browser.jar: content/browser/abouthealthreport/abouthealth.js (content/abouthealthreport/abouthealth.js) content/browser/abouthealthreport/abouthealth.css (content/abouthealthreport/abouthealth.css) #endif - content/browser/aboutaccounts/aboutaccounts.xhtml (content/aboutaccounts/aboutaccounts.xhtml) - content/browser/aboutaccounts/aboutaccounts.js (content/aboutaccounts/aboutaccounts.js) - content/browser/aboutaccounts/aboutaccounts.css (content/aboutaccounts/aboutaccounts.css) - content/browser/aboutaccounts/main.css (content/aboutaccounts/main.css) - content/browser/aboutaccounts/normalize.css (content/aboutaccounts/normalize.css) - content/browser/aboutaccounts/images/fox.png (content/aboutaccounts/images/fox.png) - content/browser/aboutaccounts/images/graphic_sync_intro.png (content/aboutaccounts/images/graphic_sync_intro.png) - content/browser/aboutaccounts/images/graphic_sync_intro@2x.png (content/aboutaccounts/images/graphic_sync_intro@2x.png) - - content/browser/aboutTabCrashed.css (content/aboutTabCrashed.css) content/browser/aboutTabCrashed.js (content/aboutTabCrashed.js) content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml) @@ -73,17 +63,15 @@ browser.jar: content/browser/browser-feeds.js (content/browser-feeds.js) content/browser/browser-fullScreenAndPointerLock.js (content/browser-fullScreenAndPointerLock.js) content/browser/browser-fullZoom.js (content/browser-fullZoom.js) - content/browser/browser-fxaccounts.js (content/browser-fxaccounts.js) content/browser/browser-gestureSupport.js (content/browser-gestureSupport.js) * content/browser/browser-media.js (content/browser-media.js) - content/browser/browser-places.js (content/browser-places.js) +* content/browser/browser-places.js (content/browser-places.js) content/browser/browser-plugins.js (content/browser-plugins.js) content/browser/browser-refreshblocker.js (content/browser-refreshblocker.js) #ifdef MOZ_SAFE_BROWSING content/browser/browser-safebrowsing.js (content/browser-safebrowsing.js) #endif content/browser/browser-sidebar.js (content/browser-sidebar.js) -* content/browser/browser-syncui.js (content/browser-syncui.js) * content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml) #ifdef CAN_DRAW_IN_TITLEBAR content/browser/browser-tabsintitlebar.js (content/browser-tabsintitlebar.js) @@ -132,23 +120,6 @@ browser.jar: content/browser/pageinfo/feeds.xml (content/pageinfo/feeds.xml) content/browser/pageinfo/permissions.js (content/pageinfo/permissions.js) content/browser/pageinfo/security.js (content/pageinfo/security.js) - content/browser/sync/aboutSyncTabs.xul (content/sync/aboutSyncTabs.xul) -* content/browser/sync/aboutSyncTabs.js (content/sync/aboutSyncTabs.js) - content/browser/sync/aboutSyncTabs.css (content/sync/aboutSyncTabs.css) - content/browser/sync/aboutSyncTabs-bindings.xml (content/sync/aboutSyncTabs-bindings.xml) - content/browser/sync/setup.xul (content/sync/setup.xul) - content/browser/sync/addDevice.js (content/sync/addDevice.js) - content/browser/sync/addDevice.xul (content/sync/addDevice.xul) - content/browser/sync/setup.js (content/sync/setup.js) - content/browser/sync/genericChange.xul (content/sync/genericChange.xul) - content/browser/sync/genericChange.js (content/sync/genericChange.js) - content/browser/sync/key.xhtml (content/sync/key.xhtml) - content/browser/sync/utils.js (content/sync/utils.js) - content/browser/sync/customize.xul (content/sync/customize.xul) - content/browser/sync/customize.js (content/sync/customize.js) - content/browser/sync/customize.css (content/sync/customize.css) - content/browser/sync/quota.xul (content/sync/quota.xul) - content/browser/sync/quota.js (content/sync/quota.js) content/browser/safeMode.css (content/safeMode.css) content/browser/safeMode.js (content/safeMode.js) content/browser/safeMode.xul (content/safeMode.xul) diff --git a/application/basilisk/components/about/AboutRedirector.cpp b/application/basilisk/components/about/AboutRedirector.cpp index 2b8608484..d52b063e2 100644 --- a/application/basilisk/components/about/AboutRedirector.cpp +++ b/application/basilisk/components/about/AboutRedirector.cpp @@ -92,10 +92,16 @@ static RedirEntry kRedirMap[] = { "welcomeback", "chrome://browser/content/aboutWelcomeBack.xhtml", nsIAboutModule::ALLOW_SCRIPT }, +#ifdef MOZ_SERVICES_SYNC + { + "sync-progress", "chrome://browser/content/sync/progress.xhtml", + nsIAboutModule::ALLOW_SCRIPT + }, { "sync-tabs", "chrome://browser/content/sync/aboutSyncTabs.xul", nsIAboutModule::ALLOW_SCRIPT }, +#endif { "home", "chrome://browser/content/abouthome/aboutHome.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::URI_MUST_LOAD_IN_CHILD | @@ -123,10 +129,6 @@ static RedirEntry kRedirMap[] = { }, #endif { - "accounts", "chrome://browser/content/aboutaccounts/aboutaccounts.xhtml", - nsIAboutModule::ALLOW_SCRIPT - }, - { "reader", "chrome://global/content/reader/aboutReader.html", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::ALLOW_SCRIPT | diff --git a/application/basilisk/components/build/nsModule.cpp b/application/basilisk/components/build/nsModule.cpp index 4e082ab6c..3fdde8823 100644 --- a/application/basilisk/components/build/nsModule.cpp +++ b/application/basilisk/components/build/nsModule.cpp @@ -97,12 +97,14 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = { { NS_ABOUT_MODULE_CONTRACTID_PREFIX "searchreset", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "sessionrestore", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "welcomeback", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, +#ifdef MOZ_SERVICES_SYNC { NS_ABOUT_MODULE_CONTRACTID_PREFIX "sync-tabs", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, + { NS_ABOUT_MODULE_CONTRACTID_PREFIX "sync-progress", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, +#endif { NS_ABOUT_MODULE_CONTRACTID_PREFIX "home", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "downloads", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, - { NS_ABOUT_MODULE_CONTRACTID_PREFIX "accounts", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, #ifdef MOZ_SERVICES_HEALTHREPORT { NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, #endif diff --git a/application/basilisk/components/customizableui/CustomizableUI.jsm b/application/basilisk/components/customizableui/CustomizableUI.jsm index cb0f519b2..31126b37c 100644 --- a/application/basilisk/components/customizableui/CustomizableUI.jsm +++ b/application/basilisk/components/customizableui/CustomizableUI.jsm @@ -200,7 +200,6 @@ var CustomizableUIInternal = { "find-button", "preferences-button", "add-ons-button", - "sync-button", ]; if (!AppConstants.MOZ_DEV_EDITION) { diff --git a/application/basilisk/components/customizableui/CustomizableWidgets.jsm b/application/basilisk/components/customizableui/CustomizableWidgets.jsm index 401b7ca74..9e8f0ec78 100644 --- a/application/basilisk/components/customizableui/CustomizableWidgets.jsm +++ b/application/basilisk/components/customizableui/CustomizableWidgets.jsm @@ -286,144 +286,6 @@ const CustomizableWidgets = [ log.debug("History view is being hidden!"); } }, { - id: "sync-button", - label: "remotetabs-panelmenu.label", - tooltiptext: "remotetabs-panelmenu.tooltiptext2", - type: "view", - viewId: "PanelUI-remotetabs", - defaultArea: CustomizableUI.AREA_PANEL, - deckIndices: { - DECKINDEX_TABS: 0, - DECKINDEX_TABSDISABLED: 1, - DECKINDEX_FETCHING: 2, - DECKINDEX_NOCLIENTS: 3, - }, - onCreated(aNode) { - // Add an observer to the button so we get the animation during sync. - // (Note the observer sets many attributes, including label and - // tooltiptext, but we only want the 'syncstatus' attribute for the - // animation) - let doc = aNode.ownerDocument; - let obnode = doc.createElementNS(kNSXUL, "observes"); - obnode.setAttribute("element", "sync-status"); - obnode.setAttribute("attribute", "syncstatus"); - aNode.appendChild(obnode); - }, - setDeckIndex(index) { - let deck = this._tabsList.ownerDocument.getElementById("PanelUI-remotetabs-deck"); - // We call setAttribute instead of relying on the XBL property setter due - // to things going wrong when we try and set the index before the XBL - // binding has been created - see bug 1241851 for the gory details. - deck.setAttribute("selectedIndex", index); - }, - - _showTabsPromise: Promise.resolve(), - // Update the tab list after any existing in-flight updates are complete. - _showTabs() { - this._showTabsPromise = this._showTabsPromise.then(() => { - return this.__showTabs(); - }); - }, - // Return a new promise to update the tab list. - __showTabs() { - let doc = this._tabsList.ownerDocument; - return SyncedTabs.getTabClients().then(clients => { - // The view may have been hidden while the promise was resolving. - if (!this._tabsList) { - return; - } - if (clients.length === 0 && !SyncedTabs.hasSyncedThisSession) { - // the "fetching tabs" deck is being shown - let's leave it there. - // When that first sync completes we'll be notified and update. - return; - } - - if (clients.length === 0) { - this.setDeckIndex(this.deckIndices.DECKINDEX_NOCLIENTS); - return; - } - - this.setDeckIndex(this.deckIndices.DECKINDEX_TABS); - this._clearTabList(); - SyncedTabs.sortTabClientsByLastUsed(clients, 50 /* maxTabs */); - let fragment = doc.createDocumentFragment(); - - for (let client of clients) { - // add a menu separator for all clients other than the first. - if (fragment.lastChild) { - let separator = doc.createElementNS(kNSXUL, "menuseparator"); - fragment.appendChild(separator); - } - this._appendClient(client, fragment); - } - this._tabsList.appendChild(fragment); - }).catch(err => { - Cu.reportError(err); - }).then(() => { - // an observer for tests. - Services.obs.notifyObservers(null, "synced-tabs-menu:test:tabs-updated", null); - }); - }, - _clearTabList () { - let list = this._tabsList; - while (list.lastChild) { - list.lastChild.remove(); - } - }, - _showNoClientMessage() { - this._appendMessageLabel("notabslabel"); - }, - _appendMessageLabel(messageAttr, appendTo = null) { - if (!appendTo) { - appendTo = this._tabsList; - } - let message = this._tabsList.getAttribute(messageAttr); - let doc = this._tabsList.ownerDocument; - let messageLabel = doc.createElementNS(kNSXUL, "label"); - messageLabel.textContent = message; - appendTo.appendChild(messageLabel); - return messageLabel; - }, - _appendClient: function (client, attachFragment) { - let doc = attachFragment.ownerDocument; - // Create the element for the remote client. - let clientItem = doc.createElementNS(kNSXUL, "label"); - clientItem.setAttribute("itemtype", "client"); - let window = doc.defaultView; - clientItem.setAttribute("tooltiptext", - window.gSyncUI.formatLastSyncDate(new Date(client.lastModified))); - clientItem.textContent = client.name; - - attachFragment.appendChild(clientItem); - - if (client.tabs.length == 0) { - let label = this._appendMessageLabel("notabsforclientlabel", attachFragment); - label.setAttribute("class", "PanelUI-remotetabs-notabsforclient-label"); - } else { - for (let tab of client.tabs) { - let tabEnt = this._createTabElement(doc, tab); - attachFragment.appendChild(tabEnt); - } - } - }, - _createTabElement(doc, tabInfo) { - let item = doc.createElementNS(kNSXUL, "toolbarbutton"); - let tooltipText = (tabInfo.title ? tabInfo.title + "\n" : "") + tabInfo.url; - item.setAttribute("itemtype", "tab"); - item.setAttribute("class", "subviewbutton"); - item.setAttribute("targetURI", tabInfo.url); - item.setAttribute("label", tabInfo.title != "" ? tabInfo.title : tabInfo.url); - item.setAttribute("image", tabInfo.icon); - item.setAttribute("tooltiptext", tooltipText); - // We need to use "click" instead of "command" here so openUILink - // respects different buttons (eg, to open in a new tab). - item.addEventListener("click", e => { - doc.defaultView.openUILink(tabInfo.url, e); - CustomizableUI.hidePanelForNode(item); - }); - return item; - }, - }, { id: "privatebrowsing-button", shortcutId: "key_privatebrowsing", defaultArea: CustomizableUI.AREA_PANEL, diff --git a/application/basilisk/components/customizableui/content/panelUI.inc.xul b/application/basilisk/components/customizableui/content/panelUI.inc.xul index 8ebd93327..da8077554 100644 --- a/application/basilisk/components/customizableui/content/panelUI.inc.xul +++ b/application/basilisk/components/customizableui/content/panelUI.inc.xul @@ -20,27 +20,6 @@ oncommand="gMenuButtonUpdateBadge.onMenuPanelCommand(event);" wrap="true" hidden="true"/> - <hbox id="PanelUI-footer-fxa"> - <hbox id="PanelUI-fxa-status" - defaultlabel="&fxaSignIn.label;" - signedinTooltiptext="&syncSettings.label;" - tooltiptext="&syncSettings.label;" - errorlabel="&fxaSignInError.label;" - unverifiedlabel="&fxaUnverified.label;" - settingslabel="&syncSettings.label;" - onclick="if (event.which == 1) gFxAccounts.onMenuPanelCommand();"> - <image id="PanelUI-fxa-avatar"/> - <toolbarbutton id="PanelUI-fxa-label" - fxabrandname="&syncBrand.fxAccount.label;"/> - </hbox> - <toolbarseparator/> - <toolbarbutton id="PanelUI-fxa-icon" - oncommand="gSyncUI.doSync();" - closemenu="none"> - <observes element="sync-status" attribute="syncstatus"/> - <observes element="sync-status" attribute="tooltiptext"/> - </toolbarbutton> - </hbox> <hbox id="PanelUI-footer-inner"> <toolbarbutton id="PanelUI-customize" label="&appMenuCustomize.label;" @@ -103,95 +82,6 @@ oncommand="PlacesCommandHook.showPlacesOrganizer('History'); CustomizableUI.hidePanelForNode(this);"/> </panelview> - <panelview id="PanelUI-remotetabs" flex="1" class="PanelUI-subView"> - <label value="&appMenuRemoteTabs.label;" class="panel-subview-header"/> - <vbox class="panel-subview-body"> - <!-- this widget has 3 boxes in the body, but only 1 is ever visible --> - <!-- When Sync is ready to sync --> - <vbox id="PanelUI-remotetabs-main" observes="sync-syncnow-state"> - <vbox id="PanelUI-remotetabs-buttons"> - <toolbarbutton id="PanelUI-remotetabs-view-sidebar" - class="subviewbutton" - oncommand="BrowserOpenSyncTabs();" - label="&appMenuRemoteTabs.sidebar.label;"/> - <toolbarbutton id="PanelUI-remotetabs-syncnow" - observes="sync-status" - class="subviewbutton" - oncommand="gSyncUI.doSync();" - closemenu="none"/> - <menuseparator id="PanelUI-remotetabs-separator"/> - </vbox> - <deck id="PanelUI-remotetabs-deck"> - <!-- Sync is ready to Sync and the "tabs" engine is enabled --> - <vbox id="PanelUI-remotetabs-tabspane"> - <vbox id="PanelUI-remotetabs-tabslist" - notabsforclientlabel="&appMenuRemoteTabs.notabs.label;" - /> - </vbox> - <!-- Sync is ready to Sync but the "tabs" engine isn't enabled--> - <hbox id="PanelUI-remotetabs-tabsdisabledpane" pack="center" flex="1"> - <vbox class="PanelUI-remotetabs-instruction-box"> - <hbox pack="center"> - <image class="fxaSyncIllustration" alt=""/> - </hbox> - <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.tabsnotsyncing.label;</label> - <hbox pack="center"> - <toolbarbutton class="PanelUI-remotetabs-prefs-button" - label="&appMenuRemoteTabs.openprefs.label;" - oncommand="gSyncUI.openSetup(null, 'synced-tabs');"/> - </hbox> - </vbox> - </hbox> - <!-- Sync is ready to Sync but we are still fetching the tabs to show --> - <vbox id="PanelUI-remotetabs-fetching"> - <!-- Show intentionally blank panel, see bug 1239845 --> - </vbox> - <!-- Sync has only 1 (ie, this) device connected --> - <hbox id="PanelUI-remotetabs-nodevicespane" pack="center" flex="1"> - <vbox class="PanelUI-remotetabs-instruction-box"> - <hbox pack="center"> - <image class="fxaSyncIllustration" alt=""/> - </hbox> - <label class="PanelUI-remotetabs-instruction-title">&appMenuRemoteTabs.noclients.title;</label> - <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.noclients.subtitle;</label> - <!-- The inner HTML for PanelUI-remotetabs-mobile-promo is built at runtime --> - <label id="PanelUI-remotetabs-mobile-promo" fxAccountsBrand="&syncBrand.fxAccount.label;"/> - </vbox> - </hbox> - </deck> - </vbox> - <!-- a box to ensure contained boxes are centered horizonally --> - <hbox pack="center" flex="1"> - <!-- When Sync is not configured --> - <vbox id="PanelUI-remotetabs-setupsync" - flex="1" - align="center" - class="PanelUI-remotetabs-instruction-box" - observes="sync-setup-state"> - <image class="fxaSyncIllustration" alt=""/> - <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label> - <toolbarbutton class="PanelUI-remotetabs-prefs-button" - label="&appMenuRemoteTabs.signin.label;" - oncommand="gSyncUI.openSetup(null, 'synced-tabs');"/> - </vbox> - <!-- When Sync needs re-authentication. This uses the exact same messaging - as "Sync is not configured" but remains a separate box so we get - the goodness of observing broadcasters to manage the hidden states --> - <vbox id="PanelUI-remotetabs-reauthsync" - flex="1" - align="center" - class="PanelUI-remotetabs-instruction-box" - observes="sync-reauth-state"> - <image class="fxaSyncIllustration" alt=""/> - <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label> - <toolbarbutton class="PanelUI-remotetabs-prefs-button" - label="&appMenuRemoteTabs.signin.label;" - oncommand="gSyncUI.openSetup(null, 'synced-tabs');"/> - </vbox> - </hbox> - </vbox> - </panelview> - <panelview id="PanelUI-bookmarks" flex="1" class="PanelUI-subView"> <label value="&bookmarksMenu.label;" class="panel-subview-header"/> <vbox class="panel-subview-body"> diff --git a/application/basilisk/components/customizableui/moz.build b/application/basilisk/components/customizableui/moz.build index 034630dc9..5797a03b0 100644 --- a/application/basilisk/components/customizableui/moz.build +++ b/application/basilisk/components/customizableui/moz.build @@ -9,7 +9,6 @@ DIRS += [ ] EXTRA_JS_MODULES += [ - 'CustomizableUI.jsm', 'CustomizableWidgets.jsm', 'CustomizeMode.jsm', 'DragPositionManager.jsm', @@ -17,5 +16,9 @@ EXTRA_JS_MODULES += [ 'ScrollbarSampler.jsm', ] +EXTRA_PP_JS_MODULES += [ + 'CustomizableUI.jsm', +] + if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'): DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1 diff --git a/application/basilisk/components/moz.build b/application/basilisk/components/moz.build index 65e8beb76..6c6cca9df 100644 --- a/application/basilisk/components/moz.build +++ b/application/basilisk/components/moz.build @@ -19,7 +19,7 @@ DIRS += [ 'sessionstore', 'shell', 'selfsupport', - 'syncedtabs', + 'sync', 'translation', ] @@ -35,6 +35,9 @@ XPIDL_MODULE = 'browsercompsbase' EXTRA_COMPONENTS += [ 'BrowserComponents.manifest', 'nsBrowserContentHandler.js', +] + +EXTRA_PP_COMPONENTS += [ 'nsBrowserGlue.js', ] diff --git a/application/basilisk/components/nsBrowserGlue.js b/application/basilisk/components/nsBrowserGlue.js index d77e97f87..82de33240 100644 --- a/application/basilisk/components/nsBrowserGlue.js +++ b/application/basilisk/components/nsBrowserGlue.js @@ -143,6 +143,7 @@ BrowserGlue.prototype = { Services.prefs.savePrefFile(null); }, +#ifdef MOZ_SERVICES_SYNC _setSyncAutoconnectDelay: function BG__setSyncAutoconnectDelay() { // Assume that a non-zero value for services.sync.autoconnectDelay should override if (Services.prefs.prefHasUserValue("services.sync.autoconnectDelay")) { @@ -164,6 +165,7 @@ BrowserGlue.prototype = { Cu.import("resource://services-sync/main.js"); Weave.Service.scheduler.delayedAutoConnect(delay); }, +#endif // nsIObserver implementation observe: function BG_observe(subject, topic, data) { @@ -210,18 +212,14 @@ BrowserGlue.prototype = { this._setPrefToSaveSession(); } break; +#ifdef MOZ_SERVICES_SYNC case "weave:service:ready": this._setSyncAutoconnectDelay(); break; - case "fxaccounts:onverified": - this._showSyncStartedDoorhanger(); - break; - case "fxaccounts:device_disconnected": - this._onDeviceDisconnected(); - break; - case "weave:engine:clients:display-uris": - this._onDisplaySyncURIs(subject); - break; + case "weave:engine:clients:display-uri": + this._onDisplaySyncURI(subject); + break; +#endif case "session-save": this._setPrefToSaveSession(true); subject.QueryInterface(Ci.nsISupportsPRBool); @@ -428,10 +426,10 @@ BrowserGlue.prototype = { os.addObserver(this, "browser-lastwindow-close-requested", false); os.addObserver(this, "browser-lastwindow-close-granted", false); } +#ifdef MOZ_SERVICES_SYNC os.addObserver(this, "weave:service:ready", false); - os.addObserver(this, "fxaccounts:onverified", false); - os.addObserver(this, "fxaccounts:device_disconnected", false); - os.addObserver(this, "weave:engine:clients:display-uris", false); + os.addObserver(this, "weave:engine:clients:display-uri", false); +#endif os.addObserver(this, "session-save", false); os.addObserver(this, "places-init-complete", false); this._isPlacesInitObserver = true; @@ -479,10 +477,10 @@ BrowserGlue.prototype = { os.removeObserver(this, "browser-lastwindow-close-requested"); os.removeObserver(this, "browser-lastwindow-close-granted"); } +#ifdef MOZ_SERVICES_SYNC os.removeObserver(this, "weave:service:ready"); - os.removeObserver(this, "fxaccounts:onverified"); - os.removeObserver(this, "fxaccounts:device_disconnected"); - os.removeObserver(this, "weave:engine:clients:display-uris"); + os.removeObserver(this, "weave:engine:clients:display-uri"); +#endif os.removeObserver(this, "session-save"); if (this._bookmarksBackupIdleTime) { this._idleService.removeIdleObserver(this, this._bookmarksBackupIdleTime); @@ -2274,90 +2272,29 @@ BrowserGlue.prototype = { chromeWindow.openPreferences(...args); }, +#ifdef MOZ_SERVICES_SYNC /** - * Called as an observer when Sync's "display URIs" notification is fired. + * Called as an observer when Sync's "display URI" notification is fired. + * + * We open the received URI in a background tab. * - * We open the received URIs in background tabs. + * Eventually, this will likely be replaced by a more robust tab syncing + * feature. This functionality is considered somewhat evil by UX because it + * opens a new tab automatically without any prompting. However, it is a + * lesser evil than sending a tab to a specific device (from e.g. Fennec) + * and having nothing happen on the receiving end. */ - _onDisplaySyncURIs: function _onDisplaySyncURIs(data) { + _onDisplaySyncURI: function _onDisplaySyncURI(data) { try { - // The payload is wrapped weirdly because of how Sync does notifications. - const URIs = data.wrappedJSObject.object; - - const findWindow = () => RecentWindow.getMostRecentBrowserWindow({private: false}); - - // win can be null, but it's ok, we'll assign it later in openTab() - let win = findWindow(); + let tabbrowser = RecentWindow.getMostRecentBrowserWindow({private: false}).gBrowser; - const openTab = URI => { - let tab; - if (!win) { - Services.appShell.hiddenDOMWindow.open(URI.uri); - win = findWindow(); - tab = win.gBrowser.tabs[0]; - } else { - tab = win.gBrowser.addTab(URI.uri); - } - tab.setAttribute("attention", true); - return tab; - }; - - const firstTab = openTab(URIs[0]); - URIs.slice(1).forEach(URI => openTab(URI)); - - let title, body; - const deviceName = Weave.Service.clientsEngine.getClientName(URIs[0].clientId); - const bundle = Services.strings.createBundle("chrome://browser/locale/accounts.properties"); - if (URIs.length == 1) { - // Due to bug 1305895, tabs from iOS may not have device information, so - // we have separate strings to handle those cases. (See Also - // unnamedTabsArrivingNotificationNoDevice.body below) - if (deviceName) { - title = bundle.formatStringFromName("tabArrivingNotificationWithDevice.title", [deviceName], 1); - } else { - title = bundle.GetStringFromName("tabArrivingNotification.title"); - } - // Use the page URL as the body. We strip the fragment and query to - // reduce size, and also format it the same way that the url bar would. - body = URIs[0].uri.replace(/[?#].*$/, ""); - if (win.gURLBar) { - body = win.gURLBar.trimValue(body); - } - } else { - title = bundle.GetStringFromName("tabsArrivingNotification.title"); - const allSameDevice = URIs.every(URI => URI.clientId == URIs[0].clientId); - const unknownDevice = allSameDevice && !deviceName; - let tabArrivingBody; - if (unknownDevice) { - tabArrivingBody = "unnamedTabsArrivingNotificationNoDevice.body"; - } else if (allSameDevice) { - tabArrivingBody = "unnamedTabsArrivingNotification2.body"; - } else { - tabArrivingBody = "unnamedTabsArrivingNotificationMultiple2.body" - } - - body = bundle.GetStringFromName(tabArrivingBody); - body = PluralForm.get(URIs.length, body); - body = body.replace("#1", URIs.length); - body = body.replace("#2", deviceName); - } - - const clickCallback = (subject, topic, data) => { - if (topic == "alertclickcallback") { - win.gBrowser.selectedTab = firstTab; - } - } - - // Specify an icon because on Windows no icon is shown at the moment - let imageURL; - if (AppConstants.platform == "win") { - imageURL = "chrome://branding/content/icon64.png"; - } - AlertsService.showAlertNotification(imageURL, title, body, true, null, clickCallback); + // The payload is wrapped weirdly because of how Sync does notifications. + tabbrowser.addTab(data.wrappedJSObject.object.uri); } catch (ex) { - Cu.reportError("Error displaying tab(s) received by Sync: " + ex); + Cu.reportError("Error displaying tab received by Sync: " + ex); } }, +#endif _onDeviceDisconnected() { let bundle = Services.strings.createBundle("chrome://browser/locale/accounts.properties"); diff --git a/application/basilisk/components/places/PlacesUIUtils.jsm b/application/basilisk/components/places/PlacesUIUtils.jsm index 17fa276aa..035fc12c2 100644 --- a/application/basilisk/components/places/PlacesUIUtils.jsm +++ b/application/basilisk/components/places/PlacesUIUtils.jsm @@ -1418,9 +1418,9 @@ this.PlacesUIUtils = { }, shouldShowTabsFromOtherComputersMenuitem: function() { - let weaveOK = Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED && - Weave.Svc.Prefs.get("firstSync", "") != "notReady"; - return weaveOK; +#ifdef MOZ_SERVICES_SYNC + // Weave code to enable menu item +#endif }, /** diff --git a/application/basilisk/components/places/moz.build b/application/basilisk/components/places/moz.build index 9e5a2c074..ea6d43538 100644 --- a/application/basilisk/components/places/moz.build +++ b/application/basilisk/components/places/moz.build @@ -6,6 +6,6 @@ JAR_MANIFESTS += ['jar.mn'] -EXTRA_JS_MODULES += [ +EXTRA_PP_JS_MODULES += [ 'PlacesUIUtils.jsm', ] diff --git a/application/basilisk/components/preferences/in-content/jar.mn b/application/basilisk/components/preferences/in-content/jar.mn index 70544f332..21f5ccf38 100644 --- a/application/basilisk/components/preferences/in-content/jar.mn +++ b/application/basilisk/components/preferences/in-content/jar.mn @@ -3,7 +3,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. browser.jar: - content/browser/preferences/in-content/preferences.js +* content/browser/preferences/in-content/preferences.js * content/browser/preferences/in-content/preferences.xul content/browser/preferences/in-content/subdialogs.js @@ -12,6 +12,8 @@ browser.jar: content/browser/preferences/in-content/advanced.js content/browser/preferences/in-content/applications.js * content/browser/preferences/in-content/content.js +#ifdef MOZ_SERVICES_SYNC content/browser/preferences/in-content/sync.js +#endif * content/browser/preferences/in-content/security.js content/browser/preferences/in-content/search.js diff --git a/application/basilisk/components/preferences/in-content/preferences.js b/application/basilisk/components/preferences/in-content/preferences.js index 35e10c58d..69cb180d5 100644 --- a/application/basilisk/components/preferences/in-content/preferences.js +++ b/application/basilisk/components/preferences/in-content/preferences.js @@ -64,7 +64,9 @@ function init_all() { register_module("paneAdvanced", gAdvancedPane); register_module("paneApplications", gApplicationsPane); register_module("paneContent", gContentPane); +#ifdef MOZ_SERVICES_SYNC register_module("paneSync", gSyncPane); +#endif register_module("paneSecurity", gSecurityPane); let categories = document.getElementById("categories"); diff --git a/application/basilisk/components/preferences/in-content/preferences.xul b/application/basilisk/components/preferences/in-content/preferences.xul index 093516140..61639aa19 100644 --- a/application/basilisk/components/preferences/in-content/preferences.xul +++ b/application/basilisk/components/preferences/in-content/preferences.xul @@ -22,8 +22,10 @@ <!ENTITY % privacyDTD SYSTEM "chrome://browser/locale/preferences/privacy.dtd"> <!ENTITY % tabsDTD SYSTEM "chrome://browser/locale/preferences/tabs.dtd"> <!ENTITY % searchDTD SYSTEM "chrome://browser/locale/preferences/search.dtd"> +#ifdef MOZ_SERVICES_SYNC <!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd"> <!ENTITY % syncDTD SYSTEM "chrome://browser/locale/preferences/sync.dtd"> +#endif <!ENTITY % securityDTD SYSTEM "chrome://browser/locale/preferences/security.dtd"> <!ENTITY % sanitizeDTD SYSTEM "chrome://browser/locale/sanitize.dtd"> @@ -40,8 +42,10 @@ %privacyDTD; %tabsDTD; %searchDTD; +#ifdef MOZ_SERVICES_SYNC %syncBrandDTD; %syncDTD; +#endif %securityDTD; %sanitizeDTD; %mainDTD; @@ -140,6 +144,7 @@ <label class="category-name" flex="1">&paneSecurity.title;</label> </richlistitem> +#ifdef MOZ_SERVICES_SYNC <richlistitem id="category-sync" class="category" value="paneSync" @@ -149,6 +154,7 @@ <image class="category-icon"/> <label class="category-name" flex="1">&paneSync.title;</label> </richlistitem> +#endif <richlistitem id="category-advanced" class="category" @@ -177,7 +183,9 @@ #include applications.xul #include content.xul #include security.xul +#ifdef MOZ_SERVICES_SYNC #include sync.xul +#endif </prefpane> </vbox> diff --git a/application/basilisk/components/preferences/in-content/sync.js b/application/basilisk/components/preferences/in-content/sync.js index 2600677a8..917b5f123 100644 --- a/application/basilisk/components/preferences/in-content/sync.js +++ b/application/basilisk/components/preferences/in-content/sync.js @@ -1,32 +1,16 @@ /* 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/. */ + * 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/. */ Components.utils.import("resource://services-sync/main.js"); Components.utils.import("resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () { - return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {}); -}); - -XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts", - "resource://gre/modules/FxAccounts.jsm"); - const PAGE_NO_ACCOUNT = 0; const PAGE_HAS_ACCOUNT = 1; const PAGE_NEEDS_UPDATE = 2; -const FXA_PAGE_LOGGED_OUT = 3; -const FXA_PAGE_LOGGED_IN = 4; - -// Indexes into the "login status" deck. -// We are in a successful verified state - everything should work! -const FXA_LOGIN_VERIFIED = 0; -// We have logged in to an unverified account. -const FXA_LOGIN_UNVERIFIED = 1; -// We are logged in locally, but the server rejected our credentials. -const FXA_LOGIN_FAILED = 2; var gSyncPane = { + _stringBundle: null, prefArray: ["engine.bookmarks", "engine.passwords", "engine.prefs", "engine.tabs", "engine.history"], @@ -45,13 +29,11 @@ var gSyncPane = { needsUpdate: function () { this.page = PAGE_NEEDS_UPDATE; let label = document.getElementById("loginError"); - label.textContent = Weave.Utils.getErrorString(Weave.Status.login); + label.value = Weave.Utils.getErrorString(Weave.Status.login); label.className = "error"; }, init: function () { - this._setupEventListeners(); - // If the Service hasn't finished initializing, wait for it. let xps = Components.classes["@mozilla.org/weave/service;1"] .getService(Components.interfaces.nsISupports) @@ -62,10 +44,6 @@ var gSyncPane = { return; } - // it may take some time before we can determine what provider to use - // and the state of that provider, so show the "please wait" page. - this._showLoadPage(xps); - let onUnload = function () { window.removeEventListener("unload", onUnload, false); try { @@ -85,247 +63,50 @@ var gSyncPane = { xps.ensureLoaded(); }, - _showLoadPage: function (xps) { - let username; - try { - username = Services.prefs.getCharPref("services.sync.username"); - } catch (e) {} - if (!username) { - this.page = FXA_PAGE_LOGGED_OUT; - } else if (xps.fxAccountsEnabled) { - // Use cached values while we wait for the up-to-date values - let cachedComputerName; - try { - cachedComputerName = Services.prefs.getCharPref("services.sync.client.name"); - } - catch (e) { - cachedComputerName = ""; - } - document.getElementById("fxaEmailAddress1").textContent = username; - this._populateComputerName(cachedComputerName); - this.page = FXA_PAGE_LOGGED_IN; - } else { // Old Sync - this.page = PAGE_HAS_ACCOUNT; - } - }, - _init: function () { let topics = ["weave:service:login:error", "weave:service:login:finish", - "weave:service:start-over:finish", + "weave:service:start-over", "weave:service:setup-complete", - "weave:service:logout:finish", - FxAccountsCommon.ONVERIFIED_NOTIFICATION, - FxAccountsCommon.ONLOGIN_NOTIFICATION, - FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION, - ]; + "weave:service:logout:finish"]; + // Add the observers now and remove them on unload - // XXXzpao This should use Services.obs.* but Weave's Obs does nice handling + //XXXzpao This should use Services.obs.* but Weave's Obs does nice handling // of `this`. Fix in a followup. (bug 583347) topics.forEach(function (topic) { Weave.Svc.Obs.add(topic, this.updateWeavePrefs, this); }, this); - window.addEventListener("unload", function() { topics.forEach(function (topic) { Weave.Svc.Obs.remove(topic, this.updateWeavePrefs, this); }, gSyncPane); }, false); - XPCOMUtils.defineLazyGetter(this, '_stringBundle', () => { - return Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties"); - }); - - XPCOMUtils.defineLazyGetter(this, '_accountsStringBundle', () => { - return Services.strings.createBundle("chrome://browser/locale/accounts.properties"); - }); - - let url = Services.prefs.getCharPref("identity.mobilepromo.android") + "sync-preferences"; - document.getElementById("fxaMobilePromo-android").setAttribute("href", url); - document.getElementById("fxaMobilePromo-android-hasFxaAccount").setAttribute("href", url); - url = Services.prefs.getCharPref("identity.mobilepromo.ios") + "sync-preferences"; - document.getElementById("fxaMobilePromo-ios").setAttribute("href", url); - document.getElementById("fxaMobilePromo-ios-hasFxaAccount").setAttribute("href", url); - - document.getElementById("tosPP-small-ToS").setAttribute("href", gSyncUtils.tosURL); - document.getElementById("tosPP-normal-ToS").setAttribute("href", gSyncUtils.tosURL); - document.getElementById("tosPP-small-PP").setAttribute("href", gSyncUtils.privacyPolicyURL); - document.getElementById("tosPP-normal-PP").setAttribute("href", gSyncUtils.privacyPolicyURL); - - fxAccounts.promiseAccountsManageURI(this._getEntryPoint()).then(url => { - document.getElementById("verifiedManage").setAttribute("href", url); - }); - + this._stringBundle = + Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties"); this.updateWeavePrefs(); - - this._initProfileImageUI(); - }, - - _toggleComputerNameControls: function(editMode) { - let textbox = document.getElementById("fxaSyncComputerName"); - textbox.disabled = !editMode; - document.getElementById("fxaChangeDeviceName").hidden = editMode; - document.getElementById("fxaCancelChangeDeviceName").hidden = !editMode; - document.getElementById("fxaSaveChangeDeviceName").hidden = !editMode; - }, - - _focusComputerNameTextbox: function() { - let textbox = document.getElementById("fxaSyncComputerName"); - let valLength = textbox.value.length; - textbox.focus(); - textbox.setSelectionRange(valLength, valLength); - }, - - _blurComputerNameTextbox: function() { - document.getElementById("fxaSyncComputerName").blur(); - }, - - _focusAfterComputerNameTextbox: function() { - // Focus the most appropriate element that's *not* the "computer name" box. - Services.focus.moveFocus(window, - document.getElementById("fxaSyncComputerName"), - Services.focus.MOVEFOCUS_FORWARD, 0); - }, - - _updateComputerNameValue: function(save) { - if (save) { - let textbox = document.getElementById("fxaSyncComputerName"); - Weave.Service.clientsEngine.localName = textbox.value; - } - this._populateComputerName(Weave.Service.clientsEngine.localName); - }, - - _setupEventListeners: function() { - function setEventListener(aId, aEventType, aCallback) - { - document.getElementById(aId) - .addEventListener(aEventType, aCallback.bind(gSyncPane)); - } - - setEventListener("noAccountSetup", "click", function (aEvent) { - aEvent.stopPropagation(); - gSyncPane.openSetup(null); - }); - setEventListener("noAccountPair", "click", function (aEvent) { - aEvent.stopPropagation(); - gSyncPane.openSetup('pair'); - }); - setEventListener("syncChangePassword", "command", - () => gSyncUtils.changePassword()); - setEventListener("syncResetPassphrase", "command", - () => gSyncUtils.resetPassphrase()); - setEventListener("syncReset", "command", gSyncPane.resetSync); - setEventListener("syncAddDeviceLabel", "click", function () { - gSyncPane.openAddDevice(); - return false; - }); - setEventListener("syncEnginesList", "select", function () { - if (this.selectedCount) - this.clearSelection(); - }); - setEventListener("syncComputerName", "change", function (e) { - gSyncUtils.changeName(e.target); - }); - setEventListener("fxaChangeDeviceName", "command", function () { - this._toggleComputerNameControls(true); - this._focusComputerNameTextbox(); - }); - setEventListener("fxaCancelChangeDeviceName", "command", function () { - // We explicitly blur the textbox because of bug 75324, then after - // changing the state of the buttons, force focus to whatever the focus - // manager thinks should be next (which on the mac, depends on an OSX - // keyboard access preference) - this._blurComputerNameTextbox(); - this._toggleComputerNameControls(false); - this._updateComputerNameValue(false); - this._focusAfterComputerNameTextbox(); - }); - setEventListener("fxaSaveChangeDeviceName", "command", function () { - // Work around bug 75324 - see above. - this._blurComputerNameTextbox(); - this._toggleComputerNameControls(false); - this._updateComputerNameValue(true); - this._focusAfterComputerNameTextbox(); - }); - setEventListener("unlinkDevice", "click", function () { - gSyncPane.startOver(true); - return false; - }); - setEventListener("loginErrorUpdatePass", "click", function () { - gSyncPane.updatePass(); - return false; - }); - setEventListener("loginErrorResetPass", "click", function () { - gSyncPane.resetPass(); - return false; - }); - setEventListener("loginErrorStartOver", "click", function () { - gSyncPane.startOver(true); - return false; - }); - setEventListener("noFxaSignUp", "command", function () { - gSyncPane.signUp(); - return false; - }); - setEventListener("noFxaSignIn", "command", function () { - gSyncPane.signIn(); - return false; - }); - setEventListener("fxaUnlinkButton", "command", function () { - gSyncPane.unlinkFirefoxAccount(true); - }); - setEventListener("verifyFxaAccount", "command", - gSyncPane.verifyFirefoxAccount); - setEventListener("unverifiedUnlinkFxaAccount", "command", function () { - /* no warning as account can't have previously synced */ - gSyncPane.unlinkFirefoxAccount(false); - }); - setEventListener("rejectReSignIn", "command", - gSyncPane.reSignIn); - setEventListener("rejectUnlinkFxaAccount", "command", function () { - gSyncPane.unlinkFirefoxAccount(true); - }); - setEventListener("fxaSyncComputerName", "keypress", function (e) { - if (e.keyCode == KeyEvent.DOM_VK_RETURN) { - document.getElementById("fxaSaveChangeDeviceName").click(); - } else if (e.keyCode == KeyEvent.DOM_VK_ESCAPE) { - document.getElementById("fxaCancelChangeDeviceName").click(); - } - }); - }, - - _initProfileImageUI: function () { - try { - if (Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled")) { - document.getElementById("fxaProfileImage").hidden = false; - } - } catch (e) { } + document.getElementById("weavePrefsDeck").setAttribute("hidden", ""); }, updateWeavePrefs: function () { - let service = Components.classes["@mozilla.org/weave/service;1"] - .getService(Components.interfaces.nsISupports) - .wrappedJSObject; if (Weave.Status.service == Weave.CLIENT_NOT_CONFIGURED || Weave.Svc.Prefs.get("firstSync", "") == "notReady") { this.page = PAGE_NO_ACCOUNT; - // else: sync was previously configured for the legacy provider, so we - // make the "old" panels available. } else if (Weave.Status.login == Weave.LOGIN_FAILED_INVALID_PASSPHRASE || Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) { this.needsUpdate(); } else { this.page = PAGE_HAS_ACCOUNT; - document.getElementById("accountName").textContent = Weave.Service.identity.account; + document.getElementById("accountName").value = Weave.Service.identity.account; document.getElementById("syncComputerName").value = Weave.Service.clientsEngine.localName; - document.getElementById("tosPP-normal").hidden = this._usingCustomServer; + document.getElementById("tosPP").hidden = this._usingCustomServer; } }, startOver: function (showDialog) { if (showDialog) { let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING + - Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_CANCEL + + Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_CANCEL + Services.prompt.BUTTON_POS_1_DEFAULT; let buttonChoice = Services.prompt.confirmEx(window, @@ -336,8 +117,9 @@ var gSyncPane = { null, null, null, {}); // If the user selects cancel, just bail - if (buttonChoice == 1) + if (buttonChoice == 1) { return; + } } Weave.Service.startOver(); @@ -345,33 +127,19 @@ var gSyncPane = { }, updatePass: function () { - if (Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) + if (Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) { gSyncUtils.changePassword(); - else + } else { gSyncUtils.updatePassphrase(); + } }, resetPass: function () { - if (Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) + if (Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) { gSyncUtils.resetPassword(); - else + } else { gSyncUtils.resetPassphrase(); - }, - - _getEntryPoint: function () { - let params = new URLSearchParams(document.URL.split("#")[0].split("?")[1] || ""); - return params.get("entrypoint") || "preferences"; - }, - - _openAboutAccounts: function(action) { - let entryPoint = this._getEntryPoint(); - let params = new URLSearchParams(); - if (action) { - params.set("action", action); } - params.set("entrypoint", entryPoint); - - this.replaceTabWithUrl("about:accounts?" + params); }, /** @@ -384,163 +152,16 @@ var gSyncPane = { * "reset" -- reset sync */ openSetup: function (wizardType) { - let service = Components.classes["@mozilla.org/weave/service;1"] - .getService(Components.interfaces.nsISupports) - .wrappedJSObject; - - if (service.fxAccountsEnabled) { - this._openAboutAccounts(); + let win = Services.wm.getMostRecentWindow("Weave:AccountSetup"); + if (win) { + win.focus(); } else { - let win = Services.wm.getMostRecentWindow("Weave:AccountSetup"); - if (win) - win.focus(); - else { - window.openDialog("chrome://browser/content/sync/setup.xul", - "weaveSetup", "centerscreen,chrome,resizable=no", - wizardType); - } - } - }, - - openContentInBrowser: function(url, options) { - let win = Services.wm.getMostRecentWindow("navigator:browser"); - if (!win) { - // no window to use, so use _openLink to create a new one. We don't - // always use that as it prefers to open a new window rather than use - // an existing one. - gSyncUtils._openLink(url); - return; - } - win.switchToTabHavingURI(url, true, options); - }, - - // Replace the current tab with the specified URL. - replaceTabWithUrl(url) { - // Get the <browser> element hosting us. - let browser = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .chromeEventHandler; - // And tell it to load our URL. - browser.loadURI(url); - }, - - signUp: function() { - this._openAboutAccounts("signup"); - }, - - signIn: function() { - this._openAboutAccounts("signin"); - }, - - reSignIn: function() { - this._openAboutAccounts("reauth"); - }, - - - clickOrSpaceOrEnterPressed: function(event) { - // Note: charCode is deprecated, but 'char' not yet implemented. - // Replace charCode with char when implemented, see Bug 680830 - return ((event.type == "click" && event.button == 0) || - (event.type == "keypress" && - (event.charCode == KeyEvent.DOM_VK_SPACE || event.keyCode == KeyEvent.DOM_VK_RETURN))); - }, - - openChangeProfileImage: function(event) { - if (this.clickOrSpaceOrEnterPressed(event)) { - fxAccounts.promiseAccountsChangeProfileURI(this._getEntryPoint(), "avatar") - .then(url => { - this.openContentInBrowser(url, { - replaceQueryString: true - }); - }); - // Prevent page from scrolling on the space key. - event.preventDefault(); + window.openDialog("chrome://browser/content/sync/setup.xul", + "weaveSetup", "centerscreen,chrome,resizable=no", + wizardType); } }, - openManageFirefoxAccount: function(event) { - if (this.clickOrSpaceOrEnterPressed(event)) { - this.manageFirefoxAccount(); - // Prevent page from scrolling on the space key. - event.preventDefault(); - } - }, - - manageFirefoxAccount: function() { - fxAccounts.promiseAccountsManageURI(this._getEntryPoint()) - .then(url => { - this.openContentInBrowser(url, { - replaceQueryString: true - }); - }); - }, - - verifyFirefoxAccount: function() { - let showVerifyNotification = (data) => { - let isError = !data; - let maybeNot = isError ? "Not" : ""; - let sb = this._accountsStringBundle; - let title = sb.GetStringFromName("verification" + maybeNot + "SentTitle"); - let email = !isError && data ? data.email : ""; - let body = sb.formatStringFromName("verification" + maybeNot + "SentBody", [email], 1); - new Notification(title, { body }) - } - - let onError = () => { - showVerifyNotification(); - }; - - let onSuccess = data => { - if (data) { - showVerifyNotification(data); - } else { - onError(); - } - }; - - fxAccounts.resendVerificationEmail() - .then(fxAccounts.getSignedInUser, onError) - .then(onSuccess, onError); - }, - - openOldSyncSupportPage: function() { - let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "old-sync"; - this.openContentInBrowser(url); - }, - - unlinkFirefoxAccount: function(confirm) { - if (confirm) { - // We use a string bundle shared with aboutAccounts. - let sb = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties"); - let disconnectLabel = sb.GetStringFromName("disconnect.label"); - let title = sb.GetStringFromName("disconnect.verify.title"); - let body = sb.GetStringFromName("disconnect.verify.bodyHeading") + - "\n\n" + - sb.GetStringFromName("disconnect.verify.bodyText"); - 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 factory = Cc["@mozilla.org/prompter;1"] - .getService(Ci.nsIPromptFactory); - let prompt = factory.getPrompt(window, Ci.nsIPrompt); - let bag = prompt.QueryInterface(Ci.nsIWritablePropertyBag2); - bag.setPropertyAsBool("allowTabModal", true); - - let pressed = prompt.confirmEx(title, body, buttonFlags, - disconnectLabel, null, null, null, {}); - - if (pressed != 0) { // 0 is the "continue" button - return; - } - } - fxAccounts.signOut().then(() => { - this.updateWeavePrefs(); - }); - }, - openQuotaDialog: function () { let win = Services.wm.getMostRecentWindow("Sync:ViewQuota"); if (win) { @@ -552,27 +173,21 @@ var gSyncPane = { }, openAddDevice: function () { - if (!Weave.Utils.ensureMPUnlocked()) + if (!Weave.Utils.ensureMPUnlocked()) { return; + } let win = Services.wm.getMostRecentWindow("Sync:AddDevice"); - if (win) + if (win) { win.focus(); - else + } else { window.openDialog("chrome://browser/content/sync/addDevice.xul", "syncAddDevice", "centerscreen,chrome,resizable=no"); + } }, resetSync: function () { this.openSetup("reset"); }, - - _populateComputerName(value) { - let textbox = document.getElementById("fxaSyncComputerName"); - if (!textbox.hasAttribute("placeholder")) { - textbox.setAttribute("placeholder", - Weave.Utils.getDefaultDeviceName()); - } - textbox.value = value; - }, }; + diff --git a/application/basilisk/components/preferences/in-content/sync.xul b/application/basilisk/components/preferences/in-content/sync.xul index cf0e81ca1..7ca075483 100644 --- a/application/basilisk/components/preferences/in-content/sync.xul +++ b/application/basilisk/components/preferences/in-content/sync.xul @@ -1,35 +1,22 @@ -# 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/. - -<!-- Sync panel --> - -<preferences id="syncEnginePrefs" hidden="true" data-category="paneSync"> - <preference id="engine.addons" - name="services.sync.engine.addons" - type="bool"/> - <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.prefs" - name="services.sync.engine.prefs" - type="bool"/> - <preference id="engine.passwords" - name="services.sync.engine.passwords" - type="bool"/> -</preferences> +<!-- 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/. --> <script type="application/javascript" src="chrome://browser/content/preferences/in-content/sync.js"/> <script type="application/javascript" src="chrome://browser/content/sync/utils.js"/> +<preferences> +<!-- <preference id="engine.addons" name="services.sync.engine.addons" type="bool"/> --> + <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.prefs" name="services.sync.engine.prefs" type="bool"/> + <preference id="engine.passwords" name="services.sync.engine.passwords" type="bool"/> +</preferences> + + <hbox id="header-sync" class="header" hidden="true" @@ -39,22 +26,19 @@ </hbox> <deck id="weavePrefsDeck" data-category="paneSync" hidden="true"> - <!-- These panels are for the "legacy" sync provider --> <vbox id="noAccount" align="center"> <spacer flex="1"/> <description id="syncDesc"> &weaveDesc.label; </description> <separator/> - <label id="noAccountSetup" class="text-link"> - &setupButton.label; - </label> - <vbox id="pairDevice"> - <separator/> - <label id="noAccountPair" class="text-link"> - &pairDevice.label; - </label> - </vbox> + <label class="text-link" + onclick="event.stopPropagation(); gSyncPane.openSetup(null);" + value="&setupButton.label;"/> + <separator/> + <label class="text-link" + onclick="event.stopPropagation(); gSyncPane.openSetup('pair');" + value="&pairDevice.label;"/> <spacer flex="3"/> </vbox> @@ -63,7 +47,7 @@ <!-- label is set to account name --> <caption id="accountCaption" align="center"> <image id="accountCaptionImage"/> - <label id="accountName"/> + <label id="accountName" value=""/> </caption> <hbox> @@ -71,28 +55,39 @@ label="&manageAccount.label;" accesskey="&manageAccount.accesskey;"> <menupopup> - <menuitem id="syncViewQuota" label="&viewQuota.label;" + <menuitem label="&viewQuota.label;" oncommand="gSyncPane.openQuotaDialog();"/> - <menuseparator/> - <menuitem id="syncChangePassword" label="&changePassword2.label;"/> - <menuitem id="syncResetPassphrase" label="&myRecoveryKey.label;"/> <menuseparator/> - <menuitem id="syncReset" label="&resetSync2.label;"/> + <menuitem label="&changePassword2.label;" + oncommand="gSyncUtils.changePassword();"/> + <menuitem label="&myRecoveryKey.label;" + oncommand="gSyncUtils.resetPassphrase();"/> + <menuseparator/> + <menuitem label="&resetSync2.label;" + oncommand="gSyncPane.resetSync();"/> </menupopup> </button> </hbox> <hbox> <label id="syncAddDeviceLabel" - class="text-link"> - &pairDevice.label; - </label> + class="text-link" + onclick="gSyncPane.openAddDevice(); return false;" + value="&pairDevice.label;"/> </hbox> <vbox> - <label>&syncMy.label;</label> + <label value="&syncMy.label;" /> <richlistbox id="syncEnginesList" - orient="vertical"> + orient="vertical" + onselect="if (this.selectedCount) this.clearSelection();"> + <!-- + <richlistitem> + <checkbox label="&engine.addons.label;" + accesskey="&engine.addons.accesskey;" + preference="engine.addons"/> + </richlistitem> + --> <richlistitem> <checkbox label="&engine.bookmarks.label;" accesskey="&engine.bookmarks.accesskey;" @@ -130,228 +125,42 @@ </columns> <rows> <row align="center"> - <label control="syncComputerName"> - &syncDeviceName.label; - </label> - <textbox id="syncComputerName"/> + <label value="&syncDeviceName.label;" + accesskey="&syncDeviceName.accesskey;" + control="syncComputerName"/> + <textbox id="syncComputerName" + onchange="gSyncUtils.changeName(this)"/> </row> </rows> </grid> <hbox> - <label id="unlinkDevice" class="text-link"> - &unlinkDevice.label; - </label> + <label class="text-link" + onclick="gSyncPane.startOver(true); return false;" + value="&unlinkDevice.label;"/> </hbox> </groupbox> - <vbox id="tosPP-normal"> - <label id="tosPP-normal-ToS" class="text-link"> - &prefs.tosLink.label; - </label> - <label id="tosPP-normal-PP" class="text-link"> - &prefs.ppLink.label; - </label> - </vbox> - </vbox> - - <vbox id="needsUpdate" align="center" pack="center"> - <hbox> - <label id="loginError"/> - <label id="loginErrorUpdatePass" class="text-link"> - &updatePass.label; - </label> - <label id="loginErrorResetPass" class="text-link"> - &resetPass.label; - </label> + <hbox id="tosPP" pack="center"> + <label class="text-link" + onclick="event.stopPropagation();gSyncUtils.openToS();" + value="&prefs.tosLink.label;"/> + <label class="text-link" + onclick="event.stopPropagation();gSyncUtils.openPrivacyPolicy();" + value="&prefs.ppLink.label;"/> </hbox> - <label id="loginErrorStartOver" class="text-link"> - &unlinkDevice.label; - </label> </vbox> - <!-- These panels are for the Firefox Accounts identity provider --> - <vbox id="noFxaAccount"> - <hbox> - <vbox id="fxaContentWrapper"> - <groupbox id="noFxaGroup"> - <vbox> - <label id="noFxaCaption">&signedOut.caption;</label> - <description id="noFxaDescription" flex="1">&signedOut.description;</description> - <hbox class="fxaAccountBox"> - <vbox> - <image class="fxaFirefoxLogo"/> - </vbox> - <vbox flex="1"> - <label id="signedOutAccountBoxTitle">&signedOut.accountBox.title;</label> - <hbox class="fxaAccountBoxButtons"> - <button id="noFxaSignUp" label="&signedOut.accountBox.create;" accesskey="&signedOut.accountBox.create.accesskey;"></button> - <button id="noFxaSignIn" label="&signedOut.accountBox.signin;" accesskey="&signedOut.accountBox.signin.accesskey;"></button> - </hbox> - </vbox> - </hbox> - </vbox> - </groupbox> - </vbox> - <vbox> - <image class="fxaSyncIllustration"/> - </vbox> - </hbox> - <label class="fxaMobilePromo"> - &mobilePromo3.start;<!-- We put these comments to avoid inserting white spaces - --><label id="fxaMobilePromo-android" - class="androidLink text-link"><!-- - -->&mobilePromo3.androidLink;</label><!-- - -->&mobilePromo3.iOSBefore;<!-- - --><label id="fxaMobilePromo-ios" - class="iOSLink text-link"><!-- - -->&mobilePromo3.iOSLink;</label><!-- - -->&mobilePromo3.end; - </label> - </vbox> - - <vbox id="hasFxaAccount"> + <vbox id="needsUpdate" align="center" pack="center"> <hbox> - <vbox id="fxaContentWrapper"> - <groupbox id="fxaGroup"> - <caption><label>&syncBrand.fxAccount.label;</label></caption> - <deck id="fxaLoginStatus"> - - <!-- logged in and verified and all is good --> - <hbox id="fxaLoginVerified" class="fxaAccountBox"> - <vbox align="center" pack="center"> - <image id="fxaProfileImage" class="actionable" - role="button" - onclick="gSyncPane.openChangeProfileImage(event);" hidden="true" - onkeypress="gSyncPane.openChangeProfileImage(event);" - tooltiptext="&profilePicture.tooltip;"/> - </vbox> - <vbox flex="1" pack="center"> - <label id="fxaDisplayName" hidden="true"/> - <label id="fxaEmailAddress1"/> - <hbox class="fxaAccountBoxButtons"> - <button id="fxaUnlinkButton" label="&disconnect.label;" accesskey="&disconnect.accesskey;"/> - <html:a id="verifiedManage" target="_blank" - accesskey="&verifiedManage.accesskey;" - onkeypress="gSyncPane.openManageFirefoxAccount(event);"><!-- - -->&verifiedManage.label;</html:a> - </hbox> - </vbox> - </hbox> - - <!-- logged in to an unverified account --> - <hbox id="fxaLoginUnverified" class="fxaAccountBox"> - <vbox> - <image id="fxaProfileImage"/> - </vbox> - <vbox flex="1"> - <hbox> - <vbox><image id="fxaLoginRejectedWarning"/></vbox> - <description flex="1"> - &signedInUnverified.beforename.label; - <label id="fxaEmailAddress2"/> - &signedInUnverified.aftername.label; - </description> - </hbox> - <hbox class="fxaAccountBoxButtons"> - <button id="verifyFxaAccount" accesskey="&verify.accesskey;">&verify.label;</button> - <button id="unverifiedUnlinkFxaAccount" accesskey="&forget.accesskey;">&forget.label;</button> - </hbox> - </vbox> - </hbox> - - <!-- logged in locally but server rejected credentials --> - <hbox id="fxaLoginRejected" class="fxaAccountBox"> - <vbox> - <image id="fxaProfileImage"/> - </vbox> - <vbox flex="1"> - <hbox> - <vbox><image id="fxaLoginRejectedWarning"/></vbox> - <description flex="1"> - &signedInLoginFailure.beforename.label; - <label id="fxaEmailAddress3"/> - &signedInLoginFailure.aftername.label; - </description> - </hbox> - <hbox class="fxaAccountBoxButtons"> - <button id="rejectReSignIn" accessky="&signIn.accesskey;">&signIn.label;</button> - <button id="rejectUnlinkFxaAccount" accesskey="&forget.accesskey;">&forget.label;</button> - </hbox> - </vbox> - </hbox> - </deck> - </groupbox> - <groupbox id="syncOptions"> - <caption><label>&signedIn.engines.label;</label></caption> - <hbox id="fxaSyncEngines"> - <vbox align="start" flex="1"> - <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"/> - </vbox> - <vbox align="start" flex="1"> - <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> - <spacer/> - </hbox> - </groupbox> - </vbox> - <vbox> - <image class="fxaSyncIllustration"/> - </vbox> + <label id="loginError" value=""/> + <label class="text-link" + onclick="gSyncPane.updatePass(); return false;" + value="&updatePass.label;"/> + <label class="text-link" + onclick="gSyncPane.resetPass(); return false;" + value="&resetPass.label;"/> </hbox> - <groupbox> - <caption> - <label control="fxaSyncComputerName"> - &fxaSyncDeviceName.label; - </label> - </caption> - <hbox id="fxaDeviceName"> - <textbox id="fxaSyncComputerName" disabled="true"/> - <hbox> - <button id="fxaChangeDeviceName" - label="&changeSyncDeviceName.label;" - accesskey="&changeSyncDeviceName.accesskey;"/> - <button id="fxaCancelChangeDeviceName" - label="&cancelChangeSyncDeviceName.label;" - accesskey="&cancelChangeSyncDeviceName.accesskey;" - hidden="true"/> - <button id="fxaSaveChangeDeviceName" - label="&saveChangeSyncDeviceName.label;" - accesskey="&saveChangeSyncDeviceName.accesskey;" - hidden="true"/> - </hbox> - </hbox> - </groupbox> - <label class="fxaMobilePromo"> - &mobilePromo3.start;<!-- We put these comments to avoid inserting white spaces - --><label class="androidLink text-link" id="fxaMobilePromo-android-hasFxaAccount"><!-- - -->&mobilePromo3.androidLink;</label><!-- - -->&mobilePromo3.iOSBefore;<!-- - --><label class="iOSLink text-link" id="fxaMobilePromo-ios-hasFxaAccount"><!-- - -->&mobilePromo3.iOSLink;</label><!-- - -->&mobilePromo3.end; - </label> - <vbox id="tosPP-small" align="start"> - <label id="tosPP-small-ToS" class="text-link"> - &prefs.tosLink.label; - </label> - <label id="tosPP-small-PP" class="text-link"> - &fxaPrivacyNotice.link.label; - </label> - </vbox> + <label class="text-link" + onclick="gSyncPane.startOver(true); return false;" + value="&unlinkDevice.label;"/> </vbox> </deck> diff --git a/application/basilisk/base/content/sync/aboutSyncTabs-bindings.xml b/application/basilisk/components/sync/aboutSyncTabs-bindings.xml index e6108209a..e6108209a 100644 --- a/application/basilisk/base/content/sync/aboutSyncTabs-bindings.xml +++ b/application/basilisk/components/sync/aboutSyncTabs-bindings.xml diff --git a/application/basilisk/base/content/sync/aboutSyncTabs.css b/application/basilisk/components/sync/aboutSyncTabs.css index 5a353175b..5a353175b 100644 --- a/application/basilisk/base/content/sync/aboutSyncTabs.css +++ b/application/basilisk/components/sync/aboutSyncTabs.css diff --git a/application/basilisk/base/content/sync/aboutSyncTabs.js b/application/basilisk/components/sync/aboutSyncTabs.js index f4bb607ea..410494b5b 100644 --- a/application/basilisk/base/content/sync/aboutSyncTabs.js +++ b/application/basilisk/components/sync/aboutSyncTabs.js @@ -11,14 +11,6 @@ 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, @@ -26,8 +18,6 @@ var RemoteTabViewer = { 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); @@ -36,14 +26,12 @@ var RemoteTabViewer = { 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) { + createItem: function(attrs) { let item = document.createElement("richlistitem"); - // Copy the attributes from the argument into the item. + // Copy the attributes from the argument into the item for (let attr in attrs) { item.setAttribute(attr, attrs[attr]); } @@ -55,7 +43,7 @@ var RemoteTabViewer = { return item; }, - filterTabs: function (event) { + filterTabs: function(event) { let val = event.target.value.toLowerCase(); let numTabs = this._tabsList.getRowCount(); let clientTabs = 0; @@ -65,7 +53,7 @@ var RemoteTabViewer = { let item = this._tabsList.getItemAtIndex(i); let hide = false; if (item.getAttribute("type") == "tab") { - if (!item.getAttribute("url").toLowerCase().includes(val) && + if (!item.getAttribute("url").toLowerCase().includes(val) && !item.getAttribute("title").toLowerCase().includes(val)) { hide = true; } else { @@ -88,10 +76,10 @@ var RemoteTabViewer = { } }, - openSelected: function () { + openSelected: function() { let items = this._tabsList.selectedItems; let urls = []; - for (let i = 0; i < items.length; i++) { + 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]); @@ -104,7 +92,7 @@ var RemoteTabViewer = { } }, - bookmarkSingleTab: function () { + bookmarkSingleTab: function() { let item = this._tabsList.selectedItems[0]; let uri = Weave.Utils.makeURI(item.getAttribute("url")); let title = item.getAttribute("title"); @@ -119,10 +107,10 @@ var RemoteTabViewer = { }, window.top); }, - bookmarkSelectedTabs: function () { + bookmarkSelectedTabs: function() { let items = this._tabsList.selectedItems; let URIs = []; - for (let i = 0; i < items.length; i++) { + 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) { @@ -157,7 +145,7 @@ var RemoteTabViewer = { _buildListRequested: false, - buildList: function (forceSync) { + buildList: function (force) { if (this._waitingForBuildList) { this._buildListRequested = true; return; @@ -168,37 +156,27 @@ var RemoteTabViewer = { this._clearTabList(); - if (Weave.Service.isLoggedIn) { - this._refetchTabs(forceSync); + if (Weave.Service.isLoggedIn && this._refetchTabs(force)) { this._generateWeaveTabList(); } else { - // XXXzpao We should say something about not being logged in & not having data + //XXXzpao We should say something about not being logged in & not having data // or tell the appropriate condition. (bug 583344) } - let complete = () => { + function 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. + // Clear out existing richlistitems let count = list.getRowCount(); if (count > 0) { for (let i = count - 1; i >= 0; i--) { @@ -214,7 +192,7 @@ var RemoteTabViewer = { let seenURLs = new Set(); let localURLs = engine.getOpenURLs(); - for (let [, client] of Object.entries(engine.getAllClients())) { + for (let [guid, client] in Iterator(engine.getAllClients())) { // Create the client node, but don't add it in-case we don't show any tabs let appendClient = true; @@ -248,37 +226,7 @@ var RemoteTabViewer = { } }, - _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) { + adjustContextMenu: function(event) { let mode = "all"; switch (this._tabsList.selectedItems.length) { case 0: @@ -303,7 +251,7 @@ var RemoteTabViewer = { } }, - _refetchTabs: function (force) { + _refetchTabs: function(force) { if (!force) { // Don't bother refetching tabs if we already did so recently let lastFetch = 0; @@ -320,40 +268,40 @@ var RemoteTabViewer = { } } - // Ask Sync to just do the tabs engine if it can. - Weave.Service.sync(["tabs"]); + // if Clients hasn't synced yet this session, we need to sync it as well. + if (Weave.Service.clientsEngine.lastSync == 0) { + Weave.Service.clientsEngine.sync(); + } + + // Force a sync only for the tabs engine + let engine = Weave.Service.engineManager.get("tabs"); + engine.lastModified = null; + engine.sync(); Services.prefs.setIntPref("services.sync.lastTabFetch", Math.floor(Date.now() / 1000)); return true; }, - observe: function (subject, topic, data) { + 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. + if (subject == "tabs") { this.buildList(false); } break; - case "cloudsync:tabs:update": - this.buildList(false); - break; } }, - handleClick: function (event) { + handleClick: function(event) { if (event.target.getAttribute("type") != "tab") { return; } + if (event.button == 1) { let url = event.target.getAttribute("url"); openUILink(url, event); @@ -362,3 +310,4 @@ var RemoteTabViewer = { } } } + diff --git a/application/basilisk/base/content/sync/aboutSyncTabs.xul b/application/basilisk/components/sync/aboutSyncTabs.xul index a4aa0032f..a4aa0032f 100644 --- a/application/basilisk/base/content/sync/aboutSyncTabs.xul +++ b/application/basilisk/components/sync/aboutSyncTabs.xul diff --git a/application/basilisk/base/content/sync/addDevice.js b/application/basilisk/components/sync/addDevice.js index 0390d4397..0390d4397 100644 --- a/application/basilisk/base/content/sync/addDevice.js +++ b/application/basilisk/components/sync/addDevice.js diff --git a/application/basilisk/base/content/sync/addDevice.xul b/application/basilisk/components/sync/addDevice.xul index 83c3b7b3c..f2371aad0 100644 --- a/application/basilisk/base/content/sync/addDevice.xul +++ b/application/basilisk/components/sync/addDevice.xul @@ -43,7 +43,7 @@ &pairDevice.dialog.description.label; <label class="text-link" value="&addDevice.showMeHow.label;" - href="https://services.mozilla.com/sync/help/add-device"/> + href="http://www.palemoon.org/sync/help/easy-setup.shtml"/> </description> <separator class="groove-thin"/> <description> diff --git a/application/basilisk/base/content/sync/genericChange.js b/application/basilisk/components/sync/genericChange.js index 51a74f1b1..df6639178 100644 --- a/application/basilisk/base/content/sync/genericChange.js +++ b/application/basilisk/components/sync/genericChange.js @@ -32,6 +32,7 @@ var Change = { onLoad: function Change_onLoad() { /* Load labels */ let introText = document.getElementById("introText"); + let introText2 = document.getElementById("introText2"); let warningText = document.getElementById("warningText"); // load some other elements & info from the window @@ -69,7 +70,6 @@ var Change = { 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); @@ -120,7 +120,7 @@ var Change = { _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; @@ -141,10 +141,11 @@ var Change = { case "UpdatePassphrase": case "ResetPassphrase": return this.doChangePassphrase(); + break; case "ChangePassword": return this.doChangePassword(); + break; } - return undefined; }, doGeneratePassphrase: function () { @@ -212,10 +213,10 @@ var Change = { [valid, errorString] = gSyncUtils.validatePassword(this._firstBox, this._secondBox); } else { - if (!this._updatingPassphrase) - return; - - valid = this._passphraseBox.value != ""; + //Pale Moon: Enforce minimum length of 8 for allowed custom passphrase + //and don't restrict it to "out of sync" situations only. People who + //go to this page generally know what they are doing ;) + valid = this._passphraseBox.value.length >= 8; } if (errorString == "") diff --git a/application/basilisk/base/content/sync/genericChange.xul b/application/basilisk/components/sync/genericChange.xul index db74a1b31..3c0b2cd6c 100644 --- a/application/basilisk/base/content/sync/genericChange.xul +++ b/application/basilisk/components/sync/genericChange.xul @@ -67,7 +67,7 @@ <label id="generatePassphraseButton" hidden="true" value="&syncGenerateNewKey.label;" - class="text-link" + class="text-link inline-link" onclick="event.stopPropagation(); Change.doGeneratePassphrase();"/> </hbox> @@ -105,7 +105,7 @@ <description> &existingRecoveryKey.description; <label class="text-link" - href="https://services.mozilla.com/sync/help/manual-setup"> + href="http://www.palemoon.org/sync/help/recoverykey.shtml"> &addDevice.showMeHow.label; </label> </description> diff --git a/application/basilisk/components/sync/jar.mn b/application/basilisk/components/sync/jar.mn new file mode 100644 index 000000000..3782038cd --- /dev/null +++ b/application/basilisk/components/sync/jar.mn @@ -0,0 +1,22 @@ +# 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/. + +browser.jar: + content/browser/sync/aboutSyncTabs.xul + content/browser/sync/aboutSyncTabs.js + content/browser/sync/aboutSyncTabs.css + content/browser/sync/aboutSyncTabs-bindings.xml + content/browser/sync/setup.xul + content/browser/sync/addDevice.js + content/browser/sync/addDevice.xul + content/browser/sync/setup.js + content/browser/sync/genericChange.xul + content/browser/sync/genericChange.js + content/browser/sync/key.xhtml + content/browser/sync/notification.xml + content/browser/sync/quota.xul + content/browser/sync/quota.js + content/browser/sync/utils.js + content/browser/sync/progress.js + content/browser/sync/progress.xhtml
\ No newline at end of file diff --git a/application/basilisk/base/content/sync/key.xhtml b/application/basilisk/components/sync/key.xhtml index 1363132e7..92abf0ee6 100644 --- a/application/basilisk/base/content/sync/key.xhtml +++ b/application/basilisk/components/sync/key.xhtml @@ -44,7 +44,7 @@ <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> +<p>&syncKey.findOutMore1.label;<a href="http://www.palemoon.org/sync/">http://www.palemoon.org/sync/</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; diff --git a/application/basilisk/components/syncedtabs/jar.mn b/application/basilisk/components/sync/moz.build index ba2b105a1..2d64d506c 100644 --- a/application/basilisk/components/syncedtabs/jar.mn +++ b/application/basilisk/components/sync/moz.build @@ -1,7 +1,8 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: # 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/. -browser.jar: - content/browser/syncedtabs/sidebar.xhtml - content/browser/syncedtabs/sidebar.js +JAR_MANIFESTS += ['jar.mn'] + diff --git a/application/basilisk/components/sync/notification.xml b/application/basilisk/components/sync/notification.xml new file mode 100644 index 000000000..8ac881e08 --- /dev/null +++ b/application/basilisk/components/sync/notification.xml @@ -0,0 +1,129 @@ +<?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/. --> + +<!DOCTYPE bindings [ +<!ENTITY % notificationDTD SYSTEM "chrome://global/locale/notification.dtd"> +%notificationDTD; +]> + +<bindings id="notificationBindings" + xmlns="http://www.mozilla.org/xbl" + xmlns:xbl="http://www.mozilla.org/xbl" + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + + <binding id="notificationbox" extends="chrome://global/content/bindings/notification.xml#notificationbox"> + <content> + <xul:vbox xbl:inherits="hidden=notificationshidden"> + <xul:spacer/> + <children includes="notification"/> + </xul:vbox> + <children/> + </content> + + <implementation> + <constructor><![CDATA[ + let temp = {}; + Cu.import("resource://services-common/observers.js", temp); + temp.Observers.add("weave:notification:added", this.onNotificationAdded, this); + temp.Observers.add("weave:notification:removed", this.onNotificationRemoved, this); + + for each (var notification in Weave.Notifications.notifications) + this._appendNotification(notification); + ]]></constructor> + + <destructor><![CDATA[ + let temp = {}; + Cu.import("resource://services-common/observers.js", temp); + temp.Observers.remove("weave:notification:added", this.onNotificationAdded, this); + temp.Observers.remove("weave:notification:removed", this.onNotificationRemoved, this); + ]]></destructor> + + <method name="onNotificationAdded"> + <parameter name="subject"/> + <parameter name="data"/> + <body><![CDATA[ + this._appendNotification(subject); + ]]></body> + </method> + + <method name="onNotificationRemoved"> + <parameter name="subject"/> + <parameter name="data"/> + <body><![CDATA[ + // If the view of the notification hasn't been removed yet, remove it. + var notifications = this.allNotifications; + for each (var notification in notifications) { + if (notification.notification == subject) { + notification.close(); + break; + } + } + ]]></body> + </method> + + <method name="_appendNotification"> + <parameter name="notification"/> + <body><![CDATA[ + var node = this.appendNotification(notification.description, + notification.title, + notification.iconURL, + notification.priority, + notification.buttons); + node.notification = notification; + ]]></body> + </method> + + </implementation> + </binding> + + <binding id="notification" extends="chrome://global/content/bindings/notification.xml#notification"> + <content> + <xul:hbox class="notification-inner outset" flex="1" xbl:inherits="type"> + <xul:toolbarbutton ondblclick="event.stopPropagation();" + class="messageCloseButton close-icon tabbable" + xbl:inherits="hidden=hideclose" + tooltiptext="&closeNotification.tooltip;" + oncommand="document.getBindingParent(this).close()"/> + <xul:hbox anonid="details" align="center" flex="1"> + <xul:image anonid="messageImage" class="messageImage" xbl:inherits="src=image,type"/> + <xul:description anonid="messageText" class="messageText" xbl:inherits="xbl:text=label"/> + + <!-- The children are the buttons defined by the notification. --> + <xul:hbox oncommand="document.getBindingParent(this)._doButtonCommand(event);"> + <children/> + </xul:hbox> + </xul:hbox> + </xul:hbox> + </content> + <implementation> + <!-- Note: this used to be a field, but for some reason it kept getting + - reset to its default value for TabNotification elements. + - As a property, that doesn't happen, even though the property stores + - its value in a JS property |_notification| that is not defined + - in XBL as a field or property. Maybe this is wrong, but it works. + --> + <property name="notification" + onget="return this._notification" + onset="this._notification = val; return val;"/> + <method name="close"> + <body><![CDATA[ + Weave.Notifications.remove(this.notification); + + // We should be able to call the base class's close method here + // to remove the notification element from the notification box, + // but we can't because of bug 373652, so instead we copied its code + // and execute it below. + var control = this.control; + if (control) + control.removeNotification(this); + else + this.hidden = true; + ]]></body> + </method> + </implementation> + </binding> + +</bindings> diff --git a/application/basilisk/components/sync/progress.js b/application/basilisk/components/sync/progress.js new file mode 100644 index 000000000..101160fa8 --- /dev/null +++ b/application/basilisk/components/sync/progress.js @@ -0,0 +1,71 @@ +/* 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 {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://services-sync/main.js"); + +var gProgressBar; +var gCounter = 0; + +function onLoad(event) { + Services.obs.addObserver(onEngineSync, "weave:engine:sync:finish", false); + Services.obs.addObserver(onEngineSync, "weave:engine:sync:error", false); + Services.obs.addObserver(onServiceSync, "weave:service:sync:finish", false); + Services.obs.addObserver(onServiceSync, "weave:service:sync:error", false); + + gProgressBar = document.getElementById('uploadProgressBar'); + + if (Services.prefs.getPrefType("services.sync.firstSync") != Ci.nsIPrefBranch.PREF_INVALID) { + gProgressBar.hidden = false; + } + else { + gProgressBar.hidden = true; + } +} + +function onUnload(event) { + cleanUpObservers(); +} + +function cleanUpObservers() { + try { + Services.obs.removeObserver(onEngineSync, "weave:engine:sync:finish"); + Services.obs.removeObserver(onEngineSync, "weave:engine:sync:error"); + Services.obs.removeObserver(onServiceSync, "weave:service:sync:finish"); + Services.obs.removeObserver(onServiceSync, "weave:service:sync:error"); + } + catch (e) { + // may be double called by unload & exit. Ignore. + } +} + +function onEngineSync(subject, topic, data) { + // The Clients engine syncs first. At this point we don't necessarily know + // yet how many engines will be enabled, so we'll ignore the Clients engine + // and evaluate how many engines are enabled when the first "real" engine + // syncs. + if (data == "clients") { + return; + } + + if (!gCounter && + Services.prefs.getPrefType("services.sync.firstSync") != Ci.nsIPrefBranch.PREF_INVALID) { + gProgressBar.max = Weave.Service.engineManager.getEnabled().length; + } + + gCounter += 1; + gProgressBar.setAttribute("value", gCounter); +} + +function onServiceSync(subject, topic, data) { + // To address the case where 0 engines are synced, we will fill the + // progress bar so the user knows that the sync has finished. + gProgressBar.setAttribute("value", gProgressBar.max); + cleanUpObservers(); +} + +function closeTab() { + window.close(); +} diff --git a/application/basilisk/components/sync/progress.xhtml b/application/basilisk/components/sync/progress.xhtml new file mode 100644 index 000000000..d403cb20d --- /dev/null +++ b/application/basilisk/components/sync/progress.xhtml @@ -0,0 +1,55 @@ +<?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 % syncProgressDTD + SYSTEM "chrome://browser/locale/syncProgress.dtd"> + %syncProgressDTD; + <!ENTITY % syncSetupDTD + SYSTEM "chrome://browser/locale/syncSetup.dtd"> + %syncSetupDTD; + <!ENTITY % globalDTD + SYSTEM "chrome://global/locale/global.dtd"> + %globalDTD; +]> + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>&syncProgress.pageTitle;</title> + + <link rel="stylesheet" type="text/css" media="all" + href="chrome://browser/skin/syncProgress.css"/> + + <link rel="icon" type="image/png" id="favicon" + href="chrome://browser/skin/sync-16.png"/> + + <script type="text/javascript;version=1.8" + src="chrome://browser/content/sync/progress.js"/> + </head> + <body onload="onLoad(event)" onunload="onUnload(event)" dir="&locale.dir;"> + <title>&setup.successPage.title;</title> + <div id="floatingBox" class="main-content"> + <div id="title"> + <h1>&setup.successPage.title;</h1> + </div> + <div id="successLogo"> + <img id="brandSyncLogo" src="chrome://browser/skin/sync-128.png" alt="&syncProgress.logoAltText;" /> + </div> + <div id="loadingText"> + <p id="blurb">&syncProgress.textBlurb; </p> + </div> + <div id="progressBar"> + <progress id="uploadProgressBar" value="0"/> + </div> + <div id="bottomRow"> + <button id="closeButton" onclick="closeTab()">&syncProgress.closeButton; </button> + </div> + </div> + </body> +</html> diff --git a/application/basilisk/base/content/sync/quota.js b/application/basilisk/components/sync/quota.js index b416a44cc..b416a44cc 100644 --- a/application/basilisk/base/content/sync/quota.js +++ b/application/basilisk/components/sync/quota.js diff --git a/application/basilisk/base/content/sync/quota.xul b/application/basilisk/components/sync/quota.xul index 99e6ed78b..99e6ed78b 100644 --- a/application/basilisk/base/content/sync/quota.xul +++ b/application/basilisk/components/sync/quota.xul diff --git a/application/basilisk/base/content/sync/setup.js b/application/basilisk/components/sync/setup.js index f9dae1bd4..e8d67a5f6 100644 --- a/application/basilisk/base/content/sync/setup.js +++ b/application/basilisk/components/sync/setup.js @@ -1,4 +1,3 @@ -// -*- 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/. */ @@ -51,9 +50,7 @@ var gSyncSetup = { server: false }, - get _remoteSites() { - return [Weave.Service.serverURL, RECAPTCHA_DOMAIN]; - }, + get _remoteSites() [Weave.Service.serverURL, RECAPTCHA_DOMAIN], get _usingMainServers() { if (this._settingUpNew) @@ -72,7 +69,7 @@ var gSyncSetup = { 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 + //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); @@ -81,7 +78,7 @@ var gSyncSetup = { }); }; addRem(true); - window.addEventListener("unload", () => addRem(false), false); + window.addEventListener("unload", function() addRem(false), false); window.setTimeout(function () { // Force Service to be loaded so that engines are registered. @@ -123,14 +120,14 @@ var gSyncSetup = { startNewAccountSetup: function () { if (!Weave.Utils.ensureMPUnlocked()) - return; + return false; this._settingUpNew = true; this.wizard.pageIndex = NEW_ACCOUNT_START_PAGE; }, useExistingAccount: function () { if (!Weave.Utils.ensureMPUnlocked()) - return; + return false; this._settingUpNew = false; if (this.wizardType == "pair") { // We're already pairing, so there's no point in pairing again. @@ -512,6 +509,7 @@ var gSyncSetup = { onWizardBack: function () { switch (this.wizard.pageIndex) { case NEW_ACCOUNT_START_PAGE: + case EXISTING_ACCOUNT_LOGIN_PAGE: this.wizard.pageIndex = INTRO_PAGE; return false; case EXISTING_ACCOUNT_CONNECT_PAGE: @@ -552,12 +550,19 @@ var gSyncSetup = { for (let i = 0;i < prefs.length;i++) { Weave.Svc.Prefs.set(prefs[i], isChecked(prefs[i])); } + + // XXX: Addons syncing is currently not operational; + // Make doubly-sure to always disable addons syncing pref + Weave.Svc.Prefs.set("engine.addons", false); + 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"); + + gSyncUtils.openFirstSyncProgressPage(); } Weave.Utils.nextTick(Weave.Service.sync, Weave.Service); window.close(); @@ -797,6 +802,7 @@ var gSyncSetup = { let el = document.getElementById("server"); let valid = false; let feedback = document.getElementById("serverFeedbackRow"); + let str = ""; if (el.value) { valid = this._validateServer(el); let str = valid ? "" : "serverInvalid.label"; @@ -932,7 +938,12 @@ var gSyncSetup = { 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; + let blessedcount = 0; + for each (let i in ids) { + if (i) { + blessedcount++; + } + } // bug 600141 does not apply, as this does not have to support existing strings document.getElementById("addonCount").value = PluralForm.get(blessedcount, @@ -956,7 +967,7 @@ var gSyncSetup = { box.appendChild(node); } - for (let name of Weave.Service.clientsEngine.stats.names) { + for each (let name in Weave.Service.clientsEngine.stats.names) { // Don't list the current client if (name == Weave.Service.clientsEngine.localName) continue; @@ -998,7 +1009,7 @@ var gSyncSetup = { if (string) { try { str = this._stringBundle.GetStringFromName(string); - } catch (e) {} + } catch(e) {} if (!str) str = Weave.Utils.getErrorString(string); @@ -1027,7 +1038,7 @@ var gSyncSetup = { // 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 + //XXX TODO we should really log any responseStatus other than 200 }, onProgressChange: function() {}, onStatusChange: function() {}, diff --git a/application/basilisk/base/content/sync/setup.xul b/application/basilisk/components/sync/setup.xul index 11c085931..cf2cc77e4 100644 --- a/application/basilisk/base/content/sync/setup.xul +++ b/application/basilisk/components/sync/setup.xul @@ -43,7 +43,7 @@ &pairDevice.dialog.description.label; <label class="text-link" value="&addDevice.showMeHow.label;" - href="https://services.mozilla.com/sync/help/add-device"/> + href="http://www.palemoon.org/sync/help/easy-setup.shtml"/> </description> <separator class="groove-thin"/> <description> @@ -183,12 +183,12 @@ onclick="document.getElementById('tos').focus(); document.getElementById('tos').click()"> &setup.tosAgree1.label; - <label class="text-link" + <label class="text-link inline-link" onclick="event.stopPropagation();gSyncUtils.openToS();"> &setup.tosLink.label; </label> &setup.tosAgree2.label; - <label class="text-link" + <label class="text-link inline-link" onclick="event.stopPropagation();gSyncUtils.openPrivacyPolicy();"> &setup.ppLink.label; </label> @@ -221,7 +221,7 @@ &pairDevice.setup.description.label; <label class="text-link" value="&addDevice.showMeHow.label;" - href="https://services.mozilla.com/sync/help/easy-setup"/> + href="http://www.palemoon.org/sync/help/easy-setup.shtml"/> </description> <label value="&addDevice.setup.enterCode.label;" control="easySetupPIN1"/> @@ -340,7 +340,7 @@ <description> &existingRecoveryKey.description; <label class="text-link" - href="https://services.mozilla.com/sync/help/manual-setup"> + href="http://www.palemoon.org/sync/help/recoverykey.shtml"> &addDevice.showMeHow.label; </label> <spacer id="passphraseHelpSpacer"/> @@ -359,7 +359,7 @@ <grid> <columns> <column/> - <column flex="1" style="margin-inline-end: 2px"/> + <column flex="1" style="-moz-margin-end: 2px"/> </columns> <rows> <row align="center"> @@ -375,7 +375,8 @@ <checkbox label="&engine.addons.label;" accesskey="&engine.addons.accesskey;" id="engine.addons" - checked="true"/> + checked="false" + hidden="true"/> <checkbox label="&engine.bookmarks.label;" accesskey="&engine.bookmarks.accesskey;" id="engine.bookmarks" diff --git a/application/basilisk/base/content/sync/utils.js b/application/basilisk/components/sync/utils.js index 92981f7b4..d41ecf18a 100644 --- a/application/basilisk/base/content/sync/utils.js +++ b/application/basilisk/components/sync/utils.js @@ -14,13 +14,6 @@ var gSyncUtils = { 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, @@ -77,22 +70,16 @@ var gSyncUtils = { 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); + this._openLink(Weave.Svc.Prefs.get("termsURL")); }, - get privacyPolicyURL() { - let root = this.fxAccountsEnabled ? "fxa." : ""; - return Weave.Svc.Prefs.get(root + "privacyURL"); + openPrivacyPolicy: function () { + this._openLink(Weave.Svc.Prefs.get("privacyURL")); }, - openPrivacyPolicy: function () { - this._openLink(this.privacyPolicyURL); + openFirstSyncProgressPage: function () { + this._openLink("about:sync-progress"); }, /** @@ -134,7 +121,7 @@ var gSyncUtils = { /** * Print passphrase backup document. - * + * * @param elid : ID of the form element containing the passphrase. */ passphrasePrint: function(elid) { @@ -162,7 +149,7 @@ var gSyncUtils = { /** * Save passphrase backup document to disk as HTML file. - * + * * @param elid : ID of the form element containing the passphrase. */ passphraseSave: function(elid) { @@ -200,7 +187,7 @@ var gSyncUtils = { * * @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) { diff --git a/application/basilisk/components/syncedtabs/EventEmitter.jsm b/application/basilisk/components/syncedtabs/EventEmitter.jsm deleted file mode 100644 index ec3225f0f..000000000 --- a/application/basilisk/components/syncedtabs/EventEmitter.jsm +++ /dev/null @@ -1,45 +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"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -this.EXPORTED_SYMBOLS = [ - "EventEmitter" -]; - -// Simple event emitter abstraction for storage objects to use. -function EventEmitter () { - this._events = new Map(); -} - -EventEmitter.prototype = { - on(event, listener) { - if (this._events.has(event)) { - this._events.get(event).add(listener); - } else { - this._events.set(event, new Set([listener])); - } - }, - off(event, listener) { - if (!this._events.has(event)) { - return; - } - this._events.get(event).delete(listener); - }, - emit(event, ...args) { - if (!this._events.has(event)) { - return; - } - for (let listener of this._events.get(event).values()) { - try { - listener.apply(this, args); - } catch (e) { - Cu.reportError(e); - } - } - }, -}; - diff --git a/application/basilisk/components/syncedtabs/SyncedTabsDeckComponent.js b/application/basilisk/components/syncedtabs/SyncedTabsDeckComponent.js deleted file mode 100644 index c35277795..000000000 --- a/application/basilisk/components/syncedtabs/SyncedTabsDeckComponent.js +++ /dev/null @@ -1,169 +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"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -Cu.import("resource:///modules/syncedtabs/SyncedTabsDeckStore.js"); -Cu.import("resource:///modules/syncedtabs/SyncedTabsDeckView.js"); -Cu.import("resource:///modules/syncedtabs/SyncedTabsListStore.js"); -Cu.import("resource:///modules/syncedtabs/TabListComponent.js"); -Cu.import("resource:///modules/syncedtabs/TabListView.js"); -let { getChromeWindow } = Cu.import("resource:///modules/syncedtabs/util.js", {}); - -XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () { - return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {}); -}); - -let log = Cu.import("resource://gre/modules/Log.jsm", {}) - .Log.repository.getLogger("Sync.RemoteTabs"); - -this.EXPORTED_SYMBOLS = [ - "SyncedTabsDeckComponent" -]; - -/* SyncedTabsDeckComponent - * This component instantiates views and storage objects as well as defines - * behaviors that will be passed down to the views. This helps keep the views - * isolated and easier to test. - */ - -function SyncedTabsDeckComponent({ - window, SyncedTabs, fxAccounts, deckStore, listStore, listComponent, DeckView, getChromeWindowMock, -}) { - this._window = window; - this._SyncedTabs = SyncedTabs; - this._fxAccounts = fxAccounts; - this._DeckView = DeckView || SyncedTabsDeckView; - // used to stub during tests - this._getChromeWindow = getChromeWindowMock || getChromeWindow; - - this._deckStore = deckStore || new SyncedTabsDeckStore(); - this._syncedTabsListStore = listStore || new SyncedTabsListStore(SyncedTabs); - this.tabListComponent = listComponent || new TabListComponent({ - window: this._window, - store: this._syncedTabsListStore, - View: TabListView, - SyncedTabs: SyncedTabs, - clipboardHelper: Cc["@mozilla.org/widget/clipboardhelper;1"] - .getService(Ci.nsIClipboardHelper), - getChromeWindow: this._getChromeWindow, - }); -} - -SyncedTabsDeckComponent.prototype = { - PANELS: { - TABS_CONTAINER: "tabs-container", - TABS_FETCHING: "tabs-fetching", - NOT_AUTHED_INFO: "notAuthedInfo", - SINGLE_DEVICE_INFO: "singleDeviceInfo", - TABS_DISABLED: "tabs-disabled", - }, - - get container() { - return this._deckView ? this._deckView.container : null; - }, - - init() { - Services.obs.addObserver(this, this._SyncedTabs.TOPIC_TABS_CHANGED, false); - Services.obs.addObserver(this, FxAccountsCommon.ONLOGIN_NOTIFICATION, false); - - // Go ahead and trigger sync - this._SyncedTabs.syncTabs() - .catch(Cu.reportError); - - this._deckView = new this._DeckView(this._window, this.tabListComponent, { - onAndroidClick: event => this.openAndroidLink(event), - oniOSClick: event => this.openiOSLink(event), - onSyncPrefClick: event => this.openSyncPrefs(event) - }); - - this._deckStore.on("change", state => this._deckView.render(state)); - // Trigger the initial rendering of the deck view - // Object.values only in nightly - this._deckStore.setPanels(Object.keys(this.PANELS).map(k => this.PANELS[k])); - // Set the initial panel to display - this.updatePanel(); - }, - - uninit() { - Services.obs.removeObserver(this, this._SyncedTabs.TOPIC_TABS_CHANGED); - Services.obs.removeObserver(this, FxAccountsCommon.ONLOGIN_NOTIFICATION); - this._deckView.destroy(); - }, - - observe(subject, topic, data) { - switch (topic) { - case this._SyncedTabs.TOPIC_TABS_CHANGED: - this._syncedTabsListStore.getData(); - this.updatePanel(); - break; - case FxAccountsCommon.ONLOGIN_NOTIFICATION: - this.updatePanel(); - break; - default: - break; - } - }, - - // There's no good way to mock fxAccounts in browser tests where it's already - // been instantiated, so we have this method for stubbing. - _accountStatus() { - return this._fxAccounts.accountStatus(); - }, - - getPanelStatus() { - return this._accountStatus().then(exists => { - if (!exists) { - return this.PANELS.NOT_AUTHED_INFO; - } - if (!this._SyncedTabs.isConfiguredToSyncTabs) { - return this.PANELS.TABS_DISABLED; - } - if (!this._SyncedTabs.hasSyncedThisSession) { - return this.PANELS.TABS_FETCHING; - } - return this._SyncedTabs.getTabClients().then(clients => { - if (clients.length) { - return this.PANELS.TABS_CONTAINER; - } - return this.PANELS.SINGLE_DEVICE_INFO; - }); - }) - .catch(err => { - Cu.reportError(err); - return this.PANELS.NOT_AUTHED_INFO; - }); - }, - - updatePanel() { - // return promise for tests - return this.getPanelStatus() - .then(panelId => this._deckStore.selectPanel(panelId)) - .catch(Cu.reportError); - }, - - openAndroidLink(event) { - let href = Services.prefs.getCharPref("identity.mobilepromo.android") + "synced-tabs-sidebar"; - this._openUrl(href, event); - }, - - openiOSLink(event) { - let href = Services.prefs.getCharPref("identity.mobilepromo.ios") + "synced-tabs-sidebar"; - this._openUrl(href, event); - }, - - _openUrl(url, event) { - this._window.openUILink(url, event); - }, - - openSyncPrefs() { - this._getChromeWindow(this._window).gSyncUI.openSetup(null, "tabs-sidebar"); - } -}; - diff --git a/application/basilisk/components/syncedtabs/SyncedTabsDeckStore.js b/application/basilisk/components/syncedtabs/SyncedTabsDeckStore.js deleted file mode 100644 index ede6914c8..000000000 --- a/application/basilisk/components/syncedtabs/SyncedTabsDeckStore.js +++ /dev/null @@ -1,60 +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"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -let { EventEmitter } = Cu.import("resource:///modules/syncedtabs/EventEmitter.jsm", {}); - -this.EXPORTED_SYMBOLS = [ - "SyncedTabsDeckStore" -]; - -/** - * SyncedTabsDeckStore - * - * This store keeps track of the deck view state, including the panels and which - * one is selected. The view listens for change events on the store, which are - * triggered whenever the state changes. If it's a small change, the state - * will have `isUpdatable` set to true so the view can skip rerendering the whole - * DOM. - */ -function SyncedTabsDeckStore() { - EventEmitter.call(this); - this._panels = []; -} - -Object.assign(SyncedTabsDeckStore.prototype, EventEmitter.prototype, { - _change(isUpdatable = false) { - let panels = this._panels.map(panel => { - return {id: panel, selected: panel === this._selectedPanel}; - }); - this.emit("change", {panels, isUpdatable: isUpdatable}); - }, - - /** - * Sets the selected panelId and triggers a change event. - * @param {String} panelId - ID of the panel to select. - */ - selectPanel(panelId) { - if (this._panels.indexOf(panelId) === -1 || this._selectedPanel === panelId) { - return; - } - this._selectedPanel = panelId; - this._change(true); - }, - - /** - * Update the set of panels in the deck and trigger a change event. - * @param {Array} panels - an array of IDs for each panel in the deck. - */ - setPanels(panels) { - if (panels === this._panels) { - return; - } - this._panels = panels || []; - this._change(); - } -}); diff --git a/application/basilisk/components/syncedtabs/SyncedTabsDeckView.js b/application/basilisk/components/syncedtabs/SyncedTabsDeckView.js deleted file mode 100644 index e9efff323..000000000 --- a/application/basilisk/components/syncedtabs/SyncedTabsDeckView.js +++ /dev/null @@ -1,116 +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"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -let { getChromeWindow } = Cu.import("resource:///modules/syncedtabs/util.js", {}); - -let log = Cu.import("resource://gre/modules/Log.jsm", {}) - .Log.repository.getLogger("Sync.RemoteTabs"); - -this.EXPORTED_SYMBOLS = [ - "SyncedTabsDeckView" -]; - -/** - * SyncedTabsDeckView - * - * Instances of SyncedTabsDeckView render DOM nodes from a given state. - * No state is kept internaly and the DOM will completely - * rerender unless the state flags `isUpdatable`, which helps - * make small changes without the overhead of a full rerender. - */ -const SyncedTabsDeckView = function (window, tabListComponent, props) { - this.props = props; - - this._window = window; - this._doc = window.document; - - this._tabListComponent = tabListComponent; - this._deckTemplate = this._doc.getElementById("deck-template"); - this.container = this._doc.createElement("div"); -}; - -SyncedTabsDeckView.prototype = { - render(state) { - if (state.isUpdatable) { - this.update(state); - } else { - this.create(state); - } - }, - - create(state) { - let deck = this._doc.importNode(this._deckTemplate.content, true).firstElementChild; - this._clearChilden(); - - let tabListWrapper = this._doc.createElement("div"); - tabListWrapper.className = "tabs-container sync-state"; - this._tabListComponent.init(); - tabListWrapper.appendChild(this._tabListComponent.container); - deck.appendChild(tabListWrapper); - this.container.appendChild(deck); - - this._generateDevicePromo(); - - this._attachListeners(); - this.update(state); - }, - - _getBrowserBundle() { - return getChromeWindow(this._window).document.getElementById("bundle_browser"); - }, - - _generateDevicePromo() { - let bundle = this._getBrowserBundle(); - let formatArgs = ["android", "ios"].map(os => { - let link = this._doc.createElement("a"); - link.textContent = bundle.getString(`appMenuRemoteTabs.mobilePromo.${os}`); - link.className = `${os}-link text-link`; - link.setAttribute("href", "#"); - return link.outerHTML; - }); - // Put it all together... - let contents = bundle.getFormattedString("appMenuRemoteTabs.mobilePromo.text2", formatArgs); - this.container.querySelector(".device-promo").innerHTML = contents; - }, - - destroy() { - this._tabListComponent.uninit(); - this.container.remove(); - }, - - update(state) { - // Note that we may also want to update elements that are outside of the - // deck, so use the document to find the class names rather than our - // container. - for (let panel of state.panels) { - if (panel.selected) { - Array.prototype.map.call(this._doc.getElementsByClassName(panel.id), - item => item.classList.add("selected")); - } else { - Array.prototype.map.call(this._doc.getElementsByClassName(panel.id), - item => item.classList.remove("selected")); - } - } - }, - - _clearChilden() { - while (this.container.firstChild) { - this.container.removeChild(this.container.firstChild); - } - }, - - _attachListeners() { - this.container.querySelector(".android-link").addEventListener("click", this.props.onAndroidClick); - this.container.querySelector(".ios-link").addEventListener("click", this.props.oniOSClick); - let syncPrefLinks = this.container.querySelectorAll(".sync-prefs"); - for (let link of syncPrefLinks) { - link.addEventListener("click", this.props.onSyncPrefClick); - } - }, -}; - diff --git a/application/basilisk/components/syncedtabs/SyncedTabsListStore.js b/application/basilisk/components/syncedtabs/SyncedTabsListStore.js deleted file mode 100644 index 8f03d9a89..000000000 --- a/application/basilisk/components/syncedtabs/SyncedTabsListStore.js +++ /dev/null @@ -1,235 +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"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -let { EventEmitter } = Cu.import("resource:///modules/syncedtabs/EventEmitter.jsm", {}); - -this.EXPORTED_SYMBOLS = [ - "SyncedTabsListStore" -]; - -/** - * SyncedTabsListStore - * - * Instances of this store encapsulate all of the state associated with a synced tabs list view. - * The state includes the clients, their tabs, the row that is currently selected, - * and the filtered query. - */ -function SyncedTabsListStore(SyncedTabs) { - EventEmitter.call(this); - this._SyncedTabs = SyncedTabs; - this.data = []; - this._closedClients = {}; - this._selectedRow = [-1, -1]; - this.filter = ""; - this.inputFocused = false; -} - -Object.assign(SyncedTabsListStore.prototype, EventEmitter.prototype, { - // This internal method triggers the "change" event that views - // listen for. It denormalizes the state so that it's easier for - // the view to deal with. updateType hints to the view what - // actually needs to be rerendered or just updated, and can be - // empty (to (re)render everything), "searchbox" (to rerender just the tab list), - // or "all" (to skip rendering and just update all attributes of existing nodes). - _change(updateType) { - let selectedParent = this._selectedRow[0]; - let selectedChild = this._selectedRow[1]; - let rowSelected = false; - // clone the data so that consumers can't mutate internal storage - let data = Cu.cloneInto(this.data, {}); - let tabCount = 0; - - data.forEach((client, index) => { - client.closed = !!this._closedClients[client.id]; - - if (rowSelected || selectedParent < 0) { - return; - } - if (this.filter) { - if (selectedParent < tabCount + client.tabs.length) { - client.tabs[selectedParent - tabCount].selected = true; - client.tabs[selectedParent - tabCount].focused = !this.inputFocused; - rowSelected = true; - } else { - tabCount += client.tabs.length; - } - return; - } - if (selectedParent === index && selectedChild === -1) { - client.selected = true; - client.focused = !this.inputFocused; - rowSelected = true; - } else if (selectedParent === index) { - client.tabs[selectedChild].selected = true; - client.tabs[selectedChild].focused = !this.inputFocused; - rowSelected = true; - } - }); - - // If this were React the view would be smart enough - // to not re-render the whole list unless necessary. But it's - // not, so updateType is a hint to the view of what actually - // needs to be rerendered. - this.emit("change", { - clients: data, - canUpdateAll: updateType === "all", - canUpdateInput: updateType === "searchbox", - filter: this.filter, - inputFocused: this.inputFocused - }); - }, - - /** - * Moves the row selection from a child to its parent, - * which occurs when the parent of a selected row closes. - */ - _selectParentRow() { - this._selectedRow[1] = -1; - }, - - _toggleBranch(id, closed) { - this._closedClients[id] = closed; - if (this._closedClients[id]) { - this._selectParentRow(); - } - this._change("all"); - }, - - _isOpen(client) { - return !this._closedClients[client.id]; - }, - - moveSelectionDown() { - let branchRow = this._selectedRow[0]; - let childRow = this._selectedRow[1]; - let branch = this.data[branchRow]; - - if (this.filter) { - this.selectRow(branchRow + 1); - return; - } - - if (branchRow < 0) { - this.selectRow(0, -1); - } else if ((!branch.tabs.length || childRow >= branch.tabs.length - 1 || !this._isOpen(branch)) && branchRow < this.data.length) { - this.selectRow(branchRow + 1, -1); - } else if (childRow < branch.tabs.length) { - this.selectRow(branchRow, childRow + 1); - } - }, - - moveSelectionUp() { - let branchRow = this._selectedRow[0]; - let childRow = this._selectedRow[1]; - - if (this.filter) { - this.selectRow(branchRow - 1); - return; - } - - if (branchRow < 0) { - this.selectRow(0, -1); - } else if (childRow < 0 && branchRow > 0) { - let prevBranch = this.data[branchRow - 1]; - let newChildRow = this._isOpen(prevBranch) ? prevBranch.tabs.length - 1 : -1; - this.selectRow(branchRow - 1, newChildRow); - } else if (childRow >= 0) { - this.selectRow(branchRow, childRow - 1); - } - }, - - // Selects a row and makes sure the selection is within bounds - selectRow(parent, child) { - let maxParentRow = this.filter ? this._tabCount() : this.data.length; - let parentRow = parent; - if (parent <= -1) { - parentRow = 0; - } else if (parent >= maxParentRow) { - return; - } - - let childRow = child; - if (parentRow === -1 || this.filter || typeof child === "undefined" || child < -1) { - childRow = -1; - } else if (child >= this.data[parentRow].tabs.length) { - childRow = this.data[parentRow].tabs.length - 1; - } - - if (this._selectedRow[0] === parentRow && this._selectedRow[1] === childRow) { - return; - } - - this._selectedRow = [parentRow, childRow]; - this.inputFocused = false; - this._change("all"); - }, - - _tabCount() { - return this.data.reduce((prev, curr) => curr.tabs.length + prev, 0); - }, - - toggleBranch(id) { - this._toggleBranch(id, !this._closedClients[id]); - }, - - closeBranch(id) { - this._toggleBranch(id, true); - }, - - openBranch(id) { - this._toggleBranch(id, false); - }, - - focusInput() { - this.inputFocused = true; - // A change type of "all" updates rather than rebuilds, which is what we - // want here - only the selection/focus has changed. - this._change("all"); - }, - - blurInput() { - this.inputFocused = false; - // A change type of "all" updates rather than rebuilds, which is what we - // want here - only the selection/focus has changed. - this._change("all"); - }, - - clearFilter() { - this.filter = ""; - this._selectedRow = [-1, -1]; - return this.getData(); - }, - - // Fetches data from the SyncedTabs module and triggers - // and update - getData(filter) { - let updateType; - let hasFilter = typeof filter !== "undefined"; - if (hasFilter) { - this.filter = filter; - this._selectedRow = [-1, -1]; - - // When a filter is specified we tell the view that only the list - // needs to be rerendered so that it doesn't disrupt the input - // field's focus. - updateType = "searchbox"; - } - - // return promise for tests - return this._SyncedTabs.getTabClients(this.filter) - .then(result => { - if (!hasFilter) { - // Only sort clients and tabs if we're rendering the whole list. - this._SyncedTabs.sortTabClientsByLastUsed(result); - } - this.data = result; - this._change(updateType); - }) - .catch(Cu.reportError); - } -}); diff --git a/application/basilisk/components/syncedtabs/TabListComponent.js b/application/basilisk/components/syncedtabs/TabListComponent.js deleted file mode 100644 index aa60e4769..000000000 --- a/application/basilisk/components/syncedtabs/TabListComponent.js +++ /dev/null @@ -1,138 +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"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -let log = Cu.import("resource://gre/modules/Log.jsm", {}) - .Log.repository.getLogger("Sync.RemoteTabs"); - -XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils", - "resource:///modules/PlacesUIUtils.jsm"); - -this.EXPORTED_SYMBOLS = [ - "TabListComponent" -]; - -/** - * TabListComponent - * - * The purpose of this component is to compose the view, state, and actions. - * It defines high level actions that act on the state and passes them to the - * view for it to trigger during user interaction. It also subscribes the view - * to state changes so it can rerender. - */ - -function TabListComponent({window, store, View, SyncedTabs, clipboardHelper, - getChromeWindow}) { - this._window = window; - this._store = store; - this._View = View; - this._clipboardHelper = clipboardHelper; - this._getChromeWindow = getChromeWindow; - // used to trigger Sync from context menu - this._SyncedTabs = SyncedTabs; -} - -TabListComponent.prototype = { - get container() { - return this._view.container; - }, - - init() { - log.debug("Initializing TabListComponent"); - - this._view = new this._View(this._window, { - onSelectRow: (...args) => this.onSelectRow(...args), - onOpenTab: (...args) => this.onOpenTab(...args), - onOpenTabs: (...args) => this.onOpenTabs(...args), - onMoveSelectionDown: (...args) => this.onMoveSelectionDown(...args), - onMoveSelectionUp: (...args) => this.onMoveSelectionUp(...args), - onToggleBranch: (...args) => this.onToggleBranch(...args), - onBookmarkTab: (...args) => this.onBookmarkTab(...args), - onCopyTabLocation: (...args) => this.onCopyTabLocation(...args), - onSyncRefresh: (...args) => this.onSyncRefresh(...args), - onFilter: (...args) => this.onFilter(...args), - onClearFilter: (...args) => this.onClearFilter(...args), - onFilterFocus: (...args) => this.onFilterFocus(...args), - onFilterBlur: (...args) => this.onFilterBlur(...args) - }); - - this._store.on("change", state => this._view.render(state)); - this._view.render({clients: []}); - // get what's already available... - this._store.getData(); - this._store.focusInput(); - }, - - uninit() { - this._view.destroy(); - }, - - onFilter(query) { - this._store.getData(query); - }, - - onClearFilter() { - this._store.clearFilter(); - }, - - onFilterFocus() { - this._store.focusInput(); - }, - - onFilterBlur() { - this._store.blurInput(); - }, - - onSelectRow(position) { - this._store.selectRow(position[0], position[1]); - }, - - onMoveSelectionDown() { - this._store.moveSelectionDown(); - }, - - onMoveSelectionUp() { - this._store.moveSelectionUp(); - }, - - onToggleBranch(id) { - this._store.toggleBranch(id); - }, - - onBookmarkTab(uri, title) { - this._window.top.PlacesCommandHook - .bookmarkLink(this._window.top.PlacesUtils.bookmarksMenuFolderId, uri, title) - .catch(Cu.reportError); - }, - - onOpenTab(url, where, params) { - this._window.openUILinkIn(url, where, params); - }, - - onOpenTabs(urls, where) { - if (!PlacesUIUtils.confirmOpenInTabs(urls.length, this._window)) { - return; - } - if (where == "window") { - this._window.openDialog(this._window.getBrowserURL(), "_blank", - "chrome,dialog=no,all", urls.join("|")); - } else { - let loadInBackground = where == "tabshifted" ? true : false; - this._getChromeWindow(this._window).gBrowser.loadTabs(urls, loadInBackground, false); - } - }, - - onCopyTabLocation(url) { - this._clipboardHelper.copyString(url); - }, - - onSyncRefresh() { - this._SyncedTabs.syncTabs(true); - } -}; diff --git a/application/basilisk/components/syncedtabs/TabListView.js b/application/basilisk/components/syncedtabs/TabListView.js deleted file mode 100644 index dab15101b..000000000 --- a/application/basilisk/components/syncedtabs/TabListView.js +++ /dev/null @@ -1,568 +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"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); - -let { getChromeWindow } = Cu.import("resource:///modules/syncedtabs/util.js", {}); - -let log = Cu.import("resource://gre/modules/Log.jsm", {}) - .Log.repository.getLogger("Sync.RemoteTabs"); - -this.EXPORTED_SYMBOLS = [ - "TabListView" -]; - -function getContextMenu(window) { - return getChromeWindow(window).document.getElementById("SyncedTabsSidebarContext"); -} - -function getTabsFilterContextMenu(window) { - return getChromeWindow(window).document.getElementById("SyncedTabsSidebarTabsFilterContext"); -} - -/* - * TabListView - * - * Given a state, this object will render the corresponding DOM. - * It maintains no state of it's own. It listens for DOM events - * and triggers actions that may cause the state to change and - * ultimately the view to rerender. - */ -function TabListView(window, props) { - this.props = props; - - this._window = window; - this._doc = this._window.document; - - this._tabsContainerTemplate = this._doc.getElementById("tabs-container-template"); - this._clientTemplate = this._doc.getElementById("client-template"); - this._emptyClientTemplate = this._doc.getElementById("empty-client-template"); - this._tabTemplate = this._doc.getElementById("tab-template"); - this.tabsFilter = this._doc.querySelector(".tabsFilter"); - this.clearFilter = this._doc.querySelector(".textbox-search-clear"); - this.searchBox = this._doc.querySelector(".search-box"); - this.searchIcon = this._doc.querySelector(".textbox-search-icon"); - - this.container = this._doc.createElement("div"); - - this._attachFixedListeners(); - - this._setupContextMenu(); -} - -TabListView.prototype = { - render(state) { - // Don't rerender anything; just update attributes, e.g. selection - if (state.canUpdateAll) { - this._update(state); - return; - } - // Rerender the tab list - if (state.canUpdateInput) { - this._updateSearchBox(state); - this._createList(state); - return; - } - // Create the world anew - this._create(state); - }, - - // Create the initial DOM from templates - _create(state) { - let wrapper = this._doc.importNode(this._tabsContainerTemplate.content, true).firstElementChild; - this._clearChilden(); - this.container.appendChild(wrapper); - - this.list = this.container.querySelector(".list"); - - this._createList(state); - this._updateSearchBox(state); - - this._attachListListeners(); - }, - - _createList(state) { - this._clearChilden(this.list); - for (let client of state.clients) { - if (state.filter) { - this._renderFilteredClient(client); - } else { - this._renderClient(client); - } - } - if (this.list.firstChild) { - const firstTab = this.list.firstChild.querySelector(".item.tab:first-child .item-title"); - if (firstTab) { - firstTab.setAttribute("tabindex", 2); - } - } - }, - - destroy() { - this._teardownContextMenu(); - this.container.remove(); - }, - - _update(state) { - this._updateSearchBox(state); - for (let client of state.clients) { - let clientNode = this._doc.getElementById("item-" + client.id); - if (clientNode) { - this._updateClient(client, clientNode); - } - - client.tabs.forEach((tab, index) => { - let tabNode = this._doc.getElementById('tab-' + client.id + '-' + index); - this._updateTab(tab, tabNode, index); - }); - } - }, - - // Client rows are hidden when the list is filtered - _renderFilteredClient(client, filter) { - client.tabs.forEach((tab, index) => { - let node = this._renderTab(client, tab, index); - this.list.appendChild(node); - }); - }, - - _renderClient(client) { - let itemNode = client.tabs.length ? - this._createClient(client) : - this._createEmptyClient(client); - - this._updateClient(client, itemNode); - - let tabsList = itemNode.querySelector(".item-tabs-list"); - client.tabs.forEach((tab, index) => { - let node = this._renderTab(client, tab, index); - tabsList.appendChild(node); - }); - - this.list.appendChild(itemNode); - return itemNode; - }, - - _renderTab(client, tab, index) { - let itemNode = this._createTab(tab); - this._updateTab(tab, itemNode, index); - return itemNode; - }, - - _createClient(item) { - return this._doc.importNode(this._clientTemplate.content, true).firstElementChild; - }, - - _createEmptyClient(item) { - return this._doc.importNode(this._emptyClientTemplate.content, true).firstElementChild; - }, - - _createTab(item) { - return this._doc.importNode(this._tabTemplate.content, true).firstElementChild; - }, - - _clearChilden(node) { - let parent = node || this.container; - while (parent.firstChild) { - parent.removeChild(parent.firstChild); - } - }, - - // These listeners are attached only once, when we initialize the view - _attachFixedListeners() { - this.tabsFilter.addEventListener("input", this.onFilter.bind(this)); - this.tabsFilter.addEventListener("focus", this.onFilterFocus.bind(this)); - this.tabsFilter.addEventListener("blur", this.onFilterBlur.bind(this)); - this.clearFilter.addEventListener("click", this.onClearFilter.bind(this)); - this.searchIcon.addEventListener("click", this.onFilterFocus.bind(this)); - }, - - // These listeners have to be re-created every time since we re-create the list - _attachListListeners() { - this.list.addEventListener("click", this.onClick.bind(this)); - this.list.addEventListener("mouseup", this.onMouseUp.bind(this)); - this.list.addEventListener("keydown", this.onKeyDown.bind(this)); - }, - - _updateSearchBox(state) { - if (state.filter) { - this.searchBox.classList.add("filtered"); - } else { - this.searchBox.classList.remove("filtered"); - } - this.tabsFilter.value = state.filter; - if (state.inputFocused) { - this.searchBox.setAttribute("focused", true); - this.tabsFilter.focus(); - } else { - this.searchBox.removeAttribute("focused"); - } - }, - - /** - * Update the element representing an item, ensuring it's in sync with the - * underlying data. - * @param {client} item - Item to use as a source. - * @param {Element} itemNode - Element to update. - */ - _updateClient(item, itemNode) { - itemNode.setAttribute("id", "item-" + item.id); - let lastSync = new Date(item.lastModified); - let lastSyncTitle = getChromeWindow(this._window).gSyncUI.formatLastSyncDate(lastSync); - itemNode.setAttribute("title", lastSyncTitle); - if (item.closed) { - itemNode.classList.add("closed"); - } else { - itemNode.classList.remove("closed"); - } - if (item.selected) { - itemNode.classList.add("selected"); - } else { - itemNode.classList.remove("selected"); - } - if (item.isMobile) { - itemNode.classList.add("device-image-mobile"); - } else { - itemNode.classList.add("device-image-desktop"); - } - if (item.focused) { - itemNode.focus(); - } - itemNode.dataset.id = item.id; - itemNode.querySelector(".item-title").textContent = item.name; - }, - - /** - * Update the element representing a tab, ensuring it's in sync with the - * underlying data. - * @param {tab} item - Item to use as a source. - * @param {Element} itemNode - Element to update. - */ - _updateTab(item, itemNode, index) { - itemNode.setAttribute("title", `${item.title}\n${item.url}`); - itemNode.setAttribute("id", "tab-" + item.client + '-' + index); - if (item.selected) { - itemNode.classList.add("selected"); - } else { - itemNode.classList.remove("selected"); - } - if (item.focused) { - itemNode.focus(); - } - itemNode.dataset.url = item.url; - - itemNode.querySelector(".item-title").textContent = item.title; - - if (item.icon) { - let icon = itemNode.querySelector(".item-icon-container"); - icon.style.backgroundImage = "url(" + item.icon + ")"; - } - }, - - onMouseUp(event) { - if (event.which == 2) { // Middle click - this.onClick(event); - } - }, - - onClick(event) { - let itemNode = this._findParentItemNode(event.target); - if (!itemNode) { - return; - } - - if (itemNode.classList.contains("tab")) { - let url = itemNode.dataset.url; - if (url) { - this.onOpenSelected(url, event); - } - } - - // Middle click on a client - if (itemNode.classList.contains("client")) { - let where = getChromeWindow(this._window).whereToOpenLink(event); - if (where != "current") { - const tabs = itemNode.querySelector(".item-tabs-list").childNodes; - const urls = [...tabs].map(tab => tab.dataset.url); - this.props.onOpenTabs(urls, where); - } - } - - if (event.target.classList.contains("item-twisty-container") - && event.which != 2) { - this.props.onToggleBranch(itemNode.dataset.id); - return; - } - - let position = this._getSelectionPosition(itemNode); - this.props.onSelectRow(position); - }, - - /** - * Handle a keydown event on the list box. - * @param {Event} event - Triggering event. - */ - onKeyDown(event) { - if (event.keyCode == this._window.KeyEvent.DOM_VK_DOWN) { - event.preventDefault(); - this.props.onMoveSelectionDown(); - } else if (event.keyCode == this._window.KeyEvent.DOM_VK_UP) { - event.preventDefault(); - this.props.onMoveSelectionUp(); - } else if (event.keyCode == this._window.KeyEvent.DOM_VK_RETURN) { - let selectedNode = this.container.querySelector('.item.selected'); - if (selectedNode.dataset.url) { - this.onOpenSelected(selectedNode.dataset.url, event); - } else if (selectedNode) { - this.props.onToggleBranch(selectedNode.dataset.id); - } - } - }, - - onBookmarkTab() { - let item = this._getSelectedTabNode(); - if (item) { - let title = item.querySelector(".item-title").textContent; - this.props.onBookmarkTab(item.dataset.url, title); - } - }, - - onCopyTabLocation() { - let item = this._getSelectedTabNode(); - if (item) { - this.props.onCopyTabLocation(item.dataset.url); - } - }, - - onOpenSelected(url, event) { - let where = getChromeWindow(this._window).whereToOpenLink(event); - this.props.onOpenTab(url, where, {}); - }, - - onOpenSelectedFromContextMenu(event) { - let item = this._getSelectedTabNode(); - if (item) { - let where = event.target.getAttribute("where"); - let params = { - private: event.target.hasAttribute("private"), - }; - this.props.onOpenTab(item.dataset.url, where, params); - } - }, - - onFilter(event) { - let query = event.target.value; - if (query) { - this.props.onFilter(query); - } else { - this.props.onClearFilter(); - } - }, - - onClearFilter() { - this.props.onClearFilter(); - }, - - onFilterFocus() { - this.props.onFilterFocus(); - }, - onFilterBlur() { - this.props.onFilterBlur(); - }, - - _getSelectedTabNode() { - let item = this.container.querySelector('.item.selected'); - if (this._isTab(item) && item.dataset.url) { - return item; - } - return null; - }, - - // Set up the custom context menu - _setupContextMenu() { - Services.els.addSystemEventListener(this._window, "contextmenu", this, false); - for (let getMenu of [getContextMenu, getTabsFilterContextMenu]) { - let menu = getMenu(this._window); - menu.addEventListener("popupshowing", this, true); - menu.addEventListener("command", this, true); - } - }, - - _teardownContextMenu() { - // Tear down context menu - Services.els.removeSystemEventListener(this._window, "contextmenu", this, false); - for (let getMenu of [getContextMenu, getTabsFilterContextMenu]) { - let menu = getMenu(this._window); - menu.removeEventListener("popupshowing", this, true); - menu.removeEventListener("command", this, true); - } - }, - - handleEvent(event) { - switch (event.type) { - case "contextmenu": - this.handleContextMenu(event); - break; - - case "popupshowing": { - if (event.target.getAttribute("id") == "SyncedTabsSidebarTabsFilterContext") { - this.handleTabsFilterContextMenuShown(event); - } - break; - } - - case "command": { - let menu = event.target.closest("menupopup"); - switch (menu.getAttribute("id")) { - case "SyncedTabsSidebarContext": - this.handleContentContextMenuCommand(event); - break; - - case "SyncedTabsSidebarTabsFilterContext": - this.handleTabsFilterContextMenuCommand(event); - break; - } - break; - } - } - }, - - handleTabsFilterContextMenuShown(event) { - let document = event.target.ownerDocument; - let focusedElement = document.commandDispatcher.focusedElement; - if (focusedElement != this.tabsFilter) { - this.tabsFilter.focus(); - } - for (let item of event.target.children) { - if (!item.hasAttribute("cmd")) { - continue; - } - let command = item.getAttribute("cmd"); - let controller = document.commandDispatcher.getControllerForCommand(command); - if (controller.isCommandEnabled(command)) { - item.removeAttribute("disabled"); - } else { - item.setAttribute("disabled", "true"); - } - } - }, - - handleContentContextMenuCommand(event) { - let id = event.target.getAttribute("id"); - switch (id) { - case "syncedTabsOpenSelected": - case "syncedTabsOpenSelectedInTab": - case "syncedTabsOpenSelectedInWindow": - case "syncedTabsOpenSelectedInPrivateWindow": - this.onOpenSelectedFromContextMenu(event); - break; - case "syncedTabsBookmarkSelected": - this.onBookmarkTab(); - break; - case "syncedTabsCopySelected": - this.onCopyTabLocation(); - break; - case "syncedTabsRefresh": - case "syncedTabsRefreshFilter": - this.props.onSyncRefresh(); - break; - } - }, - - handleTabsFilterContextMenuCommand(event) { - let command = event.target.getAttribute("cmd"); - let dispatcher = getChromeWindow(this._window).document.commandDispatcher; - let controller = dispatcher.focusedElement.controllers.getControllerForCommand(command); - controller.doCommand(command); - }, - - handleContextMenu(event) { - let menu; - - if (event.target == this.tabsFilter) { - menu = getTabsFilterContextMenu(this._window); - } else { - let itemNode = this._findParentItemNode(event.target); - if (itemNode) { - let position = this._getSelectionPosition(itemNode); - this.props.onSelectRow(position); - } - menu = getContextMenu(this._window); - this.adjustContextMenu(menu); - } - - menu.openPopupAtScreen(event.screenX, event.screenY, true, event); - }, - - adjustContextMenu(menu) { - let item = this.container.querySelector('.item.selected'); - let showTabOptions = this._isTab(item); - - let el = menu.firstChild; - - while (el) { - if (showTabOptions || el.getAttribute("id") === "syncedTabsRefresh") { - el.hidden = false; - } else { - el.hidden = true; - } - - el = el.nextSibling; - } - }, - - /** - * Find the parent item element, from a given child element. - * @param {Element} node - Child element. - * @return {Element} Element for the item, or null if not found. - */ - _findParentItemNode(node) { - while (node && node !== this.list && node !== this._doc.documentElement && - !node.classList.contains("item")) { - node = node.parentNode; - } - - if (node !== this.list && node !== this._doc.documentElement) { - return node; - } - - return null; - }, - - _findParentBranchNode(node) { - while (node && !node.classList.contains("list") && node !== this._doc.documentElement && - !node.parentNode.classList.contains("list")) { - node = node.parentNode; - } - - if (node !== this.list && node !== this._doc.documentElement) { - return node; - } - - return null; - }, - - _getSelectionPosition(itemNode) { - let parent = this._findParentBranchNode(itemNode); - let parentPosition = this._indexOfNode(parent.parentNode, parent); - let childPosition = -1; - // if the node is not a client, find its position within the parent - if (parent !== itemNode) { - childPosition = this._indexOfNode(itemNode.parentNode, itemNode); - } - return [parentPosition, childPosition]; - }, - - _indexOfNode(parent, child) { - return Array.prototype.indexOf.call(parent.childNodes, child); - }, - - _isTab(item) { - return item && item.classList.contains("tab"); - } -}; diff --git a/application/basilisk/components/syncedtabs/moz.build b/application/basilisk/components/syncedtabs/moz.build deleted file mode 100644 index a6515d6a1..000000000 --- a/application/basilisk/components/syncedtabs/moz.build +++ /dev/null @@ -1,17 +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/. - -JAR_MANIFESTS += ['jar.mn'] - -EXTRA_JS_MODULES.syncedtabs += [ - 'EventEmitter.jsm', - 'SyncedTabsDeckComponent.js', - 'SyncedTabsDeckStore.js', - 'SyncedTabsDeckView.js', - 'SyncedTabsListStore.js', - 'TabListComponent.js', - 'TabListView.js', - 'util.js', -] - diff --git a/application/basilisk/components/syncedtabs/sidebar.js b/application/basilisk/components/syncedtabs/sidebar.js deleted file mode 100644 index 84df95e9d..000000000 --- a/application/basilisk/components/syncedtabs/sidebar.js +++ /dev/null @@ -1,30 +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"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://services-sync/SyncedTabs.jsm"); -Cu.import("resource:///modules/syncedtabs/SyncedTabsDeckComponent.js"); - -XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts", - "resource://gre/modules/FxAccounts.jsm"); - -this.syncedTabsDeckComponent = new SyncedTabsDeckComponent({window, SyncedTabs, fxAccounts}); - -let onLoaded = () => { - syncedTabsDeckComponent.init(); - document.getElementById("template-container").appendChild(syncedTabsDeckComponent.container); -}; - -let onUnloaded = () => { - removeEventListener("DOMContentLoaded", onLoaded); - removeEventListener("unload", onUnloaded); - syncedTabsDeckComponent.uninit(); -}; - -addEventListener("DOMContentLoaded", onLoaded); -addEventListener("unload", onUnloaded); diff --git a/application/basilisk/components/syncedtabs/sidebar.xhtml b/application/basilisk/components/syncedtabs/sidebar.xhtml deleted file mode 100644 index 3efcbea0e..000000000 --- a/application/basilisk/components/syncedtabs/sidebar.xhtml +++ /dev/null @@ -1,114 +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 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" [ - <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd"> - %browserDTD; - <!ENTITY % globalDTD - SYSTEM "chrome://global/locale/global.dtd"> - %globalDTD; - <!ENTITY % syncBrandDTD - SYSTEM "chrome://browser/locale/syncBrand.dtd"> - %syncBrandDTD; -]> -<html xmlns="http://www.w3.org/1999/xhtml" - xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> - <head> - <script src="chrome://browser/content/syncedtabs/sidebar.js" type="application/javascript;version=1.8"></script> - <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/> - - <link rel="stylesheet" type="text/css" media="all" href="chrome://browser/skin/syncedtabs/sidebar.css"/> - <link rel="stylesheet" type="text/css" media="all" href="chrome://global/skin/"/> - <link rel="stylesheet" type="text/css" media="all" href="chrome://global/skin/textbox.css"/> - <link rel="stylesheet" type="text/css" media="all" href="chrome://browser/content/browser.css"/> - <title>&syncedTabs.sidebar.label;</title> - </head> - - <body dir="&locale.dir;" role="application"> - <template id="client-template"> - <div class="item client" role="option" tabindex="-1"> - <div class="item-title-container"> - <div class="item-twisty-container"></div> - <div class="item-icon-container"></div> - <p class="item-title"></p> - </div> - <div class="item-tabs-list"></div> - </div> - </template> - <template id="empty-client-template"> - <div class="item empty client" role="option" tabindex="-1"> - <div class="item-title-container"> - <div class="item-twisty-container"></div> - <div class="item-icon-container"></div> - <p class="item-title"></p> - </div> - <div class="item-tabs-list"> - <div class="item empty" role="option" tabindex="-1"> - <div class="item-title-container"> - <div class="item-icon-container"></div> - <p class="item-title">&syncedTabs.sidebar.notabs.label;</p> - </div> - </div> - </div> - </div> - </template> - <template id="tab-template"> - <div class="item tab" role="option" tabindex="-1"> - <div class="item-title-container"> - <div class="item-icon-container"></div> - <p class="item-title"></p> - </div> - </div> - </template> - - <template id="tabs-container-template"> - <div class="tabs-container"> - <div class="list" role="listbox"></div> - </div> - </template> - - <template id="deck-template"> - <div class="deck"> - <div class="tabs-fetching sync-state"> - <!-- Show intentionally blank panel, see bug 1239845 --> - </div> - <div class="notAuthedInfo sync-state"> - <p>&syncedTabs.sidebar.notsignedin.label;</p> - <p><a href="#" class="sync-prefs text-link">&fxaSignIn.label;</a></p> - </div> - <div class="singleDeviceInfo sync-state"> - <p>&syncedTabs.sidebar.noclients.title;</p> - <p>&syncedTabs.sidebar.noclients.subtitle;</p> - <p class="device-promo" fxAccountsBrand="&syncBrand.fxAccount.label;"></p> - </div> - <div class="tabs-disabled sync-state"> - <p>&syncedTabs.sidebar.tabsnotsyncing.label;</p> - <p><a href="#" class="sync-prefs text-link">&syncedTabs.sidebar.openprefs.label;</a></p> - </div> - </div> - </template> - - <div class="content-container"> - <!-- the non-scrollable header --> - <div class="content-header"> - <div class="sidebar-search-container tabs-container sync-state"> - <div class="search-box compact"> - <div class="textbox-input-box"> - <input type="text" class="tabsFilter textbox-input" tabindex="1"/> - <div class="textbox-search-icons"> - <a class="textbox-search-clear"></a> - <a class="textbox-search-icon"></a> - </div> - </div> - </div> - </div> - </div> - <!-- the scrollable content area where our templates are inserted --> - <div id="template-container" class="content-scrollable" tabindex="-1"> - </div> - </div> - </body> -</html> diff --git a/application/basilisk/components/syncedtabs/util.js b/application/basilisk/components/syncedtabs/util.js deleted file mode 100644 index e09a1a528..000000000 --- a/application/basilisk/components/syncedtabs/util.js +++ /dev/null @@ -1,23 +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"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -this.EXPORTED_SYMBOLS = [ - "getChromeWindow" -]; - -// Get the chrome (ie, browser) window hosting this content. -function getChromeWindow(window) { - return window - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem) - .rootTreeItem - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow) - .wrappedJSObject; -} diff --git a/application/basilisk/configure.in b/application/basilisk/configure.in index 4e7a06390..13f2ad54d 100644 --- a/application/basilisk/configure.in +++ b/application/basilisk/configure.in @@ -16,3 +16,10 @@ AC_SUBST(MC_BASILISK) dnl Optional parts of the build. +dnl ======================================================== +dnl = Disable Sync +dnl ======================================================== +MOZ_ARG_DISABLE_BOOL(sync, +[ --disable-sync Disable Sync], + MOZ_SERVICES_SYNC=, + MOZ_SERVICES_SYNC=1)
\ No newline at end of file diff --git a/application/basilisk/locales/en-US/chrome/browser/aboutAccounts.dtd b/application/basilisk/locales/en-US/chrome/browser/aboutAccounts.dtd deleted file mode 100644 index 358722156..000000000 --- a/application/basilisk/locales/en-US/chrome/browser/aboutAccounts.dtd +++ /dev/null @@ -1,16 +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/. --> - -<!ENTITY aboutAccounts.welcome "Welcome to &syncBrand.shortName.label;"> -<!ENTITY aboutAccounts.connected "Account connected"> - -<!ENTITY aboutAccountsConfig.description "Sign in to sync your tabs, bookmarks, passwords & more."> -<!ENTITY aboutAccountsConfig.startButton.label "Get started"> -<!ENTITY aboutAccountsConfig.useOldSync.label "Using an older version of Sync?"> -<!ENTITY aboutAccountsConfig.syncPreferences.label "Sync preferences"> -<!ENTITY aboutAccounts.noConnection.title "No connection"> -<!ENTITY aboutAccounts.noConnection.description "You must be connected to the Internet to sign in."> -<!ENTITY aboutAccounts.noConnection.retry "Try again"> -<!ENTITY aboutAccounts.badConfig.title "Bad configuration"> -<!ENTITY aboutAccounts.badConfig.description "Unable to determine your Firefox Account server configuration. Please try again later."> diff --git a/application/basilisk/locales/en-US/chrome/browser/browser.dtd b/application/basilisk/locales/en-US/chrome/browser/browser.dtd index d02a6eedb..87f4a7807 100644 --- a/application/basilisk/locales/en-US/chrome/browser/browser.dtd +++ b/application/basilisk/locales/en-US/chrome/browser/browser.dtd @@ -723,43 +723,19 @@ you can use these alternative items. Otherwise, their values should be empty. - The word "toolbar" is appended automatically and should not be contained below! --> <!ENTITY tabsToolbar.label "Browser tabs"> -<!-- LOCALIZATION NOTE (syncTabsMenu3.label): This appears in the history menu --> -<!ENTITY syncTabsMenu3.label "Synced Tabs"> - -<!ENTITY syncedTabs.sidebar.label "Synced Tabs"> -<!ENTITY syncedTabs.sidebar.noclients.label "Sign in to Firefox from your other devices to view their tabs here."> -<!ENTITY syncedTabs.sidebar.noclients.title "No synced tabs… yet!"> -<!ENTITY syncedTabs.sidebar.noclients.subtitle "Want to see your tabs from other devices here?"> -<!ENTITY syncedTabs.sidebar.notsignedin.label "Sign in to view a list of tabs from your other devices."> -<!ENTITY syncedTabs.sidebar.notabs.label "No open tabs"> -<!ENTITY syncedTabs.sidebar.openprefs.label "Open &syncBrand.shortName.label; Preferences"> -<!-- LOCALIZATION NOTE (syncedTabs.sidebar.tabsnotsyncing.label): This is shown - when Sync is configured but syncing tabs is disabled. --> -<!ENTITY syncedTabs.sidebar.tabsnotsyncing.label "Turn on tab syncing to view a list of tabs from your other devices."> - -<!ENTITY syncedTabs.context.open.label "Open"> -<!ENTITY syncedTabs.context.open.accesskey "O"> -<!ENTITY syncedTabs.context.openInNewTab.label "Open in a New Tab"> -<!ENTITY syncedTabs.context.openInNewTab.accesskey "w"> -<!ENTITY syncedTabs.context.openInNewWindow.label "Open in a New Window"> -<!ENTITY syncedTabs.context.openInNewWindow.accesskey "N"> -<!ENTITY syncedTabs.context.openInNewPrivateWindow.label "Open in a New Private Window"> -<!ENTITY syncedTabs.context.openInNewPrivateWindow.accesskey "P"> -<!ENTITY syncedTabs.context.bookmarkSingleTab.label "Bookmark This Tab…"> -<!ENTITY syncedTabs.context.bookmarkSingleTab.accesskey "B"> -<!ENTITY syncedTabs.context.copy.label "Copy"> -<!ENTITY syncedTabs.context.copy.accesskey "C"> - +#ifdef MOZ_SERVICES_SYNC +<!-- LOCALIZATION NOTE (syncTabsMenu2.label): This appears in the history menu --> +<!ENTITY syncTabsMenu2.label "Tabs From Other Devices"> <!ENTITY syncBrand.shortName.label "Sync"> -<!ENTITY syncSignIn.label "Sign In To &syncBrand.shortName.label;…"> -<!ENTITY syncSignIn.accesskey "Y"> +<!ENTITY syncSetup.label "Set Up &syncBrand.shortName.label;…"> +<!ENTITY syncSetup.accesskey "Y"> <!ENTITY syncSyncNowItem.label "Sync Now"> <!ENTITY syncSyncNowItem.accesskey "S"> -<!ENTITY syncReAuthItem.label "Reconnect to &syncBrand.shortName.label;…"> -<!ENTITY syncReAuthItem.accesskey "R"> <!ENTITY syncToolbarButton.label "Sync"> +<!ENTITY syncTabsToolbarButton.label "Synced Tabs"> +#endif <!ENTITY customizeMode.menuAndToolbars.header2 "Additional Tools and Features"> <!ENTITY customizeMode.menuAndToolbars.empty "Want more tools?"> diff --git a/application/basilisk/locales/en-US/chrome/browser/preferences/sync.dtd b/application/basilisk/locales/en-US/chrome/browser/preferences/sync.dtd index a5b290052..f6ef3b876 100644 --- a/application/basilisk/locales/en-US/chrome/browser/preferences/sync.dtd +++ b/application/basilisk/locales/en-US/chrome/browser/preferences/sync.dtd @@ -39,80 +39,9 @@ <!-- Device Settings --> <!ENTITY syncDeviceName.label "Device Name:"> -<!ENTITY fxaSyncDeviceName.label "Device Name"> -<!ENTITY changeSyncDeviceName.label "Change Device Name…"> -<!ENTITY changeSyncDeviceName.accesskey "h"> -<!ENTITY cancelChangeSyncDeviceName.label "Cancel"> -<!ENTITY cancelChangeSyncDeviceName.accesskey "n"> -<!ENTITY saveChangeSyncDeviceName.label "Save"> -<!ENTITY saveChangeSyncDeviceName.accesskey "v"> +<!ENTITY syncDeviceName.accesskey "c"> <!ENTITY unlinkDevice.label "Unlink This Device"> <!-- Footer stuff --> <!ENTITY prefs.tosLink.label "Terms of Service"> <!ENTITY prefs.ppLink.label "Privacy Policy"> - -<!-- Firefox Accounts stuff --> -<!ENTITY fxaPrivacyNotice.link.label "Privacy Notice"> -<!ENTITY determiningAcctStatus.label "Determining your account status…"> - -<!-- LOCALIZATION NOTE (signedInUnverified.beforename.label, -signedInUnverified.aftername.label): these two string are used respectively -before and after the account email address. Localizers can use one of them, or -both, to better adapt this sentence to their language. ---> -<!ENTITY signedInUnverified.beforename.label ""> -<!ENTITY signedInUnverified.aftername.label "is not verified."> - -<!-- LOCALIZATION NOTE (signedInLoginFailure.beforename.label, -signedInLoginFailure.aftername.label): these two string are used respectively -before and after the account email address. Localizers can use one of them, or -both, to better adapt this sentence to their language. ---> -<!ENTITY signedInLoginFailure.beforename.label "Please sign in to reconnect"> -<!ENTITY signedInLoginFailure.aftername.label ""> - -<!ENTITY notSignedIn.label "You are not signed in."> -<!ENTITY signIn.label "Sign in"> -<!ENTITY signIn.accesskey "g"> -<!ENTITY profilePicture.tooltip "Change profile picture"> -<!ENTITY verifiedManage.label "Manage Account"> -<!ENTITY verifiedManage.accesskey "o"> -<!ENTITY disconnect.label "Disconnect…"> -<!ENTITY disconnect.accesskey "D"> -<!ENTITY verify.label "Verify Email"> -<!ENTITY verify.accesskey "V"> -<!ENTITY forget.label "Forget this Email"> -<!ENTITY forget.accesskey "F"> - -<!ENTITY welcome.description "Access your tabs, bookmarks, passwords and more wherever you use &brandShortName;."> -<!ENTITY welcome.signIn.label "Sign In"> -<!ENTITY welcome.createAccount.label "Create Account"> - -<!ENTITY welcome.useOldSync.label "Using an older version of Sync?"> - -<!ENTITY signedOut.caption "Take your Web with you"> -<!ENTITY signedOut.description "Synchronize your bookmarks, history, tabs, passwords, add-ons, and preferences across all your devices."> -<!ENTITY signedOut.accountBox.title "Connect with a &syncBrand.fxAccount.label;"> -<!ENTITY signedOut.accountBox.create "Create Account"> -<!ENTITY signedOut.accountBox.create.accesskey "C"> -<!ENTITY signedOut.accountBox.signin "Sign In"> -<!ENTITY signedOut.accountBox.signin.accesskey "I"> - -<!ENTITY signedIn.engines.label "Sync across all devices"> - -<!-- LOCALIZATION NOTE (mobilePromo3.*): the following strings will be used to - create a single sentence with active links. - The resulting sentence in English is: "Download Firefox for - Android or iOS to sync with your mobile device." --> - -<!ENTITY mobilePromo3.start "Download Firefox for "> -<!-- LOCALIZATION NOTE (mobilePromo3.androidLink): This is a link title that links to https://www.mozilla.org/firefox/android/ --> -<!ENTITY mobilePromo3.androidLink "Android"> - -<!-- LOCALIZATION NOTE (mobilePromo3.iOSBefore): This is text displayed between mobilePromo3.androidLink and mobilePromo3.iosLink --> -<!ENTITY mobilePromo3.iOSBefore " or "> -<!-- LOCALIZATION NOTE (mobilePromo3.iOSLink): This is a link title that links to https://www.mozilla.org/firefox/ios/ --> -<!ENTITY mobilePromo3.iOSLink "iOS"> - -<!ENTITY mobilePromo3.end " to sync with your mobile device."> diff --git a/application/basilisk/locales/en-US/chrome/browser/syncBrand.dtd b/application/basilisk/locales/en-US/chrome/browser/syncBrand.dtd index 71a9f68af..bc4d1b3e0 100644 --- a/application/basilisk/locales/en-US/chrome/browser/syncBrand.dtd +++ b/application/basilisk/locales/en-US/chrome/browser/syncBrand.dtd @@ -4,4 +4,3 @@ <!ENTITY syncBrand.shortName.label "Sync"> <!ENTITY syncBrand.fullName.label "Pale Moon Sync"> -<!ENTITY syncBrand.fxAccount.label "Firefox Account"> diff --git a/application/basilisk/locales/en-US/chrome/browser/syncKey.dtd b/application/basilisk/locales/en-US/chrome/browser/syncKey.dtd index 2ff001842..f37f2c92e 100644 --- a/application/basilisk/locales/en-US/chrome/browser/syncKey.dtd +++ b/application/basilisk/locales/en-US/chrome/browser/syncKey.dtd @@ -5,12 +5,12 @@ <!ENTITY syncKey.page.title "Your &syncBrand.fullName.label; Key"> <!ENTITY syncKey.page.description2 "This key is used to decode the data in your &syncBrand.fullName.label; account. You will need to enter the key each time you configure &syncBrand.fullName.label; on a new device."> <!ENTITY syncKey.keepItSecret.heading "Keep it secret"> -<!ENTITY syncKey.keepItSecret.description "Your &syncBrand.fullName.label; account is encrypted to protect your privacy. Without this key, it would take years for anyone to decode your personal information. You are the only person who holds this key. This means you’re the only one who can access your &syncBrand.fullName.label; data."> +<!ENTITY syncKey.keepItSecret.description "Your &syncBrand.fullName.label; account is encrypted to protect your privacy. Without this key, it would take years for anyone to decode your personal information. You are the only person who holds this key. This means you're the only one who can access your &syncBrand.fullName.label; data."> <!ENTITY syncKey.keepItSafe.heading "Keep it safe"> <!ENTITY syncKey.keepItSafe1.description "Do not lose this key."> -<!ENTITY syncKey.keepItSafe2.description " We don’t keep a copy of your key (that wouldn’t be keeping it secret!) so "> -<!ENTITY syncKey.keepItSafe3.description "we can’t help you recover it"> -<!ENTITY syncKey.keepItSafe4a.description " if it’s lost. You’ll need to use this key any time you connect a new device to &syncBrand.fullName.label;."> +<!ENTITY syncKey.keepItSafe2.description " We don't keep a copy of your key (that wouldn't be keeping it secret!) so "> +<!ENTITY syncKey.keepItSafe3.description "we can't help you recover it"> +<!ENTITY syncKey.keepItSafe4a.description " if it's lost. You'll need to use this key any time you connect a new device to &syncBrand.fullName.label;."> <!ENTITY syncKey.findOutMore1.label "Find out more about &syncBrand.fullName.label; and your privacy at "> <!ENTITY syncKey.findOutMore2.label "."> <!ENTITY syncKey.footer1.label "&syncBrand.fullName.label; Terms of Service are available at "> diff --git a/application/basilisk/locales/en-US/chrome/browser/syncProgress.dtd b/application/basilisk/locales/en-US/chrome/browser/syncProgress.dtd new file mode 100644 index 000000000..db45cb935 --- /dev/null +++ b/application/basilisk/locales/en-US/chrome/browser/syncProgress.dtd @@ -0,0 +1,15 @@ +<!-- 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/. --> + +<!ENTITY % brandDTD + SYSTEM "chrome://branding/locale/brand.dtd"> + %brandDTD; + +<!-- These strings are used in the sync progress upload page --> +<!ENTITY syncProgress.pageTitle "Your First Sync"> +<!ENTITY syncProgress.textBlurb "Your data is now being encrypted and uploaded in the background. You can close this tab and continue using &brandShortName;."> +<!ENTITY syncProgress.closeButton "Close"> +<!ENTITY syncProgress.logoAltText "&brandShortName; logo"> +<!ENTITY syncProgress.diffText "&brandShortName; will now automatically sync in the background. You can close this tab and continue using &brandShortName;."> + diff --git a/application/basilisk/locales/en-US/chrome/browser/syncQuota.properties b/application/basilisk/locales/en-US/chrome/browser/syncQuota.properties index 099090ec9..0e1b857ca 100644 --- a/application/basilisk/locales/en-US/chrome/browser/syncQuota.properties +++ b/application/basilisk/locales/en-US/chrome/browser/syncQuota.properties @@ -30,7 +30,7 @@ quota.remove.label = Remove quota.treeCaption.label = Uncheck items to stop syncing them and free up space on the server. # LOCALIZATION NOTE (quota.removal.label): %S is a list of engines that will be # disabled and whose data will be removed once the user confirms. -quota.removal.label = Firefox Sync will remove the following data: %S. +quota.removal.label = Sync will remove the following data: %S. # LOCALIZATION NOTE (quota.list.separator): This is the separator string used # for the list of engines (incl. spaces where appropriate) quota.list.separator = ,\u0020 diff --git a/application/basilisk/locales/en-US/chrome/browser/syncSetup.dtd b/application/basilisk/locales/en-US/chrome/browser/syncSetup.dtd index 2657156b7..7ee938e5d 100644 --- a/application/basilisk/locales/en-US/chrome/browser/syncSetup.dtd +++ b/application/basilisk/locales/en-US/chrome/browser/syncSetup.dtd @@ -6,13 +6,13 @@ <!-- First page of the wizard --> -<!ENTITY setup.pickSetupType.description2 "Welcome! If you’ve never used &syncBrand.fullName.label; before, you will need to create a new account."> +<!ENTITY setup.pickSetupType.description2 "Welcome! If you've never used &syncBrand.fullName.label; before, you will need to create a new account."> <!ENTITY button.createNewAccount.label "Create a New Account"> <!ENTITY button.haveAccount.label "I Have an Account"> <!ENTITY setup.choicePage.title.label "Have you used &syncBrand.fullName.label; before?"> -<!ENTITY setup.choicePage.new.label "I’ve never used &syncBrand.shortName.label; before"> -<!ENTITY setup.choicePage.existing2.label "I’m already using &syncBrand.shortName.label; on another device"> +<!ENTITY setup.choicePage.new.label "I've never used &syncBrand.shortName.label; before"> +<!ENTITY setup.choicePage.existing2.label "I'm already using &syncBrand.shortName.label; on another device"> <!-- New Account AND Existing Account --> <!ENTITY server.label "Server"> @@ -33,6 +33,8 @@ <!ENTITY setup.choosePassword.accesskey "P"> <!ENTITY setup.confirmPassword.label "Confirm Password"> <!ENTITY setup.confirmPassword.accesskey "m"> +<!ENTITY setup.setupMetro.label "Sync with Windows 8 style &brandShortName;"> +<!ENTITY setup.setupMetro.accesskey "S"> <!-- LOCALIZATION NOTE: tosAgree1, tosLink, tosAgree2, ppLink, tosAgree3 are joined with implicit white space, so spaces in the strings aren't necessary --> @@ -60,7 +62,7 @@ <!-- Existing Account Page 1: Pair a Device (incl. Pair a Device dialog strings) --> <!ENTITY pairDevice.title.label "Pair a Device"> <!ENTITY addDevice.showMeHow.label "Show me how."> -<!ENTITY addDevice.dontHaveDevice.label "I don’t have the device with me"> +<!ENTITY addDevice.dontHaveDevice.label "I don't have the device with me"> <!ENTITY pairDevice.setup.description.label "To activate, select "Pair a Device" on your other device."> <!ENTITY addDevice.setup.enterCode.label "Then, enter this code:"> <!ENTITY pairDevice.dialog.description.label "To activate your new device, select "Set Up Sync" on the device."> @@ -72,7 +74,7 @@ <!-- Existing Account Page 2: Manual Login --> <!ENTITY setup.signInPage.title.label "Sign In"> -<!ENTITY existingRecoveryKey.description "You can get a copy of your Recovery Key by going to &syncBrand.shortName.label; Preferences on your other device, and selecting "My Recovery Key" under "Manage Account"."> +<!ENTITY existingRecoveryKey.description "You can get a copy of your Recovery Key by going to &syncBrand.shortName.label; Options on your other device, and selecting "My Recovery Key" under "Manage Account"."> <!ENTITY verifying.label "Verifying…"> <!ENTITY resetPassword.label "Reset Password"> <!ENTITY resetSyncKey.label "I have lost my other device."> @@ -96,14 +98,14 @@ <!ENTITY engine.addons.label "Add-ons"> <!ENTITY engine.addons.accesskey "A"> -<!ENTITY choice2a.merge.main.label "Merge this device’s data with my &syncBrand.shortName.label; data"> +<!ENTITY choice2a.merge.main.label "Merge this device's data with my &syncBrand.shortName.label; data"> <!ENTITY choice2.merge.recommended.label "Recommended:"> <!ENTITY choice2a.client.main.label "Replace all data on this device with my &syncBrand.shortName.label; data"> -<!ENTITY choice2a.server.main.label "Replace all other devices with this device’s data"> +<!ENTITY choice2a.server.main.label "Replace all other devices with this device's data"> <!-- Confirm Merge Options --> <!ENTITY setup.optionsConfirmPage.title "Confirm"> -<!ENTITY confirm.merge2.label "&syncBrand.fullName.label; will now merge all this device’s browser data into your Sync account."> +<!ENTITY confirm.merge2.label "&syncBrand.fullName.label; will now merge all this device's browser data into your Sync account."> <!ENTITY confirm.client3.label "Warning: The following &brandShortName; data on this device will be deleted:"> <!ENTITY confirm.client2.moreinfo.label "&brandShortName; will then copy your &syncBrand.fullName.label; data to this device."> <!ENTITY confirm.server2.label "Warning: The following devices will be overwritten with your local data:"> diff --git a/application/basilisk/locales/en-US/chrome/browser/syncSetup.properties b/application/basilisk/locales/en-US/chrome/browser/syncSetup.properties index 9d388af86..8a5170adb 100644 --- a/application/basilisk/locales/en-US/chrome/browser/syncSetup.properties +++ b/application/basilisk/locales/en-US/chrome/browser/syncSetup.properties @@ -35,33 +35,17 @@ passwordsCount.label = #1 password;#1 passwords # LOCALIZATION NOTE (addonsCount.label): Semicolon-separated list of plural forms. # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals # #1 is the number of add-ons, see the link above for forms -addonsCount.label = #1 add-on;#1 add-ons +addonsCount.label = #1 addon;#1 addons save.recoverykey.title = Save Recovery Key -save.recoverykey.defaultfilename = Firefox Recovery Key.html +save.recoverykey.defaultfilename = Pale Moon Recovery Key.html -newAccount.action.label = Firefox Sync is now set up to automatically sync all of your browser data. +newAccount.action.label = Sync is now set up to automatically sync all of your browser data. newAccount.change.label = You can choose exactly what to sync by selecting Sync Options below. -resetClient.change2.label = Firefox Sync will now merge all this device’s browser data into your Sync account. -wipeClient.change2.label = Firefox Sync will now replace all of the browser data on this device with the data in your Sync account. -wipeRemote.change2.label = Firefox Sync will now replace all of the browser data in your Sync account with the data on this device. +resetClient.change2.label = Sync will now merge all this device's browser data into your Sync account. +wipeClient.change2.label = Sync will now replace all of the browser data on this device with the data in your Sync account. +wipeRemote.change2.label = Sync will now replace all of the browser data in your Sync account with the data on this device. existingAccount.change.label = You can change this preference by selecting Sync Options below. # Several other strings are used (via Weave.Status.login), but they come from # /services/sync - -# Firefox Accounts based setup. -continue.label = Continue - -# LOCALIZATION NOTE (disconnect.label, disconnect.verify.title, disconnect.verify.bodyHeading, disconnect.verify.bodyText): -# These strings are used in the confirmation dialog shown when the user hits the disconnect button -# LOCALIZATION NOTE (disconnect.label): This is the label for the disconnect button -disconnect.label = Disconnect -disconnect.verify.title = Disconnect -disconnect.verify.bodyHeading = Disconnect from Sync? -disconnect.verify.bodyText = Your browsing data will remain on this computer, but it will no longer sync with your account. - -relinkVerify.title = Merge Warning -relinkVerify.heading = Are you sure you want to sign in to Sync? -# LOCALIZATION NOTE (relinkVerify.description): Email address of a user previously signed into sync. -relinkVerify.description = A different user was previously signed in to Sync on this computer. Signing in will merge this browser’s bookmarks, passwords and other settings with %S diff --git a/application/basilisk/locales/jar.mn b/application/basilisk/locales/jar.mn index 1a9b7f315..1e1e9be2f 100644 --- a/application/basilisk/locales/jar.mn +++ b/application/basilisk/locales/jar.mn @@ -7,7 +7,6 @@ @AB_CD@.jar: % locale browser @AB_CD@ %locale/browser/ * locale/browser/bookmarks.html (generic/profile/bookmarks.html.in) - locale/browser/aboutAccounts.dtd (%chrome/browser/aboutAccounts.dtd) locale/browser/aboutDialog.dtd (%chrome/browser/aboutDialog.dtd) locale/browser/aboutPrivateBrowsing.dtd (%chrome/browser/aboutPrivateBrowsing.dtd) locale/browser/aboutPrivateBrowsing.properties (%chrome/browser/aboutPrivateBrowsing.properties) @@ -20,8 +19,7 @@ locale/browser/aboutSessionRestore.dtd (%chrome/browser/aboutSessionRestore.dtd) locale/browser/aboutTabCrashed.dtd (%chrome/browser/aboutTabCrashed.dtd) locale/browser/syncCustomize.dtd (%chrome/browser/syncCustomize.dtd) - locale/browser/aboutSyncTabs.dtd (%chrome/browser/aboutSyncTabs.dtd) - locale/browser/browser.dtd (%chrome/browser/browser.dtd) +* locale/browser/browser.dtd (%chrome/browser/browser.dtd) locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd) locale/browser/browser.properties (%chrome/browser/browser.properties) locale/browser/customizableui/customizableWidgets.properties (%chrome/browser/customizableui/customizableWidgets.properties) @@ -90,6 +88,10 @@ locale/browser/syncKey.dtd (%chrome/browser/syncKey.dtd) locale/browser/syncQuota.dtd (%chrome/browser/syncQuota.dtd) locale/browser/syncQuota.properties (%chrome/browser/syncQuota.properties) +#ifdef MOZ_SERVICES_SYNC + locale/browser/syncProgress.dtd (%chrome/browser/syncProgress.dtd) + locale/browser/aboutSyncTabs.dtd (%chrome/browser/aboutSyncTabs.dtd) +#endif % resource search-plugins chrome://browser/locale/searchplugins/ #if BUILD_FASTER locale/browser/searchplugins/ (searchplugins/*.xml) diff --git a/application/basilisk/themes/linux/jar.mn b/application/basilisk/themes/linux/jar.mn index 189027812..5835b1ca6 100644 --- a/application/basilisk/themes/linux/jar.mn +++ b/application/basilisk/themes/linux/jar.mn @@ -9,7 +9,6 @@ browser.jar: skin/classic/browser/sanitizeDialog.css skin/classic/browser/aboutSessionRestore-window-icon.png skin/classic/browser/aboutSyncTabs.css -* skin/classic/browser/syncedtabs/sidebar.css (syncedtabs/sidebar.css) skin/classic/browser/actionicon-tab.png * skin/classic/browser/browser.css * skin/classic/browser/devedition.css @@ -125,6 +124,7 @@ browser.jar: skin/classic/browser/syncQuota.css skin/classic/browser/syncProgress-horizontalbar.png skin/classic/browser/syncProgress-horizontalbar@2x.png + skin/classic/browser/syncProgress.css [extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar: % override chrome://browser/skin/feeds/audioFeedIcon.png chrome://browser/skin/feeds/feedIcon.png diff --git a/application/basilisk/themes/linux/syncProgress.css b/application/basilisk/themes/linux/syncProgress.css new file mode 100644 index 000000000..d7aa59976 --- /dev/null +++ b/application/basilisk/themes/linux/syncProgress.css @@ -0,0 +1,46 @@ +/* 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/. */ +@import url(chrome://global/skin/inContentUI.css); + +:root { + height: 100%; + width: 100%; + padding: 0; +} + +body { + margin: 0; + padding: 0 2em; +} + +#floatingBox { + margin: 4em auto; + max-width: 40em; + min-width: 23em; + padding: 1em 1.5em; + position: relative; + text-align: center; +} + +#successLogo { + margin: 1em 2em; +} + +#loadingText { + margin: 2em 6em; +} + +#progressBar { + margin: 2em 10em; +} + +#uploadProgressBar{ + width: 100%; +} + +#bottomRow { + margin-top: 2em; + padding: 0; + text-align: end; +} diff --git a/application/basilisk/themes/linux/syncedtabs/sidebar.css b/application/basilisk/themes/linux/syncedtabs/sidebar.css deleted file mode 100644 index 04e00a7d4..000000000 --- a/application/basilisk/themes/linux/syncedtabs/sidebar.css +++ /dev/null @@ -1,69 +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/. */ - -%include ../../shared/syncedtabs/sidebar.inc.css - -/* These styles are intended to mimic XUL trees and the XUL search box. */ - -html { - border: 1px solid ThreeDShadow; - background-color: -moz-Field; - color: -moz-FieldText; - box-sizing: border-box; -} - -.item { - padding-inline-end: 0; -} - -.item-title { - margin: 1px 0 0; - margin-inline-end: 6px; -} - - -.search-box { - -moz-appearance: textfield; - cursor: text; - margin: 2px 4px; - border: 2px solid; - -moz-border-top-colors: ThreeDShadow ThreeDDarkShadow; - -moz-border-right-colors: ThreeDHighlight ThreeDLightShadow; - -moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow; - -moz-border-left-colors: ThreeDShadow ThreeDDarkShadow; - padding: 2px 2px 3px; - padding-inline-start: 4px; - background-color: -moz-Field; - color: -moz-FieldText; -} - -.textbox-search-clear { - background-image: url(moz-icon://stock/gtk-clear?size=menu); - background-repeat: no-repeat; - width: 16px; - height: 16px; -} - -.textbox-search-icon { - background-image: url(moz-icon://stock/gtk-find?size=menu); - background-repeat: no-repeat; - width: 16px; - height: 16px; - display: block; -} - -.textbox-search-icon[searchbutton]:not([disabled]) , -.textbox-search-clear:not([disabled]) { - cursor: pointer; -} - -.item.client .item-twisty-container { - -moz-appearance: treetwistyopen; - margin-top: 3px; - margin-left: 2px; -} - -.item.client.closed .item-twisty-container { - -moz-appearance: treetwisty; -} diff --git a/application/basilisk/themes/osx/jar.mn b/application/basilisk/themes/osx/jar.mn index 27802843d..39fcf6343 100644 --- a/application/basilisk/themes/osx/jar.mn +++ b/application/basilisk/themes/osx/jar.mn @@ -8,7 +8,6 @@ browser.jar: skin/classic/browser/sanitizeDialog.css skin/classic/browser/aboutSessionRestore-window-icon.png skin/classic/browser/aboutSyncTabs.css -* skin/classic/browser/syncedtabs/sidebar.css (syncedtabs/sidebar.css) skin/classic/browser/actionicon-tab.png skin/classic/browser/actionicon-tab@2x.png * skin/classic/browser/browser.css @@ -179,6 +178,7 @@ browser.jar: skin/classic/browser/syncProgress-toolbar@2x.png skin/classic/browser/syncProgress-toolbar-inverted.png skin/classic/browser/syncProgress-toolbar-inverted@2x.png + skin/classic/browser/syncProgress.css skin/classic/browser/Toolbar-background-noise.png (Toolbar-background-noise.png) skin/classic/browser/lion/toolbarbutton-dropmarker.png (toolbarbutton-dropmarker-lion.png) skin/classic/browser/toolbarbutton-dropmarker@2x.png (toolbarbutton-dropmarker-lion@2x.png) diff --git a/application/basilisk/themes/osx/syncProgress.css b/application/basilisk/themes/osx/syncProgress.css new file mode 100644 index 000000000..d7aa59976 --- /dev/null +++ b/application/basilisk/themes/osx/syncProgress.css @@ -0,0 +1,46 @@ +/* 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/. */ +@import url(chrome://global/skin/inContentUI.css); + +:root { + height: 100%; + width: 100%; + padding: 0; +} + +body { + margin: 0; + padding: 0 2em; +} + +#floatingBox { + margin: 4em auto; + max-width: 40em; + min-width: 23em; + padding: 1em 1.5em; + position: relative; + text-align: center; +} + +#successLogo { + margin: 1em 2em; +} + +#loadingText { + margin: 2em 6em; +} + +#progressBar { + margin: 2em 10em; +} + +#uploadProgressBar{ + width: 100%; +} + +#bottomRow { + margin-top: 2em; + padding: 0; + text-align: end; +} diff --git a/application/basilisk/themes/osx/syncedtabs/sidebar.css b/application/basilisk/themes/osx/syncedtabs/sidebar.css deleted file mode 100644 index 4d1de766c..000000000 --- a/application/basilisk/themes/osx/syncedtabs/sidebar.css +++ /dev/null @@ -1,154 +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/. */ - -%include ../../shared/syncedtabs/sidebar.inc.css - -/* These styles are intended to mimic XUL trees and the XUL search box. */ - -.content-container { - -moz-appearance: -moz-mac-source-list; -} - -.item { - color: -moz-DialogText; -} - -.item-title-container { - box-sizing: border-box; - align-items: center; - height: 24px; - font-size: 12px; -} - -.item.selected > .item-title-container { - color: HighlightText; - font-weight: bold; -} - -.item.selected > .item-title-container { - -moz-appearance: -moz-mac-source-list-selection; -} - -.item.selected:focus > .item-title-container { - -moz-appearance: -moz-mac-active-source-list-selection; -} - -.item.client .item-twisty-container { - min-width: 16px; - height: 16px; - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-expanded"); -} - -@media not all and (-moz-mac-yosemite-theme) { - .item.client.selected .item-twisty-container { - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-expanded-inverted"); - } - - .item.client.selected.closed .item-twisty-container { - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-collapsed-inverted"); - } - - .item.client.selected .item-twisty-container:dir(rtl) { - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-expanded-inverted"); - } - - .item.client.selected.closed .item-twisty-container:dir(rtl) { - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-collapsed-inverted-rtl"); - } -} - -.item.client.closed .item-twisty-container { - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-collapsed"); -} - -.item.client.selected:focus .item-twisty-container { - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-expanded-inverted"); -} - -.item.client.selected.closed:focus .item-twisty-container { - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-collapsed-inverted"); -} - -.item.client .item-twisty-container:dir(rtl) { - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-expanded"); -} - -.item.client.closed .item-twisty-container:dir(rtl) { - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-collapsed-rtl"); -} - -.item.client.selected:focus .item-twisty-container:dir(rtl) { - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-expanded-inverted"); -} - -.item.client.selected.closed:focus .item-twisty-container:dir(rtl) { - background-image: url("chrome://global/skin/tree/arrow-disclosure.svg#arrow-disclosure-collapsed-inverted-rtl"); -} - -@media (-moz-mac-yosemite-theme) { - .item.selected > .item-title-container { - color: -moz-dialogtext; - font-weight: 500; - } - - .item.selected:focus > .item-title-container { - color: #fff; - } -} - -.sidebar-search-container { - border-bottom: 1px solid #bdbdbd; -} - -.search-box { - -moz-appearance: searchfield; - padding: 1px; - font-size: 12px; - cursor: text; - margin: 4px 8px 10px; - border-width: 3px; - border-style: solid; - border-color: currentcolor; - border-image: none; - -moz-border-top-colors: transparent #888 #000; - -moz-border-right-colors: transparent #FFF #000; - -moz-border-bottom-colors: transparent #FFF #000; - -moz-border-left-colors: transparent #888 #000; - border-top-right-radius: 2px; - border-bottom-left-radius: 2px; - background-color: #FFF; - color: #000; - -moz-user-select: text; - text-shadow: none; -} - -.search-box.compact > .textbox-input-box > .textbox-search-icons > .textbox-search-clear { - background-image: url(chrome://global/skin/icons/searchfield-cancel.svg); - background-repeat: no-repeat; - background-size: 11px 11px; - width: 11px; - height: 11px; -} - -.search-box.compact > .textbox-input-box > .textbox-search-icons > .textbox-search-icon { - display: none; -} - -.search-box[focused="true"] { - -moz-border-top-colors: -moz-mac-focusring -moz-mac-focusring #000000; - -moz-border-right-colors: -moz-mac-focusring -moz-mac-focusring #000000; - -moz-border-bottom-colors: -moz-mac-focusring -moz-mac-focusring #000000; - -moz-border-left-colors: -moz-mac-focusring -moz-mac-focusring #000000; -} - -.search-box.compact { - padding: 0px; - /* font size is in px because the XUL it was copied from uses px */ - font-size: 11px; -} - -.textbox-search-clear, -.textbox-search-icon { - margin-top: 1px; -} diff --git a/application/basilisk/themes/shared/browser.inc b/application/basilisk/themes/shared/browser.inc index 81caf94d6..6989f064a 100644 --- a/application/basilisk/themes/shared/browser.inc +++ b/application/basilisk/themes/shared/browser.inc @@ -2,7 +2,7 @@ % Note that zoom-reset-button is a bit different since it doesn't use an image and thus has the image with display: none. %define nestedButtons #zoom-out-button, #zoom-reset-button, #zoom-in-button, #cut-button, #copy-button, #paste-button -%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #fullscreen-button, #sync-button, #feed-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button, @nestedButtons@, #e10s-button, #panic-button, #webide-button, #containers-panelmenu +%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #fullscreen-button, #sync-button, #sync-tabs-button, #feed-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button, @nestedButtons@, #e10s-button, #panic-button, #webide-button, #containers-panelmenu %ifdef XP_MACOSX % Prior to 10.7 there wasn't a native fullscreen button so we use #restore-button to exit fullscreen diff --git a/application/basilisk/themes/shared/customizableui/panelUI.inc.css b/application/basilisk/themes/shared/customizableui/panelUI.inc.css index ba36da995..5550ef295 100644 --- a/application/basilisk/themes/shared/customizableui/panelUI.inc.css +++ b/application/basilisk/themes/shared/customizableui/panelUI.inc.css @@ -61,8 +61,7 @@ height: 13px; } -#PanelUI-menu-button[badge-status="download-warning"] > .toolbarbutton-badge-stack > .toolbarbutton-badge, -#PanelUI-menu-button[badge-status="fxa-needs-authentication"] > .toolbarbutton-badge-stack > .toolbarbutton-badge { +#PanelUI-menu-button[badge-status="download-warning"] > .toolbarbutton-badge-stack > .toolbarbutton-badge { box-shadow: none; filter: drop-shadow(0 1px 0 hsla(206, 50%, 10%, .15)); } @@ -86,13 +85,7 @@ background: #D90000; } -#PanelUI-menu-button[badge-status="fxa-needs-authentication"] > .toolbarbutton-badge-stack > .toolbarbutton-badge { - height: 13px; - background: transparent url(chrome://browser/skin/warning.svg) no-repeat center; -} - -#PanelUI-menu-button[badge-status="download-warning"] > .toolbarbutton-badge-stack > .toolbarbutton-badge:-moz-window-inactive, -#PanelUI-menu-button[badge-status="fxa-needs-authentication"] > .toolbarbutton-badge-stack > .toolbarbutton-badge:-moz-window-inactive { +#PanelUI-menu-button[badge-status="download-warning"] > .toolbarbutton-badge-stack > .toolbarbutton-badge:-moz-window-inactive { filter: none; } @@ -381,9 +374,6 @@ toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"] > iframe { #PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-contents-scroller > #PanelUI-contents > .panel-wide-item, #PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-contents-scroller > #PanelUI-contents > .toolbarbutton-1:not([panel-multiview-anchor="true"]), #PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-update-status, -#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-fxa > #PanelUI-fxa-status > #PanelUI-fxa-avatar, -#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-fxa > #PanelUI-fxa-status > #PanelUI-fxa-label, -#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-fxa > #PanelUI-fxa-icon, #PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > toolbarseparator, #PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > #PanelUI-customize, #PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > #PanelUI-help:not([panel-multiview-anchor="true"]) { @@ -481,26 +471,6 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton { margin: 0; } -#main-window[customizing] #PanelUI-footer-fxa { - display: none; -} - -#PanelUI-footer-fxa:not([fxastatus="signedin"]) > toolbarseparator, -#PanelUI-footer-fxa:not([fxastatus="signedin"]) > #PanelUI-fxa-icon, -#PanelUI-footer-fxa:not([fxaprofileimage]) > #PanelUI-fxa-status > #PanelUI-fxa-avatar { - display: none; -} - -#PanelUI-footer-fxa[fxastatus="error"] > #PanelUI-fxa-status::after { - content: url(chrome://browser/skin/warning.svg); - filter: drop-shadow(0 1px 0 hsla(206,50%,10%,.15)); - width: 47px; - padding-top: 1px; - display: block; - text-align: center; - position: relative; - top: 25%; -} #PanelUI-update-status[update-status]::after { content: ""; @@ -523,40 +493,28 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton { background-color: #D90000; } -#PanelUI-fxa-status { - display: flex; - flex: 1 1 0%; - width: 1px; -} - -#PanelUI-footer-inner, -#PanelUI-footer-fxa:not([hidden]) { +#PanelUI-footer-inner { display: flex; border-top: 1px solid var(--panel-separator-color); } -#PanelUI-multiView[viewtype="subview"] #PanelUI-footer-inner, -#PanelUI-multiView[viewtype="subview"] #PanelUI-footer-fxa { +#PanelUI-multiView[viewtype="subview"] #PanelUI-footer-inner { position: relative; } -#PanelUI-footer-inner > toolbarseparator, -#PanelUI-footer-fxa > toolbarseparator { +#PanelUI-footer-inner > toolbarseparator { border: 0; border-left: 1px solid var(--panel-separator-color); margin: 7px 0 7px; -moz-appearance: none; } -#PanelUI-footer-inner:hover > toolbarseparator, -#PanelUI-footer-fxa:hover > toolbarseparator { +#PanelUI-footer-inner:hover > toolbarseparator { margin: 0; } #PanelUI-update-status, #PanelUI-help, -#PanelUI-fxa-label, -#PanelUI-fxa-icon, #PanelUI-customize, #PanelUI-quit { margin: 0; @@ -590,7 +548,6 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton { } #PanelUI-update-status > .toolbarbutton-text, -#PanelUI-fxa-label > .toolbarbutton-text, #PanelUI-customize > .toolbarbutton-text { margin: 0; padding: 0 6px; @@ -598,37 +555,23 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton { } #PanelUI-help > .toolbarbutton-text, -#PanelUI-quit > .toolbarbutton-text, -#PanelUI-fxa-avatar > .toolbarbutton-text { +#PanelUI-quit > .toolbarbutton-text { display: none; } #PanelUI-update-status > .toolbarbutton-icon, -#PanelUI-fxa-label > .toolbarbutton-icon, -#PanelUI-fxa-icon > .toolbarbutton-icon, #PanelUI-customize > .toolbarbutton-icon, #PanelUI-help > .toolbarbutton-icon, #PanelUI-quit > .toolbarbutton-icon { margin-inline-end: 0; } -#PanelUI-fxa-icon { - padding-inline-start: 15px; - padding-inline-end: 15px; -} - -#PanelUI-fxa-label, #PanelUI-customize { flex: 1; padding-inline-start: 15px; border-inline-start-style: none; } -#PanelUI-footer-fxa[fxaprofileimage="set"] > #PanelUI-fxa-status > #PanelUI-fxa-label, -#PanelUI-footer-fxa[fxaprofileimage="enabled"]:not([fxastatus="error"]) > #PanelUI-fxa-status > #PanelUI-fxa-label { - padding-inline-start: 0px; -} - #PanelUI-update-status { width: calc(@menuPanelWidth@ + 30px); padding-inline-start: 15px; @@ -639,130 +582,6 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton { list-style-image: url(chrome://branding/content/icon16.png); } -#PanelUI-fxa-label, -#PanelUI-fxa-icon { - list-style-image: url(chrome://browser/skin/sync-horizontalbar.png); -} - -#PanelUI-remotetabs { - --panel-ui-sync-illustration-height: 157.5px; -} - -.PanelUI-remotetabs-instruction-title, -.PanelUI-remotetabs-instruction-label, -#PanelUI-remotetabs-mobile-promo { - /* If you change the margin here, the min-height of the synced tabs panel - (e.g. #PanelUI-remotetabs[mainview] #PanelUI-remotetabs-setupsync, etc) may - need adjusting (see bug 1248506) */ - margin: 15px; - text-align: center; - text-shadow: none; - max-width: 15em; - color: GrayText; -} - -.PanelUI-remotetabs-instruction-title { - font-size: 1.3em; -} - -/* The boxes with "instructions" get extra top and bottom padding for space - around the illustration and buttons */ -.PanelUI-remotetabs-instruction-box { - /* If you change the padding here, the min-height of the synced tabs panel - (e.g. #PanelUI-remotetabs[mainview] #PanelUI-remotetabs-setupsync, etc) may - need adjusting (see bug 1248506) */ - padding-bottom: 30px; - padding-top: 15px; -} - -.PanelUI-remotetabs-prefs-button { - -moz-appearance: none; - background-color: #0096dd; - /* !important for the color as an OSX specific rule when a lightweight theme - is used for buttons in the toolbox overrides. See bug 1238531 for details */ - color: white !important; - border-radius: 2px; - /* If you change the margin or padding below, the min-height of the synced tabs - panel (e.g. #PanelUI-remotetabs[mainview] #PanelUI-remotetabs-setupsync, - etc) may need adjusting (see bug 1248506) */ - margin-top: 10px; - margin-bottom: 10px; - padding: 8px; - text-shadow: none; - min-width: 200px; -} - -.PanelUI-remotetabs-prefs-button:hover, -.PanelUI-remotetabs-prefs-button:hover:active { - background-color: #018acb; -} - -.remotetabs-promo-link { - margin: 0; -} - -.PanelUI-remotetabs-notabsforclient-label { - color: GrayText; - /* This margin is to line this label up with the labels in toolbarbuttons. */ - margin-left: 28px; -} - -.fxaSyncIllustration { - height: var(--panel-ui-sync-illustration-height); - list-style-image: url(chrome://browser/skin/fxa/sync-illustration.svg); -} - -.PanelUI-remotetabs-prefs-button > .toolbarbutton-text { - /* !important to override ".cui-widget-panel toolbarbutton > .toolbarbutton-text" above. */ - text-align: center !important; - text-shadow: none; -} - -#PanelUI-remotetabs[mainview] { /* panel anchored to toolbar button might be too skinny */ - min-width: 19em; -} - -/* Work around bug 1224412 - these boxes will cause scrollbars to appear when - the panel is anchored to a toolbar button. -*/ -#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-setupsync, -#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-reauthsync, -#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-nodevicespane, -#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-tabsdisabledpane { - min-height: calc(var(--panel-ui-sync-illustration-height) + - 20px + /* margin of .PanelUI-remotetabs-prefs-button */ - 16px + /* padding of .PanelUI-remotetabs-prefs-button */ - 30px + /* margin of .PanelUI-remotetabs-instruction-label */ - 30px + 15px + /* padding of .PanelUI-remotetabs-instruction-box */ - 11em); -} - -#PanelUI-remotetabs-tabslist > label[itemtype="client"] { - color: GrayText; -} - -/* Collapse the non-active vboxes in the remotetabs deck to use only the - height the active box needs */ -#PanelUI-remotetabs-deck:not([selectedIndex="1"]) > #PanelUI-remotetabs-tabsdisabledpane, -#PanelUI-remotetabs-deck:not([selectedIndex="2"]) > #PanelUI-remotetabs-fetching, -#PanelUI-remotetabs-deck:not([selectedIndex="3"]) > #PanelUI-remotetabs-nodevicespane { - visibility: collapse; -} - -#PanelUI-remotetabs-main[devices-status="single"] > #PanelUI-remotetabs-buttons { - display: none; -} - -#PanelUI-fxa-icon[syncstatus="active"]:not([disabled]) { - list-style-image: url(chrome://browser/skin/syncProgress-horizontalbar.png); -} - -#PanelUI-footer-fxa[fxastatus="migrate-signup"] > #PanelUI-fxa-status > #PanelUI-fxa-label, -#PanelUI-footer-fxa[fxastatus="migrate-verify"] > #PanelUI-fxa-status > #PanelUI-fxa-label { - list-style-image: url(chrome://browser/skin/warning.svg); - -moz-image-region: auto; -} - #PanelUI-customize { list-style-image: url(chrome://browser/skin/menuPanel-customize.png); } @@ -780,46 +599,12 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton { list-style-image: url(chrome://browser/skin/menuPanel-exit.png); } -#PanelUI-fxa-label, -#PanelUI-fxa-icon, #PanelUI-customize, #PanelUI-help, #PanelUI-quit { -moz-image-region: rect(0, 16px, 16px, 0); } -#PanelUI-footer-fxa[fxastatus="signedin"] > #PanelUI-fxa-status > #PanelUI-fxa-label > .toolbarbutton-icon, -#PanelUI-footer-fxa[fxastatus="error"][fxaprofileimage="set"] > #PanelUI-fxa-status > #PanelUI-fxa-label > .toolbarbutton-icon { - display: none; -} - -#PanelUI-footer-fxa[fxastatus="error"]:not([fxaprofileimage="set"]) > #PanelUI-fxa-status > #PanelUI-fxa-avatar { - display: none; -} - -#PanelUI-fxa-status[disabled], -#PanelUI-fxa-icon[disabled] { - pointer-events: none; -} - -#PanelUI-fxa-avatar { - width: 32px; - height: 32px; - border-radius: 50%; - background-repeat: no-repeat; - background-position: 0 0; - background-size: contain; - align-self: center; - margin: 0px 7px; - padding: 0px; - border: 0px none; - margin-inline-end: 0; -} - -#PanelUI-footer-fxa[fxaprofileimage="enabled"] > #PanelUI-fxa-status > #PanelUI-fxa-avatar { - list-style-image: url(chrome://browser/skin/fxa/default-avatar.svg); -} - #PanelUI-customize:hover, #PanelUI-help:not([disabled]):hover, #PanelUI-quit:not([disabled]):hover { @@ -837,16 +622,10 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton { } #PanelUI-help[disabled], -#PanelUI-quit[disabled], -#PanelUI-fxa-icon[disabled], -#PanelUI-fxa-avatar[disabled], -#PanelUI-fxa-label[disabled] > .toolbarbutton-icon, -#PanelUI-fxa-status::after { +#PanelUI-quit[disabled] { opacity: 0.4; } -#PanelUI-fxa-status:not([disabled]):hover, -#PanelUI-fxa-icon:not([disabled]):hover, #PanelUI-help:not([disabled]):hover, #PanelUI-customize:hover, #PanelUI-quit:not([disabled]):hover { @@ -854,8 +633,6 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton { background-color: var(--arrowpanel-dimmed); } -#PanelUI-fxa-status:not([disabled]):hover:active, -#PanelUI-fxa-icon:not([disabled]):hover:active, #PanelUI-help:not([disabled]):hover:active, #PanelUI-customize:hover:active, #PanelUI-quit:not([disabled]):hover:active { @@ -864,27 +641,6 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton { box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset; } -#PanelUI-fxa-status:not([disabled]):hover, -#PanelUI-fxa-status:not([disabled]):hover:active, -#PanelUI-fxa-icon:not([disabled]):hover, -#PanelUI-fxa-icon:not([disabled]):hover:active { - outline: none; -} - -#PanelUI-footer-fxa[fxastatus="error"] { - background-color: hsl(42,94%,88%); - border-top: 1px solid hsl(42,94%,70%); -} - -#PanelUI-footer-fxa[fxastatus="error"] > #PanelUI-fxa-status:hover { - background-color: hsl(42,94%,85%); -} - -#PanelUI-footer-fxa[fxastatus="error"] > #PanelUI-fxa-status:hover:active { - background-color: hsl(42,94%,82%); - box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset; -} - #PanelUI-update-status { color: black; } @@ -1150,19 +906,16 @@ menuitem.panel-subview-footer@menuStateActive@, color: GrayText; } -#PanelUI-remotetabs-tabslist > toolbarbutton, #PanelUI-historyItems > toolbarbutton { list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); } @media (min-resolution: 1.1dppx) { - #PanelUI-remotetabs-tabslist > toolbarbutton, #PanelUI-historyItems > toolbarbutton { list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png"); } } -#PanelUI-remotetabs-tabslist > toolbarbutton > .toolbarbutton-icon, #PanelUI-recentlyClosedWindows > toolbarbutton > .toolbarbutton-icon, #PanelUI-recentlyClosedTabs > toolbarbutton > .toolbarbutton-icon, #PanelUI-historyItems > toolbarbutton > .toolbarbutton-icon { @@ -1616,15 +1369,6 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left { list-style-image: url(chrome://branding/content/icon32.png); } - #PanelUI-fxa-label, - #PanelUI-fxa-icon { - list-style-image: url(chrome://browser/skin/sync-horizontalbar@2x.png); - } - - #PanelUI-fxa-icon[syncstatus="active"]:not([disabled]) { - list-style-image: url(chrome://browser/skin/syncProgress-horizontalbar@2x.png); - } - #PanelUI-customize { list-style-image: url(chrome://browser/skin/menuPanel-customize@2x.png); } @@ -1641,8 +1385,6 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left { list-style-image: url(chrome://browser/skin/menuPanel-exit@2x.png); } - #PanelUI-fxa-label, - #PanelUI-fxa-icon, #PanelUI-customize, #PanelUI-help, #PanelUI-quit { @@ -1650,8 +1392,6 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left { } #PanelUI-update-status > .toolbarbutton-icon, - #PanelUI-fxa-label > .toolbarbutton-icon, - #PanelUI-fxa-icon > .toolbarbutton-icon, #PanelUI-customize > .toolbarbutton-icon, #PanelUI-help > .toolbarbutton-icon, #PanelUI-quit > .toolbarbutton-icon { diff --git a/application/basilisk/themes/shared/menupanel.inc.css b/application/basilisk/themes/shared/menupanel.inc.css index 266e1c83e..2feb941a2 100644 --- a/application/basilisk/themes/shared/menupanel.inc.css +++ b/application/basilisk/themes/shared/menupanel.inc.css @@ -48,11 +48,32 @@ toolbarpaletteitem[place="palette"] > #save-page-button { -moz-image-region: rect(0px, 352px, 32px, 320px); } +/* Start Sync Buttons */ + #sync-button[cui-areatype="menu-panel"], toolbarpaletteitem[place="palette"] > #sync-button { + -moz-image-region: rect(0px, 384px, 32px, 352px) +} + +#sync-button[cui-areatype="menu-panel"][status="active"] { + list-style-image: url("chrome://browser/skin/syncProgress-menuPanel.png"); + -moz-image-region: rect(0, 32px, 32px, 0); +} + +@media (min-resolution: 1.1dppx) { + #sync-button[cui-areatype="menu-panel"][status="active"] { + list-style-image: url("chrome://browser/skin/syncProgress-menuPanel@2x.png"); + -moz-image-region: rect(0, 64px, 64px, 0); + } +} + +#sync-tabs-button[cui-areatype="menu-panel"], +toolbarpaletteitem[place="palette"] > #sync-tabs-button { -moz-image-region: rect(0px, 1024px, 32px, 992px); } +/* End Sync Buttons */ + #containers-panelmenu[cui-areatype="menu-panel"], toolbarpaletteitem[place="palette"] > #containers-panelmenu { -moz-image-region: rect(0px, 1056px, 32px, 1024px); diff --git a/application/basilisk/themes/shared/syncedtabs/sidebar.inc.css b/application/basilisk/themes/shared/syncedtabs/sidebar.inc.css deleted file mode 100644 index 4e76a7fc5..000000000 --- a/application/basilisk/themes/shared/syncedtabs/sidebar.inc.css +++ /dev/null @@ -1,234 +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/. - -/* These styles are intended to mimic XUL trees and the XUL search box. */ - -html { - height: 100%; -} - -body { - height: 100%; - margin: 0; - font: message-box; - color: #333333; - -moz-user-select: none; -} - -/* The content-container holds the non-scrollable header and the scrollable - content area. -*/ -.content-container { - display: flex; - flex-flow: column; - height: 100%; -} - -/* The content header is not scrollable */ -.content-header { - flex: 0 1 auto; -} - -/* The main content area is scrollable and fills the rest of the area */ -.content-scrollable { - flex: 1 1 auto; - overflow: auto; -} - -.emptyListInfo { - cursor: default; - padding: 3em 1em; - text-align: center; -} - -.list, -.item-tabs-list { - display: flex; - flex-flow: column; - flex-grow: 1; -} - -.item.client { - opacity: 1; - max-height: unset; - display: unset; -} - -.item.client.closed .item-tabs-list { - display: none; -} - -.item { - display: inline-block; - opacity: 1; - flex: 1; - min-width: 0; - white-space: nowrap; - overflow: hidden; - outline: none; - color: -moz-FieldText; -} - -.item.selected > .item-title-container { - background-color: -moz-cellhighlight; - color: -moz-cellhighlighttext; - font-weight: bold; -} - -.item.selected:focus > .item-title-container { - background-color: Highlight; - color: HighlightText; -} - -.client .item.tab > .item-title-container { - padding-inline-start: 35px; -} - -.item.tab > .item-title-container { - padding-inline-start: 20px; -} - -.item.client.device-image-desktop > .item-title-container > .item-icon-container { - background-image: url("chrome://browser/skin/sync-desktopIcon.svg#icon"); -} - -.item.client.device-image-desktop.selected:focus > .item-title-container > .item-icon-container { - background-image: url("chrome://browser/skin/sync-desktopIcon.svg#icon-inverted"); -} - -.item.client.device-image-mobile > .item-title-container > .item-icon-container { - background-image: url("chrome://browser/skin/sync-mobileIcon.svg#icon"); -} - -.item.client.device-image-mobile.selected:focus > .item-title-container > .item-icon-container { - background-image: url("chrome://browser/skin/sync-mobileIcon.svg#icon-inverted"); -} - -.item.tab > .item-title-container > .item-icon-container { - background-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); -} - -@media (min-resolution: 1.1dppx) { -.item.tab > .item-title-container > .item-icon-container { - background-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png"); - } -} - -.item-icon-container { - min-width: 16px; - max-width: 16px; - min-height: 16px; - max-height: 16px; - margin-right: 5px; - margin-left: 5px; - background-size: 16px 16px; - background-size: contain; - background-repeat: no-repeat; - background-position: center; -} - -.item-title-container { - display: flex; - flex-flow: row; - overflow: hidden; - flex-grow: 1; - padding: 1px 0px 1px 0px; -} - -.item-title { - flex-grow: 1; - overflow: hidden; - text-overflow: ellipsis; - margin: 0px; - line-height: 1.3; - cursor: default; -} - -.item[hidden] { - opacity: 0; - max-height: 0; - transition: opacity 150ms ease-in-out, max-height 150ms ease-in-out 150ms; -} - -.item.empty .item-title-container { - color: #aeaeae; -} - -.client .item.empty > .item-title-container { - padding-inline-start: 35px; -} - -.text-input-box { - display: flex; - flex-flow: row nowrap; -} - -.textbox-input-box { - display: flex; - flex-direction: row; -} - -.tabsFilter { - flex: 1; - /* min-width of anything to override the implicit "-moz-min-content" value. - 0px is safe as the sidebar itself has a constrained size meaning we will - never actually hit this minimum - */ - min-width: 0px; -} - -.sync-state > p { - padding-inline-end: 10px; - padding-inline-start: 10px; - color: #888; -} - -.text-link { - color: rgb(0, 149, 221); - cursor: pointer; -} - -.text-link:hover { - text-decoration: underline; -} - -.text-link, -.text-link:focus { - margin: 0px; - padding: 0px; - border: 0px; -} - -.deck .sync-state { - display: none; - opacity: 0; - transition: opacity 1.5s; - border-top: 1px solid #bdbdbd; -} - -.deck .sync-state.tabs-container { - border-top: 0px; -} - -.deck .sync-state.selected { - display: unset; - opacity: 100; -} - -.sidebar-search-container.tabs-container:not(.selected) { - display: none; -} - -.textbox-search-clear:not([disabled]) { - cursor: default; -} - -.textbox-search-icons .textbox-search-clear, -.filtered .textbox-search-icons .textbox-search-icon { - display: none; -} - -.filtered .textbox-search-icons .textbox-search-clear { - display: block; -} diff --git a/application/basilisk/themes/shared/toolbarbuttons.inc.css b/application/basilisk/themes/shared/toolbarbuttons.inc.css index c043b8192..2f74b8361 100644 --- a/application/basilisk/themes/shared/toolbarbuttons.inc.css +++ b/application/basilisk/themes/shared/toolbarbuttons.inc.css @@ -52,10 +52,35 @@ toolbar[brighttext] #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarke -moz-image-region: rect(0, 252px, 18px, 234px); } +/* Start Sync Buttons */ + #sync-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 270px, 18px, 252px); +} + +#sync-button[cui-areatype="toolbar"][status="active"] { + list-style-image: url("chrome://browser/skin/syncProgress-toolbar.png"); + -moz-image-region: rect(0, 18px, 18px, 0); +} + +@media (-moz-os-version: windows-win7) { + #sync-button[cui-areatype="toolbar"][status="active"] { + list-style-image: url("chrome://browser/skin/syncProgress-toolbar-win7.png"); + -moz-image-region: rect(0, 18px, 18px, 0); + } +} + +toolbar[brighttext] #sync-button[cui-areatype="toolbar"][status="active"] { + list-style-image: url("chrome://browser/skin/syncProgress-toolbar-inverted.png"); + -moz-image-region: rect(0, 18px, 18px, 0); +} + +#sync-tabs-button[cui-areatype="toolbar"] { -moz-image-region: rect(0, 792px, 18px, 774px); } +/* End Sync Buttons */ + #containers-panelmenu[cui-areatype="toolbar"] { -moz-image-region: rect(0, 810px, 18px, 792px); } @@ -226,10 +251,35 @@ toolbar[brighttext] #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarke -moz-image-region: rect(0, 504px, 36px, 468px); } + /* Start Sync Buttons */ + #sync-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 540px, 36px, 504px); + } + + #sync-button[cui-areatype="toolbar"][status="active"] { + list-style-image: url("chrome://browser/skin/syncProgress-toolbar@2x.png"); + -moz-image-region: rect(0, 36px, 36px, 0); + } + + @media (-moz-os-version: windows-win7) { + #sync-button[cui-areatype="toolbar"][status="active"] { + list-style-image: url("chrome://browser/skin/syncProgress-toolbar-win7@2x.png"); + -moz-image-region: rect(0, 36px, 36px, 0); + } + } + + toolbar[brighttext] #sync-button[cui-areatype="toolbar"][status="active"] { + list-style-image: url("chrome://browser/skin/syncProgress-toolbar-inverted@2x.png"); + -moz-image-region: rect(0, 36px, 36px, 0); + } + + #sync-tabs-button[cui-areatype="toolbar"] { -moz-image-region: rect(0, 1584px, 36px, 1548px); } + /* End Sync Buttons */ + #containers-panelmenu[cui-areatype="toolbar"] { -moz-image-region: rect(0, 1620px, 36px, 1584px); } diff --git a/application/basilisk/themes/windows/jar.mn b/application/basilisk/themes/windows/jar.mn index e8db7eed2..09004f57d 100644 --- a/application/basilisk/themes/windows/jar.mn +++ b/application/basilisk/themes/windows/jar.mn @@ -8,7 +8,6 @@ browser.jar: skin/classic/browser/sanitizeDialog.css skin/classic/browser/aboutSessionRestore-window-icon.png skin/classic/browser/aboutSyncTabs.css -* skin/classic/browser/syncedtabs/sidebar.css (syncedtabs/sidebar.css) skin/classic/browser/actionicon-tab.png skin/classic/browser/actionicon-tab@2x.png skin/classic/browser/actionicon-tab-win7.png @@ -167,6 +166,7 @@ browser.jar: skin/classic/browser/syncProgress-toolbar-inverted@2x.png skin/classic/browser/syncProgress-toolbar-win7.png skin/classic/browser/syncProgress-toolbar-win7@2x.png + skin/classic/browser/syncProgress.css [extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar: % override chrome://browser/skin/page-livemarks.png chrome://browser/skin/feeds/feedIcon16.png diff --git a/application/basilisk/themes/windows/syncProgress.css b/application/basilisk/themes/windows/syncProgress.css new file mode 100644 index 000000000..d7aa59976 --- /dev/null +++ b/application/basilisk/themes/windows/syncProgress.css @@ -0,0 +1,46 @@ +/* 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/. */ +@import url(chrome://global/skin/inContentUI.css); + +:root { + height: 100%; + width: 100%; + padding: 0; +} + +body { + margin: 0; + padding: 0 2em; +} + +#floatingBox { + margin: 4em auto; + max-width: 40em; + min-width: 23em; + padding: 1em 1.5em; + position: relative; + text-align: center; +} + +#successLogo { + margin: 1em 2em; +} + +#loadingText { + margin: 2em 6em; +} + +#progressBar { + margin: 2em 10em; +} + +#uploadProgressBar{ + width: 100%; +} + +#bottomRow { + margin-top: 2em; + padding: 0; + text-align: end; +} diff --git a/application/basilisk/themes/windows/syncedtabs/sidebar.css b/application/basilisk/themes/windows/syncedtabs/sidebar.css deleted file mode 100644 index 6473206bc..000000000 --- a/application/basilisk/themes/windows/syncedtabs/sidebar.css +++ /dev/null @@ -1,132 +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/. */ - -%include ../../shared/syncedtabs/sidebar.inc.css - -/* These styles are intended to mimic XUL trees and the XUL search box. */ - -html { - background-color: #EEF3FA; -} - -.item { - padding-inline-end: 0; -} - -.item-title { - margin: 1px 0 0; -} - -.item-title { - margin-inline-end: 6px; -} - -.search-box { - -moz-appearance: textfield; - cursor: text; - margin: 2px 4px; - padding: 2px 2px 3px; - padding-inline-start: 4px; - color: -moz-FieldText; -} - -.textbox-search-icon { - width: 16px; - height: 16px; - background-image: url(chrome://global/skin/icons/Search-glass.png); - background-repeat: no-repeat; - display: block; -} - -.textbox-search-icon:-moz-locale-dir(rtl) { - transform: scaleX(-1); -} - -.textbox-search-icon[searchbutton]:not([disabled]) { - cursor: pointer; -} - -.textbox-search-clear { - width: 16px; - height: 16px; - background-image: url(chrome://global/skin/icons/Search-close.png); - background-repeat: no-repeat; -} - -.textbox-search-clear:not([disabled]) { - cursor: default; -} - -.textbox-search-icon:not([disabled]) { - cursor: text; -} - -.textbox-search-clear:not([disabled]):hover , -.textbox-search-icon:not([disabled]):hover { - background-position: -16px 0; -} - -.textbox-search-clear:not([disabled]):hover:active , -.textbox-search-icon:not([disabled]):hover:active { - background-position: -32px 0; -} - -.client .item.tab > .item-title-container { - padding-inline-start: 26px; -} -.item.tab > .item-title-container { - padding-inline-start: 14px; -} - -.item-icon-container { - min-width: 16px; - max-width: 16px; - min-height: 16px; - max-height: 16px; - margin-right: 5px; - background-size: 16px 16px; - background-repeat: no-repeat; - background-position: center; -} - -.item-twisty-container { - background-size: contain; - background-repeat: no-repeat; - background-position: center; - padding-top: 5px; - min-width: 9px; /* The image's width is 9 pixels */ - height: 9px; -} - -.item.client .item-twisty-container { - background-image: url("chrome://global/skin/tree/twisty.svg#open"); -} - -.item.client.closed .item-twisty-container { - background-image: url("chrome://global/skin/tree/twisty.svg#clsd"); -} - -.item.client .item-twisty-container:hover { - background-image: url("chrome://global/skin/tree/twisty.svg#open-hover"); -} - -.item.client.closed .item-twisty-container:hover { - background-image: url("chrome://global/skin/tree/twisty.svg#clsd-hover"); -} - -.item.client .item-twisty-container:dir(rtl) { - background-image: url("chrome://global/skin/tree/twisty.svg#open-rtl"); -} - -.item.client.closed .item-twisty-container:dir(rtl) { - background-image: url("chrome://global/skin/tree/twisty.svg#clsd-rtl"); -} - -.item.client .item-twisty-container:hover:dir(rtl) { - background-image: url("chrome://global/skin/tree/twisty.svg#open-hover-rtl"); -} - -.item.client.closed .item-twisty-container:hover:dir(rtl) { - background-image: url("chrome://global/skin/tree/twisty.svg#clsd-hover-rtl"); -} diff --git a/application/palemoon/configure.in b/application/palemoon/configure.in index 96f63781e..eb02af3c0 100644 --- a/application/palemoon/configure.in +++ b/application/palemoon/configure.in @@ -36,7 +36,3 @@ MOZ_ARG_DISABLE_BOOL(sync, MOZ_SERVICES_SYNC=, MOZ_SERVICES_SYNC=1) -if test -z "$MOZ_SERVICES_SYNC"; then - MOZ_SERVICES_CLOUDSYNC= -fi - diff --git a/old-configure.in b/old-configure.in index 0ccc0540e..6a7bc701f 100644 --- a/old-configure.in +++ b/old-configure.in @@ -2246,7 +2246,6 @@ MOZ_DEVTOOLS= MOZ_PLACES=1 MOZ_SERVICES_HEALTHREPORT=1 MOZ_SERVICES_SYNC=1 -MOZ_SERVICES_CLOUDSYNC=1 MOZ_USERINFO=1 case "$target_os" in @@ -5006,12 +5005,6 @@ if test -n "$MOZ_SERVICES_SYNC"; then AC_DEFINE(MOZ_SERVICES_SYNC) fi -dnl Build Services/CloudSync if required -AC_SUBST(MOZ_SERVICES_CLOUDSYNC) -if test -n "$MOZ_SERVICES_CLOUDSYNC"; then - AC_DEFINE(MOZ_SERVICES_CLOUDSYNC) -fi - dnl ======================================================== if test "$MOZ_DEBUG"; then diff --git a/services/cloudsync/CloudSync.jsm b/services/cloudsync/CloudSync.jsm deleted file mode 100644 index 2c1057ea9..000000000 --- a/services/cloudsync/CloudSync.jsm +++ /dev/null @@ -1,89 +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"; - -this.EXPORTED_SYMBOLS = ["CloudSync"]; - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Adapters", - "resource://gre/modules/CloudSyncAdapters.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Local", - "resource://gre/modules/CloudSyncLocal.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Bookmarks", - "resource://gre/modules/CloudSyncBookmarks.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Tabs", - "resource://gre/modules/CloudSyncTabs.jsm"); - -var API_VERSION = 1; - -var _CloudSync = function () { -}; - -_CloudSync.prototype = { - _adapters: null, - - get adapters () { - if (!this._adapters) { - this._adapters = new Adapters(); - } - return this._adapters; - }, - - _bookmarks: null, - - get bookmarks () { - if (!this._bookmarks) { - this._bookmarks = new Bookmarks(); - } - return this._bookmarks; - }, - - _local: null, - - get local () { - if (!this._local) { - this._local = new Local(); - } - return this._local; - }, - - _tabs: null, - - get tabs () { - if (!this._tabs) { - this._tabs = new Tabs(); - } - return this._tabs; - }, - - get tabsReady () { - return this._tabs ? true: false; - }, - - get version () { - return API_VERSION; - }, -}; - -this.CloudSync = function CloudSync () { - return _cloudSyncInternal.instance; -}; - -Object.defineProperty(CloudSync, "ready", { - get: function () { - return _cloudSyncInternal.ready; - } -}); - -var _cloudSyncInternal = { - instance: null, - ready: false, -}; - -XPCOMUtils.defineLazyGetter(_cloudSyncInternal, "instance", function () { - _cloudSyncInternal.ready = true; - return new _CloudSync(); -}.bind(this)); diff --git a/services/cloudsync/CloudSyncAdapters.jsm b/services/cloudsync/CloudSyncAdapters.jsm deleted file mode 100644 index 16264a4f7..000000000 --- a/services/cloudsync/CloudSyncAdapters.jsm +++ /dev/null @@ -1,88 +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"; - -this.EXPORTED_SYMBOLS = ["Adapters"]; - -Components.utils.import("resource://gre/modules/Services.jsm"); -Components.utils.import("resource://gre/modules/CloudSyncEventSource.jsm"); - -this.Adapters = function () { - let eventTypes = [ - "sync", - ]; - - let suspended = true; - - let suspend = function () { - if (!suspended) { - Services.obs.removeObserver(observer, "cloudsync:user-sync", false); - suspended = true; - } - }.bind(this); - - let resume = function () { - if (suspended) { - Services.obs.addObserver(observer, "cloudsync:user-sync", false); - suspended = false; - } - }.bind(this); - - let eventSource = new EventSource(eventTypes, suspend, resume); - let registeredAdapters = new Map(); - - function register (name, opts) { - opts = opts || {}; - registeredAdapters.set(name, opts); - } - - function unregister (name) { - if (!registeredAdapters.has(name)) { - throw new Error("adapter is not registered: " + name) - } - registeredAdapters.delete(name); - } - - function getAdapterNames () { - let result = []; - for (let name of registeredAdapters.keys()) { - result.push(name); - } - return result; - } - - function getAdapter (name) { - if (!registeredAdapters.has(name)) { - throw new Error("adapter is not registered: " + name) - } - return registeredAdapters.get(name); - } - - function countAdapters () { - return registeredAdapters.size; - } - - let observer = { - observe: function (subject, topic, data) { - switch (topic) { - case "cloudsync:user-sync": - eventSource.emit("sync"); - break; - } - } - }; - - this.addEventListener = eventSource.addEventListener; - this.removeEventListener = eventSource.removeEventListener; - this.register = register.bind(this); - this.get = getAdapter.bind(this); - this.unregister = unregister.bind(this); - this.__defineGetter__("names", getAdapterNames); - this.__defineGetter__("count", countAdapters); -}; - -Adapters.prototype = { - -}; diff --git a/services/cloudsync/CloudSyncBookmarks.jsm b/services/cloudsync/CloudSyncBookmarks.jsm deleted file mode 100644 index bb2e48d59..000000000 --- a/services/cloudsync/CloudSyncBookmarks.jsm +++ /dev/null @@ -1,795 +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"; - -this.EXPORTED_SYMBOLS = ["Bookmarks"]; - -const Cu = Components.utils; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://services-common/utils.js"); -Cu.import("resource://services-crypto/utils.js"); -Cu.import("resource://gre/modules/PlacesUtils.jsm"); -Cu.import("resource:///modules/PlacesUIUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", - "resource://gre/modules/NetUtil.jsm"); - -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/CloudSyncPlacesWrapper.jsm"); -Cu.import("resource://gre/modules/CloudSyncEventSource.jsm"); -Cu.import("resource://gre/modules/CloudSyncBookmarksFolderCache.jsm"); - -const ITEM_TYPES = [ - "NULL", - "BOOKMARK", - "FOLDER", - "SEPARATOR", - "DYNAMIC_CONTAINER", // no longer used by Places, but this ID should not be used for future item types -]; - -const CS_UNKNOWN = 0x1; -const CS_FOLDER = 0x1 << 1; -const CS_SEPARATOR = 0x1 << 2; -const CS_QUERY = 0x1 << 3; -const CS_LIVEMARK = 0x1 << 4; -const CS_BOOKMARK = 0x1 << 5; - -const EXCLUDE_BACKUP_ANNO = "places/excludeFromBackup"; - -const DATA_VERSION = 1; - -function asyncCallback(ctx, func, args) { - function invoke() { - func.apply(ctx, args); - } - CommonUtils.nextTick(invoke); -} - -var Record = function (params) { - this.id = params.guid; - this.parent = params.parent || null; - this.index = params.position; - this.title = params.title; - this.dateAdded = Math.floor(params.dateAdded/1000); - this.lastModified = Math.floor(params.lastModified/1000); - this.uri = params.url; - - let annos = params.annos || {}; - Object.defineProperty(this, "annos", { - get: function () { - return annos; - }, - enumerable: false - }); - - switch (params.type) { - case PlacesUtils.bookmarks.TYPE_FOLDER: - if (PlacesUtils.LMANNO_FEEDURI in annos) { - this.type = CS_LIVEMARK; - this.feed = annos[PlacesUtils.LMANNO_FEEDURI]; - this.site = annos[PlacesUtils.LMANNO_SITEURI]; - } else { - this.type = CS_FOLDER; - } - break; - case PlacesUtils.bookmarks.TYPE_BOOKMARK: - if (this.uri.startsWith("place:")) { - this.type = CS_QUERY; - } else { - this.type = CS_BOOKMARK; - } - break; - case PlacesUtils.bookmarks.TYPE_SEPARATOR: - this.type = CS_SEPARATOR; - break; - default: - this.type = CS_UNKNOWN; - } -}; - -Record.prototype = { - version: DATA_VERSION, -}; - -var Bookmarks = function () { - let createRootFolder = function (name) { - let ROOT_FOLDER_ANNO = "cloudsync/rootFolder/" + name; - let ROOT_SHORTCUT_ANNO = "cloudsync/rootShortcut/" + name; - - let deferred = Promise.defer(); - let placesRootId = PlacesUtils.placesRootId; - let rootFolderId; - let rootShortcutId; - - function createAdapterShortcut(result) { - rootFolderId = result; - let uri = "place:folder=" + rootFolderId; - return PlacesWrapper.insertBookmark(PlacesUIUtils.allBookmarksFolderId, uri, - PlacesUtils.bookmarks.DEFAULT_INDEX, name); - } - - function setRootFolderCloudSyncAnnotation(result) { - rootShortcutId = result; - return PlacesWrapper.setItemAnnotation(rootFolderId, ROOT_FOLDER_ANNO, - 1, 0, PlacesUtils.annotations.EXPIRE_NEVER); - } - - function setRootShortcutCloudSyncAnnotation() { - return PlacesWrapper.setItemAnnotation(rootShortcutId, ROOT_SHORTCUT_ANNO, - 1, 0, PlacesUtils.annotations.EXPIRE_NEVER); - } - - function setRootFolderExcludeFromBackupAnnotation() { - return PlacesWrapper.setItemAnnotation(rootFolderId, EXCLUDE_BACKUP_ANNO, - 1, 0, PlacesUtils.annotations.EXPIRE_NEVER); - } - - function finish() { - deferred.resolve(rootFolderId); - } - - Promise.resolve(PlacesUtils.bookmarks.createFolder(placesRootId, name, PlacesUtils.bookmarks.DEFAULT_INDEX)) - .then(createAdapterShortcut) - .then(setRootFolderCloudSyncAnnotation) - .then(setRootShortcutCloudSyncAnnotation) - .then(setRootFolderExcludeFromBackupAnnotation) - .then(finish, deferred.reject); - - return deferred.promise; - }; - - let getRootFolder = function (name) { - let ROOT_FOLDER_ANNO = "cloudsync/rootFolder/" + name; - let ROOT_SHORTCUT_ANNO = "cloudsync/rootShortcut/" + name; - let deferred = Promise.defer(); - - function checkRootFolder(folderIds) { - if (!folderIds.length) { - return createRootFolder(name); - } - return Promise.resolve(folderIds[0]); - } - - function createFolderObject(folderId) { - return new RootFolder(folderId, name); - } - - PlacesWrapper.getLocalIdsWithAnnotation(ROOT_FOLDER_ANNO) - .then(checkRootFolder, deferred.reject) - .then(createFolderObject) - .then(deferred.resolve, deferred.reject); - - return deferred.promise; - }; - - let deleteRootFolder = function (name) { - let ROOT_FOLDER_ANNO = "cloudsync/rootFolder/" + name; - let ROOT_SHORTCUT_ANNO = "cloudsync/rootShortcut/" + name; - - let deferred = Promise.defer(); - let placesRootId = PlacesUtils.placesRootId; - - function getRootShortcutId() { - return PlacesWrapper.getLocalIdsWithAnnotation(ROOT_SHORTCUT_ANNO); - } - - function deleteShortcut(shortcutIds) { - if (!shortcutIds.length) { - return Promise.resolve(); - } - return PlacesWrapper.removeItem(shortcutIds[0]); - } - - function getRootFolderId() { - return PlacesWrapper.getLocalIdsWithAnnotation(ROOT_FOLDER_ANNO); - } - - function deleteFolder(folderIds) { - let deleteFolderDeferred = Promise.defer(); - - if (!folderIds.length) { - return Promise.resolve(); - } - - let rootFolderId = folderIds[0]; - PlacesWrapper.removeFolderChildren(rootFolderId).then( - function () { - return PlacesWrapper.removeItem(rootFolderId); - } - ).then(deleteFolderDeferred.resolve, deleteFolderDeferred.reject); - - return deleteFolderDeferred.promise; - } - - getRootShortcutId().then(deleteShortcut) - .then(getRootFolderId) - .then(deleteFolder) - .then(deferred.resolve, deferred.reject); - - return deferred.promise; - }; - - /* PUBLIC API */ - this.getRootFolder = getRootFolder.bind(this); - this.deleteRootFolder = deleteRootFolder.bind(this); - -}; - -this.Bookmarks = Bookmarks; - -var RootFolder = function (rootId, rootName) { - let suspended = true; - let ignoreAll = false; - - let suspend = function () { - if (!suspended) { - PlacesUtils.bookmarks.removeObserver(observer); - suspended = true; - } - }.bind(this); - - let resume = function () { - if (suspended) { - PlacesUtils.bookmarks.addObserver(observer, false); - suspended = false; - } - }.bind(this); - - let eventTypes = [ - "add", - "remove", - "change", - "move", - ]; - - let eventSource = new EventSource(eventTypes, suspend, resume); - - let folderCache = new FolderCache; - folderCache.insert(rootId, null); - - let getCachedFolderIds = function (cache, roots) { - let nodes = [...roots]; - let results = []; - - while (nodes.length) { - let node = nodes.shift(); - results.push(node); - let children = cache.getChildren(node); - nodes = nodes.concat([...children]); - } - return results; - }; - - let getLocalItems = function () { - let deferred = Promise.defer(); - - let folders = getCachedFolderIds(folderCache, folderCache.getChildren(rootId)); - - function getFolders(ids) { - let types = [ - PlacesUtils.bookmarks.TYPE_FOLDER, - ]; - return PlacesWrapper.getItemsById(ids, types); - } - - function getContents(parents) { - parents.push(rootId); - let types = [ - PlacesUtils.bookmarks.TYPE_BOOKMARK, - PlacesUtils.bookmarks.TYPE_SEPARATOR, - ]; - return PlacesWrapper.getItemsByParentId(parents, types) - } - - function getParentGuids(results) { - results = Array.prototype.concat.apply([], results); - let promises = []; - results.map(function (result) { - let promise = PlacesWrapper.localIdToGuid(result.parent).then( - function (guidResult) { - result.parent = guidResult; - return Promise.resolve(result); - }, - Promise.reject.bind(Promise) - ); - promises.push(promise); - }); - return Promise.all(promises); - } - - function getAnnos(results) { - results = Array.prototype.concat.apply([], results); - let promises = []; - results.map(function (result) { - let promise = PlacesWrapper.getItemAnnotationsForLocalId(result.id).then( - function (annos) { - result.annos = annos; - return Promise.resolve(result); - }, - Promise.reject.bind(Promise) - ); - promises.push(promise); - }); - return Promise.all(promises); - } - - let promises = [ - getFolders(folders), - getContents(folders), - ]; - - Promise.all(promises) - .then(getParentGuids) - .then(getAnnos) - .then(function (results) { - results = results.map((result) => new Record(result)); - deferred.resolve(results); - }, - deferred.reject); - - return deferred.promise; - }; - - let getLocalItemsById = function (guids) { - let deferred = Promise.defer(); - - let types = [ - PlacesUtils.bookmarks.TYPE_BOOKMARK, - PlacesUtils.bookmarks.TYPE_FOLDER, - PlacesUtils.bookmarks.TYPE_SEPARATOR, - PlacesUtils.bookmarks.TYPE_DYNAMIC_CONTAINER, - ]; - - function getParentGuids(results) { - let promises = []; - results.map(function (result) { - let promise = PlacesWrapper.localIdToGuid(result.parent).then( - function (guidResult) { - result.parent = guidResult; - return Promise.resolve(result); - }, - Promise.reject.bind(Promise) - ); - promises.push(promise); - }); - return Promise.all(promises); - } - - PlacesWrapper.getItemsByGuid(guids, types) - .then(getParentGuids) - .then(function (results) { - results = results.map((result) => new Record(result)); - deferred.resolve(results); - }, - deferred.reject); - - return deferred.promise; - }; - - let _createItem = function (item) { - let deferred = Promise.defer(); - - function getFolderId() { - if (item.parent) { - return PlacesWrapper.guidToLocalId(item.parent); - } - return Promise.resolve(rootId); - } - - function create(folderId) { - let deferred = Promise.defer(); - - if (!folderId) { - folderId = rootId; - } - let index = item.hasOwnProperty("index") ? item.index : PlacesUtils.bookmarks.DEFAULT_INDEX; - - function complete(localId) { - folderCache.insert(localId, folderId); - deferred.resolve(localId); - } - - switch (item.type) { - case CS_BOOKMARK: - case CS_QUERY: - PlacesWrapper.insertBookmark(folderId, item.uri, index, item.title, item.id) - .then(complete, deferred.reject); - break; - case CS_FOLDER: - PlacesWrapper.createFolder(folderId, item.title, index, item.id) - .then(complete, deferred.reject); - break; - case CS_SEPARATOR: - PlacesWrapper.insertSeparator(folderId, index, item.id) - .then(complete, deferred.reject); - break; - case CS_LIVEMARK: - let livemark = { - title: item.title, - parentId: folderId, - index: item.index, - feedURI: item.feed, - siteURI: item.site, - guid: item.id, - }; - PlacesUtils.livemarks.addLivemark(livemark) - .then(complete, deferred.reject); - break; - default: - deferred.reject("invalid item type: " + item.type); - } - - return deferred.promise; - } - - getFolderId().then(create) - .then(deferred.resolve, deferred.reject); - - return deferred.promise; - }; - - let _deleteItem = function (item) { - let deferred = Promise.defer(); - - PlacesWrapper.guidToLocalId(item.id).then( - function (localId) { - folderCache.remove(localId); - return PlacesWrapper.removeItem(localId); - } - ).then(deferred.resolve, deferred.reject); - - return deferred.promise; - }; - - let _updateItem = function (item) { - let deferred = Promise.defer(); - - PlacesWrapper.guidToLocalId(item.id).then( - function (localId) { - let promises = []; - - if (item.hasOwnProperty("dateAdded")) { - promises.push(PlacesWrapper.setItemDateAdded(localId, item.dateAdded)); - } - - if (item.hasOwnProperty("lastModified")) { - promises.push(PlacesWrapper.setItemLastModified(localId, item.lastModified)); - } - - if ((CS_BOOKMARK | CS_FOLDER) & item.type && item.hasOwnProperty("title")) { - promises.push(PlacesWrapper.setItemTitle(localId, item.title)); - } - - if (CS_BOOKMARK & item.type && item.hasOwnProperty("uri")) { - promises.push(PlacesWrapper.changeBookmarkURI(localId, item.uri)); - } - - if (item.hasOwnProperty("parent")) { - let deferred = Promise.defer(); - PlacesWrapper.guidToLocalId(item.parent) - .then( - function (parent) { - let index = item.hasOwnProperty("index") ? item.index : PlacesUtils.bookmarks.DEFAULT_INDEX; - if (CS_FOLDER & item.type) { - folderCache.setParent(localId, parent); - } - return PlacesWrapper.moveItem(localId, parent, index); - } - ) - .then(deferred.resolve, deferred.reject); - promises.push(deferred.promise); - } - - if (item.hasOwnProperty("index") && !item.hasOwnProperty("parent")) { - promises.push(Task.spawn(function* () { - let localItem = (yield getLocalItemsById([item.id]))[0]; - let parent = yield PlacesWrapper.guidToLocalId(localItem.parent); - let index = item.index; - if (CS_FOLDER & item.type) { - folderCache.setParent(localId, parent); - } - yield PlacesWrapper.moveItem(localId, parent, index); - })); - } - - Promise.all(promises) - .then(deferred.resolve, deferred.reject); - } - ); - - return deferred.promise; - }; - - let mergeRemoteItems = function (items) { - ignoreAll = true; - let deferred = Promise.defer(); - - let newFolders = {}; - let newItems = []; - let updatedItems = []; - let deletedItems = []; - - let sortItems = function () { - let promises = []; - - let exists = function (item) { - let existsDeferred = Promise.defer(); - if (!item.id) { - Object.defineProperty(item, "__exists__", { - value: false, - enumerable: false - }); - existsDeferred.resolve(item); - } else { - PlacesWrapper.guidToLocalId(item.id).then( - function (localId) { - Object.defineProperty(item, "__exists__", { - value: localId ? true : false, - enumerable: false - }); - existsDeferred.resolve(item); - }, - existsDeferred.reject - ); - } - return existsDeferred.promise; - } - - let handleSortedItem = function (item) { - if (!item.__exists__ && !item.deleted) { - if (CS_FOLDER == item.type) { - newFolders[item.id] = item; - item._children = []; - } else { - newItems.push(item); - } - } else if (item.__exists__ && item.deleted) { - deletedItems.push(item); - } else if (item.__exists__) { - updatedItems.push(item); - } - } - - for (let item of items) { - if (!item || 'object' !== typeof(item)) { - continue; - } - - let promise = exists(item).then(handleSortedItem, Promise.reject.bind(Promise)); - promises.push(promise); - } - - return Promise.all(promises); - } - - let processNewFolders = function () { - let newFolderGuids = Object.keys(newFolders); - let newFolderRoots = []; - - for (let guid of newFolderGuids) { - let item = newFolders[guid]; - if (item.parent && newFolderGuids.indexOf(item.parent) >= 0) { - let parent = newFolders[item.parent]; - parent._children.push(item.id); - } else { - newFolderRoots.push(guid); - } - }; - - let promises = []; - for (let guid of newFolderRoots) { - let root = newFolders[guid]; - let promise = Promise.resolve(); - promise = promise.then( - function () { - return _createItem(root); - }, - Promise.reject.bind(Promise) - ); - let items = [].concat(root._children); - - while (items.length) { - let item = newFolders[items.shift()]; - items = items.concat(item._children); - promise = promise.then( - function () { - return _createItem(item); - }, - Promise.reject.bind(Promise) - ); - } - promises.push(promise); - } - - return Promise.all(promises); - } - - let processItems = function () { - let promises = []; - - for (let item of newItems) { - promises.push(_createItem(item)); - } - - for (let item of updatedItems) { - promises.push(_updateItem(item)); - } - - for (let item of deletedItems) { - _deleteItem(item); - } - - return Promise.all(promises); - } - - sortItems().then(processNewFolders) - .then(processItems) - .then(function () { - ignoreAll = false; - deferred.resolve(items); - }, - function (err) { - ignoreAll = false; - deferred.reject(err); - }); - - return deferred.promise; - }; - - let ignore = function (id, parent) { - if (ignoreAll) { - return true; - } - - if (rootId == parent || folderCache.has(parent)) { - return false; - } - - return true; - }; - - let handleItemAdded = function (id, parent, index, type, uri, title, dateAdded, guid, parentGuid) { - let deferred = Promise.defer(); - - if (PlacesUtils.bookmarks.TYPE_FOLDER == type) { - folderCache.insert(id, parent); - } - - eventSource.emit("add", guid); - deferred.resolve(); - - return deferred.promise; - }; - - let handleItemRemoved = function (id, parent, index, type, uri, guid, parentGuid) { - let deferred = Promise.defer(); - - if (PlacesUtils.bookmarks.TYPE_FOLDER == type) { - folderCache.remove(id); - } - - eventSource.emit("remove", guid); - deferred.resolve(); - - return deferred.promise; - }; - - let handleItemChanged = function (id, property, isAnnotation, newValue, lastModified, type, parent, guid, parentGuid) { - let deferred = Promise.defer(); - - eventSource.emit('change', guid); - deferred.resolve(); - - return deferred.promise; - }; - - let handleItemMoved = function (id, oldParent, oldIndex, newParent, newIndex, type, guid, oldParentGuid, newParentGuid) { - let deferred = Promise.defer(); - - function complete() { - eventSource.emit('move', guid); - deferred.resolve(); - } - - if (PlacesUtils.bookmarks.TYPE_FOLDER != type) { - complete(); - return deferred.promise; - } - - if (folderCache.has(oldParent) && folderCache.has(newParent)) { - // Folder move inside cloudSync root, so just update parents/children. - folderCache.setParent(id, newParent); - complete(); - } else if (!folderCache.has(oldParent)) { - // Folder moved in from ouside cloudSync root. - PlacesWrapper.updateCachedFolderIds(folderCache, newParent) - .then(complete, complete); - } else if (!folderCache.has(newParent)) { - // Folder moved out from inside cloudSync root. - PlacesWrapper.updateCachedFolderIds(folderCache, oldParent) - .then(complete, complete); - } - - return deferred.promise; - }; - - let observer = { - onBeginBatchUpdate: function () { - }, - - onEndBatchUpdate: function () { - }, - - onItemAdded: function (id, parent, index, type, uri, title, dateAdded, guid, parentGuid) { - if (ignore(id, parent)) { - return; - } - - asyncCallback(this, handleItemAdded, Array.prototype.slice.call(arguments)); - }, - - onItemRemoved: function (id, parent, index, type, uri, guid, parentGuid) { - if (ignore(id, parent)) { - return; - } - - asyncCallback(this, handleItemRemoved, Array.prototype.slice.call(arguments)); - }, - - onItemChanged: function (id, property, isAnnotation, newValue, lastModified, type, parent, guid, parentGuid) { - if (ignore(id, parent)) { - return; - } - - asyncCallback(this, handleItemChanged, Array.prototype.slice.call(arguments)); - }, - - onItemMoved: function (id, oldParent, oldIndex, newParent, newIndex, type, guid, oldParentGuid, newParentGuid) { - if (ignore(id, oldParent) && ignore(id, newParent)) { - return; - } - - asyncCallback(this, handleItemMoved, Array.prototype.slice.call(arguments)); - } - }; - - /* PUBLIC API */ - this.addEventListener = eventSource.addEventListener; - this.removeEventListener = eventSource.removeEventListener; - this.getLocalItems = getLocalItems.bind(this); - this.getLocalItemsById = getLocalItemsById.bind(this); - this.mergeRemoteItems = mergeRemoteItems.bind(this); - - let rootGuid = null; // resolved before becoming ready (below) - this.__defineGetter__("id", function () { - return rootGuid; - }); - this.__defineGetter__("name", function () { - return rootName; - }); - - let deferred = Promise.defer(); - let getGuidForRootFolder = function () { - return PlacesWrapper.localIdToGuid(rootId); - } - PlacesWrapper.updateCachedFolderIds(folderCache, rootId) - .then(getGuidForRootFolder, getGuidForRootFolder) - .then(function (guid) { - rootGuid = guid; - deferred.resolve(this); - }.bind(this), - deferred.reject); - return deferred.promise; -}; - -RootFolder.prototype = { - BOOKMARK: CS_BOOKMARK, - FOLDER: CS_FOLDER, - SEPARATOR: CS_SEPARATOR, - QUERY: CS_QUERY, - LIVEMARK: CS_LIVEMARK, -}; diff --git a/services/cloudsync/CloudSyncBookmarksFolderCache.jsm b/services/cloudsync/CloudSyncBookmarksFolderCache.jsm deleted file mode 100644 index f3c3fc8f2..000000000 --- a/services/cloudsync/CloudSyncBookmarksFolderCache.jsm +++ /dev/null @@ -1,105 +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"; - -this.EXPORTED_SYMBOLS = ["FolderCache"]; - -// Cache for bookmarks folder heirarchy. -var FolderCache = function () { - this.cache = new Map(); -} - -FolderCache.prototype = { - has: function (id) { - return this.cache.has(id); - }, - - insert: function (id, parentId) { - if (this.cache.has(id)) { - return; - } - - if (parentId && !(this.cache.has(parentId))) { - throw new Error("insert :: parentId not found in cache: " + parentId); - } - - this.cache.set(id, { - parent: parentId || null, - children: new Set(), - }); - - if (parentId) { - this.cache.get(parentId).children.add(id); - } - }, - - remove: function (id) { - if (!(this.cache.has(id))) { - throw new Error("remote :: id not found in cache: " + id); - } - - let parentId = this.cache.get(id).parent; - if (parentId) { - this.cache.get(parentId).children.delete(id); - } - - for (let child of this.cache.get(id).children) { - this.cache.get(child).parent = null; - } - - this.cache.delete(id); - }, - - setParent: function (id, parentId) { - if (!(this.cache.has(id))) { - throw new Error("setParent :: id not found in cache: " + id); - } - - if (parentId && !(this.cache.has(parentId))) { - throw new Error("setParent :: parentId not found in cache: " + parentId); - } - - let oldParent = this.cache.get(id).parent; - if (oldParent) { - this.cache.get(oldParent).children.delete(id); - } - this.cache.get(id).parent = parentId; - this.cache.get(parentId).children.add(id); - - return true; - }, - - getParent: function (id) { - if (this.cache.has(id)) { - return this.cache.get(id).parent; - } - - throw new Error("getParent :: id not found in cache: " + id); - }, - - getChildren: function (id) { - if (this.cache.has(id)) { - return this.cache.get(id).children; - } - - throw new Error("getChildren :: id not found in cache: " + id); - }, - - setChildren: function (id, children) { - for (let child of children) { - if (!this.cache.has(child)) { - this.insert(child, id); - } else { - this.setParent(child, id); - } - } - }, - - dump: function () { - dump("FolderCache: " + JSON.stringify(this.cache) + "\n"); - }, -}; - -this.FolderCache = FolderCache; diff --git a/services/cloudsync/CloudSyncEventSource.jsm b/services/cloudsync/CloudSyncEventSource.jsm deleted file mode 100644 index edb9c426b..000000000 --- a/services/cloudsync/CloudSyncEventSource.jsm +++ /dev/null @@ -1,65 +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/. */ - -this.EXPORTED_SYMBOLS = ["EventSource"]; - -Components.utils.import("resource://services-common/utils.js"); - -var EventSource = function (types, suspendFunc, resumeFunc) { - this.listeners = new Map(); - for (let type of types) { - this.listeners.set(type, new Set()); - } - - this.suspend = suspendFunc || function () {}; - this.resume = resumeFunc || function () {}; - - this.addEventListener = this.addEventListener.bind(this); - this.removeEventListener = this.removeEventListener.bind(this); -}; - -EventSource.prototype = { - addEventListener: function (type, listener) { - if (!this.listeners.has(type)) { - return; - } - this.listeners.get(type).add(listener); - this.resume(); - }, - - removeEventListener: function (type, listener) { - if (!this.listeners.has(type)) { - return; - } - this.listeners.get(type).delete(listener); - if (!this.hasListeners()) { - this.suspend(); - } - }, - - hasListeners: function () { - for (let l of this.listeners.values()) { - if (l.size > 0) { - return true; - } - } - return false; - }, - - emit: function (type, arg) { - if (!this.listeners.has(type)) { - return; - } - CommonUtils.nextTick( - function () { - for (let listener of this.listeners.get(type)) { - listener.call(undefined, arg); - } - }, - this - ); - }, -}; - -this.EventSource = EventSource; diff --git a/services/cloudsync/CloudSyncLocal.jsm b/services/cloudsync/CloudSyncLocal.jsm deleted file mode 100644 index 998c0c3c4..000000000 --- a/services/cloudsync/CloudSyncLocal.jsm +++ /dev/null @@ -1,87 +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"; - -this.EXPORTED_SYMBOLS = ["Local"]; - -const Cu = Components.utils; -const Cc = Components.classes; -const Ci = Components.interfaces; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://services-common/stringbundle.js"); -Cu.import("resource://services-common/utils.js"); -Cu.import("resource://services-crypto/utils.js"); -Cu.import("resource://gre/modules/Preferences.jsm"); - -function lazyStrings(name) { - let bundle = "chrome://weave/locale/services/" + name + ".properties"; - return () => new StringBundle(bundle); -} - -this.Str = {}; -XPCOMUtils.defineLazyGetter(Str, "errors", lazyStrings("errors")); -XPCOMUtils.defineLazyGetter(Str, "sync", lazyStrings("sync")); - -function makeGUID() { - return CommonUtils.encodeBase64URL(CryptoUtils.generateRandomBytes(9)); -} - -this.Local = function () { - let prefs = new Preferences("services.cloudsync."); - this.__defineGetter__("prefs", function () { - return prefs; - }); -}; - -Local.prototype = { - get id() { - let clientId = this.prefs.get("client.GUID", ""); - return clientId == "" ? this.id = makeGUID(): clientId; - }, - - set id(value) { - this.prefs.set("client.GUID", value); - }, - - get name() { - let clientName = this.prefs.get("client.name", ""); - - if (clientName != "") { - return clientName; - } - - // Generate a client name if we don't have a useful one yet - let env = Cc["@mozilla.org/process/environment;1"] - .getService(Ci.nsIEnvironment); - let user = env.get("USER") || env.get("USERNAME"); - let appName; - let brand = new StringBundle("chrome://branding/locale/brand.properties"); - let brandName = brand.get("brandShortName"); - - try { - let syncStrings = new StringBundle("chrome://browser/locale/sync.properties"); - appName = syncStrings.getFormattedString("sync.defaultAccountApplication", [brandName]); - } catch (ex) { - } - - appName = appName || brandName; - - let system = - // 'device' is defined on unix systems - Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2).get("device") || - // hostname of the system, usually assigned by the user or admin - Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2).get("host") || - // fall back on ua info string - Cc["@mozilla.org/network/protocol;1?name=http"].getService(Ci.nsIHttpProtocolHandler).oscpu; - - return this.name = Str.sync.get("client.name2", [user, appName, system]); - }, - - set name(value) { - this.prefs.set("client.name", value); - }, -}; - diff --git a/services/cloudsync/CloudSyncPlacesWrapper.jsm b/services/cloudsync/CloudSyncPlacesWrapper.jsm deleted file mode 100644 index dd8c5c52e..000000000 --- a/services/cloudsync/CloudSyncPlacesWrapper.jsm +++ /dev/null @@ -1,375 +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"; - -this.EXPORTED_SYMBOLS = ["PlacesWrapper"]; - -const {interfaces: Ci, utils: Cu} = Components; -const REASON_ERROR = Ci.mozIStorageStatementCallback.REASON_ERROR; - -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/PlacesUtils.jsm"); -Cu.import("resource:///modules/PlacesUIUtils.jsm"); -Cu.import("resource://services-common/utils.js"); - -var PlacesQueries = function () { -} - -PlacesQueries.prototype = { - cachedStmts: {}, - - getQuery: function (queryString) { - if (queryString in this.cachedStmts) { - return this.cachedStmts[queryString]; - } - - let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection; - return this.cachedStmts[queryString] = db.createAsyncStatement(queryString); - } -}; - -var PlacesWrapper = function () { -} - -PlacesWrapper.prototype = { - placesQueries: new PlacesQueries(), - - guidToLocalId: function (guid) { - let deferred = Promise.defer(); - - let stmt = "SELECT id AS item_id " + - "FROM moz_bookmarks " + - "WHERE guid = :guid"; - let query = this.placesQueries.getQuery(stmt); - - function getLocalId(results) { - let result = results[0] && results[0]["item_id"]; - return Promise.resolve(result); - } - - query.params.guid = guid.toString(); - - this.asyncQuery(query, ["item_id"]) - .then(getLocalId, deferred.reject) - .then(deferred.resolve, deferred.reject); - - return deferred.promise; - }, - - localIdToGuid: function (id) { - let deferred = Promise.defer(); - - let stmt = "SELECT guid " + - "FROM moz_bookmarks " + - "WHERE id = :item_id"; - let query = this.placesQueries.getQuery(stmt); - - function getGuid(results) { - let result = results[0] && results[0]["guid"]; - return Promise.resolve(result); - } - - query.params.item_id = id; - - this.asyncQuery(query, ["guid"]) - .then(getGuid, deferred.reject) - .then(deferred.resolve, deferred.reject); - - return deferred.promise; - }, - - getItemsById: function (ids, types) { - let deferred = Promise.defer(); - let stmt = "SELECT b.id, b.type, b.parent, b.position, b.title, b.guid, b.dateAdded, b.lastModified, p.url " + - "FROM moz_bookmarks b " + - "LEFT JOIN moz_places p ON b.fk = p.id " + - "WHERE b.id in (" + ids.join(",") + ") AND b.type in (" + types.join(",") + ")"; - let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection; - let query = db.createAsyncStatement(stmt); - - this.asyncQuery(query, ["id", "type", "parent", "position", "title", "guid", "dateAdded", "lastModified", "url"]) - .then(deferred.resolve, deferred.reject); - - return deferred.promise; - }, - - getItemsByParentId: function (parents, types) { - let deferred = Promise.defer(); - let stmt = "SELECT b.id, b.type, b.parent, b.position, b.title, b.guid, b.dateAdded, b.lastModified, p.url " + - "FROM moz_bookmarks b " + - "LEFT JOIN moz_places p ON b.fk = p.id " + - "WHERE b.parent in (" + parents.join(",") + ") AND b.type in (" + types.join(",") + ")"; - let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection; - let query = db.createAsyncStatement(stmt); - - this.asyncQuery(query, ["id", "type", "parent", "position", "title", "guid", "dateAdded", "lastModified", "url"]) - .then(deferred.resolve, deferred.reject); - - return deferred.promise; - }, - - getItemsByGuid: function (guids, types) { - let deferred = Promise.defer(); - guids = guids.map(JSON.stringify); - let stmt = "SELECT b.id, b.type, b.parent, b.position, b.title, b.guid, b.dateAdded, b.lastModified, p.url " + - "FROM moz_bookmarks b " + - "LEFT JOIN moz_places p ON b.fk = p.id " + - "WHERE b.guid in (" + guids.join(",") + ") AND b.type in (" + types.join(",") + ")"; - let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection; - let query = db.createAsyncStatement(stmt); - - this.asyncQuery(query, ["id", "type", "parent", "position", "title", "guid", "dateAdded", "lastModified", "url"]) - .then(deferred.resolve, deferred.reject); - - return deferred.promise; - }, - - updateCachedFolderIds: function (folderCache, folder) { - let deferred = Promise.defer(); - let stmt = "SELECT id, guid " + - "FROM moz_bookmarks " + - "WHERE parent = :parent_id AND type = :item_type"; - let query = this.placesQueries.getQuery(stmt); - - query.params.parent_id = folder; - query.params.item_type = PlacesUtils.bookmarks.TYPE_FOLDER; - - this.asyncQuery(query, ["id", "guid"]).then( - function (items) { - let previousIds = folderCache.getChildren(folder); - let currentIds = new Set(); - for (let item of items) { - currentIds.add(item.id); - } - let newIds = new Set(); - let missingIds = new Set(); - - for (let currentId of currentIds) { - if (!previousIds.has(currentId)) { - newIds.add(currentId); - } - } - for (let previousId of previousIds) { - if (!currentIds.has(previousId)) { - missingIds.add(previousId); - } - } - - folderCache.setChildren(folder, currentIds); - - let promises = []; - for (let newId of newIds) { - promises.push(this.updateCachedFolderIds(folderCache, newId)); - } - Promise.all(promises) - .then(deferred.resolve, deferred.reject); - - for (let missingId of missingIds) { - folderCache.remove(missingId); - } - }.bind(this) - ); - - return deferred.promise; - }, - - getLocalIdsWithAnnotation: function (anno) { - let deferred = Promise.defer(); - let stmt = "SELECT a.item_id " + - "FROM moz_anno_attributes n " + - "JOIN moz_items_annos a ON n.id = a.anno_attribute_id " + - "WHERE n.name = :anno_name"; - let query = this.placesQueries.getQuery(stmt); - - query.params.anno_name = anno.toString(); - - this.asyncQuery(query, ["item_id"]) - .then(function (items) { - let results = []; - for (let item of items) { - results.push(item.item_id); - } - deferred.resolve(results); - }, - deferred.reject); - - return deferred.promise; - }, - - getItemAnnotationsForLocalId: function (id) { - let deferred = Promise.defer(); - let stmt = "SELECT a.name, b.content " + - "FROM moz_anno_attributes a " + - "JOIN moz_items_annos b ON a.id = b.anno_attribute_id " + - "WHERE b.item_id = :item_id"; - let query = this.placesQueries.getQuery(stmt); - - query.params.item_id = id; - - this.asyncQuery(query, ["name", "content"]) - .then(function (results) { - let annos = {}; - for (let result of results) { - annos[result.name] = result.content; - } - deferred.resolve(annos); - }, - deferred.reject); - - return deferred.promise; - }, - - insertBookmark: function (parent, uri, index, title, guid) { - let parsedURI; - try { - parsedURI = CommonUtils.makeURI(uri) - } catch (e) { - return Promise.reject("unable to parse URI '" + uri + "': " + e); - } - - try { - let id = PlacesUtils.bookmarks.insertBookmark(parent, parsedURI, index, title, guid); - return Promise.resolve(id); - } catch (e) { - return Promise.reject("unable to insert bookmark " + JSON.stringify(arguments) + ": " + e); - } - }, - - setItemAnnotation: function (item, anno, value, flags, exp) { - try { - return Promise.resolve(PlacesUtils.annotations.setItemAnnotation(item, anno, value, flags, exp)); - } catch (e) { - return Promise.reject(e); - } - }, - - itemHasAnnotation: function (item, anno) { - try { - return Promise.resolve(PlacesUtils.annotations.itemHasAnnotation(item, anno)); - } catch (e) { - return Promise.reject(e); - } - }, - - createFolder: function (parent, name, index, guid) { - try { - return Promise.resolve(PlacesUtils.bookmarks.createFolder(parent, name, index, guid)); - } catch (e) { - return Promise.reject("unable to create folder ['" + name + "']: " + e); - } - }, - - removeFolderChildren: function (folder) { - try { - PlacesUtils.bookmarks.removeFolderChildren(folder); - return Promise.resolve(); - } catch (e) { - return Promise.reject(e); - } - }, - - insertSeparator: function (parent, index, guid) { - try { - return Promise.resolve(PlacesUtils.bookmarks.insertSeparator(parent, index, guid)); - } catch (e) { - return Promise.reject(e); - } - }, - - removeItem: function (item) { - try { - return Promise.resolve(PlacesUtils.bookmarks.removeItem(item)); - } catch (e) { - return Promise.reject(e); - } - }, - - setItemDateAdded: function (item, dateAdded) { - try { - return Promise.resolve(PlacesUtils.bookmarks.setItemDateAdded(item, dateAdded)); - } catch (e) { - return Promise.reject(e); - } - }, - - setItemLastModified: function (item, lastModified) { - try { - return Promise.resolve(PlacesUtils.bookmarks.setItemLastModified(item, lastModified)); - } catch (e) { - return Promise.reject(e); - } - }, - - setItemTitle: function (item, title) { - try { - return Promise.resolve(PlacesUtils.bookmarks.setItemTitle(item, title)); - } catch (e) { - return Promise.reject(e); - } - }, - - changeBookmarkURI: function (item, uri) { - try { - uri = CommonUtils.makeURI(uri); - return Promise.resolve(PlacesUtils.bookmarks.changeBookmarkURI(item, uri)); - } catch (e) { - return Promise.reject(e); - } - }, - - moveItem: function (item, parent, index) { - try { - return Promise.resolve(PlacesUtils.bookmarks.moveItem(item, parent, index)); - } catch (e) { - return Promise.reject(e); - } - }, - - setItemIndex: function (item, index) { - try { - return Promise.resolve(PlacesUtils.bookmarks.setItemIndex(item, index)); - } catch (e) { - return Promise.reject(e); - } - }, - - asyncQuery: function (query, names) { - let deferred = Promise.defer(); - let storageCallback = { - results: [], - handleResult: function (results) { - if (!names) { - return; - } - - let row; - while ((row = results.getNextRow()) != null) { - let item = {}; - for (let name of names) { - item[name] = row.getResultByName(name); - } - this.results.push(item); - } - }, - - handleError: function (error) { - deferred.reject(error); - }, - - handleCompletion: function (reason) { - if (REASON_ERROR == reason) { - return; - } - - deferred.resolve(this.results); - } - }; - - query.executeAsync(storageCallback); - return deferred.promise; - }, -}; - -this.PlacesWrapper = new PlacesWrapper(); diff --git a/services/cloudsync/CloudSyncTabs.jsm b/services/cloudsync/CloudSyncTabs.jsm deleted file mode 100644 index 7debc2678..000000000 --- a/services/cloudsync/CloudSyncTabs.jsm +++ /dev/null @@ -1,318 +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"; - -this.EXPORTED_SYMBOLS = ["Tabs"]; - -const Cu = Components.utils; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/CloudSyncEventSource.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://services-common/observers.js"); - -XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); -XPCOMUtils.defineLazyServiceGetter(this, "Session", "@mozilla.org/browser/sessionstore;1", "nsISessionStore"); - -const DATA_VERSION = 1; - -var ClientRecord = function (params) { - this.id = params.id; - this.name = params.name || "?"; - this.tabs = new Set(); -} - -ClientRecord.prototype = { - version: DATA_VERSION, - - update: function (params) { - if (this.id !== params.id) { - throw new Error("expected " + this.id + " to equal " + params.id); - } - - this.name = params.name; - } -}; - -var TabRecord = function (params) { - this.url = params.url || ""; - this.update(params); -}; - -TabRecord.prototype = { - version: DATA_VERSION, - - update: function (params) { - if (this.url && this.url !== params.url) { - throw new Error("expected " + this.url + " to equal " + params.url); - } - - if (params.lastUsed && params.lastUsed < this.lastUsed) { - return; - } - - this.title = params.title || ""; - this.icon = params.icon || ""; - this.lastUsed = params.lastUsed || 0; - }, -}; - -var TabCache = function () { - this.tabs = new Map(); - this.clients = new Map(); -}; - -TabCache.prototype = { - merge: function (client, tabs) { - if (!client || !client.id) { - return; - } - - if (!tabs) { - return; - } - - let cRecord; - if (this.clients.has(client.id)) { - try { - cRecord = this.clients.get(client.id); - } catch (e) { - throw new Error("unable to update client: " + e); - } - } else { - cRecord = new ClientRecord(client); - this.clients.set(cRecord.id, cRecord); - } - - for (let tab of tabs) { - if (!tab || 'object' !== typeof(tab)) { - continue; - } - - let tRecord; - if (this.tabs.has(tab.url)) { - tRecord = this.tabs.get(tab.url); - try { - tRecord.update(tab); - } catch (e) { - throw new Error("unable to update tab: " + e); - } - } else { - tRecord = new TabRecord(tab); - this.tabs.set(tRecord.url, tRecord); - } - - if (tab.deleted) { - cRecord.tabs.delete(tRecord); - } else { - cRecord.tabs.add(tRecord); - } - } - }, - - clear: function (client) { - if (client) { - this.clients.delete(client.id); - } else { - this.clients = new Map(); - this.tabs = new Map(); - } - }, - - get: function () { - let results = []; - for (let client of this.clients.values()) { - results.push(client); - } - return results; - }, - - isEmpty: function () { - return 0 == this.clients.size; - }, - -}; - -this.Tabs = function () { - let suspended = true; - - let topics = [ - "pageshow", - "TabOpen", - "TabClose", - "TabSelect", - ]; - - let update = function (event) { - if (event.originalTarget.linkedBrowser) { - if (PrivateBrowsingUtils.isBrowserPrivate(event.originalTarget.linkedBrowser) && - !PrivateBrowsingUtils.permanentPrivateBrowsing) { - return; - } - } - - eventSource.emit("change"); - }; - - let registerListenersForWindow = function (window) { - for (let topic of topics) { - window.addEventListener(topic, update, false); - } - window.addEventListener("unload", unregisterListeners, false); - }; - - let unregisterListenersForWindow = function (window) { - window.removeEventListener("unload", unregisterListeners, false); - for (let topic of topics) { - window.removeEventListener(topic, update, false); - } - }; - - let unregisterListeners = function (event) { - unregisterListenersForWindow(event.target); - }; - - let observer = { - observe: function (subject, topic, data) { - switch (topic) { - case "domwindowopened": - let onLoad = () => { - subject.removeEventListener("load", onLoad, false); - // Only register after the window is done loading to avoid unloads. - registerListenersForWindow(subject); - }; - - // Add tab listeners now that a window has opened. - subject.addEventListener("load", onLoad, false); - break; - } - } - }; - - let resume = function () { - if (suspended) { - Observers.add("domwindowopened", observer); - let wins = Services.wm.getEnumerator("navigator:browser"); - while (wins.hasMoreElements()) { - registerListenersForWindow(wins.getNext()); - } - } - }.bind(this); - - let suspend = function () { - if (!suspended) { - Observers.remove("domwindowopened", observer); - let wins = Services.wm.getEnumerator("navigator:browser"); - while (wins.hasMoreElements()) { - unregisterListenersForWindow(wins.getNext()); - } - } - }.bind(this); - - let eventTypes = [ - "change", - ]; - - let eventSource = new EventSource(eventTypes, suspend, resume); - - let tabCache = new TabCache(); - - let getWindowEnumerator = function () { - return Services.wm.getEnumerator("navigator:browser"); - }; - - let shouldSkipWindow = function (win) { - return win.closed || - PrivateBrowsingUtils.isWindowPrivate(win); - }; - - let getTabState = function (tab) { - return JSON.parse(Session.getTabState(tab)); - }; - - let getLocalTabs = function (filter) { - let deferred = Promise.defer(); - - filter = (undefined === filter) ? true : filter; - let filteredUrls = new RegExp("^(about:.*|chrome://weave/.*|wyciwyg:.*|file:.*)$"); // FIXME: should be a pref (B#1044304) - - let allTabs = []; - - let currentState = JSON.parse(Session.getBrowserState()); - currentState.windows.forEach(function (window) { - if (window.isPrivate) { - return; - } - window.tabs.forEach(function (tab) { - if (!tab.entries.length) { - return; - } - - // Get only the latest entry - // FIXME: support full history (B#1044306) - let entry = tab.entries[tab.index - 1]; - - if (!entry.url || filter && filteredUrls.test(entry.url)) { - return; - } - - allTabs.push(new TabRecord({ - title: entry.title, - url: entry.url, - icon: tab.attributes && tab.attributes.image || "", - lastUsed: tab.lastAccessed, - })); - }); - }); - - deferred.resolve(allTabs); - - return deferred.promise; - }; - - let mergeRemoteTabs = function (client, tabs) { - let deferred = Promise.defer(); - - deferred.resolve(tabCache.merge(client, tabs)); - Observers.notify("cloudsync:tabs:update"); - - return deferred.promise; - }; - - let clearRemoteTabs = function (client) { - let deferred = Promise.defer(); - - deferred.resolve(tabCache.clear(client)); - Observers.notify("cloudsync:tabs:update"); - - return deferred.promise; - }; - - let getRemoteTabs = function () { - let deferred = Promise.defer(); - - deferred.resolve(tabCache.get()); - - return deferred.promise; - }; - - let hasRemoteTabs = function () { - return !tabCache.isEmpty(); - }; - - /* PUBLIC API */ - this.addEventListener = eventSource.addEventListener; - this.removeEventListener = eventSource.removeEventListener; - this.getLocalTabs = getLocalTabs.bind(this); - this.mergeRemoteTabs = mergeRemoteTabs.bind(this); - this.clearRemoteTabs = clearRemoteTabs.bind(this); - this.getRemoteTabs = getRemoteTabs.bind(this); - this.hasRemoteTabs = hasRemoteTabs.bind(this); -}; - -Tabs.prototype = { -}; -this.Tabs = Tabs; diff --git a/services/cloudsync/docs/api.md b/services/cloudsync/docs/api.md deleted file mode 100644 index bca3193a4..000000000 --- a/services/cloudsync/docs/api.md +++ /dev/null @@ -1,234 +0,0 @@ -### Importing the JS module - -```` -Cu.import("resource://gre/modules/CloudSync.jsm"); - -let cloudSync = CloudSync(); -console.log(cloudSync); // Module is imported -```` - -### cloudSync.local - -#### id - -Local device ID. Is unique. - -```` -let localId = cloudSync.local.id; -```` - -#### name - -Local device name. - -```` -let localName = cloudSync.local.name; -```` - -### CloudSync.tabs - -#### addEventListener(type, callback) - -Add an event handler for Tabs events. Valid type is `change`. The callback receives no arguments. - -```` -function handleTabChange() { - // Tabs have changed. -} - -cloudSync.tabs.addEventListener("change", handleTabChange); -```` - -Change events are emitted when a tab is opened or closed, when a tab is selected, or when the page changes for an open tab. - -#### removeEventListener(type, callback) - -Remove an event handler. Pass the type and function that were passed to addEventListener. - -```` -cloudSync.tabs.removeEventListener("change", handleTabChange); -```` - -#### mergeRemoteTabs(client, tabs) - -Merge remote tabs from upstream by updating existing items, adding new tabs, and deleting existing tabs. Accepts a client and a list of tabs. Returns a promise. - -```` -let remoteClient = { - id: "fawe78", - name: "My Firefox client", -}; - -let remoteTabs = [ - {title: "Google", - url: "https://www.google.com", - icon: "https://www.google.com/favicon.ico", - lastUsed: 1400799296192}, - {title: "Reddit", - url: "http://www.reddit.com", - icon: "http://www.reddit.com/favicon.ico", - lastUsed: 1400799296192 - deleted: true}, -]; - -cloudSync.tabs.mergeRemoteTabs(client, tabs).then( - function() { - console.log("merge complete"); - } -); -```` - -#### getLocalTabs() - -Returns a promise. Passes a list of local tabs when complete. - -```` -cloudSync.tabs.getLocalTabs().then( - function(tabs) { - console.log(JSON.stringify(tabs)); - } -); -```` - -#### clearRemoteTabs(client) - -Clears all tabs for a remote client. - -```` -let remoteClient = { - id: "fawe78", - name: "My Firefox client", -}; - -cloudSync.tabs.clearRemoteTabs(client); -```` - -### cloudSync.bookmarks - -#### getRootFolder(name) - -Gets the named root folder, creating it if it doesn't exist. The root folder object has a number of methods (see the next section for details). - -```` -cloudSync.bookmarks.getRootFolder("My Bookmarks").then( - function(rootFolder) { - console.log(rootFolder); - } -); -```` - -### cloudSync.bookmarks.RootFolder - -This is a root folder object for bookmarks, created by `cloudSync.bookmarks.getRootFolder`. - -#### BOOKMARK - -Bookmark type. Used in results objects. - -```` -let bookmarkType = rootFolder.BOOKMARK; -```` - -#### FOLDER - -Folder type. Used in results objects. - -```` -let folderType = rootFolder.FOLDER; -```` - -#### SEPARATOR - -Separator type. Used in results objects. - -```` -let separatorType = rootFolder.SEPARATOR; -```` - -#### addEventListener(type, callback) - -Add an event handler for Tabs events. Valid types are `add, remove, change, move`. The callback receives an ID corresponding to the target item. - -```` -function handleBoookmarkEvent(id) { - console.log("event for id:", id); -} - -rootFolder.addEventListener("add", handleBookmarkEvent); -rootFolder.addEventListener("remove", handleBookmarkEvent); -rootFolder.addEventListener("change", handleBookmarkEvent); -rootFolder.addEventListener("move", handleBookmarkEvent); -```` - -#### removeEventListener(type, callback) - -Remove an event handler. Pass the type and function that were passed to addEventListener. - -```` -rootFolder.removeEventListener("add", handleBookmarkEvent); -rootFolder.removeEventListener("remove", handleBookmarkEvent); -rootFolder.removeEventListener("change", handleBookmarkEvent); -rootFolder.removeEventListener("move", handleBookmarkEvent); -```` - -#### getLocalItems() - -Callback receives a list of items on the local client. Results have the following form: - -```` -{ - id: "faw8e7f", // item guid - parent: "f7sydf87y", // parent folder guid - dateAdded: 1400799296192, // timestamp - lastModified: 1400799296192, // timestamp - uri: "https://www.google.ca", // null for FOLDER and SEPARATOR - title: "Google" - type: rootFolder.BOOKMARK, // should be one of rootFolder.{BOOKMARK, FOLDER, SEPARATOR}, - index: 0 // must be unique among folder items -} -```` - -```` -rootFolder.getLocalItems().then( - function(items) { - console.log(JSON.stringify(items)); - } -); -```` - -#### getLocalItemsById([...]) - -Callback receives a list of items, specified by ID, on the local client. Results have the same form as `getLocalItems()` above. - -```` -rootFolder.getLocalItemsById(["213r23f", "f22fy3f3"]).then( - function(items) { - console.log(JSON.stringify(items)); - } -); -```` - -#### mergeRemoteItems([...]) - -Merge remote items from upstream by updating existing items, adding new items, and deleting existing items. Folders are created first so that subsequent operations will succeed. Items have the same form as `getLocalItems()` above. Items that do not have an ID will have an ID generated for them. The results structure will contain this generated ID. - -```` -rootFolder.mergeRemoteItems([ - { - id: 'f2398f23', - type: rootFolder.FOLDER, - title: 'Folder 1', - parent: '9f8237f928' - }, - { - id: '9f8237f928', - type: rootFolder.FOLDER, - title: 'Folder 0', - } - ]).then( - function(items) { - console.log(items); // any generated IDs are filled in now - console.log("merge completed"); - } -); -````
\ No newline at end of file diff --git a/services/cloudsync/docs/architecture.rst b/services/cloudsync/docs/architecture.rst deleted file mode 100644 index a7a8aa7ba..000000000 --- a/services/cloudsync/docs/architecture.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. _cloudsync_architecture: - -============ -Architecture -============ - -CloudSync offers functionality similar to Firefox Sync for data sources. Third-party addons -(sync adapters) consume local data, send and receive updates from the cloud, and merge remote data. - - -Files -===== - -CloudSync.jsm - Main module; Includes other modules and exposes them. - -CloudSyncAdapters.jsm - Provides an API for addons to register themselves. Will be used to - list available adapters and to notify adapters when sync operations - are requested manually by the user. - -CloudSyncBookmarks.jsm - Provides operations for interacting with bookmarks. - -CloudSyncBookmarksFolderCache.jsm - Implements a cache used to store folder hierarchy for filtering bookmark events. - -CloudSyncEventSource.jsm - Implements an event emitter. Used to provide addEventListener and removeEventListener - for tabs and bookmarks. - -CloudSyncLocal.jsm - Provides information about the local device, such as name and a unique id. - -CloudSyncPlacesWrapper.jsm - Wraps parts of the Places API in promises. Some methods are implemented to be asynchronous - where they are not in the places API. - -CloudSyncTabs.jsm - Provides operations for fetching local tabs and for populating the about:sync-tabs page. - - -Data Sources -============ - -CloudSync provides data for tabs and bookmarks. For tabs, local open pages can be enumerated and -remote tabs can be merged for displaying in about:sync-tabs. For bookmarks, updates are tracked -for a named folder (given by each adapter) and handled by callbacks registered using addEventListener, -and remote changes can be merged into the local database. - -Versioning -========== - -The API carries an integer version number (clouySync.version). Data records are versioned separately and individually. diff --git a/services/cloudsync/docs/dataformat.rst b/services/cloudsync/docs/dataformat.rst deleted file mode 100644 index 916581459..000000000 --- a/services/cloudsync/docs/dataformat.rst +++ /dev/null @@ -1,77 +0,0 @@ -.. _cloudsync_dataformat: - -=========== -Data Format -=========== - -All fields are required unless noted otherwise. - -Bookmarks -========= - -Record ------- - -type: - record type; one of CloudSync.bookmarks.{BOOKMARK, FOLDER, SEPARATOR, QUERY, LIVEMARK} - -id: - GUID for this bookmark item - -parent: - id of parent folder - -index: - item index in parent folder; should be unique and contiguous, or they will be adjusted internally - -title: - bookmark or folder title; not meaningful for separators - -dateAdded: - timestamp (in milliseconds) for item added - -lastModified: - timestamp (in milliseconds) for last modification - -uri: - bookmark URI; not meaningful for folders or separators - -version: - data layout version - -Tabs -==== - -ClientRecord ------------- - -id: - GUID for this client - -name: - name for this client; not guaranteed to be unique - -tabs: - list of tabs open on this client; see TabRecord - -version: - data layout version - - -TabRecord ---------- - -title: - name for this tab - -url: - URL for this tab; only one tab for each URL is stored - -icon: - favicon URL for this tab; optional - -lastUsed: - timetamp (in milliseconds) for last use - -version: - data layout version diff --git a/services/cloudsync/docs/example.rst b/services/cloudsync/docs/example.rst deleted file mode 100644 index 33d0f0531..000000000 --- a/services/cloudsync/docs/example.rst +++ /dev/null @@ -1,132 +0,0 @@ -.. _cloudsync_example: - -======= -Example -======= - -.. code-block:: javascript - - Cu.import("resource://gre/modules/CloudSync.jsm"); - - let HelloWorld = { - onLoad: function() { - let cloudSync = CloudSync(); - console.log("CLOUDSYNC -- hello world", cloudSync.local.id, cloudSync.local.name, cloudSync.adapters); - cloudSync.adapters.register('helloworld', {}); - console.log("CLOUDSYNC -- " + JSON.stringify(cloudSync.adapters.getAdapterNames())); - - - cloudSync.tabs.addEventListener("change", function() { - console.log("tab change"); - cloudSync.tabs.getLocalTabs().then( - function(records) { - console.log(JSON.stringify(records)); - } - ); - }); - - cloudSync.tabs.getLocalTabs().then( - function(records) { - console.log(JSON.stringify(records)); - } - ); - - let remoteClient = { - id: "001", - name: "FakeClient", - }; - let remoteTabs1 = [ - {url:"https://www.google.ca",title:"Google",icon:"https://www.google.ca/favicon.ico",lastUsed:Date.now()}, - ]; - let remoteTabs2 = [ - {url:"https://www.google.ca",title:"Google Canada",icon:"https://www.google.ca/favicon.ico",lastUsed:Date.now()}, - {url:"http://www.reddit.com",title:"Reddit",icon:"http://www.reddit.com/favicon.ico",lastUsed:Date.now()}, - ]; - cloudSync.tabs.mergeRemoteTabs(remoteClient, remoteTabs1).then( - function() { - return cloudSync.tabs.mergeRemoteTabs(remoteClient, remoteTabs2); - } - ).then( - function() { - return cloudSync.tabs.getRemoteTabs(); - } - ).then( - function(tabs) { - console.log("remote tabs:", tabs); - } - ); - - cloudSync.bookmarks.getRootFolder("Hello World").then( - function(rootFolder) { - console.log(rootFolder.name, rootFolder.id); - rootFolder.addEventListener("add", function(guid) { - console.log("CLOUDSYNC -- bookmark item added: " + guid); - rootFolder.getLocalItemsById([guid]).then( - function(items) { - console.log("CLOUDSYNC -- items: " + JSON.stringify(items)); - } - ); - }); - rootFolder.addEventListener("remove", function(guid) { - console.log("CLOUDSYNC -- bookmark item removed: " + guid); - rootFolder.getLocalItemsById([guid]).then( - function(items) { - console.log("CLOUDSYNC -- items: " + JSON.stringify(items)); - } - ); - }); - rootFolder.addEventListener("change", function(guid) { - console.log("CLOUDSYNC -- bookmark item changed: " + guid); - rootFolder.getLocalItemsById([guid]).then( - function(items) { - console.log("CLOUDSYNC -- items: " + JSON.stringify(items)); - } - ); - }); - rootFolder.addEventListener("move", function(guid) { - console.log("CLOUDSYNC -- bookmark item moved: " + guid); - rootFolder.getLocalItemsById([guid]).then( - function(items) { - console.log("CLOUDSYNC -- items: " + JSON.stringify(items)); - } - ); - }); - - function logLocalItems() { - return rootFolder.getLocalItems().then( - function(items) { - console.log("CLOUDSYNC -- local items: " + JSON.stringify(items)); - } - ); - } - - let items = [ - {"id":"9fdoci2KOME6","type":rootFolder.FOLDER,"parent":rootFolder.id,"title":"My Bookmarks 1"}, - {"id":"1fdoci2KOME5","type":rootFolder.FOLDER,"parent":rootFolder.id,"title":"My Bookmarks 2"}, - {"id":"G_UL4ZhOyX8m","type":rootFolder.BOOKMARK,"parent":"1fdoci2KOME5","title":"reddit: the front page of the internet","uri":"http://www.reddit.com/"}, - ]; - function mergeSomeItems() { - return rootFolder.mergeRemoteItems(items); - } - - logLocalItems().then( - mergeSomeItems - ).then( - function(processedItems) { - console.log("!!!", processedItems); - console.log("merge complete"); - }, - function(error) { - console.log("merge failed:", error); - } - ).then( - logLocalItems - ); - } - ); - - - }, - }; - - window.addEventListener("load", function(e) { HelloWorld.onLoad(e); }, false); diff --git a/services/cloudsync/docs/index.rst b/services/cloudsync/docs/index.rst deleted file mode 100644 index d7951776d..000000000 --- a/services/cloudsync/docs/index.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _cloudsync: - -===================== -CloudSync -===================== - -CloudSync is a service that provides access to tabs and bookmarks data -for third-party sync addons. Addons can read local bookmarks and tabs. -Bookmarks and tab data can be merged from remote devices. - -Addons are responsible for maintaining an upstream representation, as -well as sending and receiving data over the network. - -.. toctree:: - :maxdepth: 1 - - architecture - dataformat - example diff --git a/services/cloudsync/moz.build b/services/cloudsync/moz.build deleted file mode 100644 index 93197c9fe..000000000 --- a/services/cloudsync/moz.build +++ /dev/null @@ -1,21 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -SPHINX_TREES['cloudsync'] = 'docs' - -EXTRA_JS_MODULES += [ - 'CloudSync.jsm', - 'CloudSyncAdapters.jsm', - 'CloudSyncBookmarks.jsm', - 'CloudSyncBookmarksFolderCache.jsm', - 'CloudSyncEventSource.jsm', - 'CloudSyncLocal.jsm', - 'CloudSyncPlacesWrapper.jsm', - 'CloudSyncTabs.jsm', -] - -XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini'] -BROWSER_CHROME_MANIFESTS += ['tests/mochitest/browser.ini'] diff --git a/services/cloudsync/tests/mochitest/browser.ini b/services/cloudsync/tests/mochitest/browser.ini deleted file mode 100644 index c9eddbf71..000000000 --- a/services/cloudsync/tests/mochitest/browser.ini +++ /dev/null @@ -1,5 +0,0 @@ -[DEFAULT] -support-files= - other_window.html - -[browser_tabEvents.js]
\ No newline at end of file diff --git a/services/cloudsync/tests/mochitest/browser_tabEvents.js b/services/cloudsync/tests/mochitest/browser_tabEvents.js deleted file mode 100644 index 9d80090a0..000000000 --- a/services/cloudsync/tests/mochitest/browser_tabEvents.js +++ /dev/null @@ -1,79 +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/. */ - -function test() { - - let local = {}; - - Components.utils.import("resource://gre/modules/CloudSync.jsm", local); - Components.utils.import("resource:///modules/sessionstore/TabStateFlusher.jsm", local); - - let cloudSync = local.CloudSync(); - let opentabs = []; - - waitForExplicitFinish(); - - let testURL = "chrome://mochitests/content/browser/services/cloudsync/tests/mochitest/other_window.html"; - let expected = [ - testURL, - testURL+"?x=1", - testURL+"?x=%20a", - // testURL+"?x=å", - ]; - - let nevents = 0; - let nflushed = 0; - function handleTabChangeEvent () { - cloudSync.tabs.removeEventListener("change", handleTabChangeEvent); - ++ nevents; - info("tab change event " + nevents); - next(); - } - - function getLocalTabs() { - cloudSync.tabs.getLocalTabs().then( - function (tabs) { - for (let tab of tabs) { - ok(expected.indexOf(tab.url) >= 0, "found an expected tab"); - } - - is(tabs.length, expected.length, "found the right number of tabs"); - - opentabs.forEach(function (tab) { - gBrowser.removeTab(tab); - }); - - is(nevents, 1, "expected number of change events"); - - finish(); - } - ) - } - - cloudSync.tabs.addEventListener("change", handleTabChangeEvent); - - expected.forEach(function(url) { - let tab = gBrowser.addTab(url); - - function flush() { - tab.linkedBrowser.removeEventListener("load", flush, true); - local.TabStateFlusher.flush(tab.linkedBrowser).then(() => { - ++ nflushed; - info("flushed " + nflushed); - next(); - }); - } - - tab.linkedBrowser.addEventListener("load", flush, true); - - opentabs.push(tab); - }); - - function next() { - if (nevents == 1 && nflushed == expected.length) { - getLocalTabs(); - } - } - -} diff --git a/services/cloudsync/tests/mochitest/other_window.html b/services/cloudsync/tests/mochitest/other_window.html deleted file mode 100644 index a9ded2bd6..000000000 --- a/services/cloudsync/tests/mochitest/other_window.html +++ /dev/null @@ -1,7 +0,0 @@ -<!-- - Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ ---> -<!DOCTYPE HTML> -<html> -</html> diff --git a/services/cloudsync/tests/xpcshell/head.js b/services/cloudsync/tests/xpcshell/head.js deleted file mode 100644 index bd517cafa..000000000 --- a/services/cloudsync/tests/xpcshell/head.js +++ /dev/null @@ -1,10 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -var {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components; - -"use strict"; - -(function initCloudSyncTestingInfrastructure () { - do_get_profile(); -}).call(this); diff --git a/services/cloudsync/tests/xpcshell/test_bookmarks.js b/services/cloudsync/tests/xpcshell/test_bookmarks.js deleted file mode 100644 index d4e1d2b75..000000000 --- a/services/cloudsync/tests/xpcshell/test_bookmarks.js +++ /dev/null @@ -1,73 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://gre/modules/CloudSync.jsm"); - -function run_test () { - run_next_test(); -} - -function cleanup () { - -} - -add_task(function* test_merge_bookmarks_flat () { - try { - let rootFolder = yield CloudSync().bookmarks.getRootFolder("TEST"); - ok(rootFolder.id, "root folder id is ok"); - - let items = [ - {"id":"G_UL4ZhOyX8m","type":rootFolder.BOOKMARK,"title":"reddit: the front page of the internet 1","uri":"http://www.reddit.com",index:2}, - {"id":"G_UL4ZhOyX8n","type":rootFolder.BOOKMARK,"title":"reddit: the front page of the internet 2","uri":"http://www.reddit.com?1",index:1}, - ]; - yield rootFolder.mergeRemoteItems(items); - - let localItems = yield rootFolder.getLocalItems(); - equal(Object.keys(localItems).length, items.length, "found merged items"); - } finally { - yield CloudSync().bookmarks.deleteRootFolder("TEST"); - } -}); - -add_task(function* test_merge_bookmarks_in_folders () { - try { - let rootFolder = yield CloudSync().bookmarks.getRootFolder("TEST"); - ok(rootFolder.id, "root folder id is ok"); - - let items = [ - {"id":"G_UL4ZhOyX8m","type":rootFolder.BOOKMARK,"title":"reddit: the front page of the internet 1","uri":"http://www.reddit.com",index:2}, - {"id":"G_UL4ZhOyX8n","type":rootFolder.BOOKMARK,parent:"G_UL4ZhOyX8x","title":"reddit: the front page of the internet 2","uri":"http://www.reddit.com/?a=å%20ä%20ö",index:1}, - {"id":"G_UL4ZhOyX8x","type":rootFolder.FOLDER}, - ]; - yield rootFolder.mergeRemoteItems(items); - - let localItems = yield rootFolder.getLocalItems(); - equal(localItems.length, items.length, "found merged items"); - - localItems.forEach(function(item) { - ok(item.id == "G_UL4ZhOyX8m" || - item.id == "G_UL4ZhOyX8n" || - item.id == "G_UL4ZhOyX8x"); - if (item.id == "G_UL4ZhOyX8n") { - equal(item.parent, "G_UL4ZhOyX8x") - } else { - equal(item.parent, rootFolder.id); - } - }); - - let folder = (yield rootFolder.getLocalItemsById(["G_UL4ZhOyX8x"]))[0]; - equal(folder.id, "G_UL4ZhOyX8x"); - equal(folder.type, rootFolder.FOLDER); - - let bookmark = (yield rootFolder.getLocalItemsById(["G_UL4ZhOyX8n"]))[0]; - equal(bookmark.id, "G_UL4ZhOyX8n"); - equal(bookmark.parent, "G_UL4ZhOyX8x"); - equal(bookmark.title, "reddit: the front page of the internet 2"); - equal(bookmark.index, 0); - equal(bookmark.uri, "http://www.reddit.com/?a=%C3%A5%20%C3%A4%20%C3%B6"); - } finally { - yield CloudSync().bookmarks.deleteRootFolder("TEST"); - } -});
\ No newline at end of file diff --git a/services/cloudsync/tests/xpcshell/test_lazyload.js b/services/cloudsync/tests/xpcshell/test_lazyload.js deleted file mode 100644 index 5928875d5..000000000 --- a/services/cloudsync/tests/xpcshell/test_lazyload.js +++ /dev/null @@ -1,18 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://gre/modules/CloudSync.jsm"); - -function run_test() { - run_next_test(); -} - -add_task(function test_lazyload() { - ok(!CloudSync.ready, "CloudSync.ready is false before CloudSync() invoked"); - let cs1 = CloudSync(); - ok(CloudSync.ready, "CloudSync.ready is true after CloudSync() invoked"); - let cs2 = CloudSync(); - ok(cs1 === cs2, "CloudSync() returns the same instance on multiple invocations"); -}); diff --git a/services/cloudsync/tests/xpcshell/test_module.js b/services/cloudsync/tests/xpcshell/test_module.js deleted file mode 100644 index 6d31345ed..000000000 --- a/services/cloudsync/tests/xpcshell/test_module.js +++ /dev/null @@ -1,19 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://gre/modules/CloudSync.jsm"); - -function run_test () { - run_next_test(); -} - -add_task(function test_module_load () { - ok(CloudSync); - let cloudSync = CloudSync(); - ok(cloudSync.adapters); - ok(cloudSync.bookmarks); - ok(cloudSync.local); - ok(cloudSync.tabs); -}); diff --git a/services/cloudsync/tests/xpcshell/test_tabs.js b/services/cloudsync/tests/xpcshell/test_tabs.js deleted file mode 100644 index 50f7a73de..000000000 --- a/services/cloudsync/tests/xpcshell/test_tabs.js +++ /dev/null @@ -1,29 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://gre/modules/CloudSync.jsm"); - -function run_test () { - run_next_test(); -} - -add_task(function* test_get_remote_tabs () { - let cloudSync = CloudSync(); - let clients = yield cloudSync.tabs.getRemoteTabs(); - equal(clients.length, 0); - - yield cloudSync.tabs.mergeRemoteTabs({ - id: "001", - name: "FakeClient", - },[ - {url:"https://www.google.ca?a=å%20ä%20ö",title:"Google Canada",icon:"https://www.google.ca/favicon.ico",lastUsed:0}, - {url:"http://www.reddit.com",title:"Reddit",icon:"http://www.reddit.com/favicon.ico",lastUsed:1}, - ]); - ok(cloudSync.tabs.hasRemoteTabs()); - - clients = yield cloudSync.tabs.getRemoteTabs(); - equal(clients.length, 1); - equal(clients[0].tabs.size, 2); -}); diff --git a/services/cloudsync/tests/xpcshell/xpcshell.ini b/services/cloudsync/tests/xpcshell/xpcshell.ini deleted file mode 100644 index 08d2eff3a..000000000 --- a/services/cloudsync/tests/xpcshell/xpcshell.ini +++ /dev/null @@ -1,10 +0,0 @@ -[DEFAULT] -head = head.js -tail = -firefox-appdir = browser -skip-if = toolkit == 'android' - -[test_module.js] -[test_tabs.js] -[test_bookmarks.js] -[test_lazyload.js] diff --git a/services/moz.build b/services/moz.build index 2109d512a..91f1e285e 100644 --- a/services/moz.build +++ b/services/moz.build @@ -14,6 +14,3 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android': if CONFIG['MOZ_SERVICES_SYNC']: DIRS += ['sync'] - -if CONFIG['MOZ_SERVICES_CLOUDSYNC']: - DIRS += ['cloudsync'] diff --git a/services/sync/tests/unit/test_fxa_node_reassignment.js b/services/sync/tests/unit/test_fxa_node_reassignment.js deleted file mode 100644 index 2f61afd6f..000000000 --- a/services/sync/tests/unit/test_fxa_node_reassignment.js +++ /dev/null @@ -1,321 +0,0 @@ -/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-_("Test that node reassignment happens correctly using the FxA identity mgr.");
-// The node-reassignment logic is quite different for FxA than for the legacy
-// provider. In particular, there's no special request necessary for
-// reassignment - it comes from the token server - so we need to ensure the
-// Fxa cluster manager grabs a new token.
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://services-common/rest.js");
-Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/status.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/rotaryengine.js");
-Cu.import("resource://services-sync/browserid_identity.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-
-Service.engineManager.clear();
-
-function run_test() {
- Log.repository.getLogger("Sync.AsyncResource").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.ErrorHandler").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.Resource").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.RESTRequest").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
- Log.repository.getLogger("Sync.SyncScheduler").level = Log.Level.Trace;
- initTestLogging();
-
- Service.engineManager.register(RotaryEngine);
-
- // Setup the FxA identity manager and cluster manager.
- Status.__authManager = Service.identity = new BrowserIDManager();
- Service._clusterManager = Service.identity.createClusterManager(Service);
-
- // None of the failures in this file should result in a UI error.
- function onUIError() {
- do_throw("Errors should not be presented in the UI.");
- }
- Svc.Obs.add("weave:ui:login:error", onUIError);
- Svc.Obs.add("weave:ui:sync:error", onUIError);
-
- run_next_test();
-}
-
-
-// API-compatible with SyncServer handler. Bind `handler` to something to use
-// as a ServerCollection handler.
-function handleReassign(handler, req, resp) {
- resp.setStatusLine(req.httpVersion, 401, "Node reassignment");
- resp.setHeader("Content-Type", "application/json");
- let reassignBody = JSON.stringify({error: "401inator in place"});
- resp.bodyOutputStream.write(reassignBody, reassignBody.length);
-}
-
-let numTokenRequests = 0;
-
-function prepareServer(cbAfterTokenFetch) {
- let config = makeIdentityConfig({username: "johndoe"});
- let server = new SyncServer();
- server.registerUser("johndoe");
- server.start();
-
- // Set the token endpoint for the initial token request that's done implicitly
- // via configureIdentity.
- config.fxaccount.token.endpoint = server.baseURI + "1.1/johndoe";
- // And future token fetches will do magic around numReassigns.
- let numReassigns = 0;
- return configureIdentity(config).then(() => {
- Service.identity._tokenServerClient = {
- getTokenFromBrowserIDAssertion: function(uri, assertion, cb) {
- // Build a new URL with trailing zeros for the SYNC_VERSION part - this
- // will still be seen as equivalent by the test server, but different
- // by sync itself.
- numReassigns += 1;
- let trailingZeros = new Array(numReassigns + 1).join('0');
- let token = config.fxaccount.token;
- token.endpoint = server.baseURI + "1.1" + trailingZeros + "/johndoe";
- token.uid = config.username;
- numTokenRequests += 1;
- cb(null, token);
- if (cbAfterTokenFetch) {
- cbAfterTokenFetch();
- }
- },
- };
- Service.clusterURL = config.fxaccount.token.endpoint;
- return server;
- });
-}
-
-function getReassigned() {
- try {
- return Services.prefs.getBoolPref("services.sync.lastSyncReassigned");
- } catch (ex if (ex.result == Cr.NS_ERROR_UNEXPECTED)) {
- return false;
- } catch (ex) {
- do_throw("Got exception retrieving lastSyncReassigned: " +
- Utils.exceptionStr(ex));
- }
-}
-
-/**
- * Make a test request to `url`, then watch the result of two syncs
- * to ensure that a node request was made.
- * Runs `between` between the two. This can be used to undo deliberate failure
- * setup, detach observers, etc.
- */
-function syncAndExpectNodeReassignment(server, firstNotification, between,
- secondNotification, url) {
- _("Starting syncAndExpectNodeReassignment\n");
- let deferred = Promise.defer();
- function onwards() {
- let numTokenRequestsBefore;
- function onFirstSync() {
- _("First sync completed.");
- Svc.Obs.remove(firstNotification, onFirstSync);
- Svc.Obs.add(secondNotification, onSecondSync);
-
- do_check_eq(Service.clusterURL, "");
-
- // Track whether we fetched a new token.
- numTokenRequestsBefore = numTokenRequests;
-
- // Allow for tests to clean up error conditions.
- between();
- }
- function onSecondSync() {
- _("Second sync completed.");
- Svc.Obs.remove(secondNotification, onSecondSync);
- Service.scheduler.clearSyncTriggers();
-
- // Make absolutely sure that any event listeners are done with their work
- // before we proceed.
- waitForZeroTimer(function () {
- _("Second sync nextTick.");
- do_check_eq(numTokenRequests, numTokenRequestsBefore + 1, "fetched a new token");
- Service.startOver();
- server.stop(deferred.resolve);
- });
- }
-
- Svc.Obs.add(firstNotification, onFirstSync);
- Service.sync();
- }
-
- // Make sure that it works!
- _("Making request to " + url + " which should 401");
- let request = new RESTRequest(url);
- request.get(function () {
- do_check_eq(request.response.status, 401);
- Utils.nextTick(onwards);
- });
- yield deferred.promise;
-}
-
-add_task(function test_momentary_401_engine() {
- _("Test a failure for engine URLs that's resolved by reassignment.");
- let server = yield prepareServer();
- let john = server.user("johndoe");
-
- _("Enabling the Rotary engine.");
- let engine = Service.engineManager.get("rotary");
- engine.enabled = true;
-
- // We need the server to be correctly set up prior to experimenting. Do this
- // through a sync.
- let global = {syncID: Service.syncID,
- storageVersion: STORAGE_VERSION,
- rotary: {version: engine.version,
- syncID: engine.syncID}}
- john.createCollection("meta").insert("global", global);
-
- _("First sync to prepare server contents.");
- Service.sync();
-
- _("Setting up Rotary collection to 401.");
- let rotary = john.createCollection("rotary");
- let oldHandler = rotary.collectionHandler;
- rotary.collectionHandler = handleReassign.bind(this, undefined);
-
- // We want to verify that the clusterURL pref has been cleared after a 401
- // inside a sync. Flag the Rotary engine to need syncing.
- john.collection("rotary").timestamp += 1000;
-
- function between() {
- _("Undoing test changes.");
- rotary.collectionHandler = oldHandler;
-
- function onLoginStart() {
- // lastSyncReassigned shouldn't be cleared until a sync has succeeded.
- _("Ensuring that lastSyncReassigned is still set at next sync start.");
- Svc.Obs.remove("weave:service:login:start", onLoginStart);
- do_check_true(getReassigned());
- }
-
- _("Adding observer that lastSyncReassigned is still set on login.");
- Svc.Obs.add("weave:service:login:start", onLoginStart);
- }
-
- yield syncAndExpectNodeReassignment(server,
- "weave:service:sync:finish",
- between,
- "weave:service:sync:finish",
- Service.storageURL + "rotary");
-});
-
-// This test ends up being a failing info fetch *after we're already logged in*.
-add_task(function test_momentary_401_info_collections_loggedin() {
- _("Test a failure for info/collections after login that's resolved by reassignment.");
- let server = yield prepareServer();
-
- _("First sync to prepare server contents.");
- Service.sync();
-
- _("Arrange for info/collections to return a 401.");
- let oldHandler = server.toplevelHandlers.info;
- server.toplevelHandlers.info = handleReassign;
-
- function undo() {
- _("Undoing test changes.");
- server.toplevelHandlers.info = oldHandler;
- }
-
- do_check_true(Service.isLoggedIn, "already logged in");
-
- yield syncAndExpectNodeReassignment(server,
- "weave:service:sync:error",
- undo,
- "weave:service:sync:finish",
- Service.infoURL);
-});
-
-// This test ends up being a failing info fetch *before we're logged in*.
-// In this case we expect to recover during the login phase - so the first
-// sync succeeds.
-add_task(function test_momentary_401_info_collections_loggedout() {
- _("Test a failure for info/collections before login that's resolved by reassignment.");
-
- let oldHandler;
- let sawTokenFetch = false;
-
- function afterTokenFetch() {
- // After a single token fetch, we undo our evil handleReassign hack, so
- // the next /info request returns the collection instead of a 401
- server.toplevelHandlers.info = oldHandler;
- sawTokenFetch = true;
- }
-
- let server = yield prepareServer(afterTokenFetch);
-
- // Return a 401 for the next /info request - it will be reset immediately
- // after a new token is fetched.
- oldHandler = server.toplevelHandlers.info
- server.toplevelHandlers.info = handleReassign;
-
- do_check_false(Service.isLoggedIn, "not already logged in");
-
- Service.sync();
- do_check_eq(Status.sync, SYNC_SUCCEEDED, "sync succeeded");
- // sync was successful - check we grabbed a new token.
- do_check_true(sawTokenFetch, "a new token was fetched by this test.")
- // and we are done.
- Service.startOver();
- let deferred = Promise.defer();
- server.stop(deferred.resolve);
- yield deferred.promise;
-});
-
-// This test ends up being a failing meta/global fetch *after we're already logged in*.
-add_task(function test_momentary_401_storage_loggedin() {
- _("Test a failure for any storage URL after login that's resolved by" +
- "reassignment.");
- let server = yield prepareServer();
-
- _("First sync to prepare server contents.");
- Service.sync();
-
- _("Arrange for meta/global to return a 401.");
- let oldHandler = server.toplevelHandlers.storage;
- server.toplevelHandlers.storage = handleReassign;
-
- function undo() {
- _("Undoing test changes.");
- server.toplevelHandlers.storage = oldHandler;
- }
-
- do_check_true(Service.isLoggedIn, "already logged in");
-
- yield syncAndExpectNodeReassignment(server,
- "weave:service:sync:error",
- undo,
- "weave:service:sync:finish",
- Service.storageURL + "meta/global");
-});
-
-// This test ends up being a failing meta/global fetch *before we've logged in*.
-add_task(function test_momentary_401_storage_loggedout() {
- _("Test a failure for any storage URL before login, not just engine parts. " +
- "Resolved by reassignment.");
- let server = yield prepareServer();
-
- // Return a 401 for all storage requests.
- let oldHandler = server.toplevelHandlers.storage;
- server.toplevelHandlers.storage = handleReassign;
-
- function undo() {
- _("Undoing test changes.");
- server.toplevelHandlers.storage = oldHandler;
- }
-
- do_check_false(Service.isLoggedIn, "already logged in");
-
- yield syncAndExpectNodeReassignment(server,
- "weave:service:login:error",
- undo,
- "weave:service:sync:finish",
- Service.storageURL + "meta/global");
-});
-
diff --git a/services/sync/tests/unit/test_fxa_service_cluster.js b/services/sync/tests/unit/test_fxa_service_cluster.js deleted file mode 100644 index f6f97184a..000000000 --- a/services/sync/tests/unit/test_fxa_service_cluster.js +++ /dev/null @@ -1,68 +0,0 @@ -/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/util.js");
-Cu.import("resource://testing-common/services/sync/fxa_utils.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-
-add_task(function test_findCluster() {
- _("Test FxA _findCluster()");
-
- _("_findCluster() throws on 500 errors.");
- initializeIdentityWithTokenServerResponse({
- status: 500,
- headers: [],
- body: "",
- });
-
- yield Service.identity.initializeWithCurrentIdentity();
- yield Assert.rejects(Service.identity.whenReadyToAuthenticate.promise,
- "should reject due to 500");
-
- Assert.throws(function() {
- Service._clusterManager._findCluster();
- });
-
- _("_findCluster() returns null on authentication errors.");
- initializeIdentityWithTokenServerResponse({
- status: 401,
- headers: {"content-type": "application/json"},
- body: "{}",
- });
-
- yield Service.identity.initializeWithCurrentIdentity();
- yield Assert.rejects(Service.identity.whenReadyToAuthenticate.promise,
- "should reject due to 401");
-
- cluster = Service._clusterManager._findCluster();
- Assert.strictEqual(cluster, null);
-
- _("_findCluster() works with correct tokenserver response.");
- let endpoint = "http://example.com/something";
- initializeIdentityWithTokenServerResponse({
- status: 200,
- headers: {"content-type": "application/json"},
- body:
- JSON.stringify({
- api_endpoint: endpoint,
- duration: 300,
- id: "id",
- key: "key",
- uid: "uid",
- })
- });
-
- yield Service.identity.initializeWithCurrentIdentity();
- yield Service.identity.whenReadyToAuthenticate.promise;
- cluster = Service._clusterManager._findCluster();
- // The cluster manager ensures a trailing "/"
- Assert.strictEqual(cluster, endpoint + "/");
-
- Svc.Prefs.resetBranch("");
-});
-
-function run_test() {
- initTestLogging();
- run_next_test();
-}
diff --git a/services/sync/tests/unit/test_fxa_startOver.js b/services/sync/tests/unit/test_fxa_startOver.js deleted file mode 100644 index e27d86ea0..000000000 --- a/services/sync/tests/unit/test_fxa_startOver.js +++ /dev/null @@ -1,63 +0,0 @@ -/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://testing-common/services/sync/utils.js");
-Cu.import("resource://services-sync/identity.js");
-Cu.import("resource://services-sync/browserid_identity.js");
-Cu.import("resource://services-sync/service.js");
-
-function run_test() {
- initTestLogging("Trace");
- run_next_test();
-}
-
-add_task(function* test_startover() {
- let oldValue = Services.prefs.getBoolPref("services.sync-testing.startOverKeepIdentity", true);
- Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", false);
-
- ensureLegacyIdentityManager();
- yield configureIdentity({username: "johndoe"});
-
- // The boolean flag on the xpcom service should reflect a legacy provider.
- let xps = Cc["@mozilla.org/weave/service;1"]
- .getService(Components.interfaces.nsISupports)
- .wrappedJSObject;
- do_check_false(xps.fxAccountsEnabled);
-
- // we expect the "legacy" provider (but can't instanceof that, as BrowserIDManager
- // extends it)
- do_check_false(Service.identity instanceof BrowserIDManager);
-
- Service.serverURL = "https://localhost/";
- Service.clusterURL = Service.serverURL;
-
- Service.login();
- // We should have a cluster URL
- do_check_true(Service.clusterURL.length > 0);
-
- // remember some stuff so we can reset it after.
- let oldIdentity = Service.identity;
- let oldClusterManager = Service._clusterManager;
- let deferred = Promise.defer();
- Services.obs.addObserver(function observeStartOverFinished() {
- Services.obs.removeObserver(observeStartOverFinished, "weave:service:start-over:finish");
- deferred.resolve();
- }, "weave:service:start-over:finish", false);
-
- Service.startOver();
- yield deferred.promise; // wait for the observer to fire.
-
- // the xpcom service should indicate FxA is enabled.
- do_check_true(xps.fxAccountsEnabled);
- // should have swapped identities.
- do_check_true(Service.identity instanceof BrowserIDManager);
- // should have clobbered the cluster URL
- do_check_eq(Service.clusterURL, "");
-
- // we should have thrown away the old identity provider and cluster manager.
- do_check_neq(oldIdentity, Service.identity);
- do_check_neq(oldClusterManager, Service._clusterManager);
-
- // reset the world.
- Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", oldValue);
-});
diff --git a/services/sync/tests/unit/xpcshell.ini b/services/sync/tests/unit/xpcshell.ini index 7e97835ac..28424129b 100644 --- a/services/sync/tests/unit/xpcshell.ini +++ b/services/sync/tests/unit/xpcshell.ini @@ -122,11 +122,6 @@ skip-if = os == "android" [test_syncscheduler.js] [test_upgrade_old_sync_key.js] -# Firefox Accounts specific tests -[test_fxa_startOver.js] -[test_fxa_service_cluster.js] -[test_fxa_node_reassignment.js] - # Finally, we test each engine. [test_addons_engine.js] run-sequentially = Hardcoded port in static files. diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index 1e2204f7e..ae0eea1c4 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -102,13 +102,6 @@ MOZ_SAFE_BROWSING: false, #endif - MOZ_SERVICES_CLOUDSYNC: -#ifdef MOZ_SERVICES_CLOUDSYNC - true, -#else - false, -#endif - MOZ_UPDATER: #ifdef MOZ_UPDATER true, diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index e0acdb19e..8f66417c1 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -151,8 +151,7 @@ for var in ('ANDROID_PACKAGE_NAME', for var in ('MOZ_TOOLKIT_SEARCH', 'MOZ_SYSTEM_NSS', 'MOZ_UPDATER', - 'MOZ_SWITCHBOARD', - 'MOZ_SERVICES_CLOUDSYNC'): + 'MOZ_SWITCHBOARD'): if CONFIG[var]: DEFINES[var] = True |