Notify users when there's an error installing an app (bug 694414)

This commit is contained in:
Kumar McMillan 2011-11-04 11:41:28 -05:00
Родитель b4aebfbc20
Коммит 08020c28d9
8 изменённых файлов: 284 добавлений и 10 удалений

Просмотреть файл

@ -120,3 +120,7 @@
{% endif %}
{% endif %}
</div> {# install-shell #}
{% if addon.is_webapp() %}
{% include 'addons/includes/apps_error_msg.html' %}
{% endif %}

Просмотреть файл

@ -0,0 +1,4 @@
<div class="apps-error-msg modal hidden popup error">
<h2></h2>
<p></p>
</div>

98
media/js/zamboni/apps.js Normal file
Просмотреть файл

@ -0,0 +1,98 @@
/*
Provides the apps module, a wrapper around navigator.mozApps
*/
(function(exports) {
"use strict";
/*
apps.install(manifestUrl, options)
It's just like navigator.apps.install with the following enhancements:
- If navigator.apps.install doesn't exist, an error is displayed
- If the install resulted in errors, they are displayed to the user
This requires at least one apps-error-msg div to be present.
See also: https://developer.mozilla.org/en/Apps/Apps_JavaScript_API/navigator.mozApps.install
The recognized option attributes are as follows:
data
Optional dict to pass as navigator.apps.install(url, data, ...)
success
Optional callback for when app installation was successful
error
Optional callback for when app installation resulted in error
errModalCallback
Callback to pass into $.modal(...)
domContext
Something other than document, useful for testing
navigator
Something other than the global navigator, useful for testing
*/
exports.install = function(manifestUrl, opt) {
opt = $.extend({'domContext': document,
'navigator': navigator,
'data': undefined,
'success': undefined,
'error': undefined,
'errModalCallback': undefined}, opt || {});
var self = this,
errSummary,
showError = true;
/* Try and install the app. */
if (opt.navigator.mozApps && opt.navigator.mozApps.install) {
opt.navigator.mozApps.install(manifestUrl, opt.data, opt.success, function(errorOb) {
switch (errorOb.code) {
case 'denied':
// User canceled installation.
showError = false;
break;
case 'permissionDenied':
errSummary = gettext('App installation not allowed');
break;
case 'manifestURLError':
errSummary = gettext('App manifest is malformed');
break;
case 'networkError':
errSummary = gettext('App host could not be reached');
break;
case 'manifestParseError':
errSummary = gettext('App manifest is unparsable');
break;
case 'invalidManifest':
errSummary = gettext('App manifest is invalid');
break;
default:
errSummary = gettext('Unknown error');
break;
}
if (showError) {
self._showError(errSummary, errorOb.message, opt);
}
if (opt.error) {
opt.error.call(this, errorOb);
}
});
} else {
self._showError(gettext('App installation failed'),
gettext('This system does not support installing apps'),
opt);
}
};
exports._showError = function(errSummary, errMessage, opt) {
var $errTarget = $('<a>'),
$modal = $('.apps-error-msg:first', opt.domContext).modal(
$errTarget,
{width: '400px', close: true,
callback: opt.errModalCallback});
$errTarget.trigger('click'); // show the modal
$('.apps-error-msg h2', opt.domContext).text(errSummary);
$('.apps-error-msg p', opt.domContext).text(errMessage);
$(opt.domContext).trigger('error_shown.apps');
};
})(typeof exports === 'undefined' ? (this.apps = {}) : exports);

Просмотреть файл

@ -127,16 +127,11 @@ var purchases = {
}
},
install_app: function(url, receipt) {
/* Try and install the app. */
if (navigator.mozApps && navigator.mozApps.install) {
var data = {};
if(receipt) {
data['receipt'] = receipt;
}
navigator.mozApps.install(url, data);
} else {
// Notify that it can't be installed.
var data = {};
if(receipt) {
data['receipt'] = receipt;
}
apps.install(url, {data: data});
}
};

Просмотреть файл

