Release Preview 20 shared desktop, Android and Sargo updates

Restore Gaia settings and media workflows, extend native network adapters, and align the APK payload. Generate French/English changelogs and website entries from the simplified JSON source.

Validation: shared JS and Tundra unit tests; desktop workflows and persistence; signed APK payload parity; Sargo RAM and installed startup with boot readback. Android runtime qualification is recorded separately.
This commit is contained in:
OverSu 2026-10-13 00:19:45 +02:00
commit 1311bed5e9
170 changed files with 19698 additions and 2495 deletions

View file

@ -1,4 +1,52 @@
/**
* Update setting value based on slider position.
* Base on sound panel's implementation.
*
* @module SliderHandler
*/
/**
* Update setting value based on slider position.
* Base on sound panel's implementation.
*
* @module SliderHandler
*/
/**
* Update setting value based on slider position.
* Base on sound panel's implementation.
*
* @module SliderHandler
*/
/**
* Update setting value based on slider position.
* Base on sound panel's implementation.
*
* @module SliderHandler
*/
/**
* Update setting value based on slider position.
* Base on sound panel's implementation.
*
* @module SliderHandler
*/
/**
* Update setting value based on slider position.
* Base on sound panel's implementation.
*
* @module SliderHandler
*/
/**
* Update setting value based on slider position.
* Base on sound panel's implementation.
*
* @module SliderHandler
*/
/**
* Update setting value based on slider position.
* Base on sound panel's implementation.
*
* @module SliderHandler
*/
/**
* Update setting value based on slider position.
* Base on sound panel's implementation.
@ -128,6 +176,5 @@ define('panels/display/slider_handler',["require"],function(require) {
return new SliderHandler();
};
});
define('panels/display/display',['require','shared/settings_listener','panels/display/slider_handler'],function(require){'use strict';var SettingsListener=require('shared/settings_listener');var SliderHandler=require('panels/display/slider_handler');const AUTO_BRIGHTNESS_SETTING='screen.automatic-brightness';const SCREEN_BRIGHTNESS='screen.brightness';var Display=function(){this.elements=null;};Display.prototype={init:function d_init(elements,data){this.elements=elements;this.initBrightnessItems(data);SliderHandler().init(elements.brightnessManualInput,SCREEN_BRIGHTNESS);},initBrightnessItems:function d_init_brightness_items(data){var brightnessAuto=this.elements.brightnessAuto;var brightnessAutoCheckbox=this.elements.brightnessAutoCheckbox;var brightnessManual=this.elements.brightnessManual;var brightnessManualInput=this.elements.brightnessManualInput;if(data.ambientLight){brightnessAuto.hidden=false;SettingsListener.observe(AUTO_BRIGHTNESS_SETTING,false,function(value){brightnessAutoCheckbox.checked=value;brightnessManual.hidden=value;}.bind(this));}else{brightnessAuto.hidden=true;brightnessManual.hidden=false;var cset={};cset[AUTO_BRIGHTNESS_SETTING]=false;SettingsListener.getSettingsLock().set(cset);}
SettingsListener.observe(SCREEN_BRIGHTNESS,0.5,function(value){brightnessManualInput.value=value;}.bind(this));}};return function ctor_display(){return new Display();};});define('panels/display/panel',['require','modules/settings_panel','panels/display/display','shared/lazy_loader'],function(require){'use strict';var SettingsPanel=require('modules/settings_panel');var DisplayModule=require('panels/display/display');var LazyLoader=require('shared/lazy_loader');var displayElements={};return function ctor_display_panel(){var display=DisplayModule();return SettingsPanel({onInit:function dp_onInit(panel){displayElements={brightnessManual:panel.querySelector('.brightness-manual'),brightnessManualInput:panel.querySelector('.brightness-manual input'),brightnessAuto:panel.querySelector('.brightness-auto'),brightnessAutoCheckbox:panel.querySelector('.brightness-auto gaia-checkbox')};LazyLoader.getJSON('/resources/device-features.json').then(function(data){display.init(displayElements,data);});}});};});

View file

@ -0,0 +1,492 @@
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/feedback_send/feedback_send',['require','modules/dialog_service','modules/settings_service','modules/settings_cache','shared/async_storage'],function(require){'use strict';var DialogService=require('modules/dialog_service');var SettingsService=require('modules/settings_service');var SettingsCache=require('modules/settings_cache');require('shared/async_storage');var SendFeedback=function(){};SendFeedback.prototype={_SettingsCache:SettingsCache,_SettingsService:SettingsService,init:function(elements){this.elements=elements;this.options={};this._sendData={product:'Firefox OS',platform:'Firefox OS'};this._showEmail=false;},_isHappy:function(){var happy=this.options&&this.options.feel;return happy==='feedback-happy';},updateTitle:function(){var id='feedback_whyfeel_'+(this._isHappy()?'happy':'sad');this.elements.title.setAttribute('data-l10n-id',id);},getPreviousInputs:function(){window.asyncStorage.getItem('feedback',function(value){this._inputData=value||{};}.bind(this));},keepAllInputs:function(){window.asyncStorage.setItem('feedback',this._inputData);},get _inputData(){return{description:this.elements.description.value,email:this.elements.emailInput.value,emailEnable:this._showEmail};},set _inputData(data){this.elements.description.value=data.description||'';this.elements.emailInput.value=data.email||'';this._showEmail=!data.emailEnable;this.enableEmail();},send:function(){this.elements.sendBtn.disabled=true;if(!navigator.onLine){this._messageHandler('connect-error');return;}
var emailBar=this.elements.emailColumn;var emailInput=this.elements.emailInput;var contextInput=this.elements.description;if(contextInput.textLength===0){this._messageHandler('empty-comment');return;}else{this._sendData.description=contextInput.value;}
if(!emailBar.hidden){this._sendData.email=emailInput.value;}else{delete this._sendData.email;}
if(!emailBar.hidden&&(!emailInput.value.length||!emailInput.validity.valid)){this._messageHandler('wrong-email');return;}
var currentSetting=this._SettingsCache.cache;var feedbackUrl=currentSetting['feedback.url'];this._sendData.version=currentSetting['deviceinfo.os'];this._sendData.device=currentSetting['deviceinfo.hardware'];this._sendData.locale=currentSetting['language.current'];this._sendData.happy=this._isHappy();this._xhr=new XMLHttpRequest({mozSystem:true});this._xhr.open('POST',feedbackUrl,true);this._xhr.setRequestHeader('Content-type','application/json');this._xhr.timeout=5000;this._xhr.onload=this._responseHandler.bind(this);this._xhr.ontimeout=function(){this._messageHandler('timeout');}.bind(this);this._xhr.send(JSON.stringify(this._sendData));},enableEmail:function(){var original=this._showEmail;this._showEmail=!original;this.elements.emailEnable.checked=!original;this.elements.emailColumn.hidden=original;},back:function(){this.keepAllInputs();this._SettingsService.navigate('improveBrowserOS-chooseFeedback');},_responseHandler:function(){switch(this._xhr.status){case 201:this._messageHandler('success');break;case 429:this._messageHandler('success');break;case 404:this._messageHandler('server-off');break;case 400:this._messageHandler('unknown-error');break;default:this._messageHandler('unknown-error');break;}},_messageHandler:function(type){if(type==='success'){this._openDoneDialog();}else{this.keepAllInputs();this._openAlertDialog(type);}
this.elements.sendBtn.disabled=false;},_openAlertDialog:function(type){DialogService.alert({id:'feedback-errormessage-'+type},{submitButton:{id:'ok',style:'full'}});},_openDoneDialog:function(){DialogService.alert({id:'feedback-complete-msg'},{title:'sendFeedbackTitle',submitButton:{id:'done',style:'full'}}).then(function(){this._SettingsService.navigate('improveBrowserOS');}.bind(this));}};return function ctor_send_feedback(){return new SendFeedback();};});define('panels/feedback_send/panel',['require','modules/settings_panel','panels/feedback_send/feedback_send'],function(require){'use strict';var SettingsPanel=require('modules/settings_panel');var SendFeedback=require('panels/feedback_send/feedback_send');return function ctor_sendFeedbackPanel(){var elements={};var sendFeedback=SendFeedback();var eventMapping=[{elementName:'sendBtn',eventType:'click',methodName:'send'},{elementName:'emailEnable',eventType:'change',methodName:'enableEmail'},{elementName:'header',eventType:'action',methodName:'back'}];function bindEvents(elements){eventMapping.forEach(function(map){map.method=sendFeedback[map.methodName].bind(sendFeedback);elements[map.elementName].addEventListener(map.eventType,map.method);});}
function unbindEvents(elements){eventMapping.forEach(function(map){if(!map.method){return;}
elements[map.elementName].removeEventListener(map.eventType,map.method);});}
return SettingsPanel({onInit:function(panel){elements={title:panel.querySelector('#feedback-title'),description:panel.querySelector('#feedback-description'),emailInput:panel.querySelector('#feedback-email'),emailColumn:panel.querySelector('#feedback-emailbar'),emailEnable:panel.querySelector('#email-enable'),sendBtn:panel.querySelector('#feedback-send-btn'),header:panel.querySelector('#feedback-header')};sendFeedback.init(elements);},onBeforeShow:function(panel,options){bindEvents(elements);sendFeedback.options=options;sendFeedback.updateTitle();sendFeedback.getPreviousInputs();},onBeforeHide:function(){unbindEvents(elements);if(document.hidden){sendFeedback.keepAllInputs();}}});};});

View file

@ -0,0 +1,508 @@
var Normalizer={initAsciiNormalizer:function normalizer_init(){var equivalentChars={'a':'áăǎâäȧạȁàảȃāąåḁⱥãǽǣæ','A':'ÁĂǍÂÄȦẠȀÀẢȂĀĄÅḀȺÃǼǢÆ','b':'ḃḅɓḇƀƃ','B':'ḂḄƁḆɃƂ','c':'ćčçĉċƈȼ','C':'ĆČÇĈĊƇȻ','d':'ďḑḓḋḍɗḏđƌð','D':'ĎḐḒḊḌƊḎĐƋ','e':'éĕěȩêḙëėẹȅèẻȇēę','E':'ÉĔĚȨÊḘËĖẸȄÈẺȆĒĘ','f':'ḟƒ','F':'ḞƑ','g':'ǵğǧģĝġɠḡǥ','G':'ǴĞǦĢĜĠƓḠǤ','h':'ḫȟḩĥⱨḧḣḥħ','H':'ḪȞḨĤⱧḦḢḤĦ','i':'íĭǐîïịȉìỉȋīįɨĩḭı','I':'ÍĬǏÎÏỊȈÌỈȊĪĮƗĨḬ','j':'ĵɉ','J':'ĴɈ','k':'ḱǩķⱪꝃḳƙḵꝁ','K':'ḰǨĶⱩꝂḲƘḴꝀ','l':'ĺƚľļḽḷⱡꝉḻŀɫł','L':'ĹȽĽĻḼḶⱠꝈḺĿⱢŁ','m':'ḿṁṃɱ','M':'ḾṀṂⱮ','n':'ńňņṋṅṇǹɲṉƞñ','N':'ŃŇŅṊṄṆǸƝṈȠÑ','o':'óŏǒôöȯọőȍòỏơȏꝋꝍōǫøõœ','O':'ÓŎǑÔÖȮỌŐȌÒỎƠȎꝊꝌŌǪØÕŒ','p':'ṕṗꝓƥᵽꝑ','P':'ṔṖꝒƤⱣꝐ','q':'ꝗ','Q':'Ꝗ','r':'ŕřŗṙṛȑȓṟɍɽ','R':'ŔŘŖṘṚȐȒṞɌⱤ','s':'śšşŝșṡṣß','S':'ŚŠŞŜȘṠṢ','t':'ťţṱțⱦṫṭƭṯʈŧ','T':'ŤŢṰȚȾṪṬƬṮƮŦ','u':'úŭǔûṷüṳụűȕùủưȗūųůũṵ','U':'ÚŬǓÛṶÜṲỤŰȔÙỦƯȖŪŲŮŨṴ','v':'ṿʋṽ','V':'ṾƲṼ','w':'ẃŵẅẇẉẁⱳ','W':'ẂŴẄẆẈẀⱲ','x':'ẍẋ','X':'ẌẊ','y':'ýŷÿẏỵỳƴỷỿȳɏỹ','Y':'ÝŶŸẎỴỲƳỶỾȲɎỸ','z':'źžẑⱬżẓȥẕƶ','Z':'ŹŽẐⱫŻẒȤẔƵ'};this._toAsciiForm={};for(var letter in equivalentChars){var accentedForms=equivalentChars[letter];for(var i=accentedForms.length-1;i>=0;i--){this._toAsciiForm[accentedForms[i]]=letter;}}},toAscii:function normalizer_toAscii(str){if(!str||typeof str!='string'){return'';}
if(!this._toAsciiForm){Normalizer.initAsciiNormalizer();}
var result='';for(var i=0,len=str.length;i<len;i++){result+=this._toAsciiForm[str.charAt(i)]||str.charAt(i);}
return result;},escapeHTML:function normalizer_escapeHTML(str,escapeQuotes){if(Array.isArray(str)){return Normalizer.escapeHTML(str.join(' '),escapeQuotes);}
if(!str||typeof str!='string'){return'';}
var escaped=str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');if(escapeQuotes){return escaped.replace(/"/g,'&quot;').replace(/'/g,'&#x27;');}
return escaped;},unescapeHTML:function normalizer_unescapeHTML(text){return text.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&quot;/g,'"').replace(/&#x27;/g,'\'');},escapeRegExp:function normalizer_escapeRegExp(str){return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,'\\$&');}};define("shared/text_normalizer",(function(global){return function(){var ret,fn;return ret||global.Normalizer;};}(this)));var FxAccountsIACHelper=function FxAccountsIACHelper(){var DEFAULT_CONNECTION_STRING='fxa-mgmt';var default_rules={'manifestURLs':['app://system.gaiamobile.org/manifest.webapp','app://smart-system.gaiamobile.org/manifest.webapp']};var CONNECTION_STRING=DEFAULT_CONNECTION_STRING;var rules=default_rules;var port;var callbacks={};var eventListeners={};var init=function init(options){if(!options){return;}
if(options.keyword&&typeof(options.keyword)=='string'&&options.keyword.length>0){CONNECTION_STRING=options.keyword;}
if(options.rules&&typeof(options.rules)=='object'){rules=options.rules;}};var addEventListener=function addEventListener(eventName,listener){if(!eventListeners[eventName]){eventListeners[eventName]=[];}
eventListeners[eventName].push(listener);};var removeEventListener=function removeEventListener(eventName,listener){var listeners=eventListeners[eventName];if(!listeners){return;}
var index=listeners.indexOf(listener);if(index===-1){return;}
listeners.splice(index,1);};var reset=function reset(){CONNECTION_STRING=DEFAULT_CONNECTION_STRING;rules=default_rules;eventListeners={};callbacks={};port=null;};var onMessage=function onMessage(evt){if(evt&&evt.data){var message=evt.data;if(message.eventName){var listeners=eventListeners[message.eventName];if(!listeners){return;}
for(var listener in listeners){if(listeners[listener]&&typeof listeners[listener]==='function'){listeners[listener]();}}
return;}
var cbs,cb;if(message.methodName){cbs=callbacks[message.methodName];if(!cbs||!cbs.length){console.warn('No callbacks for method '+message.methodName);return;}
while(cbs.length){cb=cbs.shift();if(!message.error){cb.successCb(message.data);}else{cb.errorCb(message.error);}}}}else{console.error('Unknown');}};var getSelf=function getSelf(cb,error){var request=navigator.mozApps.getSelf();request.onsuccess=function onSuccess(evt){cb(evt.target.result);};request.onerror=function onError(){if(error&&typeof(error)==='function'){error();}};};var requestQueue=[];var isConnecting=false;var connect=function connect(cb){if(isConnecting){return requestQueue.push(cb);}
isConnecting=true;_connect(function onConnect(err){var next;isConnecting=false;if(typeof cb==='function'){cb(err);}
while(!!(next=requestQueue.shift())){next&&next(err);}});};var _connect=function _connect(callback){getSelf(function onApp(app){if(!app){return;}
app.connect(CONNECTION_STRING,rules).then(function(ports){if(!ports||ports.length!==1){return;}
port=ports[0];callback&&callback();});});};var sendMessage=function sendMessage(message,successCb,errorCb){if(port){_sendMessage(message,successCb,errorCb);return;}
connect(function(){_sendMessage(message,successCb,errorCb);});};var _sendMessage=function _sendMessage(message,successCb,errorCb){var name=message.name;if(!name){return;}
if(!callbacks[name]){callbacks[name]=[];}
callbacks[name].push({successCb:successCb,errorCb:errorCb});port.onmessage=onMessage;port.postMessage(message);};var getAccount=function getAccount(successCb,errorCb){sendMessage({'name':'getAccount'},successCb,errorCb);};var openFlow=function openFlow(successCb,errorCb){sendMessage({'name':'openFlow'},successCb,errorCb);};var logout=function logout(successCb,errorCb){sendMessage({'name':'logout'},successCb,errorCb);};var refreshAuthentication=function refreshAuthentication(email,successCb,errorCb){sendMessage({'name':'refreshAuthentication','email':email},successCb,errorCb);};var resendVerificationEmail=function resendVerificationEmail(email,successCb,errorCb){sendMessage({'name':'resendVerificationEmail','email':email},successCb,errorCb);};connect();return{'addEventListener':addEventListener,'getAccount':getAccount,'init':init,'logout':logout,'openFlow':openFlow,'refreshAuthentication':refreshAuthentication,'removeEventListener':removeEventListener,'resendVerificationEmail':resendVerificationEmail,'reset':reset};}();define("shared/fxa_iac_client",(function(global){return function(){var ret,fn;return ret||global.FxAccountsIACHelper;};}(this)));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_accounts/firefox_accounts',['require','shared/text_normalizer','shared/fxa_iac_client','modules/dialog_service'],function(require){var normalizer=require('shared/text_normalizer');var fxaHelper=require('shared/fxa_iac_client');var dialogService=require('modules/dialog_service');var FirefoxAccounts=function(){this._boundRefreshStatus=this._boundRefreshStatus||this.refreshStatus.bind(this);};FirefoxAccounts.prototype={onInit:function fxa_init(elements){this._elements=elements;},onBeforeShow:function fxa_beforeShow(){fxaHelper.addEventListener('onlogin',this._boundRefreshStatus);fxaHelper.addEventListener('onverified',this._boundRefreshStatus);fxaHelper.addEventListener('onlogout',this._boundRefreshStatus);this._boundRefreshStatus();},onBeforeHide:function fxa_beforeHide(){fxaHelper.removeEventListener('onlogin',this._boundRefreshStatus);fxaHelper.removeEventListener('onverified',this._boundRefreshStatus);fxaHelper.removeEventListener('onlogout',this._boundRefreshStatus);},refreshStatus:function fxa_refreshStatus(){fxaHelper.getAccount(this._onFxAccountStateChange.bind(this),this._onFxAccountError.bind(this));},_onFxAccountStateChange:function fxa_onFxAccountStateChange(e){var email=e?normalizer.escapeHTML(e.email):'';if(!e){this._hideLoggedInPanel();this._hideUnverifiedPanel();this._showLoggedOutPanel();}else if(e.verified){this._hideLoggedOutPanel();this._hideUnverifiedPanel();this._showLoggedInPanel(email);}else{this._hideLoggedOutPanel();this._hideLoggedInPanel();this._showUnverifiedPanel(email);}},_onFxAccountError:function fxa_onFxAccountError(err){console.error('FxaPanel: Error getting Firefox Account: '+err.error);},_hideLoggedOutPanel:function fxa_hideLoggedOutPanel(){this._elements.loginBtn.onclick=null;this._elements.loggedOutPanel.hidden=true;},_showLoggedOutPanel:function fxa_showLoggedOutPanel(){this._elements.loginBtn.onclick=this._onLoginClick.bind(this);this._elements.loggedOutPanel.hidden=false;},_hideLoggedInPanel:function fxa_hideLoggedInPanel(){this._elements.loggedInPanel.hidden=true;this._elements.loggedInEmail.textContent='';this._elements.logoutBtn.onclick=null;},_showLoggedInPanel:function fxa_showLoggedInPanel(email){document.l10n.setAttributes(this._elements.loggedInEmail,'fxa-logged-in-text',{email:email});this._elements.loggedInPanel.hidden=false;this._elements.logoutBtn.onclick=this._onLogoutClick.bind(this);},_hideUnverifiedPanel:function fxa_hideUnverifiedPanel(){this._elements.unverifiedPanel.hidden=true;this._elements.unverifiedEmail.textContent='';this._elements.cancelBtn.onclick=null;if(this._elements.resendLink){this._elements.resendLink.onclick=null;}},_showUnverifiedPanel:function fxa_showUnverifiedPanel(email){this._elements.unverifiedPanel.hidden=false;this._elements.cancelBtn.onclick=this._onLogoutClick.bind(this);document.l10n.setAttributes(this._elements.unverifiedEmail,'fxa-verification-email-sent-msg',{email:email});this._elements.resendLink.onclick=this._onResendClick.bind(this);},_onLogoutClick:function fxa_onLogoutClick(e){e.stopPropagation();e.preventDefault();fxaHelper.logout(this._onFxAccountStateChange.bind(this),this._onFxAccountError.bind(this));},_onResendClick:function fxa__onResendClick(e){e.stopPropagation();e.preventDefault();if(e.target.classList.contains('disabled')){return;}
fxaHelper.getAccount((accts)=>{var email=accts&&accts.email;if(!email){return this._onFxAccountStateChange(accts);}
fxaHelper.resendVerificationEmail(email,this._onResend.bind(this,email),this._onFxAccountError.bind(this));},this._onFxAccountError.bind(this));},_onResend:function fxa__onResend(email){dialogService.alert({id:'fxa-resend-alert',args:{email:email}});this._elements.resendLink.classList.add('disabled');setTimeout(()=>{this._elements.resendLink.classList.remove('disabled');},60000);},_onLoginClick:function fxa_onLoginClick(e){e.stopPropagation();e.preventDefault();fxaHelper.openFlow(this._onFxAccountStateChange.bind(this),this._onFxAccountError.bind(this));}};return function ctor_firefox_accounts(){return new FirefoxAccounts();};});define('panels/firefox_accounts/panel',['require','modules/settings_panel','panels/firefox_accounts/firefox_accounts'],function(require){var SettingsPanel=require('modules/settings_panel');var FirefoxAccounts=require('panels/firefox_accounts/firefox_accounts');return function ctor_firefox_account_panel(){var elements;var firefoxAccounts=FirefoxAccounts();return SettingsPanel({onInit:function(panel){elements={fxaContainer:document.getElementById('fxa'),loggedOutPanel:document.getElementById('fxa-logged-out'),loggedInPanel:document.getElementById('fxa-logged-in'),unverifiedPanel:document.getElementById('fxa-unverified'),resendEmail:document.getElementById('fxa-resend-email'),cancelBtn:document.getElementById('fxa-cancel-confirmation'),loginBtn:document.getElementById('fxa-login'),logoutBtn:document.getElementById('fxa-logout'),loggedInEmail:document.getElementById('fxa-logged-in-text'),unverifiedEmail:document.getElementById('fxa-unverified-text'),resendLink:document.getElementById('fxa-resend')};firefoxAccounts.onInit(elements);},onBeforeShow:function(){firefoxAccounts.onBeforeShow();},onBeforeHide:function(){firefoxAccounts.onBeforeHide();}});};});

View file

@ -0,0 +1,505 @@
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();}});};});

View file

@ -0,0 +1,171 @@
/**
* Handle support panel functionality with SIM and without SIM
*/
/**
* Handle support panel functionality with SIM and without SIM
*/
/**
* Handle support panel functionality with SIM and without SIM
*/
/**
* Handle support panel functionality with SIM and without SIM
*/
/**
* Handle support panel functionality with SIM and without SIM
*/
/**
* Handle support panel functionality with SIM and without SIM
*/
define('panels/help/support',["require", "modules/settings_cache", "shared/lazy_loader"],function(require) {
'use strict';
var SettingsCache = require('modules/settings_cache');
var LazyLoader = require('shared/lazy_loader');
var Support = function() {};
Support.prototype = {
/**
* initialization
*/
init: function support_init(elements) {
this._elements = elements;
/**
* We'll stash the support info in here when reading from the
* Settings.
* If no values are found in Settings for support info We'll
* refer to the JSON File Data.
*/
this._callSupportInfo = null;
var url = 'https://vulpes-os.org/';
this._elements.userGuide.addEventListener('click', () => {
this._elements.userGuide.blur();
var activity = new window.MozActivity({
name: 'view',
data: { type: 'url', url: url }
});
// For workaround jshint.
activity.onsuccess = function() {};
});
// parse support information from data
this._getSupportInfo(this._displaySupportInfo.bind(this));
},
/**
* Clean states for test
*/
uninit: function() {
this._elements = null;
this._supportInfo = null;
this._callSupportInfo = null;
},
/**
* get support data from cache or from resource file
*/
_getSupportInfo: function support_getSupportInfo(callback) {
if (this._supportInfo) {
callback(this._supportInfo);
return;
}
LazyLoader.getJSON('/resources/support.json')
.then(function loadSupportInfo(data) {
this._supportInfo = data;
callback(this._supportInfo);
}.bind(this)).catch(function(error) {
console.warn('Support information:', error);
callback({onlinesupport: {title: 'Vulpes OS', href: 'https://vulpes-os.org/'}, callsupport: []});
});
},
/**
* create support url items
*/
_createLinkNode: function support_createLinkNode(data, type) {
var link = document.createElement('a');
link.setAttribute('href', data.href);
link.classList.add('link-text');
if (type == 'tel') {
link.textContent = data.title + ' (' + data.href + ')';
} else {
link.textContent = data.title;
}
return link;
},
/**
* Indicate to our panel that there is support info present.
*/
_enableSupportInfo: function support_enableSupportInfo() {
this._elements.help.dataset.hasSupportInfo = true;
},
/**
* Local helper function to set the online support information
* once it's retrieved or we've determined that we'll use
* what's in the build JSON file.
*/
_setOnlineSupportInfo:
function support_setOnlineSupportInfo(onlineSupportInfo) {
this._enableSupportInfo();
var nodes = this._createLinkNode(onlineSupportInfo);
this._elements.supportText.appendChild(nodes);
},
/**
* Local helper function to set the information once we've
* retrieved it.
*/
_setCallSupportInfo:
function support_setCallSupportInfo(supportInfo) {
this._enableSupportInfo();
for (var id in supportInfo) {
this._elements.supportNumber
.appendChild(this._createLinkNode(supportInfo[id], 'tel'));
}
},
_renderSupportInfo: function support_renderSupportInfo(result) {
var onlineSupportInfo = null;
var onlineSupportTitle = result['support.onlinesupport.title'];
if (typeof onlineSupportTitle === 'string' && onlineSupportTitle !== '') {
onlineSupportInfo = { title: onlineSupportTitle };
onlineSupportInfo.href = result['support.onlinesupport.href'];
this._setOnlineSupportInfo(onlineSupportInfo);
} else if (this._supportInfo) {
this._setOnlineSupportInfo(this._supportInfo.onlinesupport);
}
// Check to see if we have a title for the first support number.
var callSupport1Title = result['support.callsupport1.title'];
// If we have a title we'll go ahead and load the href for it too.
if (typeof callSupport1Title === 'string' && callSupport1Title !== '') {
this._callSupportInfo = [
{
'title': callSupport1Title,
'href': result['support.callsupport1.href']
}
];
// Now check to see if we have a title for the second
// support number. If we do, we'll load it's href as well.
var callSupport2Title = result['support.callsupport2.title'];
if (typeof callSupport2Title === 'string' && callSupport2Title !== '') {
this._callSupportInfo.push({
'title': callSupport2Title,
'href': result['support.callsupport2.href']
});
// Finally set the support info retreived from Settings.
this._setCallSupportInfo(this._callSupportInfo);
}
} else if (this._supportInfo) {
// No customized values, use what's in the JSON file.
this._setCallSupportInfo(this._supportInfo.callsupport);
}
},
/**
* display Support information
*/
_displaySupportInfo: function support_displaySupportInfo(supportInfo) {
SettingsCache.getSettings(this._renderSupportInfo.bind(this));
}
};
return function ctor_support() {
return new Support();
};
});
define('panels/help/panel',['require','modules/settings_panel','panels/help/support'],function(require){'use strict';var SettingsPanel=require('modules/settings_panel');var Support=require('panels/help/support');return function ctor_support_panel(){var help=Support();return SettingsPanel({onInit:function(panel){var elements={userGuide:panel.querySelector('#user-guide'),help:panel,supportText:panel.querySelector('#help-online-support-text'),supportNumber:panel.querySelector('#help-call-support-numbers')};help.init(elements);}});};});

