diff options
Diffstat (limited to 'application/basilisk/base/content')
-rw-r--r-- | application/basilisk/base/content/browser-fxaccounts.js | 125 | ||||
-rw-r--r-- | application/basilisk/base/content/browser-syncui.js | 82 | ||||
-rw-r--r-- | application/basilisk/base/content/browser.js | 2 | ||||
-rw-r--r-- | application/basilisk/base/content/sync/quota.js | 247 | ||||
-rw-r--r-- | application/basilisk/base/content/sync/quota.xul | 65 |
5 files changed, 381 insertions, 140 deletions
diff --git a/application/basilisk/base/content/browser-fxaccounts.js b/application/basilisk/base/content/browser-fxaccounts.js index 94a591f1e..e1d556bff 100644 --- a/application/basilisk/base/content/browser-fxaccounts.js +++ b/application/basilisk/base/content/browser-fxaccounts.js @@ -77,15 +77,6 @@ var gFxAccounts = { return Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED; }, - get sendTabToDeviceEnabled() { - return Services.prefs.getBoolPref("services.sync.sendTabToDevice.enabled"); - }, - - get remoteClients() { - return Weave.Service.clientsEngine.remoteClients - .sort((a, b) => a.name.localeCompare(b.name)); - }, - init: function () { // Bail out if we're already initialized and for pop-up windows. if (this._initialized || !window.toolbar.visible) { @@ -153,11 +144,6 @@ var gFxAccounts = { profileInfoEnabled = Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled"); } catch (e) { } - // Bail out if FxA is disabled. - if (!this.weave.fxAccountsEnabled) { - return Promise.resolve(); - } - this.panelUIFooter.hidden = false; // Make sure the button is disabled in customization mode. @@ -176,6 +162,7 @@ var gFxAccounts = { 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"); @@ -191,34 +178,19 @@ var gFxAccounts = { this.panelUIFooter.removeAttribute("fxastatus"); this.panelUIFooter.removeAttribute("fxaprofileimage"); this.panelUIAvatar.style.removeProperty("list-style-image"); - let showErrorBadge = false; - if (userData) { - // At this point we consider the user as logged-in (but still can be in an error state) - if (this.loginFailed) { - let tooltipDescription = this.strings.formatStringFromName("reconnectDescription", [userData.email], 1); - this.panelUIFooter.setAttribute("fxastatus", "error"); - this.panelUILabel.setAttribute("label", errorLabel); - this.panelUIStatus.setAttribute("tooltiptext", tooltipDescription); - showErrorBadge = true; - } else if (!userData.verified) { - let tooltipDescription = this.strings.formatStringFromName("verifyDescription", [userData.email], 1); - this.panelUIFooter.setAttribute("fxastatus", "error"); - this.panelUIFooter.setAttribute("unverified", "true"); - this.panelUILabel.setAttribute("label", unverifiedLabel); - this.panelUIStatus.setAttribute("tooltiptext", tooltipDescription); - showErrorBadge = true; - } else { - this.panelUIFooter.setAttribute("fxastatus", "signedin"); - this.panelUILabel.setAttribute("label", userData.email); - } - if (profileInfoEnabled) { - this.panelUIFooter.setAttribute("fxaprofileimage", "enabled"); - } + + if (Weave.Status.service == Weave.CLIENT_NOT_CONFIGURED) { + // Leave the default state + return; } - if (showErrorBadge) { - gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_FXA, "fxa-needs-authentication"); + + if (this.loginFailed) { + this.panelUIFooter.setAttribute("fxastatus", "error"); + this.panelUILabel.setAttribute("label", errorLabel); } else { - gMenuButtonBadgeManager.removeBadge(gMenuButtonBadgeManager.BADGEID_FXA); + this.panelUIFooter.setAttribute("fxastatus", "signedin"); + this.panelUILabel.setAttribute("label", settingslabel); + this.panelUIStatus.setAttribute("tooltiptext", ""); } } @@ -322,81 +294,12 @@ var gFxAccounts = { this.openAccountsPage("reauth", { entrypoint: entryPoint }); }, - sendTabToDevice: function (url, clientId, title) { - Weave.Service.clientsEngine.sendURIToClientForDisplay(url, clientId, title); - }, - - populateSendTabToDevicesMenu: function (devicesPopup, url, title) { - // remove existing menu items - while (devicesPopup.hasChildNodes()) { - devicesPopup.removeChild(devicesPopup.firstChild); - } - - const fragment = document.createDocumentFragment(); - - const onTargetDeviceCommand = (event) => { - const clientId = event.target.getAttribute("clientId"); - const clients = clientId - ? [clientId] - : this.remoteClients.map(client => client.id); - - clients.forEach(clientId => this.sendTabToDevice(url, clientId, title)); - } - - function addTargetDevice(clientId, name) { - const targetDevice = document.createElement("menuitem"); - targetDevice.addEventListener("command", onTargetDeviceCommand, true); - targetDevice.setAttribute("class", "sendtab-target"); - targetDevice.setAttribute("clientId", clientId); - targetDevice.setAttribute("label", name); - fragment.appendChild(targetDevice); - } - - const clients = this.remoteClients; - for (let client of clients) { - addTargetDevice(client.id, client.name); - } - - // "All devices" menu item - if (clients.length > 1) { - const separator = document.createElement("menuseparator"); - fragment.appendChild(separator); - const allDevicesLabel = this.strings.GetStringFromName("sendTabToAllDevices.menuitem"); - addTargetDevice("", allDevicesLabel); - } - - devicesPopup.appendChild(fragment); - }, - updateTabContextMenu: function (aPopupMenu) { - if (!this.sendTabToDeviceEnabled) { - return; - } - - const remoteClientPresent = this.remoteClients.length > 0; - ["context_sendTabToDevice", "context_sendTabToDevice_separator"] - .forEach(id => { document.getElementById(id).hidden = !remoteClientPresent }); + // STUB }, initPageContextMenu: function (contextMenu) { - if (!this.sendTabToDeviceEnabled) { - return; - } - - const remoteClientPresent = this.remoteClients.length > 0; - // showSendLink and showSendPage are mutually exclusive - const showSendLink = remoteClientPresent - && (contextMenu.onSaveableLink || contextMenu.onPlainTextLink); - const showSendPage = !showSendLink && remoteClientPresent - && !(contextMenu.isContentSelected || - contextMenu.onImage || contextMenu.onCanvas || - contextMenu.onVideo || contextMenu.onAudio || - contextMenu.onLink || contextMenu.onTextInput); - - ["context-sendpagetodevice", "context-sep-sendpagetodevice"] - .forEach(id => contextMenu.showItem(id, showSendPage)); - ["context-sendlinktodevice", "context-sep-sendlinktodevice"] - .forEach(id => contextMenu.showItem(id, showSendLink)); + // STUB } }; diff --git a/application/basilisk/base/content/browser-syncui.js b/application/basilisk/base/content/browser-syncui.js index 51bcb15d5..3a57140f2 100644 --- a/application/basilisk/base/content/browser-syncui.js +++ b/application/basilisk/base/content/browser-syncui.js @@ -19,6 +19,7 @@ var gSyncUI = { _obs: ["weave:service:sync:start", "weave:service:sync:finish", "weave:service:sync:error", + "weave:service:quota:remaining", "weave:service:setup-complete", "weave:service:login:start", "weave:service:login:finish", @@ -246,6 +247,21 @@ var gSyncUI = { this.updateUI(); }, + onQuotaNotice: function onQuotaNotice(subject, data) { + let title = this._stringBundle.GetStringFromName("warning.sync.quota.label"); + let description = this._stringBundle.GetStringFromName("warning.sync.quota.description"); + let buttons = []; + buttons.push(new Weave.NotificationButton( + this._stringBundle.GetStringFromName("error.sync.viewQuotaButton.label"), + this._stringBundle.GetStringFromName("error.sync.viewQuotaButton.accesskey"), + function() { gSyncUI.openQuotaDialog(); return true; } + )); + + let notification = new Weave.Notification( + title, description, null, Weave.Notifications.PRIORITY_WARNING, buttons); + Weave.Notifications.replaceTitle(notification); + }, + _getAppName: function () { let brand = new StringBundle("chrome://branding/locale/brand.properties"); return brand.get("brandShortName"); @@ -293,17 +309,13 @@ var gSyncUI = { */ openSetup: function SUI_openSetup(wizardType, entryPoint = "syncbutton") { - if (this.weaveService.fxAccountsEnabled) { - this.openPrefs(entryPoint); - } 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); - } + 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); } }, @@ -328,23 +340,6 @@ var gSyncUI = { gFxAccounts.openSignInAgainPage(entryPoint); }, - openSyncedTabsPanel() { - let placement = CustomizableUI.getPlacementOfWidget("sync-button"); - let area = placement ? placement.area : CustomizableUI.AREA_NAVBAR; - let anchor = document.getElementById("sync-button") || - document.getElementById("PanelUI-menu-button"); - if (area == CustomizableUI.AREA_PANEL) { - // The button is in the panel, so we need to show the panel UI, then our - // subview. - PanelUI.show().then(() => { - PanelUI.showSubView("PanelUI-remotetabs", anchor, area); - }).catch(Cu.reportError); - } else { - // It is placed somewhere else - just try and show it. - PanelUI.showSubView("PanelUI-remotetabs", anchor, area); - } - }, - /* 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, @@ -456,6 +451,32 @@ var gSyncUI = { } }, + 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 = + 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"); + 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); + } + + this.updateUI(); + }, + + observe: function SUI_observe(subject, topic, data) { this.log.debug("observed", topic); if (this._unloaded) { @@ -487,12 +508,17 @@ var gSyncUI = { // Do nothing. 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(); break; + case "weave:service:quota:remaining": + this.onQuotaNotice(); + break; case "weave:ui:login:error": case "weave:service:login:error": this.onLoginError(); diff --git a/application/basilisk/base/content/browser.js b/application/basilisk/base/content/browser.js index d45956191..9fb997a42 100644 --- a/application/basilisk/base/content/browser.js +++ b/application/basilisk/base/content/browser.js @@ -6347,7 +6347,7 @@ function checkEmptyPageOrigin(browser = gBrowser.selectedBrowser, } function BrowserOpenSyncTabs() { - gSyncUI.openSyncedTabsPanel(); + switchToTabHavingURI("about:sync-tabs", true); } /** diff --git a/application/basilisk/base/content/sync/quota.js b/application/basilisk/base/content/sync/quota.js new file mode 100644 index 000000000..b416a44cc --- /dev/null +++ b/application/basilisk/base/content/sync/quota.js @@ -0,0 +1,247 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://services-sync/main.js"); +Cu.import("resource://gre/modules/DownloadUtils.jsm"); + +var gSyncQuota = { + + init: function init() { + this.bundle = document.getElementById("quotaStrings"); + let caption = document.getElementById("treeCaption"); + caption.firstChild.nodeValue = this.bundle.getString("quota.treeCaption.label"); + + gUsageTreeView.init(); + this.tree = document.getElementById("usageTree"); + this.tree.view = gUsageTreeView; + + this.loadData(); + }, + + loadData: function loadData() { + this._usage_req = Weave.Service.getStorageInfo(Weave.INFO_COLLECTION_USAGE, + function (error, usage) { + delete gSyncQuota._usage_req; + // displayUsageData handles null values, so no need to check 'error'. + gUsageTreeView.displayUsageData(usage); + }); + + let usageLabel = document.getElementById("usageLabel"); + let bundle = this.bundle; + + this._quota_req = Weave.Service.getStorageInfo(Weave.INFO_QUOTA, + function (error, quota) { + delete gSyncQuota._quota_req; + + if (error) { + usageLabel.value = bundle.getString("quota.usageError.label"); + return; + } + let used = gSyncQuota.convertKB(quota[0]); + if (!quota[1]) { + // No quota on the server. + usageLabel.value = bundle.getFormattedString( + "quota.usageNoQuota.label", used); + return; + } + let percent = Math.round(100 * quota[0] / quota[1]); + let total = gSyncQuota.convertKB(quota[1]); + usageLabel.value = bundle.getFormattedString( + "quota.usagePercentage.label", [percent].concat(used).concat(total)); + }); + }, + + onCancel: function onCancel() { + if (this._usage_req) { + this._usage_req.abort(); + } + if (this._quota_req) { + this._quota_req.abort(); + } + return true; + }, + + onAccept: function onAccept() { + let engines = gUsageTreeView.getEnginesToDisable(); + for each (let engine in engines) { + Weave.Service.engineManager.get(engine).enabled = false; + } + if (engines.length) { + // The 'Weave' object will disappear once the window closes. + let Service = Weave.Service; + Weave.Utils.nextTick(function() { Service.sync(); }); + } + return this.onCancel(); + }, + + convertKB: function convertKB(value) { + return DownloadUtils.convertByteUnits(value * 1024); + } + +}; + +var gUsageTreeView = { + + _ignored: {keys: true, + meta: true, + clients: true}, + + /* + * Internal data structures underlaying the tree. + */ + _collections: [], + _byname: {}, + + init: function init() { + let retrievingLabel = gSyncQuota.bundle.getString("quota.retrieving.label"); + for each (let engine in Weave.Service.engineManager.getEnabled()) { + if (this._ignored[engine.name]) + continue; + + // Some engines use the same pref, which means they can only be turned on + // and off together. We need to combine them here as well. + let existing = this._byname[engine.prefName]; + if (existing) { + existing.engines.push(engine.name); + continue; + } + + let obj = {name: engine.prefName, + title: this._collectionTitle(engine), + engines: [engine.name], + enabled: true, + sizeLabel: retrievingLabel}; + this._collections.push(obj); + this._byname[engine.prefName] = obj; + } + }, + + _collectionTitle: function _collectionTitle(engine) { + try { + return gSyncQuota.bundle.getString( + "collection." + engine.prefName + ".label"); + } catch (ex) { + return engine.Name; + } + }, + + /* + * Process the quota information as returned by info/collection_usage. + */ + displayUsageData: function displayUsageData(data) { + for each (let coll in this._collections) { + coll.size = 0; + // If we couldn't retrieve any data, just blank out the label. + if (!data) { + coll.sizeLabel = ""; + continue; + } + + for each (let engineName in coll.engines) + coll.size += data[engineName] || 0; + let sizeLabel = ""; + sizeLabel = gSyncQuota.bundle.getFormattedString( + "quota.sizeValueUnit.label", gSyncQuota.convertKB(coll.size)); + coll.sizeLabel = sizeLabel; + } + let sizeColumn = this.treeBox.columns.getNamedColumn("size"); + this.treeBox.invalidateColumn(sizeColumn); + }, + + /* + * Handle click events on the tree. + */ + onTreeClick: function onTreeClick(event) { + if (event.button == 2) + return; + + let cell = this.treeBox.getCellAt(event.clientX, event.clientY); + if (cell.col && cell.col.id == "enabled") + this.toggle(cell.row); + }, + + /* + * Toggle enabled state of an engine. + */ + toggle: function toggle(row) { + // Update the tree + let collection = this._collections[row]; + collection.enabled = !collection.enabled; + this.treeBox.invalidateRow(row); + }, + + /* + * Return a list of engines (or rather their pref names) that should be + * disabled. + */ + getEnginesToDisable: function getEnginesToDisable() { + // Tycho: return [coll.name for each (coll in this._collections) if (!coll.enabled)]; + let engines = []; + for each (let coll in this._collections) { + if (!coll.enabled) { + engines.push(coll.name); + } + } + return engines; + }, + + // nsITreeView + + get rowCount() { + return this._collections.length; + }, + + getRowProperties: function(index) { return ""; }, + getCellProperties: function(row, col) { return ""; }, + getColumnProperties: function(col) { return ""; }, + isContainer: function(index) { return false; }, + isContainerOpen: function(index) { return false; }, + isContainerEmpty: function(index) { return false; }, + isSeparator: function(index) { return false; }, + isSorted: function() { return false; }, + canDrop: function(index, orientation, dataTransfer) { return false; }, + drop: function(row, orientation, dataTransfer) {}, + getParentIndex: function(rowIndex) {}, + hasNextSibling: function(rowIndex, afterIndex) { return false; }, + getLevel: function(index) { return 0; }, + getImageSrc: function(row, col) {}, + + getCellValue: function(row, col) { + return this._collections[row].enabled; + }, + + getCellText: function getCellText(row, col) { + let collection = this._collections[row]; + switch (col.id) { + case "collection": + return collection.title; + case "size": + return collection.sizeLabel; + default: + return ""; + } + }, + + setTree: function setTree(tree) { + this.treeBox = tree; + }, + + toggleOpenState: function(index) {}, + cycleHeader: function(col) {}, + selectionChanged: function() {}, + cycleCell: function(row, col) {}, + isEditable: function(row, col) { return false; }, + isSelectable: function (row, col) { return false; }, + setCellValue: function(row, col, value) {}, + setCellText: function(row, col, value) {}, + performAction: function(action) {}, + performActionOnRow: function(action, row) {}, + performActionOnCell: function(action, row, col) {} + +}; diff --git a/application/basilisk/base/content/sync/quota.xul b/application/basilisk/base/content/sync/quota.xul new file mode 100644 index 000000000..99e6ed78b --- /dev/null +++ b/application/basilisk/base/content/sync/quota.xul @@ -0,0 +1,65 @@ +<?xml version="1.0"?> + +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://browser/skin/syncQuota.css"?> + +<!DOCTYPE dialog [ +<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> +<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd"> +<!ENTITY % syncQuotaDTD SYSTEM "chrome://browser/locale/syncQuota.dtd"> +%brandDTD; +%syncBrandDTD; +%syncQuotaDTD; +]> +<dialog id="quotaDialog" + windowtype="Sync:ViewQuota" + persist="screenX screenY width height" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:html="http://www.w3.org/1999/xhtml" + onload="gSyncQuota.init()" + buttons="accept,cancel" + title=""a.dialogTitle.label;" + ondialogcancel="return gSyncQuota.onCancel();" + ondialogaccept="return gSyncQuota.onAccept();"> + + <script type="application/javascript" + src="chrome://browser/content/sync/quota.js"/> + + <stringbundleset id="stringbundleset"> + <stringbundle id="quotaStrings" + src="chrome://browser/locale/syncQuota.properties"/> + </stringbundleset> + + <vbox flex="1"> + <label id="usageLabel" + value=""a.retrievingInfo.label;"/> + <separator/> + <tree id="usageTree" + seltype="single" + hidecolumnpicker="true" + onclick="gUsageTreeView.onTreeClick(event);" + flex="1"> + <treecols> + <treecol id="enabled" + type="checkbox" + fixed="true"/> + <splitter class="tree-splitter"/> + <treecol id="collection" + label=""a.typeColumn.label;" + flex="1"/> + <splitter class="tree-splitter"/> + <treecol id="size" + label=""a.sizeColumn.label;" + flex="1"/> + </treecols> + <treechildren flex="1"/> + </tree> + <separator/> + <description id="treeCaption"> </description> + </vbox> + +</dialog> |