Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/apps/system/js/modal_dialog.js
diff options
context:
space:
mode:
Diffstat (limited to 'apps/system/js/modal_dialog.js')
-rw-r--r--apps/system/js/modal_dialog.js443
1 files changed, 443 insertions, 0 deletions
diff --git a/apps/system/js/modal_dialog.js b/apps/system/js/modal_dialog.js
new file mode 100644
index 0000000..33f3201
--- /dev/null
+++ b/apps/system/js/modal_dialog.js
@@ -0,0 +1,443 @@
+/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+'use strict';
+
+// The modal dialog listen to mozbrowsershowmodalprompt event.
+// Blocking the current app and then show cutom modal dialog
+// (alert/confirm/prompt)
+
+var ModalDialog = {
+ // Used for element id access.
+ // e.g., 'modal-dialog-alert-ok'
+ prefix: 'modal-dialog-',
+
+ // DOM
+ elements: {},
+
+ // Get all elements when inited.
+ getAllElements: function md_getAllElements() {
+ var elementsID = ['alert', 'alert-ok', 'alert-message',
+ 'prompt', 'prompt-ok', 'prompt-cancel', 'prompt-input', 'prompt-message',
+ 'confirm', 'confirm-ok', 'confirm-cancel', 'confirm-message',
+ 'select-one', 'select-one-cancel', 'select-one-menu', 'select-one-title',
+ 'alert-title', 'confirm-title', 'prompt-title'];
+
+ var toCamelCase = function toCamelCase(str) {
+ return str.replace(/\-(.)/g, function replacer(str, p1) {
+ return p1.toUpperCase();
+ });
+ };
+
+ // Loop and add element with camel style name to Modal Dialog attribute.
+ elementsID.forEach(function createElementRef(name) {
+ this.elements[toCamelCase(name)] =
+ document.getElementById(this.prefix + name);
+ }, this);
+
+ this.screen = document.getElementById('screen');
+ this.overlay = document.getElementById('dialog-overlay');
+ },
+
+ // Save the events returned by mozbrowsershowmodalprompt for later use.
+ // The events are stored according to webapp origin
+ // e.g., 'http://uitest.gaiamobile.org': evt
+ currentEvents: {},
+
+ init: function md_init() {
+ // Get all elements initially.
+ this.getAllElements();
+ var elements = this.elements;
+
+ // Bind events
+ window.addEventListener('mozbrowsershowmodalprompt', this);
+ window.addEventListener('appopen', this);
+ window.addEventListener('appwillclose', this);
+ window.addEventListener('appterminated', this);
+ window.addEventListener('resize', this);
+ window.addEventListener('keyboardchange', this);
+ window.addEventListener('keyboardhide', this);
+ window.addEventListener('home', this);
+ window.addEventListener('holdhome', this);
+
+ for (var id in elements) {
+ var tagName = elements[id].tagName.toLowerCase();
+ if (tagName == 'button' || tagName == 'ul') {
+ elements[id].addEventListener('click', this);
+ }
+ }
+ },
+
+ // Default event handler
+ handleEvent: function md_handleEvent(evt) {
+ var elements = this.elements;
+ switch (evt.type) {
+ case 'mozbrowsershowmodalprompt':
+ var frameType = evt.target.dataset.frameType;
+ if (frameType != 'window' && frameType != 'inline-activity')
+ return;
+
+ evt.preventDefault();
+ var origin = evt.target.dataset.frameOrigin;
+ this.currentEvents[origin] = evt;
+
+ // Show modal dialog only if
+ // the frame is currently displayed.
+ if (origin == WindowManager.getDisplayedApp() ||
+ frameType == 'inline-activity')
+ this.show(evt.target, origin);
+ break;
+
+ case 'click':
+ if (evt.currentTarget === elements.confirmCancel ||
+ evt.currentTarget === elements.promptCancel ||
+ evt.currentTarget === elements.selectOneCancel) {
+ this.cancelHandler();
+ } else if (evt.currentTarget === elements.selectOneMenu) {
+ this.selectOneHandler(evt.target);
+ } else {
+ this.confirmHandler();
+ }
+ break;
+
+ case 'appopen':
+ this.show(evt.target, evt.detail.origin);
+ break;
+
+ case 'home':
+ case 'holdhome':
+ // Inline activity, which origin is different from foreground app
+ if (this.isVisible() &&
+ this.currentOrigin != WindowManager.getDisplayedApp())
+ this.cancelHandler();
+ break;
+
+ case 'appwillclose':
+ // Do nothing if the app is closed at background.
+ if (evt.detail.origin !== this.currentOrigin)
+ return;
+
+ // Reset currentOrigin
+ this.hide();
+ break;
+
+ case 'appterminated':
+ if (this.currentEvents[evt.detail.origin])
+ delete this.currentEvents[evt.detail.origin];
+
+ break;
+
+ case 'resize':
+ case 'keyboardhide':
+ if (!this.currentOrigin)
+ return;
+
+ this.setHeight(window.innerHeight - StatusBar.height);
+ break;
+
+ case 'keyboardchange':
+ this.setHeight(window.innerHeight -
+ evt.detail.height - StatusBar.height);
+ break;
+ }
+ },
+
+ setHeight: function md_setHeight(height) {
+ if (this.isVisible())
+ this.overlay.style.height = height + 'px';
+ },
+
+ // Show relative dialog and set message/input value well
+ show: function md_show(target, origin) {
+ if (!(origin in this.currentEvents))
+ return;
+
+ var _ = navigator.mozL10n.get;
+ var evt = this.currentEvents[origin];
+ this.currentOrigin = origin;
+
+ var message = evt.detail.message || '';
+ var elements = this.elements;
+ this.screen.classList.add('modal-dialog');
+
+ function escapeHTML(str) {
+ var span = document.createElement('span');
+ span.textContent = str;
+ // Escape space for displaying multiple space in message.
+ span.innerHTML = span.innerHTML.replace(/\n/g, '<br/>');
+ return span.innerHTML;
+ }
+
+ var type = evt.detail.promptType || evt.detail.type;
+ if (type !== 'selectone') {
+ message = escapeHTML(message);
+ }
+
+ switch (type) {
+ case 'alert':
+ elements.alertMessage.innerHTML = message;
+ elements.alert.classList.add('visible');
+ this.setTitle('alert', '');
+ elements.alertOk.textContent = evt.yesText ? evt.yesText : _('ok');
+ break;
+
+ case 'prompt':
+ elements.prompt.classList.add('visible');
+ elements.promptInput.value = evt.detail.initialValue;
+ elements.promptMessage.innerHTML = message;
+ this.setTitle('prompt', '');
+ elements.promptOk.textContent = evt.yesText ? evt.yesText : _('ok');
+ elements.promptCancel.textContent = evt.noText ?
+ evt.noText : _('cancel');
+ break;
+
+ case 'confirm':
+ elements.confirm.classList.add('visible');
+ elements.confirmMessage.innerHTML = message;
+ this.setTitle('confirm', '');
+ elements.confirmOk.textContent = evt.yesText ? evt.yesText : _('ok');
+ elements.confirmCancel.textContent = evt.noText ?
+ evt.noText : _('cancel');
+ break;
+
+ case 'selectone':
+ this.buildSelectOneDialog(message);
+ elements.selectOne.classList.add('visible');
+ break;
+ }
+
+ this.setHeight(window.innerHeight - StatusBar.height);
+ },
+
+ hide: function md_hide() {
+ var evt = this.currentEvents[this.currentOrigin];
+ var type = evt.detail.promptType;
+ if (type == 'prompt') {
+ this.elements.promptInput.blur();
+ }
+ this.currentOrigin = null;
+ this.screen.classList.remove('modal-dialog');
+ this.elements[type].classList.remove('visible');
+ },
+
+ setTitle: function md_setTitle(type, title) {
+ this.elements[type + 'Title'].textContent = title;
+ },
+
+ // When user clicks OK button on alert/confirm/prompt
+ confirmHandler: function md_confirmHandler() {
+ this.screen.classList.remove('modal-dialog');
+ var elements = this.elements;
+
+ var evt = this.currentEvents[this.currentOrigin];
+
+ var type = evt.detail.promptType || evt.detail.type;
+ switch (type) {
+ case 'alert':
+ elements.alert.classList.remove('visible');
+ break;
+
+ case 'prompt':
+ evt.detail.returnValue = elements.promptInput.value;
+ elements.prompt.classList.remove('visible');
+ break;
+
+ case 'confirm':
+ evt.detail.returnValue = true;
+ elements.confirm.classList.remove('visible');
+ break;
+ }
+
+ if (evt.isPseudo && evt.callback) {
+ evt.callback(evt.detail.returnValue);
+ }
+
+ if (evt.detail.unblock)
+ evt.detail.unblock();
+
+ delete this.currentEvents[this.currentOrigin];
+ },
+
+ // When user clicks cancel button on confirm/prompt or
+ // when the user try to escape the dialog with the escape key
+ cancelHandler: function md_cancelHandler() {
+ var evt = this.currentEvents[this.currentOrigin];
+ this.screen.classList.remove('modal-dialog');
+ var elements = this.elements;
+
+ var type = evt.detail.promptType || evt.detail.type;
+ switch (type) {
+ case 'alert':
+ elements.alert.classList.remove('visible');
+ break;
+
+ case 'prompt':
+ /* return null when click cancel */
+ evt.detail.returnValue = null;
+ elements.prompt.classList.remove('visible');
+ break;
+
+ case 'confirm':
+ /* return false when click cancel */
+ evt.detail.returnValue = false;
+ elements.confirm.classList.remove('visible');
+ break;
+
+ case 'selectone':
+ /* return null when click cancel */
+ evt.detail.returnValue = null;
+ elements.selectOne.classList.remove('visible');
+ break;
+ }
+
+ if (evt.isPseudo && evt.cancelCallback) {
+ evt.cancelCallback(evt.detail.returnValue);
+ }
+
+ if (evt.detail.unblock)
+ evt.detail.unblock();
+
+ delete this.currentEvents[this.currentOrigin];
+ },
+
+ // When user selects an option on selectone dialog
+ selectOneHandler: function md_confirmHandler(target) {
+ this.screen.classList.remove('modal-dialog');
+ var elements = this.elements;
+
+ var evt = this.currentEvents[this.currentOrigin];
+
+ evt.detail.returnValue = target.id;
+ elements.selectOne.classList.remove('visible');
+
+ if (evt.isPseudo && evt.callback) {
+ evt.callback(evt.detail.returnValue);
+ }
+
+ if (evt.detail.unblock)
+ evt.detail.unblock();
+
+ delete this.currentEvents[this.currentOrigin];
+ },
+
+ buildSelectOneDialog: function md_buildSelectOneDialog(data) {
+ var elements = this.elements;
+ elements.selectOneTitle.textContent = data.title;
+ elements.selectOneMenu.innerHTML = '';
+
+ if (!data.options) {
+ return;
+ }
+
+ var itemsHTML = [];
+ for (var i = 0; i < data.options.length; i++) {
+ itemsHTML.push('<li><button id="');
+ itemsHTML.push(data.options[i].id);
+ itemsHTML.push('">');
+ itemsHTML.push(data.options[i].text);
+ itemsHTML.push('</button></li>');
+ }
+
+ elements.selectOneMenu.innerHTML = itemsHTML.join('');
+ },
+
+ /**
+ * Method about customized alert
+ * @param {String} title the title of the dialog. null or empty for
+ * no title.
+ * @param {String} text message for the dialog.
+ * @param {Object} confirm {title, callback} object when confirm.
+ */
+ alert: function md_alert(title, text, confirm) {
+ this.showWithPseudoEvent({
+ type: 'alert',
+ text: text,
+ callback: confirm.callback,
+ title: title,
+ yesText: confirm.title
+ });
+ },
+
+ /**
+ * Method about customized confirm
+ * @param {String} title the title of the dialog. null or empty for
+ * no title.
+ * @param {String} text message for the dialog.
+ * @param {Object} confirm {title, callback} object when confirm.
+ * @param {Object} cancel {title, callback} object when cancel.
+ */
+ confirm: function md_confirm(title, text, confirm, cancel) {
+ this.showWithPseudoEvent({
+ type: 'confirm',
+ text: text,
+ callback: confirm.callback,
+ cancel: cancel.callback,
+ title: title,
+ yesText: confirm.title,
+ noText: cancel.title
+ });
+ },
+
+ /**
+ * Method about customized prompt
+ * @param {String} title the title of the dialog. null or empty for
+ * no title.
+ * @param {String} text message for the dialog.
+ * @param {String} default_value message in the text field.
+ * @param {Object} confirm {title, callback} object when confirm.
+ * @param {Object} cancel {title, callback} object when cancel.
+ */
+ prompt: function md_prompt(title, text, default_value, confirm, cancel) {
+ this.showWithPseudoEvent({
+ type: 'prompt',
+ text: text,
+ initialValue: default_value,
+ callback: confirm.callback,
+ cancel: cancel.callback,
+ title: title,
+ yesText: confirm.title,
+ noText: cancel.title
+ });
+ },
+
+ selectOne: function md_selectOne(data, callback) {
+ this.showWithPseudoEvent({
+ type: 'selectone',
+ text: data,
+ callback: callback
+ });
+ },
+
+ showWithPseudoEvent: function md_showWithPseudoEvent(config) {
+ var pseudoEvt = {
+ isPseudo: true,
+ detail: {
+ unblock: null
+ }
+ };
+
+ pseudoEvt.detail.message = config.text;
+ pseudoEvt.callback = config.callback;
+ pseudoEvt.detail.promptType = config.type;
+ pseudoEvt.cancelCallback = config.cancel;
+ pseudoEvt.yesText = config.yesText;
+ pseudoEvt.noText = config.noText;
+ if (config.type == 'prompt') {
+ pseudoEvt.detail.initialValue = config.initialValue;
+ }
+
+ // Create a virtual mapping in this.currentEvents,
+ // since system-app uses the different way to call ModalDialog.
+ this.currentEvents['system'] = pseudoEvt;
+ this.show(null, 'system');
+ if (config.title)
+ this.setTitle(config.type, config.title);
+ },
+
+ isVisible: function md_isVisible() {
+ return this.screen.classList.contains('modal-dialog');
+ }
+};
+
+ModalDialog.init();
+