Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/apps/system/js/popup_manager.js
diff options
context:
space:
mode:
Diffstat (limited to 'apps/system/js/popup_manager.js')
-rw-r--r--apps/system/js/popup_manager.js313
1 files changed, 313 insertions, 0 deletions
diff --git a/apps/system/js/popup_manager.js b/apps/system/js/popup_manager.js
new file mode 100644
index 0000000..583c9c8
--- /dev/null
+++ b/apps/system/js/popup_manager.js
@@ -0,0 +1,313 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+'use strict';
+
+var PopupManager = {
+ _currentPopup: {},
+ _currentOrigin: '',
+ _endTimes: 0,
+ _startTimes: 0,
+
+ throbber: document.getElementById('popup-throbber'),
+
+ overlay: document.getElementById('dialog-overlay'),
+
+ popupContainer: document.getElementById('popup-container'),
+
+ container: document.getElementById('frame-container'),
+
+ screen: document.getElementById('screen'),
+
+ closeButton: document.getElementById('popup-close'),
+
+ errorTitle: document.getElementById('popup-error-title'),
+
+ errorMessage: document.getElementById('popup-error-message'),
+
+ errorReload: document.getElementById('popup-error-reload'),
+
+ errorBack: document.getElementById('popup-error-back'),
+
+ init: function pm_init() {
+ this.title = document.getElementById('popup-title');
+ window.addEventListener('mozbrowseropenwindow', this);
+ window.addEventListener('mozbrowserclose', this);
+ window.addEventListener('appwillclose', this);
+ window.addEventListener('appopen', this);
+ window.addEventListener('appterminated', this);
+ window.addEventListener('home', this);
+ window.addEventListener('keyboardhide', this);
+ window.addEventListener('keyboardchange', this);
+ this.closeButton.addEventListener('click', this);
+ this.errorReload.addEventListener('click', this);
+ this.errorBack.addEventListener('click', this);
+ },
+
+ open: function pm_open(frame, origin) {
+ // Only one popup per origin at a time.
+ // If the popup is being shown, we swap frames.
+ if (this._currentPopup[origin]) {
+ this.container.removeChild(this._currentPopup[origin]);
+ delete this._currentPopup[origin];
+ }
+
+ this.title.textContent = this.getTitleFromUrl(frame.dataset.url);
+
+ // Reset overlay height
+ this.setHeight(window.innerHeight - StatusBar.height);
+
+ this._currentPopup[origin] = frame;
+
+ var popup = this._currentPopup[origin];
+ var dataset = popup.dataset;
+ dataset.frameType = 'popup';
+ dataset.frameName = name;
+ dataset.frameOrigin = origin;
+
+ // this seems needed, or an override to origin in close()
+ this._currentOrigin = origin;
+
+ this.container.appendChild(popup);
+
+ this.screen.classList.add('popup');
+
+ popup.addEventListener('mozbrowsererror', this);
+ popup.addEventListener('mozbrowserloadend', this);
+ popup.addEventListener('mozbrowserloadstart', this);
+ popup.addEventListener('mozbrowserlocationchange', this);
+ },
+
+ close: function pm_close(evt) {
+ if (evt && (!'frameType' in evt.target.dataset ||
+ evt.target.dataset.frameType !== 'popup'))
+ return;
+
+ var self = this;
+ this.popupContainer.addEventListener('transitionend', function wait(event) {
+ self.popupContainer.removeEventListener('transitionend', wait);
+ self.screen.classList.remove('popup');
+ self.popupContainer.classList.remove('disappearing');
+ self.container.removeChild(self._currentPopup[self._currentOrigin]);
+ delete self._currentPopup[self._currentOrigin];
+ });
+
+ this.popupContainer.classList.add('disappearing');
+
+ // We just removed the focused window leaving the system
+ // without any focused window, let's fix this.
+ window.focus();
+ },
+
+ backHandling: function pm_backHandling() {
+ if (!this._currentPopup[this._currentOrigin])
+ return;
+
+ this.close();
+ },
+
+ isVisible: function pm_isVisible() {
+ return (this._currentPopup[this._currentOrigin] != null);
+ },
+
+ setHeight: function pm_setHeight(height) {
+ if (this.isVisible())
+ this.overlay.style.height = height + 'px';
+ },
+
+ handleEvent: function pm_handleEvent(evt) {
+ switch (evt.type) {
+ case 'click':
+ switch (evt.target) {
+ case this.closeButton:
+ this.backHandling();
+ break;
+
+ case this.errorBack:
+ this.backHandling();
+ break;
+
+ case this.errorReload:
+ this.container.classList.remove('error');
+ delete this._currentPopup[this._currentOrigin].dataset.error;
+ this._currentPopup[this._currentOrigin].reload(true);
+ break;
+ }
+ break;
+
+ case 'mozbrowserloadstart':
+ this.throbber.classList.add('loading');
+ break;
+
+ case 'mozbrowserloadend':
+ this.throbber.classList.remove('loading');
+ break;
+
+ case 'mozbrowserlocationchange':
+ evt.target.dataset.url = evt.detail;
+ this.show();
+ break;
+
+ case 'mozbrowsererror':
+ this._currentPopup[evt.target.dataset.frameOrigin].dataset.error = true;
+ this.showError();
+ break;
+
+ case 'mozbrowseropenwindow':
+ var detail = evt.detail;
+ var openerType = evt.target.dataset.frameType;
+ var openerOrigin = evt.target.dataset.frameOrigin;
+
+ // Only app frame is allowed to launch popup
+ if (openerType !== 'window')
+ return;
+
+ // <a href="" target="_blank"> links should opened outside the app
+ // itself and fire an activity to be opened into a new browser window.
+ if (detail.name === '_blank') {
+ new MozActivity({ name: 'view',
+ data: { type: 'url', url: detail.url }});
+ return;
+ }
+
+ this.throbber.classList.remove('loading');
+
+ var frame = detail.frameElement;
+ frame.dataset.url = detail.url;
+
+ this.container.classList.remove('error');
+ this.open(frame, openerOrigin);
+
+ break;
+
+ case 'mozbrowserclose':
+ this.close(evt);
+ break;
+
+ case 'home':
+ // Reset overlay height before hiding
+ this.setHeight(window.innerHeight - StatusBar.height);
+ this.hide(this._currentOrigin);
+ break;
+
+ case 'appwillclose':
+ if (!this._currentPopup[evt.detail.origin])
+ return;
+
+ this.hide(evt.detail.origin);
+ break;
+
+ case 'appopen':
+ this._currentOrigin = evt.detail.origin;
+ this.show();
+ break;
+
+ case 'appterminated':
+ if (!this._currentPopup[evt.detail.origin])
+ return;
+ this.close(evt.detail.origin);
+ break;
+
+ case 'keyboardchange':
+ this.setHeight(window.innerHeight -
+ StatusBar.height - evt.detail.height);
+ break;
+
+ case 'keyboardhide':
+ this.setHeight(window.innerHeight - StatusBar.height);
+ break;
+ }
+ },
+
+ showError: function pm_showError() {
+ if (!('error' in this._currentPopup[this._currentOrigin].dataset)) {
+ this.container.classList.remove('error');
+ return;
+ }
+
+ var contentOrigin =
+ this.getTitleFromUrl(this._currentPopup[this._currentOrigin].dataset.url);
+ var _ = navigator.mozL10n.get;
+
+ if (AirplaneMode.enabled) {
+ this.errorTitle.textContent = _('airplane-is-on');
+ this.errorMessage.textContent = _('airplane-is-turned-on',
+ {name: contentOrigin});
+ } else if (!navigator.onLine) {
+ this.errorTitle.textContent = _('network-connection-unavailable');
+ this.errorMessage.textContent = _('network-error', {name: contentOrigin});
+ } else {
+ this.errorTitle.textContent = _('error-title', {name: contentOrigin});
+ this.errorMessage.textContent = _('error-message', {name: contentOrigin});
+ }
+ this.container.classList.add('error');
+ },
+
+ // This is for card view to request
+ // Return nothing if the content is the same origin as opener
+ // Return URL if the content is off-origin
+ getOpenedOriginFromOpener: function pm_getOpenedOriginOpener(origin) {
+ var opened = this._getOriginObject(this._currentPopup[origin].dataset.url);
+ var opener = this._getOriginObject(origin);
+ // Same origin means: Protocol, Domain, Port
+ if (opened.protocol == opener.protocol &&
+ opened.hostname == opener.hostname &&
+ opened.port == opener.port) {
+ return '';
+ } else {
+ return opened.protocol + '//' + opened.hostname;
+ }
+ },
+
+ getTitleFromUrl: function pm_getTitleFromUrl(url) {
+ var app = WindowManager.getCurrentDisplayedApp();
+ var opened = this._getOriginObject(url);
+ var opener = this._getOriginObject(app.frame.dataset.frameOrigin);
+ // Same origin means: Protocol, Domain, Port
+ if (opened.protocol == opener.protocol &&
+ opened.hostname == opener.hostname &&
+ opened.port == opener.port) {
+ return app.name;
+ } else {
+ return opened.protocol + '//' + opened.hostname;
+ }
+ },
+
+ _getOriginObject: function pm__getOriginObject(url) {
+ var parser = document.createElement('a');
+ parser.href = url;
+
+ return {
+ protocol: parser.protocol,
+ hostname: parser.hostname,
+ port: parser.port
+ };
+ },
+
+ getPopupFromOrigin: function pm_getPopupFromOrigin(origin) {
+ return this._currentPopup[origin];
+ },
+
+ show: function pm_show() {
+ if (!this._currentPopup[this._currentOrigin])
+ return;
+
+
+ this.showError();
+ this.screen.classList.add('popup');
+
+ var popup = this._currentPopup[this._currentOrigin];
+ this.title.textContent = this.getTitleFromUrl(popup.dataset.url);
+ popup.hidden = false;
+ },
+
+ hide: function pm_hide(origin) {
+ if (!this._currentPopup[origin])
+ return;
+
+ this.screen.classList.remove('popup');
+ this._currentPopup[origin].hidden = true;
+ }
+};
+
+PopupManager.init();
+