View file

@ -0,0 +1,490 @@
define('panels/keyboard_add_layouts/nested_template_factory',['require'],function(require){'use strict';return function ctor_nestedTemplate(parentTemplate,childTemplate){var listViews=[];var template=parentTemplate.bind({listViews:listViews,childTemplate:childTemplate});Object.defineProperty(template,'listViews',{configurable:false,get:function(){return listViews;}});return template;};});define('panels/keyboard_add_layouts/keyboard_template',['require','modules/mvvm/list_view'],function(require){'use strict';var ListView=require('modules/mvvm/list_view');return function kal_keyboardTemplate(keyboard,recycled,helper){var layoutTemplate=this.childTemplate;var listViews=this.listViews;var container,header,h2,ul,listView;if(recycled){container=recycled;h2=container.querySelector('h2');ul=container.querySelector('ul');}else{container=document.createElement('div');header=document.createElement('header');h2=document.createElement('h2');ul=document.createElement('ul');header.appendChild(h2);container.appendChild(header);container.appendChild(ul);}
listView=listViews.some(function eachListView(list){if(list.element===ul){list.set(keyboard.layouts);list.enabled=true;return true;}});if(!listView){listView=ListView(ul,keyboard.layouts,layoutTemplate);listView.enabled=true;listViews.push(listView);}
helper.observeAndCall(keyboard,{name:function refreshName(){h2.textContent=keyboard.name;}});return container;};});define('panels/keyboard_add_layouts/layout_template',['require'],function(require){'use strict';return function kal_layoutTemplate(layout,recycled,helper){var container=null;var nameBdi,checkbox;if(recycled){container=recycled;checkbox=container.querySelector('gaia-checkbox');nameBdi=container.querySelector('bdi');}else{container=document.createElement('li');checkbox=document.createElement('gaia-checkbox');nameBdi=document.createElement('bdi');checkbox.appendChild(document.createElement('label'));checkbox.lastChild.appendChild(nameBdi);container.appendChild(checkbox);}
if(layout.nameL10nId){nameBdi.dataset.l10nId=layout.nameL10nId;}
checkbox.addEventListener('change',function(e){layout.enabled=e.target.checked;});helper.observeAndCall(layout,{name:function refreshName(){nameBdi.textContent=layout.name;},enabled:function(){checkbox.checked=layout.enabled;}});return container;};});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/keyboard_add_layouts/core',['require','modules/mvvm/list_view'],function(require){'use strict';var ListView=require('modules/mvvm/list_view');function KeyboardAddLayoutsCore(context,template){this._enabled=false;this._listView=null;this._keyboardContext=context;this._keyboardTemplate=template;}
KeyboardAddLayoutsCore.prototype={get enabled(){return this._enabled;},set enabled(value){this._enabled=value;if(this._listView){this._listView.enabled=this._enabled;}
this._keyboardTemplate.listViews.forEach(function(listView){listView.enabled=this._enabled;}.bind(this));},_initInstalledLayoutListView:function kal_initListView(listViewRoot,keyboards,keyboardTemplate){this._listView=ListView(listViewRoot,keyboards,keyboardTemplate);},_showEnabledDefaultDialog:function kal_showDialog(layout,missingType){require(['modules/dialog_service'],function(DialogService){document.l10n.formatValue('keyboardType-'+missingType).then(type=>{DialogService.alert({id:'defaultKeyboardEnabled',args:{layoutName:layout.inputManifest.name,appName:layout.manifest.name}},{title:{id:'mustHaveOneKeyboard',args:{type:type}}});});});},init:function kal_onInit(elements){var that=this;this._keyboardContext.init(function(){that._keyboardContext.keyboards(function(keyboards){that._initInstalledLayoutListView(elements.listViewRoot,keyboards,that._keyboardTemplate);that.enabled=true;});});this._keyboardContext.defaultKeyboardEnabled(this._showEnabledDefaultDialog);}};return function ctor_kalCore(context,template){return new KeyboardAddLayoutsCore(context,template);};});define('panels/keyboard_add_layouts/panel',['require','modules/settings_panel','modules/keyboard_context','shared/keyboard_helper','panels/keyboard_add_layouts/nested_template_factory','panels/keyboard_add_layouts/keyboard_template','panels/keyboard_add_layouts/layout_template','panels/keyboard_add_layouts/core'],function(require){'use strict';var SettingsPanel=require('modules/settings_panel');var KeyboardContext=require('modules/keyboard_context');var KeyboardHelper=require('shared/keyboard_helper');var NestedTemplateFactory=require('panels/keyboard_add_layouts/nested_template_factory');var keyboardTemplate=require('panels/keyboard_add_layouts/keyboard_template');var layoutTemplate=require('panels/keyboard_add_layouts/layout_template');var Core=require('panels/keyboard_add_layouts/core');return function ctor_addLayoutsPanel(){var nestedTemplate=NestedTemplateFactory(keyboardTemplate,layoutTemplate);var core=Core(KeyboardContext,nestedTemplate);return SettingsPanel({onInit:function kalp_onInit(rootElement){core.init({listViewRoot:rootElement.querySelector('.keyboardAppContainer')});},onBeforeShow:function kalp_onBeforeShow(){core.enabled=true;},onBeforeHide:function kalp_onBeforeHide(){KeyboardHelper.saveToSettings();},onHide:function kalp_onHide(){core.enabled=false;}});};});

