'use strict'; var AppInstallManager = { mapDownloadErrorsToMessage: { 'NETWORK_ERROR': 'download-failed', 'DOWNLOAD_ERROR': 'download-failed', 'MISSING_MANIFEST': 'install-failed', 'INVALID_MANIFEST': 'install-failed', 'INSTALL_FROM_DENIED': 'install-failed', 'INVALID_SECURITY_LEVEL': 'install-failed', 'INVALID_PACKAGE': 'install-failed', 'APP_CACHE_DOWNLOAD_ERROR': 'download-failed' }, init: function ai_init() { this.dialog = document.getElementById('app-install-dialog'); this.msg = document.getElementById('app-install-message'); this.size = document.getElementById('app-install-size'); this.authorName = document.getElementById('app-install-author-name'); this.authorUrl = document.getElementById('app-install-author-url'); this.installButton = document.getElementById('app-install-install-button'); this.cancelButton = document.getElementById('app-install-cancel-button'); this.installCancelDialog = document.getElementById('app-install-cancel-dialog'); this.downloadCancelDialog = document.getElementById('app-download-cancel-dialog'); this.confirmCancelButton = document.getElementById('app-install-confirm-cancel-button'); this.resumeButton = document.getElementById('app-install-resume-button'); this.notifContainer = document.getElementById('install-manager-notification-container'); this.appInfos = {}; window.addEventListener('mozChromeEvent', (function ai_handleChromeEvent(e) { if (e.detail.type == 'webapps-ask-install') { this.handleAppInstallPrompt(e.detail); } }).bind(this)); window.addEventListener('applicationinstall', this.handleApplicationInstall.bind(this)); this.installButton.onclick = this.handleInstall.bind(this); this.cancelButton.onclick = this.showInstallCancelDialog.bind(this); this.confirmCancelButton.onclick = this.handleInstallCancel.bind(this); this.resumeButton.onclick = this.hideInstallCancelDialog.bind(this); this.notifContainer.onclick = this.showDownloadCancelDialog.bind(this); this.downloadCancelDialog.querySelector('.confirm').onclick = this.handleConfirmDownloadCancel.bind(this); this.downloadCancelDialog.querySelector('.cancel').onclick = this.handleCancelDownloadCancel.bind(this); // bind these handlers so that we can have only one instance and check // them later on ['handleDownloadSuccess', 'handleDownloadError', 'handleProgress', 'handleApplicationReady' ].forEach(function(name) { this[name] = this[name].bind(this); }, this); window.addEventListener('applicationready', this.handleApplicationReady); }, handleApplicationReady: function ai_handleApplicationReady(e) { window.removeEventListener('applicationready', this.handleApplicationReady); var apps = e.detail.applications; Object.keys(apps) .filter(function(key) { return apps[key].installState === 'pending'; }) .map(function(key) { return apps[key]; }) .forEach(this.prepareForDownload, this); }, handleApplicationInstall: function ai_handleApplicationInstallEvent(e) { var app = e.detail.application; if (app.installState === 'installed') { this.showInstallSuccess(app); return; } this.prepareForDownload(app); }, handleAppInstallPrompt: function ai_handleInstallPrompt(detail) { var _ = navigator.mozL10n.get; var app = detail.app; // updateManifest is used by packaged apps until they are installed var manifest = app.manifest ? app.manifest : app.updateManifest; if (!manifest) return; this.dialog.classList.add('visible'); var id = detail.id; if (manifest.size) { this.size.textContent = this.humanizeSize(manifest.size); } else { this.size.textContent = _('unknown'); } // Wrap manifest to get localized properties manifest = new ManifestHelper(manifest); var msg = _('install-app', {'name': manifest.name}); this.msg.textContent = msg; if (manifest.developer) { this.authorName.textContent = manifest.developer.name || _('unknown'); this.authorUrl.textContent = manifest.developer.url || ''; } else { this.authorName.textContent = _('unknown'); this.authorUrl.textContent = ''; } this.installCallback = (function ai_installCallback() { this.dispatchResponse(id, 'webapps-install-granted'); }).bind(this); this.installCancelCallback = (function ai_cancelCallback() { this.dispatchResponse(id, 'webapps-install-denied'); }).bind(this); }, handleInstall: function ai_handleInstall(evt) { if (evt) evt.preventDefault(); if (this.installCallback) this.installCallback(); this.installCallback = null; this.dialog.classList.remove('visible'); }, prepareForDownload: function ai_prepareForDownload(app) { var manifestURL = app.manifestURL; this.appInfos[manifestURL] = {}; // these methods are already bound to |this| app.ondownloadsuccess = this.handleDownloadSuccess; app.ondownloaderror = this.handleDownloadError; app.onprogress = this.handleProgress; }, showInstallSuccess: function ai_showInstallSuccess(app) { var manifest = app.manifest || app.updateManifest; var name = new ManifestHelper(manifest).name; var _ = navigator.mozL10n.get; var msg = _('app-install-success', { appName: name }); SystemBanner.show(msg); }, handleDownloadSuccess: function ai_handleDownloadSuccess(evt) { var app = evt.application; this.showInstallSuccess(app); this.onDownloadStop(app); this.onDownloadFinish(app); }, handleDownloadError: function ai_handleDownloadError(evt) { var app = evt.application; var _ = navigator.mozL10n.get; var manifest = app.manifest || app.updateManifest; var name = new ManifestHelper(manifest).name; var errorName = app.downloadError.name; switch (errorName) { case 'INSUFFICIENT_STORAGE': var title = _('not-enough-space'), buttonText = _('ok'), message = _('not-enough-space-message'); ModalDialog.alert(title, message, {title: buttonText}); break; default: // showing the real error to a potential developer console.info('downloadError event, error code is', errorName); var key = this.mapDownloadErrorsToMessage[errorName] || 'generic-error'; var msg = _('app-install-' + key, { appName: name }); SystemBanner.show(msg); } this.onDownloadStop(app); }, onDownloadStart: function ai_onDownloadStart(app) { if (! this.hasNotification(app)) { StatusBar.incSystemDownloads(); this.addNotification(app); this.requestWifiLock(app); } }, onDownloadStop: function ai_onDownloadStop(app) { if (this.hasNotification(app)) { StatusBar.decSystemDownloads(); this.removeNotification(app); this.releaseWifiLock(app); } }, hasNotification: function ai_hasNotification(app) { var appInfo = this.appInfos[app.manifestURL]; return appInfo && !!appInfo.installNotification; }, onDownloadFinish: function ai_onDownloadFinish(app) { delete this.appInfos[app.manifestURL]; // check if these are our handlers before removing them if (app.ondownloadsuccess === this.handleDownloadSuccess) { app.ondownloadsuccess = null; } if (app.ondownloaderror === this.handleDownloadError) { app.ondownloaderror = null; } if (app.onprogress === this.handleProgress) { app.onprogress = null; } }, addNotification: function ai_addNotification(app) { // should be unique (this is used already in applications.js) var manifestURL = app.manifestURL, manifest = app.manifest || app.updateManifest, appInfo = this.appInfos[manifestURL]; if (appInfo.installNotification) { return; } var newNotif = '