define('modules/sync_manager_bridge',['require'],function(require){'use strict';var SyncManagerBridge={_port:null,_requests:new Map(),set onsyncchange(callback){this._onsyncchange=callback;},connect:function(){if(this._port){return Promise.resolve(this._port);} return new Promise((resolve,reject)=>{navigator.mozApps.getSelf().onsuccess=event=>{var app=event.target.result;app.connect('gaia-sync-management').then(ports=>{if(!ports||!ports.length){return reject();} this._port=ports[0];this._port.onmessage=this.onmessage.bind(this);resolve(this._port);}).catch(reject);};});},iacRequest:function(request){return new Promise(resolve=>{this.connect().then(port=>{if(request.id){this._requests.set(request.id,resolve);} port.postMessage(request);});});},onmessage:function(event){var message=event.data;if(!message){return;} if(message.id&&this._requests.has(message.id)){this._requests.get(message.id)(message);this._requests.delete(message.id);return;} if(message.name!=='onsyncchange'){return;} if(this._onsyncchange){this._onsyncchange(message);}},getInfo:function(){return this.iacRequest({name:'getInfo',id:Date.now()});},};['enable','disable','sync'].forEach(requestName=>{SyncManagerBridge[requestName]=()=>{return SyncManagerBridge.iacRequest({name:requestName});};});return SyncManagerBridge;});define('modules/dialog_manager',["require", "modules/panel_cache", "shared/lazy_loader"],function(require) { 'use strict'; var PanelCache = require('modules/panel_cache'); var LazyLoader = require('shared/lazy_loader'); var DialogManager = function() { this.OVERLAY_SELECTOR = '.settings-dialog-overlay'; this._overlayDOM = document.querySelector(this.OVERLAY_SELECTOR); }; DialogManager.prototype = { /** * load panel based on passed in panelId * * @memberOf DialogManager * @access private * @param {String} panelId * @return {Promise} */ _loadPanel: function dm__loadPanel(panelId) { var promise = new Promise(function(resolve, reject) { var panelElement = document.getElementById(panelId); if (panelElement.dataset.rendered) { // already initialized resolve(); return; } panelElement.dataset.rendered = true; // XXX remove SubPanel loader once sub panel are modulized if (panelElement.dataset.requireSubPanels) { // load the panel and its sub-panels (dependencies) // (load the main panel last because it contains the scripts) var selector = 'section[id^="' + panelElement.id + '-"]'; var subPanels = document.querySelectorAll(selector); for (var i = 0, il = subPanels.length; i < il; i++) { LazyLoader.load([subPanels[i]]); } LazyLoader.load([panelElement], resolve); } else { LazyLoader.load([panelElement], resolve); } }); return promise; }, /** * promised version of PanelCache.get() * * @memberOf DialogManager * @access private * @param {String} panelId * @return {Promise} */ _getPanel: function dm__getPanel(panelId) { var promise = new Promise(function(resolve) { PanelCache.get(panelId, function(panel) { resolve(panel); }); }); return promise; }, /** * this is used to control visibility of overlayDOM * * @memberOf DialogManager * @access private * @param {Boolean} show */ _showOverlay: function dm__showOverlay(show) { this._overlayDOM.hidden = !show; }, /** * It is used to control the timing of transitions so that we can make sure * whether animation is done or not. * * @memberOf DialogManager * @access private * @param {String} method * @param {BaseDialog} dialog * @param {Object} options * @return {Promise} */ _transit: function dm__transit(method, dialog, options) { var promise = new Promise(function(resolve) { var panel = dialog.panel; var completed = false; var fallback; function finish(event) { if (event && (event.target !== panel || event.propertyName !== 'visibility')) return; if (completed) return; completed = true; clearTimeout(fallback); panel.removeEventListener('transitionend', finish); panel.removeEventListener('transitioncancel', finish); if (method === 'close') panel.hidden = true; resolve(); } if (method === 'open') panel.hidden = false; setTimeout(function() { panel.addEventListener('transitionend', finish); panel.addEventListener('transitioncancel', finish); panel.classList.toggle('current', method === 'open'); var style = window.getComputedStyle(panel); function milliseconds(value) { return parseFloat(value) * (value.trim().endsWith('ms') ? 1 : 1000) || 0; } var durations = style.transitionDuration.split(',').map(milliseconds); var delays = style.transitionDelay.split(',').map(milliseconds); var duration = Math.max.apply(Math, durations.map(function(value, index) { return value + delays[index % delays.length]; })); // Reduced motion, display changes or interrupted transitions may // omit the visibility event. Always release the dialog queue. fallback = setTimeout(finish, Math.max(0, duration) + 100); }, 150); }); return promise; }, /** * Do necessary works to open panel like loading panel, doing transition * and call related functions. * * @memberOf DialogManager * @access private * @param {BaseDialog} dialog * @param {Object} options * @return {Promise} */ _open: function dm__open(dialog, options) { var self = this; var foundPanel; return Promise.resolve() .then(function() { // 1: load panel return self._loadPanel(dialog.panel.id); }) .then(function() { // 2: Get that panel return self._getPanel(dialog.panel.id); }) .then(function(panel) { // 3: call beforeShow foundPanel = panel; return foundPanel.beforeShow(dialog.panel, options); }) .then(function() { // 4. UI stuffs + transition dialog.init(); dialog.initUI(); dialog.bindEvents(); if (dialog.TRANSITION_CLASS === 'zoom-in-80') { self._showOverlay(true); } return self._transit('open', dialog, options); }) .then(function() { // 5. show that panel as a dialog return foundPanel.show(dialog.panel, options); }); }, /** * Do necessary works to close panel like loading panel, doing transition * and call related functions. * * @memberOf DialogManager * @access private * @param {BaseDialog} dialog * @param {Object} options * @return {Promise} */ _close: function dm__close(dialog, options) { var self = this; var foundPanel; var cachedResult; return Promise.resolve() .then(function() { // 1: Get that panel return self._getPanel(dialog.panel.id); }) .then(function(panel) { // 2: Let's validate to see whether we can close this dialog or not. foundPanel = panel; var promise; // custom dialog - onSubmit if (foundPanel.onSubmit && options._type === 'submit') { promise = foundPanel.onSubmit(); // custom dialog - onCancel } else if (foundPanel.onCancel && options._type === 'cancel') { promise = foundPanel.onCancel(); // if no onSubmit & onCancel, pass directly } else { promise = Promise.resolve(); } return promise; }) .then(function(result) { cachedResult = result; // 3: call beforeHide return foundPanel.beforeHide(); }) .then(function() { // 4. transition return self._transit('close', dialog, options); }) .then(function() { // 5. call hide return foundPanel.hide(); }) .then(function() { // 6. Get result and cleanup dialog var result; // for prompt dialog, we have to get its own result from input text. if (dialog.DIALOG_CLASS === 'prompt-dialog') { result = dialog.getResult(); } else if (cachedResult) { result = cachedResult; } dialog.cleanup(); if (dialog.TRANSITION_CLASS === 'zoom-in-80') { self._showOverlay(false); } return result; }); }, /** * It is a bridge to call open or close function. * * @memberOf DialogManager * @access private * @param {String} method * @param {BaseDialog} dialog * @param {Object} options * @return {Promise} */ _navigate: function dm__navigate(method, dialog, options) { method = (method === 'open') ? '_open' : '_close'; return this[method](dialog, options); }, /** * DialogService would use this exposed API to open dialog. * * @memberOf DialogManager * @access public * @param {BaseDialog} dialog * @param {Object} options * @return {Promise} */ open: function dm_open(dialog, options) { return this._navigate('open', dialog, options); }, /** * DialogService would use this exposed API to close dialog. * * @memberOf DialogManager * @access public * @param {BaseDialog} dialog * @param {Object} options * @return {Promise} */ close: function dm_close(dialog, type, options) { options._type = type; return this._navigate('close', dialog, options); } }; var dialogManager = new DialogManager(); return dialogManager; }); define('modules/dialog/base_dialog',['require'],function(require){'use strict';var BaseDialog=function(panelDOM,options){this.panel=panelDOM;this._options=options||{};};BaseDialog.prototype.DIALOG_CLASS='dialog';BaseDialog.prototype.TRANSITION_CLASS='fade';BaseDialog.prototype.SUBMIT_BUTTON_SELECTOR='[type="submit"]';BaseDialog.prototype.CANCEL_BUTTON_SELECTOR='[type="reset"]';BaseDialog.prototype.MESSAGE_SELECTOR='.settings-dialog-message';BaseDialog.prototype.TITLE_SELECTOR='.settings-dialog-title';BaseDialog.prototype.init=function bd_init(){this.TRANSITION_CLASS=this._options.transition||this.TRANSITION_CLASS;this.panel.classList.add(this.DIALOG_CLASS);this.panel.classList.add(this.TRANSITION_CLASS);};BaseDialog.prototype.initUI=function bd_initUI(){var message=this._options.message;var title=this._options.title;var submitButton=this._options.submitButton;var cancelButton=this._options.cancelButton;this._updateMessage(message);this._updateTitle(title);this._updateSubmitButton(submitButton);this._updateCancelButton(cancelButton);};BaseDialog.prototype.bindEvents=function bd_bindEvent(){var self=this;this.getSubmitButton().onclick=function(){self._options.onWrapSubmit();};this.getCancelButton().onclick=function(){self._options.onWrapCancel();};};BaseDialog.prototype._updateMessage=function bd__updateMessage(message){var messageDOM=this.panel.querySelector(this.MESSAGE_SELECTOR);if(messageDOM&&message){message=this._getWrapL10nObject(message);document.l10n.setAttributes(messageDOM,message.id,message.args);}};BaseDialog.prototype._updateTitle=function bd__updateTitle(title){var titleDOM=this.panel.querySelector(this.TITLE_SELECTOR);if(titleDOM&&title){title=this._getWrapL10nObject(title);document.l10n.setAttributes(titleDOM,title.id,title.args);}};BaseDialog.prototype._updateSubmitButton=function bd__update(options){var buttonDOM=this.getSubmitButton();if(buttonDOM&&options){options=this._getWrapL10nObject(options);document.l10n.setAttributes(buttonDOM,options.id,options.args);buttonDOM.className=options.style||'recommend';}};BaseDialog.prototype._updateCancelButton=function bd__updateText(options){var buttonDOM=this.getCancelButton();if(buttonDOM&&options){options=this._getWrapL10nObject(options);document.l10n.setAttributes(buttonDOM,options.id,options.args);buttonDOM.className=options.style||'';}};BaseDialog.prototype._getWrapL10nObject=function bd__getWrapL10nObject(input){if(typeof input==='string'){return{id:input,args:null};}else if(typeof input==='object'){if(typeof input.id==='undefined'){throw new Error('You forgot to put l10nId - '+ JSON.stringify(input));}else{return{id:input.id,args:input.args||null,style:input.style};}}else{throw new Error('You are using the wrong L10nObject, '+'please check its format again');}};BaseDialog.prototype.getDOM=function bd_getDOM(){return this.panel;};BaseDialog.prototype.getSubmitButton=function bd_getSubmitButton(){return this.panel.querySelector(this.SUBMIT_BUTTON_SELECTOR);};BaseDialog.prototype.getCancelButton=function bd_getCancelButton(){return this.panel.querySelector(this.CANCEL_BUTTON_SELECTOR);};BaseDialog.prototype.cleanup=function bd_cleanup(){if(this.DIALOG_CLASS!=='panel-dialog'){this._updateTitle('settings-'+this.DIALOG_CLASS+'-header');this._updateSubmitButton('ok');this._updateCancelButton('cancel');} this.panel.classList.remove(this.DIALOG_CLASS);this.panel.classList.remove(this.TRANSITION_CLASS);};return BaseDialog;});define('modules/dialog/panel_dialog',['require','modules/dialog/base_dialog'],function(require){'use strict';var BaseDialog=require('modules/dialog/base_dialog');var PanelDialog=function(panelDOM,options){BaseDialog.call(this,panelDOM,options);};PanelDialog.prototype=Object.create(BaseDialog.prototype);PanelDialog.prototype.constructor=PanelDialog;PanelDialog.prototype.DIALOG_CLASS='panel-dialog';PanelDialog.prototype.TRANSITION_CLASS='fade';return function ctor_PanelDialog(panelDOM,options){return new PanelDialog(panelDOM,options);};});define('modules/dialog/alert_dialog',['require','modules/dialog/base_dialog'],function(require){'use strict';var BaseDialog=require('modules/dialog/base_dialog');var AlertDialog=function(panelDOM,options){BaseDialog.call(this,panelDOM,options);};AlertDialog.prototype=Object.create(BaseDialog.prototype);AlertDialog.prototype.constructor=AlertDialog;AlertDialog.prototype.DIALOG_CLASS='alert-dialog';AlertDialog.prototype.TRANSITION_CLASS='fade';AlertDialog.prototype.bindEvents=function(){var self=this;this.getSubmitButton().onclick=function(){self._options.onWrapSubmit();};};return function ctor_alertDialog(panelDOM,options){return new AlertDialog(panelDOM,options);};});define('modules/dialog/confirm_dialog',['require','modules/dialog/base_dialog'],function(require){'use strict';var BaseDialog=require('modules/dialog/base_dialog');var ConfirmDialog=function(panelDOM,options){BaseDialog.call(this,panelDOM,options);};ConfirmDialog.prototype=Object.create(BaseDialog.prototype);ConfirmDialog.prototype.constructor=ConfirmDialog;ConfirmDialog.prototype.DIALOG_CLASS='confirm-dialog';ConfirmDialog.prototype.TRANSITION_CLASS='fade';ConfirmDialog.prototype.bindEvents=function(){var self=this;this.getSubmitButton().onclick=function(){self._options.onWrapSubmit();};this.getCancelButton().onclick=function(){self._options.onWrapCancel();};};return function ctor_confirmDialog(panelDOM,options){return new ConfirmDialog(panelDOM,options);};});define('modules/dialog/prompt_dialog',['require','modules/dialog/base_dialog'],function(require){'use strict';var BaseDialog=require('modules/dialog/base_dialog');var PromptDialog=function(panelDOM,options){BaseDialog.call(this,panelDOM,options);};PromptDialog.prototype=Object.create(BaseDialog.prototype);PromptDialog.prototype.constructor=PromptDialog;PromptDialog.prototype.DIALOG_CLASS='prompt-dialog';PromptDialog.prototype.TRANSITION_CLASS='fade';PromptDialog.prototype.INPUT_SELECTOR='.settings-dialog-input';PromptDialog.prototype.bindEvents=function(){var self=this;this.getSubmitButton().onclick=function(){self._options.onWrapSubmit();};this.getCancelButton().onclick=function(){self._options.onWrapCancel();};};PromptDialog.prototype.initUI=function(){BaseDialog.prototype.initUI.call(this);this.getInput().value=this._options.defaultValue||'';};PromptDialog.prototype.getInput=function(){return this.panel.querySelector(this.INPUT_SELECTOR);};PromptDialog.prototype.getResult=function(){return this.getInput().value;};return function ctor_promptDialog(panelDOM,options){return new PromptDialog(panelDOM,options);};});define('modules/dialog_service',["require", "settings", "modules/defer", "modules/dialog_manager", "modules/dialog/panel_dialog", "modules/dialog/alert_dialog", "modules/dialog/confirm_dialog", "modules/dialog/prompt_dialog"],function(require) { 'use strict'; var Settings = require('settings'); var Defer = require('modules/defer'); var DialogManager = require('modules/dialog_manager'); var PanelDialog = require('modules/dialog/panel_dialog'); var AlertDialog = require('modules/dialog/alert_dialog'); var ConfirmDialog = require('modules/dialog/confirm_dialog'); var PromptDialog = require('modules/dialog/prompt_dialog'); var DialogService = function() { this._navigating = false; this._pendingRequests = []; this._settingsAlertDialogId = 'settings-alert-dialog'; this._settingsBaseDialogId = 'settings-base-dialog'; this._settingsConfirmDialogId = 'settings-confirm-dialog'; this._settingsPromptDialogId = 'settings-prompt-dialog'; }; DialogService.prototype = { /** * Alert dialog with more controls. * * @memberOf DialogService * @access public * @param {String} message * @param {Object} userOptions * @return {Promise} */ alert: function(message, userOptions) { var options = userOptions || {}; return this.show(this._settingsAlertDialogId, { type: 'alert', message: message, title: options.title, submitButton: options.submitButton }); }, /** * Confirm dialog with more controls. * * @memberOf DialogService * @access public * @param {String} message * @param {Object} userOptions * @return {Promise} */ confirm: function(message, userOptions) { var options = userOptions || {}; return this.show(this._settingsConfirmDialogId, { type: 'confirm', message: message, title: options.title, submitButton: options.submitButton, cancelButton: options.cancelButton }); }, /** * Prompt dialog with more controls. * * @memberOf DialogService * @access public * @param {String} message * @param {Object} userOptions * @return {Promise} */ prompt: function(message, userOptions) { var options = userOptions || {}; return this.show(this._settingsPromptDialogId, { type: 'prompt', message: message, title: options.title, defaultValue: options.defaultValue, submitButton: options.submitButton, cancelButton: options.cancelButton }); }, /** * Panel dialog. If you are going to show any panel as a dialog, * you have to use this method to show them. * * @memberOf DialogService * @access public * @param {String} panelId * @param {Object} userOptions * @return {Promise} */ show: function dm_show(panelId, userOptions, _pendingDefer) { var self = this; var defer; var dialog; var dialogDOM = document.getElementById(panelId); var currentPanel = Settings.currentPanel; var options = userOptions || {}; if (_pendingDefer) { defer = _pendingDefer; } else { defer = Defer(); } if (this._navigating) { this._pendingRequests.push({ defer: defer, panelId: panelId, userOptions: userOptions }); } else { if ('#' + panelId === currentPanel) { defer.reject('You are showing the same panel #' + panelId); } else { var opening; var closing = false; function close(type) { if (closing) return; closing = true; // A tap during the opening animation must not run hide/show // concurrently, or a queued dialog can inherit stale form values. Promise.resolve(opening).then(function() { return DialogManager.close(dialog, type, options); }).then(function(result) { self._navigating = false; defer.resolve({type: type, value: result}); self._execPendingRequest(); }, function(error) { // Panel validation rejects to keep the form open. Allow a // correction or cancellation without rejecting the show promise. closing = false; dialogDOM.dispatchEvent(new CustomEvent('dialogvalidationfailed', { detail: error })); }); } options.onWrapSubmit = function() { close('submit'); }; options.onWrapCancel = function() { close('cancel'); }; switch (options.type) { case 'alert': dialog = AlertDialog(dialogDOM, options); break; case 'confirm': dialog = ConfirmDialog(dialogDOM, options); break; case 'prompt': dialog = PromptDialog(dialogDOM, options); break; default: dialog = PanelDialog(dialogDOM, options); break; } this._navigating = true; opening = DialogManager.open(dialog, options); opening.catch(function(error) { // A missing host API must not lock every later Settings dialog. dialogDOM.classList.remove('current'); dialogDOM.hidden = true; var overlay = document.querySelector('.settings-dialog-overlay'); if (overlay) overlay.hidden = true; self._navigating = false; defer.reject(error); self._execPendingRequest(); }); } } return defer.promise; }, /** * This method can help us pop up any pending request and would try to * show it after previous request was done. * * @memberOf DialogService * @access private */ _execPendingRequest: function() { var request = this._pendingRequests.pop(); if (request) { this.show(request.panelId, request.userOptions, request.defer); } } }; var dialogService = new DialogService(); return dialogService; }); define('panels/firefox_sync/firefox_sync',['require','shared/settings_listener','modules/sync_manager_bridge','modules/dialog_service'],function(require){'use strict';var SettingsListener=require('shared/settings_listener');var SyncManagerBridge=require('modules/sync_manager_bridge');var DialogService=require('modules/dialog_service');const LOGGED_OUT_SCREEN='loggedout';const LOGGED_IN_SCREEN='loggedin';const ELEMENTS=[{screen:LOGGED_OUT_SCREEN,selector:'.fxsync-login',event:'click',listener:'enable'},{screen:LOGGED_IN_SCREEN,selector:'.fxsync-logout',event:'click',listener:'disable'},{screen:LOGGED_IN_SCREEN,selector:'.fxsync-user'},{screen:LOGGED_IN_SCREEN,selector:'.fxsync-sync-now',event:'click',listener:'sync'},{screen:LOGGED_IN_SCREEN,selector:'.fxsync-tos',event:'click',listener:'openTos'},{screen:LOGGED_IN_SCREEN,selector:'.fxsync-privacy',event:'click',listener:'openPrivacy'},{screen:LOGGED_IN_SCREEN,selector:'.fxsync-collections-bookmarks'},{screen:LOGGED_IN_SCREEN,selector:'.fxsync-collections-history'},{screen:LOGGED_IN_SCREEN,selector:'.fxsync-collections-passwords'},{screen:LOGGED_IN_SCREEN,selector:'.fxsync-last-sync'},{screen:LOGGED_IN_SCREEN,selector:'.fxsync-unverified'},{screen:LOGGED_IN_SCREEN,selector:'.fxsync-empty-account'}];function getElementName(str){str=str.toLowerCase().replace('.fxsync-','');return str.replace(/-([a-z])/g,g=>{return g[1].toUpperCase();});} function FirefoxSyncPanel(panel,screens){this.panel=panel;this.screens=screens;this.elements={};this.currentScreen=null;this.collections=new Map();['sync.collections.bookmarks.enabled','sync.collections.history.enabled','sync.collections.passwords.enabled'].forEach(setting=>{SettingsListener.observe(setting,true,enabled=>{enabled?this.collections.set(setting,enabled):this.collections.delete(setting);this.maybeEnableSyncNow();});});SyncManagerBridge.onsyncchange=this.onsyncchange.bind(this);} FirefoxSyncPanel.prototype={refresh(){SyncManagerBridge.getInfo().then(this.onsyncchange.bind(this));},clean(){window.clearTimeout(this.timeout);this.timeout=undefined;window.removeEventListener('offline',this.onlineListener);window.removeEventListener('online',this.onlineListener);},onsyncchange(message){if(!message||!message.state){throw new Error('Missing sync state');} switch(message.state){case'disabled':this.showScreen(LOGGED_OUT_SCREEN);this.hideEnabling();this.clean();break;case'enabling':this.showScreen(LOGGED_OUT_SCREEN);this.showEnabling();break;case'enabled':this.hideEnabling();this.showScreen(LOGGED_IN_SCREEN);this.showSyncNow();this.showUser(message.user);this.showLastSync(message.lastSync);if(message.error){LazyLoader.load('shared/js/sync/errors.js',()=>{if(message.error==ERROR_INVALID_SYNC_ACCOUNT){this.showEmptyAccount(message.user);}});}else{this.hideEmptyAccount();} break;case'syncing':this.showScreen(LOGGED_IN_SCREEN);this.showUser(message.user);this.showSyncing();break;case'errored':LazyLoader.load('shared/js/sync/errors.js',()=>{if(message.error==ERROR_UNVERIFIED_ACCOUNT){this.showScreen(LOGGED_IN_SCREEN);this.showUnverified(message.user);return;} if(message.error==ERROR_INVALID_SYNC_ACCOUNT){this.showScreen(LOGGED_IN_SCREEN);this.showEmptyAccount(message.user);return;} const IGNORED_ERRORS=[ERROR_DIALOG_CLOSED_BY_USER,ERROR_SYNC_APP_KILLED];if(IGNORED_ERRORS.indexOf(message.error)>-1){return;} var errorMsg=ERROR_UNKNOWN;var title;const KNOWN_ERRORS=[ERROR_OFFLINE,ERROR_NO_KEY_FETCH_TOKEN];if(KNOWN_ERRORS.indexOf(message.error)>-1){title=message.error;errorMsg=message.error+'-explanation';} DialogService.alert(errorMsg,{title:title}).then(()=>{this.showScreen(LOGGED_OUT_SCREEN);this.clean();});});break;}},addListener(element,event,listener){if(!element||!event||!listener){return;} element.addEventListener(event,this[listener]);},removeListener(element,event,listener){if(!element||!event||!listener){return;} element.removeEventListener(event,this[listener]);},loadElements(screen){ELEMENTS.forEach(element=>{var name=getElementName(element.selector);if(element.screen==screen){this.elements[name]=this.panel.querySelector(element.selector);this.addListener(this.elements[name],element.event,element.listener);return;} this.removeListener(this.elements[name],element.event,element.listener);this.elements[name]=null;});},showScreen(screen){if(this.currentScreen==screen){return;} this.currentScreen=screen;this.screens.loggedIn.hidden=(screen!=LOGGED_IN_SCREEN);this.screens.loggedOut.hidden=(screen!=LOGGED_OUT_SCREEN);this.loadElements(screen);},showEnabling(){this.elements.login.disabled=true;this.elements.login.dataset.l10nId='fxsync-signing';},hideEnabling(){if(!this.elements.login){return;} this.elements.login.disabled=false;this.elements.login.dataset.l10nId='fxsync-get-started';},showSyncing(){this.elements.syncNow.dataset.l10nId='fxsync-syncing';this.disableSyncNowAndCollections(true);},maybeEnableSyncNow(){if(!this.elements.syncNow){return;} this.elements.syncNow.disabled=(this.collections.size<=0)||!navigator.onLine;},showSyncNow(){this.elements.syncNow.dataset.l10nId='fxsync-sync-now';this.disableSyncNowAndCollections(false);this.elements.unverified.hidden=true;this.maybeEnableSyncNow();this.onlineListener=this.maybeEnableSyncNow.bind(this);window.addEventListener('offline',this.onlineListener);window.addEventListener('online',this.onlineListener);},showUser(email){this.elements.user.textContent=email;},showUnverified(email){this.showUser(email);this.showLastSync();this.disableSyncNowAndCollections(true);this.elements.unverified.hidden=false;},showEmptyAccount(email){this.showUser(email);this.showLastSync();this.disableSyncNowAndCollections(false);this.elements.emptyAccount.hidden=false;},hideEmptyAccount(){this.elements.emptyAccount.hidden=true;},showLastSync(time){if(!time){this.elements.lastSync.classList.add('hidden');return;} var formatter=mozIntl._gaia.RelativeDate(navigator.languages,{style:'short'});formatter.format(time).then(relDate=>{var selector='span[data-l10n-id=fxsync-last-synced]';var lastSync=this.elements.lastSync.querySelector(selector);document.l10n.setAttributes(lastSync,'fxsync-last-synced',{when:relDate});this.elements.lastSync.classList.remove('hidden');});this.timeout=window.setTimeout(()=>{this.showLastSync(time);},60*1000);},disableSyncNowAndCollections(disabled){['syncNow','collectionsBookmarks','collectionsHistory','collectionsPasswords'].forEach(name=>{this.elements[name].disabled=disabled;});},enable(){SyncManagerBridge.enable();},disable(){SyncManagerBridge.disable();},sync(){SyncManagerBridge.sync();},openTos(){window.open('https://accounts.firefox.com/legal/terms');},openPrivacy(){window.open('https://accounts.firefox.com/legal/privacy');}};return(panel,screens)=>{return new FirefoxSyncPanel(panel,screens);};});define('panels/firefox_sync/panel',['require','modules/settings_panel','modules/settings_utils','panels/firefox_sync/firefox_sync'],function(require){'use strict';var SettingsPanel=require('modules/settings_panel');var SettingsUtils=require('modules/settings_utils');var FirefoxSyncPanel=require('panels/firefox_sync/firefox_sync');return()=>{return SettingsPanel({onInit:function fxsync_onInit(panel){var screens={loggedIn:panel.querySelector('.fxsync-logged-in'),loggedOut:panel.querySelector('.fxsync-logged-out')};this.syncPanel=FirefoxSyncPanel(panel,screens);var header=panel.querySelector('gaia-header');SettingsUtils.runHeaderFontFit(header);},onShow:function fxsync_onShow(){this.syncPanel.refresh();},onHide:function fxsync_onHide(){this.syncPanel.clean();}});};});