View file

@ -0,0 +1,486 @@
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/screen_lock/screen_lock',['require','modules/dialog_service','shared/settings_listener'],function(require){'use strict';var DialogService=require('modules/dialog_service');var SettingsListener=require('shared/settings_listener');var ScreenLock=function ctor_screenlock(){return{_settings:{passcodeEnabled:false,lockscreenEnabled:false},onInit:function sl_onInit(elements){this._elements=elements;this._elements.passcodeEnable.addEventListener('click',this);this._elements.lockscreenEnable.addEventListener('click',this);this._elements.passcodeEditButton.addEventListener('click',this);this._fetchSettings();},_fetchSettings:function sl_fetchSettings(){SettingsListener.observe('lockscreen.enabled',false,function(enabled){this._toggleLockscreen(enabled);}.bind(this));SettingsListener.observe('lockscreen.passcode-lock.enabled',false,function(enabled){this._togglePasscode(enabled);}.bind(this));},_togglePasscode:function sl_togglePasscode(enabled){this._settings.passcodeEnabled=enabled;this._elements.panel.dataset.passcodeEnabled=enabled;this._elements.passcodeEnable.checked=enabled;},_toggleLockscreen:function sl_toggleLockscreen(enabled){this._settings.lockscreenEnabled=enabled;this._elements.panel.dataset.lockscreenEnabled=enabled;this._elements.lockscreenEnable.checked=enabled;},_showDialog:function sl_showDialog(mode){DialogService.show('screenLock-passcode',{mode:mode});},handleEvent:function sl_handleEvent(evt){switch(evt.target){case this._elements.passcodeEnable:evt.preventDefault();if(this._settings.passcodeEnabled){this._showDialog('confirm');}else{this._showDialog('create');}
break;case this._elements.lockscreenEnable:if(this._settings.lockscreenEnabled===true&&this._settings.passcodeEnabled===true){evt.preventDefault();this._showDialog('confirmLock');}
break;case this._elements.passcodeEditButton:this._showDialog('edit');break;}}};};return ScreenLock;});define('panels/screen_lock/panel',['require','modules/settings_panel','panels/screen_lock/screen_lock'],function(require){'use strict';var SettingsPanel=require('modules/settings_panel');var ScreenLock=require('panels/screen_lock/screen_lock');return function ctor_screenlock(){var screenLock=ScreenLock();return SettingsPanel({onInit:function(panel){var elements={panel:panel,lockscreenEnable:panel.querySelector('.lockscreen-enable'),passcodeEnable:panel.querySelector('.passcode-enable'),passcodeEditButton:panel.querySelector('.passcode-edit')};screenLock.onInit(elements);}});};});