@ -278,6 +278,10 @@
function initWebapp() {
//
// TODO(Kumar) When this is fixed, integrate with
// apps.install(manifestURL). See bug 699828
//
if (navigator.mozApps && navigator.mozApps.install) {
dom.self.find('.button')
.removeClass('disabled')

Просмотреть файл

@ -0,0 +1,162 @@
$(document).ready(function(){
module('apps errors', {
setup: function() {
this.sandbox = tests.createSandbox('#apps-error-msg');
},
teardown: function() {
this.sandbox.remove();
},
installAppWithError: function(manifestUrl, errorOb, errModalCallback) {
var sb = this.sandbox,
nav = {};
nav.mozApps = {
install: function(manifestUrl, data, success, error) {
error(errorOb);
}
};
if (!errModalCallback) {
errModalCallback = function() {
// False tells the modal code not to execute all the dom
// re-positioning for rendering. Otherwise this makes
// verifying the sandbox hard.
return false;
};
}
apps.install('http://nice.com/nice.webapp', {domContext: sb,
navigator: nav,
errModalCallback: errModalCallback});
}
});
asyncTest('test permission error', function() {
var sb = this.sandbox;
$(sb).one('error_shown.apps', function() {
equals($('.apps-error-msg h2', sb).text(),
'App installation not allowed');
equals($('.apps-error-msg p', sb).text(), 'detailed message');
start();
});
this.installAppWithError('http://nice.com/nice.webapp',
{code: 'permissionDenied',
message: "detailed message"});
});
test('test user canceled', function() {
var sb = this.sandbox,
callback;
callback = function() {
ok(false, 'dialog should not be shown when a user cancels install');
return false;
};
this.installAppWithError('http://nice.com/nice.webapp',
{code: 'denied',
message: 'user canceled installation'},
callback);
});
asyncTest('test unexpected error', function() {
var sb = this.sandbox;
$(sb).one('error_shown.apps', function() {
equals($('.apps-error-msg h2', sb).text(), 'Unknown error');
equals($('.apps-error-msg p', sb).text(), 'surprise');
start();
});
this.installAppWithError('http://nice.com/nice.webapp', {code: 'bogus',
message: "surprise"});
});
test('test successful app install', function() {
var sb = this.sandbox,
nav = {},
callback;
nav.mozApps = {
install: function(manifestUrl, data, success, error) {}
};
callback = function() {
ok(false, 'dialog should not be shown on successful app install');
return false;
};
apps.install('http://nice.com/nice.webapp', {domContext: sb,
navigator: nav,
errModalCallback: callback});
});
module('apps as wrapper', {
setup: function() {
this.sandbox = tests.createSandbox('#apps-error-msg');
},
teardown: function() {
this.sandbox.remove();
}
});
asyncTest('success callback', function() {
var sb = this.sandbox,
nav = {},
callback;
nav.mozApps = {
install: function(manifestUrl, data, success, error) {
success();
}
};
callback = function() {
ok(true, 'success was called');
start();
}
apps.install('http://nice.com/nice.webapp', {domContext: sb,
navigator: nav,
success: callback});
});
asyncTest('data', function() {
var sb = this.sandbox,
nav = {},
callback,
dataReceived;
nav.mozApps = {
install: function(manifestUrl, data, success, error) {
dataReceived = data;
success();
}
};
callback = function() {
equals(dataReceived.receipt, '<receipt>');
start();
}
apps.install('http://nice.com/nice.webapp', {domContext: sb,
navigator: nav,
success: callback,
data: {receipt: '<receipt>'}});
});
asyncTest('error callback', function() {
var sb = this.sandbox,
nav = {},
callback;
nav.mozApps = {
install: function(manifestUrl, data, success, error) {
error({code: 'someCode', message: 'some message'});
}
};
callback = function(errOb) {
equals(errOb.code, 'someCode');
start();
}
apps.install('http://nice.com/nice.webapp', {domContext: sb,
navigator: nav,
errModalCallback: function() { return false; },
error: callback});
});
});

Просмотреть файл

@ -536,7 +536,7 @@ MINIFY_BUNDLES = {
),
},
'js': {
# JS files common to the entire site.
# JS files common to the entire site (pre-impala).
'common': (
'js/lib/jquery-1.6.4.js',
'js/lib/underscore.js',
@ -616,6 +616,7 @@ MINIFY_BUNDLES = {
'js/zamboni/format.js',
'js/lib/jquery.cookie.js',
'js/zamboni/storage.js',
'js/zamboni/apps.js',
'js/zamboni/buttons.js',
'js/lib/jquery.pjax.js',
'js/impala/footer.js',
@ -753,6 +754,7 @@ MINIFY_BUNDLES = {
'js/lib/jquery.cookie.js',
'js/lib/jquery.pjax.js',
'js/impala/pjax.js',
'js/zamboni/apps.js',
'js/zamboni/browser.js',
'js/zamboni/init.js',
'js/impala/capabilities.js',

Просмотреть файл

@ -229,4 +229,9 @@
</div>
</section>
</div>
<div id="apps-error-msg">
{% include 'addons/includes/apps_error_msg.html' %}
</div>
{% endblock %}