View file

@ -0,0 +1,17 @@
define('panels/simcard_manager/sim_ui_model',['require'],function(require){'use strict';var SimUIModel=function(cardIndex){this._cardIndex=cardIndex;this._enabled=false;this._absent=false;this._locked=false;this._defaultName={id:'simWithIndex',args:{index:this._cardIndex+1}};this._name=this._defaultName;this._number='';this._operator=null;};SimUIModel.prototype={getInfo:function(){var keys=['enabled','absent','locked','name','number','operator'];var info={};keys.forEach(function(key){info[key]=this['_'+key];}.bind(this));return info;},setState:function(key,options){switch(key){case'nosim':this._enabled=false;this._absent=true;this._locked=false;this._number='';this._operator={id:'noSimCard'};this._name=this._defaultName;break;case'locked':this._enabled=false;this._absent=false;this._locked=true;this._number='';this._operator={id:'sim-pin-locked'};this._name=this._defaultName;break;case'blocked':this._enabled=true;this._absent=true;this._locked=false;this._number='';this._operator=null;this._name={id:'noSimCard'};break;case'normal':this._enabled=true;this._absent=false;this._locked=false;this._number=options.number;if(options.operator){this._operator={text:options.operator};}else{this._operator={id:'no-operator'};}
this._name=this._defaultName;break;}}};return function ctor_simUIModel(cardIndex){return new SimUIModel(cardIndex);};});define('panels/simcard_manager/simcard_manager',['require','shared/sanitizer','shared/sim_settings_helper','shared/airplane_mode_helper','shared/mobile_operator','panels/simcard_manager/sim_ui_model'],function(require){'use strict';var l10n=document.l10n;var Sanitizer=require('shared/sanitizer');var SimSettingsHelper=require('shared/sim_settings_helper');var AirplaneModeHelper=require('shared/airplane_mode_helper');var MobileOperator=require('shared/mobile_operator');var SimUIModel=require('panels/simcard_manager/sim_ui_model');var SimCardManager=function(elements){this._elements=elements;this._simcards=[];this._isAirplaneMode=false;};SimCardManager.prototype={init:function scm_init(){this._elements.outgoingCallSelect.addEventListener('change',this);this._elements.outgoingMessagesSelect.addEventListener('change',this);this._addOutgoingDataSelectEvent();this._addVoiceChangeEventOnConns();this._addCardStateChangeEventOnIccs();this._addLocalizedChangeEventOnIccs();SimSettingsHelper.observe('outgoingData',this._outgoingDataChangeEvent.bind(this));this._addAirplaneModeChangeEvent();this._isAirplaneMode=AirplaneModeHelper.getStatus()==='enabled'?true:false;this._initSimCardsInfo();this._initSimCardManagerUI();},simItemView:function({simIndex}){return Sanitizer.escapeHTML`<li class="sim-card sim-card-${simIndex}">
<div class="sim-card-icon"></div>
<div class="information-container">
<p class="sim-card-name"></p>
<p class="sim-card-operator"></p>
<bdi class="sim-card-number"></bdi>
</div>
</li>`;},_initSimCardsInfo:function scm__initSimCardsInfo(){var conns=window.navigator.mozMobileConnections;for(var cardIndex=0;cardIndex<conns.length;cardIndex++){var conn=conns[cardIndex];var iccId=conn.iccId;var simcard=SimUIModel(cardIndex);this._simcards.push(simcard);this._updateCardState(cardIndex,iccId);}},handleEvent:function scm_handlEvent(evt){var cardIndex=evt.target.value;if(cardIndex===SimSettingsHelper.EMPTY_OPTION_VALUE){return;}
switch(evt.target){case this._elements.outgoingCallSelect:SimSettingsHelper.setServiceOnCard('outgoingCall',cardIndex);break;case this._elements.outgoingMessagesSelect:SimSettingsHelper.setServiceOnCard('outgoingMessages',cardIndex);break;}},_outgoingDataChangeEvent:function scm__outgoingDataChangeEvent(cardIndex){this._elements.outgoingDataSelect.value=cardIndex;},_addOutgoingDataSelectEvent:function scm__addOutgoingDataSelectEvent(){var prevCardIndex;var newCardIndex;this._elements.outgoingDataSelect.addEventListener('focus',function(){prevCardIndex=this.selectedIndex;newCardIndex=this.selectedIndex;});this._elements.outgoingDataSelect.addEventListener('blur',function(){newCardIndex=this.selectedIndex;if(prevCardIndex!==newCardIndex){l10n.formatValue('change-outgoing-data-confirm').then(value=>{var wantToChange=window.confirm(value);if(wantToChange){SimSettingsHelper.setServiceOnCard('outgoingData',newCardIndex);}else{this.selectedIndex=prevCardIndex;}});}});},_getSimCardsCount:function scm__getSimCardsCount(){return this._simcards.length;},_getSimCardInfo:function scm__getSimCardInfo(cardIndex){return this._simcards[cardIndex].getInfo();},_getSimCard:function scm__getSimCard(cardIndex){return this._simcards[cardIndex];},_updateSimCardsUI:function scm__updateSimCardsUI(){this._simcards.forEach(function(simcard,cardIndex){this._updateSimCardUI(cardIndex);}.bind(this));},_updateSimCardUI:function scm__updateSimCardUI(cardIndex){var simcardInfo=this._getSimCardInfo(cardIndex);var selectors=['name','number','operator'];var cardSelector='.sim-card-'+cardIndex;var cardDom=this._elements.simCardContainer.querySelector(cardSelector);cardDom.classList.toggle('absent',simcardInfo.absent);cardDom.classList.toggle('locked',simcardInfo.locked);cardDom.classList.toggle('enabled',simcardInfo.enabled);cardDom.classList.toggle('with-number',!!simcardInfo.number);selectors.forEach(function(selector){var targetSelector=cardSelector+' .sim-card-'+selector;var element=this._elements.simCardContainer.querySelector(targetSelector);if(selector==='number'){element.textContent=simcardInfo[selector];}else{var l10nObj=simcardInfo[selector];if(l10nObj.id){l10n.setAttributes(element,l10nObj.id,l10nObj.args);}else{element.removeAttribute('data-l10n-id');element.textContent=l10nObj.text;}}}.bind(this));},_initSimCardManagerUI:function scm__initSimCardManagerUI(){this._initSimCardsUI();this._updateSelectOptionsUI();this._updateSimCardsUI();this._updateSimSettingsUI();},_initSimCardsUI:function scm__initSimCardsUI(){var simItemHTMLs=[];this._simcards.forEach(function(simcard,index){simItemHTMLs.push(this.simItemView({simIndex:index.toString()}));}.bind(this));this._elements.simCardContainer.innerHTML=simItemHTMLs.join('');},_updateSimSettingsUI:function scm__updateSimSettingsUI(){var firstCardInfo=this._simcards[0].getInfo();var secondCardInfo=(this._simcards[1]?this._simcards[1].getInfo():{absent:true});var hidden=firstCardInfo.absent&&secondCardInfo.absent||this._isAirplaneMode;this._elements.simSettingsHeader.hidden=hidden;this._elements.simSettingsList.hidden=hidden;},_updateSelectOptionsUI:function scm__updateSelectOptionsUI(){var firstCardInfo=this._simcards[0].getInfo();var secondCardInfo=(this._simcards[1]?this._simcards[1].getInfo():{absent:true});if(!firstCardInfo.absent&&!secondCardInfo.absent){SimSettingsHelper.getCardIndexFrom('outgoingCall',function(cardIndex){this._updateSelectOptionUI('outgoingCall',cardIndex,this._elements.outgoingCallSelect);}.bind(this));SimSettingsHelper.getCardIndexFrom('outgoingMessages',function(cardIndex){this._updateSelectOptionUI('outgoingMessages',cardIndex,this._elements.outgoingMessagesSelect);}.bind(this));SimSettingsHelper.getCardIndexFrom('outgoingData',function(cardIndex){this._updateSelectOptionUI('outgoingData',cardIndex,this._elements.outgoingDataSelect);}.bind(this));}else{var selectedCardIndex;if(firstCardInfo.absent&&secondCardInfo.absent){selectedCardIndex=0;}else{selectedCardIndex=firstCardInfo.absent?1:0;}
this._elements.outgoingCallSelect.disabled=true;this._elements.outgoingMessagesSelect.disabled=true;this._elements.outgoingDataSelect.disabled=true;this._updateSelectOptionUI('outgoingCall',selectedCardIndex,this._elements.outgoingCallSelect);this._updateSelectOptionUI('outgoingMessages',selectedCardIndex,this._elements.outgoingMessagesSelect);this._updateSelectOptionUI('outgoingData',selectedCardIndex,this._elements.outgoingDataSelect);}},_updateSelectOptionUI:function scm__updateSelectOptionUI(storageKey,selectedCardIndex,selectDOM){while(selectDOM.firstChild){selectDOM.removeChild(selectDOM.firstChild);}
this._simcards.forEach(function(simcard,index){var simcardInfo=simcard.getInfo();var option=document.createElement('option');option.value=index;if(simcardInfo.absent){option.value=SimSettingsHelper.EMPTY_OPTION_VALUE;option.text=SimSettingsHelper.EMPTY_OPTION_TEXT;}else{if(simcardInfo.name.id){l10n.setAttributes(option,simcardInfo.name.id,simcardInfo.name.args);}else{option.text=simcardInfo.name.text;}}
if(index==selectedCardIndex){option.selected=true;}
selectDOM.add(option);});if(storageKey==='outgoingCall'||storageKey==='outgoingMessages'){var option=document.createElement('option');option.value=SimSettingsHelper.ALWAYS_ASK_OPTION_VALUE;option.setAttribute('data-l10n-id','sim-manager-always-ask');if(SimSettingsHelper.ALWAYS_ASK_OPTION_VALUE===selectedCardIndex){option.selected=true;}
selectDOM.add(option);}},_isSimCardLocked:function scm__isSimCardLocked(cardState){var lockedState=['pinRequired','pukRequired','networkLocked','serviceProviderLocked','corporateLocked','network1Locked','network2Locked','hrpdNetworkLocked','ruimCorporateLocked','ruimServiceProviderLocked'];return lockedState.indexOf(cardState)!==-1;},_isSimCardBlocked:function scm__isSimCardBlocked(cardState){var uselessState=['permanentBlocked'];return uselessState.indexOf(cardState)!==-1;},_addVoiceChangeEventOnConns:function scm__addVoiceChangeEventOnConns(){var conns=window.navigator.mozMobileConnections;for(var i=0;i<conns.length;i++){var iccId=conns[i].iccId;conns[i].addEventListener('voicechange',this._updateCardStateWithUI.bind(this,i,iccId));}},_addCardStateChangeEventOnIccs:function scm__addCardStateChangeEventOnIccs(){var conns=window.navigator.mozMobileConnections;var iccManager=window.navigator.mozIccManager;for(var i=0;i<conns.length;i++){var iccId=conns[i].iccId;var icc=iccManager.getIccById(iccId);if(icc){this._addChangeEventOnIccByIccId(iccId);}}},_addLocalizedChangeEventOnIccs:function scm__addLocalizedChangeEventOnIccs(){var conns=window.navigator.mozMobileConnections;document.addEventListener('DOMRetranslated',function(){for(var i=0;i<conns.length;i++){var iccId=conns[i].iccId;this._updateCardStateWithUI(i,iccId);}}.bind(this));},_addChangeEventOnIccByIccId:function scm__addChangeEventOnIccByIccId(iccId){var self=this;var icc=window.navigator.mozIccManager.getIccById(iccId);if(icc){icc.addEventListener('cardstatechange',function(){var cardIndex=self._getCardIndexByIccId(iccId);self._updateCardStateWithUI(cardIndex,iccId);if(self._isSimCardBlocked(icc.cardState)){self._updateSelectOptionsUI();}});}},_addAirplaneModeChangeEvent:function scm__addAirplaneModeChangeEvent(){var self=this;AirplaneModeHelper.addEventListener('statechange',function(state){if(state==='enabled'||state==='disabled'){var enabled=(state==='enabled')?true:false;self._isAirplaneMode=enabled;self._updateCardsState();self._updateSimCardsUI();self._updateSimSettingsUI();}});},_updateCardsState:function scm__updateCardsState(){var conns=window.navigator.mozMobileConnections;for(var cardIndex=0;cardIndex<conns.length;cardIndex++){var iccId=conns[cardIndex].iccId;this._updateCardState(cardIndex,iccId);}},_updateCardState:function scm__updateCardState(cardIndex,iccId){var iccManager=window.navigator.mozIccManager;var conn=window.navigator.mozMobileConnections[cardIndex];var simcard=this._simcards[cardIndex];if(!iccId||this._isAirplaneMode){simcard.setState('nosim');}else{var icc=iccManager.getIccById(iccId);var iccInfo=icc.iccInfo;var cardState=icc.cardState;var operatorInfo=MobileOperator.userFacingInfo(conn);if(this._isSimCardLocked(cardState)){simcard.setState('locked');}else if(this._isSimCardBlocked(cardState)){simcard.setState('blocked');}else{simcard.setState('normal',{number:iccInfo.msisdn||iccInfo.mdn||'',operator:operatorInfo.operator});}}},_updateCardStateWithUI:function scm__updateCardStateWithUI(cardIndex,iccId){this._updateCardState(cardIndex,iccId);this._updateSimCardUI(cardIndex);this._updateSimSettingsUI();},_getCardIndexByIccId:function scm__getCardIndexByIccId(iccId){var conns=window.navigator.mozMobileConnections;var cardIndex;for(var i=0;i<conns.length;i++){if(conns[i].iccId==iccId){cardIndex=i;}}
return cardIndex;}};return SimCardManager;});define('panels/simcard_manager/panel',['require','modules/settings_panel','panels/simcard_manager/simcard_manager'],function(require){'use strict';var SettingsPanel=require('modules/settings_panel');var SimCardManager=require('panels/simcard_manager/simcard_manager');return function ctor_sim_manager_panel(){return SettingsPanel({onInit:function(panel){var simcardManager=new SimCardManager({simCardContainer:panel.querySelector('.sim-card-container'),simSettingsHeader:panel.querySelector('.sim-manager-settings-header'),simSettingsList:panel.querySelector('.sim-manager-select-list'),outgoingCallSelect:panel.querySelector('.sim-manager-outgoing-call-select'),outgoingMessagesSelect:panel.querySelector('.sim-manager-outgoing-messages-select'),outgoingDataSelect:panel.querySelector('.sim-manager-outgoing-data-select'),});simcardManager.init();}});};});

View file

@ -0,0 +1,502 @@
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/simpin/simpin',['require','shared/airplane_mode_helper','shared/simslot_manager','modules/dialog_service','shared/sanitizer','shared/toaster','modules/sim_security'],function(require){'use strict';var AirplaneModeHelper=require('shared/airplane_mode_helper');var SIMSlotManager=require('shared/simslot_manager');var DialogService=require('modules/dialog_service');var Sanitizer=require('shared/sanitizer');var Toaster=require('shared/toaster');var SimSecurity=require('modules/sim_security');var SimPin=function(elements){this._elements=elements;};SimPin.prototype={init:function simpin_init(){AirplaneModeHelper.ready(()=>{this.conns=window.navigator.mozMobileConnections;this.iccManager=window.navigator.mozIccManager;this.isAirplaneMode=(AirplaneModeHelper.getStatus()==='enabled');this._elements.simPinContainer.addEventListener('click',this);this._elements.simPinContainer.addEventListener('change',this.simPinSwitched.bind(this));this.addIccDetectedEvent();this.addIccUndetectedEvent();this.addAirplaneModeChangeEvent();this.initSimPinBack();this.initSimPinsUI();this.updateSimPinsUI();this.addChangeEventOnIccs();});},simPinView:function({simIndex,simPinArgs}){return Sanitizer.escapeHTML`
<li class="simpin-enabled simpin-enabled-${simIndex}
simpin-${simIndex}">
<gaia-switch data-ignore data-sim-index="${simIndex}">
<label data-l10n-id="simPinWithIndex"
data-l10n-args="${simPinArgs}"></label>
</gaia-switch>
</li>
<li class="simpin-change simpin-change-${simIndex} simpin-${simIndex}"
hidden>
<a class="menu-item" href="#" data-sim-index="${simIndex}"
data-type="changeSimPin">
<span data-l10n-id="changeSimPin"></span>
</a>
</li>`;},initSimPinBack:function simpin_initSimPinBack(){this._elements.simPinHeader.dataset.href=SIMSlotManager.isMultiSIM()?'#sim-manager':'#root';},initSimPinsUI:function simpin_initSimPinsUI(){var simPinHTMLs=[];[].forEach.call(this.conns,(conn,index)=>{var simPinIndex=index+1;if(!SIMSlotManager.isMultiSIM()){simPinIndex='';}
simPinHTMLs.push(this.simPinView({'simIndex':index.toString(),'simPinArgs':JSON.stringify({'index':simPinIndex})}));});this._elements.simPinContainer.innerHTML=simPinHTMLs.join('');},updateSimPinUI:function simpin_updateSimPinUI(cardIndex){var iccId=this.conns[cardIndex].iccId;var icc=this.iccManager.getIccById(iccId);var changeSimPinItem=this._elements.simPinContainer.querySelector('.simpin-change-'+cardIndex);var simPinCheckbox=this._elements.simPinContainer.querySelector('.simpin-enabled-'+cardIndex+' gaia-switch');var isSimAvailable=icc&&icc.cardState&&icc.cardState!=='unknown';if(!isSimAvailable||this.isAirplaneMode){simPinCheckbox.disabled=true;changeSimPinItem.hidden=true;return Promise.resolve();}
return SimSecurity.getCardLock(cardIndex,'pin').then((result)=>{var enabled=result.enabled;simPinCheckbox.disabled=false;simPinCheckbox.checked=enabled;changeSimPinItem.hidden=!enabled;},()=>{console.log('onerror');console.log('cardIndex',cardIndex);});},updateSimPinsUI:function simpin_updateSimPinsUI(){[].forEach.call(this.conns,(simcard,cardIndex)=>{this.updateSimPinUI(cardIndex);});},handleEvent:function simpin_handleEvent(evt){var target=evt.target;var cardIndex=target.dataset&&target.dataset.simIndex;var type=target.dataset&&target.dataset.type;cardIndex=parseInt(cardIndex,10);switch(type){case'changeSimPin':this.changeSimPin(cardIndex);break;}},simPinSwitched:function simpin_simPinSwitched(evt){var target=evt.target;var cardIndex=target.dataset&&target.dataset.simIndex;cardIndex=parseInt(cardIndex,10);this.checkSimPin(target,cardIndex);},checkSimPin:function simpin_checkSimPin(checkbox,cardIndex){var enabled=checkbox.checked;var iccId=this.conns[cardIndex].iccId;var icc=this.iccManager.getIccById(iccId);switch(icc.cardState){case'pukRequired':return DialogService.show('simpin-dialog',{method:'unlock_puk',cardIndex:cardIndex}).then((result)=>{var type=result.type;if(type==='submit'){checkbox.checked=true;this.updateSimPinUI(cardIndex);}else{checkbox.checked=!enabled;this.updateSimPinUI(cardIndex);}});default:var action=enabled?'enable_lock':'disable_lock';return DialogService.show('simpin-dialog',{method:action,cardIndex:cardIndex}).then((result)=>{var type=result.type;if(type==='submit'){this.updateSimPinUI(cardIndex);}else{checkbox.checked=!enabled;this.updateSimPinUI(cardIndex);}});}},changeSimPin:function(cardIndex){return DialogService.show('simpin-dialog',{method:'change_pin',cardIndex:cardIndex}).then(function(result){var type=result.type;if(type==='submit'){var toast;if(SIMSlotManager.isMultiSIM()){toast={messageL10nId:'simPinChangedSuccessfullyWithIndex',messageL10nArgs:{'index':+(cardIndex)+1},latency:3000,useTransition:true};}else{toast={messageL10nId:'simPinChangedSuccessfully',latency:3000,useTransition:true};}
Toaster.showToast(toast);}});},addIccDetectedEvent:function simpin_addIccDetectedEvent(){this.iccManager.addEventListener('iccdetected',(evt)=>{var iccId=evt.iccId;var icc=this.iccManager.getIccById(iccId);if(icc){var cardIndex=this.getCardIndexByIccId(iccId);this.updateSimPinUI(cardIndex);this.addChangeEventOnIccByIccId(iccId);}});},addIccUndetectedEvent:function simpin_addIccDetectedEvent(){this.iccManager.addEventListener('iccundetected',(evt)=>{this.updateSimPinsUI();});},addAirplaneModeChangeEvent:function simpin_addAirplaneModeChangeEvent(){AirplaneModeHelper.addEventListener('statechange',(status)=>{this.isAirplaneMode=(status==='enabled');this.updateSimPinsUI();});},addChangeEventOnIccs:function simpin_addChangeEventOnIccs(){for(var i=0;i<this.conns.length;i++){var iccId=this.conns[i].iccId;var icc=this.iccManager.getIccById(iccId);if(icc){this.addChangeEventOnIccByIccId(iccId);}}},addChangeEventOnIccByIccId:function simpin_addChangeEventOnIccByIccId(iccId){var icc=this.iccManager.getIccById(iccId);if(icc){icc.addEventListener('cardstatechange',()=>{var cardIndex=this.getCardIndexByIccId(iccId);this.updateSimPinUI(cardIndex);});}},getCardIndexByIccId:function simpin_getCardIndexByIccId(iccId){var cardIndex;for(var i=0;i<this.conns.length;i++){if(this.conns[i].iccId==iccId){cardIndex=i;}}
return cardIndex;}};return function ctor_simpin(elements){return new SimPin(elements);};});define('panels/simpin/panel',['require','modules/settings_panel','panels/simpin/simpin'],function(require){'use strict';var SettingsPanel=require('modules/settings_panel');var SimPin=require('panels/simpin/simpin');return function ctor_simpin_panel(){return SettingsPanel({onInit:function(panel){var elements={};elements.simPinContainer=panel.querySelector('.simpin-container');elements.simPinHeader=panel.querySelector('.simpin-header');var simpin=SimPin(elements);simpin.init();}});};});

View file

@ -0,0 +1,487 @@
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/usb_storage/usb_transfer',['require','modules/settings_cache','shared/settings_listener','modules/dialog_service','shared/async_storage','modules/media_storage'],function(require){'use strict';var SettingsCache=require('modules/settings_cache');var SettingsListener=require('shared/settings_listener');var DialogService=require('modules/dialog_service');var AsyncStorage=require('shared/async_storage');var MediaStorage=require('modules/media_storage');var _debug=false;var debug=function(){};if(_debug){debug=function ut_debug(msg){console.log('--> [UsbTransfer]: '+msg);};}
var UsbTransfer=function(){this._keyUmsEnabled='ums.enabled';this._keyUmsMode='ums.mode';this._keyTransferProtocol='usb.transfer';this._elements=null;this._usbHotProtocolSwitch=false;this._partialUmsSupport=!navigator.getDeviceStorages('sdcard').every(storage=>storage.canBeShared);this.PROTOCOL_UMS='0';this.PROTOCOL_MTP='1';this.MODE_UMS=1;this.MODE_MTP=3;};UsbTransfer.prototype={init:function ut_init(elements,option){this._elements=elements;if(option&&option.usbHotProtocolSwitch!==undefined){this._usbHotProtocolSwitch=option.usbHotProtocolSwitch;}
SettingsListener.observe(this._keyTransferProtocol,this.PROTOCOL_UMS,this._configProtocol.bind(this));SettingsListener.observe(this._keyUmsEnabled,false,this._umsEnabledHandler.bind(this));this._elements.usbEnabledCheckBox.addEventListener('change',this._umsCheckboxChange.bind(this));MediaStorage.observe('volumeState',this._updateUmsState.bind(this));},_umsCheckboxChange:function storage_umsCheckboxChange(evt){var checkbox=evt.target;var cset={};var warningKey='ums-turn-on-warning';debug('state change '+checkbox.checked);if(checkbox.checked){AsyncStorage.getItem(warningKey,(showed)=>{if(!showed){debug('show turn-on warning');this._umsTurnOnWarning(checkbox,warningKey);}else{debug('turn-on warning is showed');SettingsCache.getSettings(this._openIncompatibleSettingsDialogIfNeeded.bind(this));}});}else{cset[this._keyUmsEnabled]=false;navigator.mozSettings.createLock().set(cset);}},_umsTurnOnWarning:function storage_umsTurnOnWarning(checkbox,warningKey){DialogService.confirm('ums-confirm',{title:'ums-warning-title',submitButton:'ok',cancelButton:'cancel'}).then((result)=>{var type=result.type;if(type==='submit'){debug('turn on success');AsyncStorage.setItem(warningKey,true);SettingsCache.getSettings(this._openIncompatibleSettingsDialogIfNeeded.bind(this));}else{debug('turn on fail');var cset={};cset[this._keyUmsEnabled]=false;navigator.mozSettings.createLock().set(cset);checkbox.checked=false;}});},_openIncompatibleSettingsDialogIfNeeded:function storage_openIncompatibleSettingsDialogIfNeeded(settings){var cset={};var umsSettingKey=this._keyUmsEnabled;var oldSetting='tethering.usb.enabled';var usbTetheringSetting=settings[oldSetting];if(!usbTetheringSetting){cset[umsSettingKey]=true;navigator.mozSettings.createLock().set(cset);}else{DialogService.confirm('is-warning-storage-tethering-message',{title:'is-warning-storage-header',submitButton:{id:'enable',style:'recommend'},cancelButton:{id:'cancel'}}).then((result)=>{var enabled=result.type==='submit';var lock=navigator.mozSettings.createLock();var cset={};cset[umsSettingKey]=enabled;cset[oldSetting]=!enabled;lock.set(cset);});}},_umsEnabledHandler:function ut_umsEnabledHandler(enabled){debug('ums.enabled: '+enabled);this._elements.usbEnabledCheckBox.checked=enabled;this._updateUmsState();},_configProtocol:function ut_configProtocol(protocol){SettingsCache.getSettings((results)=>{var enabled=results[this._keyUmsEnabled];var mode=results[this._keyUmsMode];if(enabled){this._changeMode(mode,protocol);}});},_changeMode:function ut_changeMode(mode,protocol){if(mode!==this.MODE_MTP&&protocol===this.PROTOCOL_MTP){this._setMode(this.MODE_MTP);}else if(mode===this.MODE_MTP&&protocol===this.PROTOCOL_UMS){if(this._partialUmsSupport){debug('show partial warning');DialogService.show('ums-partial-warning').then((result)=>{if(result.type==='cancel'){var param={};param[this._keyTransferProtocol]=this.PROTOCOL_MTP;SettingsListener.getSettingsLock().set(param);}else{this._setMode(this.MODE_UMS);}});}else{this._setMode(this.MODE_UMS);}}else{console.log('Error: should not be executed');}},_updateUmsState:function ut_updateUmsState(){var key;debug('enabled:'+this._elements.usbEnabledCheckBox.checked+'/'+'volumeState:'+MediaStorage.volumeState);if(this._elements.usbEnabledCheckBox.checked){key='enabled';if(MediaStorage.volumeState==='shared'){this._disableProtocolSelections(true);}else{this._disableProtocolSelections(false);}}else if(MediaStorage.volumeState==='shared'){key='umsUnplugToDisable';this._disableProtocolSelections(true);}else{key='disabled';this._disableProtocolSelections(false);}
this._elements.usbEnabledInfoBlock.setAttribute('data-l10n-id',key);},_disableProtocolSelections:function ut_disableProtocolSelections(disabled){var i;if(disabled){if(!this._usbHotProtocolSwitch){for(i=0;i<this._elements.protocols.length;i++){this._elements.protocols[i].setAttribute('disabled',true);}}}else{for(i=0;i<this._elements.protocols.length;i++){this._elements.protocols[i].removeAttribute('disabled');}}},_setMode:function ut_setMode(mode){var param={};param[this._keyUmsMode]=mode;SettingsListener.getSettingsLock().set(param);}};return function ctor_usb_transfer(){return new UsbTransfer();};});define('panels/usb_storage/panel',['require','modules/settings_panel','panels/usb_storage/usb_transfer','shared/lazy_loader'],function(require){'use strict';var SettingsPanel=require('modules/settings_panel');var UsbTransferModule=require('panels/usb_storage/usb_transfer');var LazyLoader=require('shared/lazy_loader');var elements={};return function ctor_usb_storage_panel(){var usbTransfer=UsbTransferModule();return SettingsPanel({onInit:function us_onInit(panel){elements={usbEnabledCheckBox:panel.querySelector('.ums-switch'),usbEnabledInfoBlock:panel.querySelector('.ums-switch-desc'),protocols:panel.querySelectorAll('gaia-radio')};LazyLoader.getJSON('/resources/device-features.json').then(({usbHotProtocolSwitch})=>usbTransfer.init(elements,{usbHotProtocolSwitch:usbHotProtocolSwitch}));}});};});

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,485 @@
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/wifi_select_certificate_file/panel',['require','modules/settings_panel','modules/settings_service','modules/dialog_service','shared/device_storage/enumerate_all','shared/wifi_helper'],function(require){'use strict';var SettingsPanel=require('modules/settings_panel');var SettingsService=require('modules/settings_service');var DialogService=require('modules/dialog_service');var EnumerateAll=require('shared/device_storage/enumerate_all');var WifiHelper=require('shared/wifi_helper');var wifiManager=WifiHelper.getWifiManager();return function ctor_selectCertificateWifi(){var elements={};return SettingsPanel({onInit:function(panel){elements={};elements.panel=panel;elements.certificateFilesList=panel.querySelector('.wifi-certificate-files-List');},onBeforeShow:function(panel){this._cleanup();this._createScanList(elements.certificateFilesList);},_cleanup:function(){while(elements.certificateFilesList.hasChildNodes()){elements.certificateFilesList.removeChild(elements.certificateFilesList.lastChild);}},_createScanList:function(list){var storages=navigator.getDeviceStorages('sdcard');var cursor=EnumerateAll(storages,'');cursor.onsuccess=function(){var file=cursor.result;if(file){var extension=this._parseExtension(file.name);if(this._isCertificateFile(extension)){var li=this._createLinkAnchor(file);list.appendChild(li);}
cursor.continue();}}.bind(this);cursor.onerror=function(){console.warn('failed to get file:'+cursor.error.name);};},_setCertificateItemsEnabled:function(enabled){var items=elements.certificateFilesList.querySelectorAll('li');var update=enabled?function(item){item.classList.remove('disabled');}:function(item){item.classList.add('disabled');};for(var i=0;i<items.length;i++){update(items[i]);}},_createLinkAnchor:function(file){var anchor=document.createElement('a');var certificateName=this._parseFilename(file.name);anchor.textContent=certificateName;var li=document.createElement('li');li.appendChild(anchor);anchor.onclick=()=>{DialogService.show('wifi-enterCertificateNickname',{certificateName:certificateName}).then((result)=>{var type=result.type;var value=result.value;if(type==='submit'){var certRequest=wifiManager.importCert(file,'',value.nickname);this._setCertificateItemsEnabled(false);certRequest.onsuccess=()=>{SettingsService.navigate('wifi-manageCertificates');};certRequest.onerror=()=>{DialogService.alert('certificate-import-failed-description',{title:'certificate-import-failed'}).then(()=>{this._setCertificateItemsEnabled(true);});};}});};return li;},_parseFilename:function(path){return path.slice(path.lastIndexOf('/')+1,path.lastIndexOf('.'));},_parseExtension:function(filename){var array=filename.split('.');return array.length>1?array.pop():'';},_isCertificateFile:function(extension){var cerExtension=['cer','crt','pem','der'];return cerExtension.indexOf(extension)>-1;},});};});

View file

@ -0,0 +1,50 @@
define('panels/wifi_status/panel',["require", "modules/dialog_panel", "shared/wifi_helper", "modules/wifi_context"],function(require) {
'use strict';
var DialogPanel = require('modules/dialog_panel');
var WifiHelper = require('shared/wifi_helper');
var WifiContext = require('modules/wifi_context');
var wifiManager = WifiHelper.getWifiManager();
return function ctor_statusWifi() {
var elements = {};
return DialogPanel({
onInit: function(panel) {
elements = {};
elements.ip = panel.querySelector('[data-ip]');
elements.speed = panel.querySelector('[data-speed]');
elements.ssid = panel.querySelector('[data-ssid]');
elements.signal = panel.querySelector('[data-signal]');
elements.security = panel.querySelector('[data-security]');
},
onBeforeShow: function(panel, options) {
this._updateNetworkInfo();
elements.ssid.textContent = options.network.ssid;
elements.signal.setAttribute('data-l10n-id',
'signalLevel' + options.sl);
if (options.security) {
elements.security.removeAttribute('data-l10n-id');
elements.security.textContent = options.security;
} else {
elements.security.setAttribute('data-l10n-id', 'securityNone');
}
WifiContext.addEventListener('wifiConnectionInfoUpdate',
this._updateNetworkInfo);
},
onBeforeHide: function() {
WifiContext.removeEventListener('wifiConnectionInfoUpdate',
this._updateNetworkInfo);
},
_updateNetworkInfo: function() {
var info = wifiManager.connectionInformation || {};
elements.ip.textContent = info.ipAddress || '';
document.l10n.setAttributes(elements.speed,
Number.isFinite(info.linkSpeed) ? 'linkSpeedMbs' : 'unavailable',
Number.isFinite(info.linkSpeed) ? { linkSpeed: info.linkSpeed } : {});
}
});
};
});