зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1108096 - Langpack support for b2g/gaia r=ferjm,sicking
This commit is contained in:
Родитель
9e379bcc00
Коммит
2440b76622
|
@ -354,6 +354,15 @@ this.DOMApplicationRegistry = {
|
||||||
aCallback(res);
|
aCallback(res);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getAdditionalLanguages: function(aManifestURL) {
|
||||||
|
for (let id in this.webapps) {
|
||||||
|
if (this.webapps[id].manifestURL == aManifestURL) {
|
||||||
|
return this.webapps[id].additionalLanguages || {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nsIAppsService API
|
* nsIAppsService API
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -22,6 +22,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebappOSUtils",
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||||
"resource://gre/modules/NetUtil.jsm");
|
"resource://gre/modules/NetUtil.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyServiceGetter(this, "appsService",
|
||||||
|
"@mozilla.org/AppsService;1",
|
||||||
|
"nsIAppsService");
|
||||||
|
|
||||||
// Shared code for AppsServiceChild.jsm, TrustedHostedAppsUtils.jsm,
|
// Shared code for AppsServiceChild.jsm, TrustedHostedAppsUtils.jsm,
|
||||||
// Webapps.jsm and Webapps.js
|
// Webapps.jsm and Webapps.js
|
||||||
|
|
||||||
|
@ -485,6 +489,7 @@ this.AppsUtils = {
|
||||||
* Checks if the app role is allowed:
|
* Checks if the app role is allowed:
|
||||||
* Only certified apps can be themes.
|
* Only certified apps can be themes.
|
||||||
* Only privileged or certified apps can be addons.
|
* Only privileged or certified apps can be addons.
|
||||||
|
* Langpacks need to be privileged.
|
||||||
* @param aRole : the role assigned to this app.
|
* @param aRole : the role assigned to this app.
|
||||||
* @param aStatus : the APP_STATUS_* for this app.
|
* @param aStatus : the APP_STATUS_* for this app.
|
||||||
*/
|
*/
|
||||||
|
@ -492,6 +497,13 @@ this.AppsUtils = {
|
||||||
if (aRole == "theme" && aStatus !== Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
|
if (aRole == "theme" && aStatus !== Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (aRole == "langpack" && aStatus !== Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
|
||||||
|
let allow = false;
|
||||||
|
try {
|
||||||
|
allow = Services.prefs.getBoolPref("dom.apps.allow_unsigned_langpacks");
|
||||||
|
} catch(e) {}
|
||||||
|
return allow;
|
||||||
|
}
|
||||||
if (!this.allowUnsignedAddons &&
|
if (!this.allowUnsignedAddons &&
|
||||||
(aRole == "addon" &&
|
(aRole == "addon" &&
|
||||||
aStatus !== Ci.nsIPrincipal.APP_STATUS_CERTIFIED &&
|
aStatus !== Ci.nsIPrincipal.APP_STATUS_CERTIFIED &&
|
||||||
|
@ -732,7 +744,16 @@ this.AppsUtils = {
|
||||||
// Returns the hash for a JS object.
|
// Returns the hash for a JS object.
|
||||||
computeObjectHash: function(aObject) {
|
computeObjectHash: function(aObject) {
|
||||||
return this.computeHash(JSON.stringify(aObject));
|
return this.computeHash(JSON.stringify(aObject));
|
||||||
}
|
},
|
||||||
|
|
||||||
|
getAppManifestURLFromWindow: function(aWindow) {
|
||||||
|
let appId = aWindow.document.nodePrincipal.appId;
|
||||||
|
if (appId === Ci.nsIScriptSecurityManager.NO_APP_ID) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return appsService.getManifestURLByLocalId(appId);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,315 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Cu = Components.utils;
|
||||||
|
const Cc = Components.classes;
|
||||||
|
const Ci = Components.interfaces;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||||
|
"@mozilla.org/parentprocessmessagemanager;1",
|
||||||
|
"nsIMessageBroadcaster");
|
||||||
|
|
||||||
|
this.EXPORTED_SYMBOLS = ["Langpacks"];
|
||||||
|
|
||||||
|
let debug = Services.prefs.getBoolPref("dom.mozApps.debug")
|
||||||
|
? (aMsg) => {
|
||||||
|
dump("-*-*- Langpacks: " + aMsg + "\n");
|
||||||
|
}
|
||||||
|
: (aMsg) => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Langpack support
|
||||||
|
*
|
||||||
|
* Manifest format is:
|
||||||
|
*
|
||||||
|
* "languages-target" : { "app://*.gaiamobile.org/manifest.webapp": "2.2" },
|
||||||
|
* "languages-provided": {
|
||||||
|
* "de": {
|
||||||
|
* "version": 201411051234,
|
||||||
|
* "name": "Deutsch",
|
||||||
|
* "apps": {
|
||||||
|
* "app://calendar.gaiamobile.org/manifest.webapp": "/de/calendar",
|
||||||
|
* "app://email.gaiamobile.org/manifest.webapp": "/de/email"
|
||||||
|
* }
|
||||||
|
* },
|
||||||
|
* "role" : "langpack"
|
||||||
|
*/
|
||||||
|
|
||||||
|
this.Langpacks = {
|
||||||
|
|
||||||
|
_data: {},
|
||||||
|
_broadcaster: null,
|
||||||
|
_appIdFromManifestURL: null,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
ppmm.addMessageListener("Webapps:GetLocalizationResource", this);
|
||||||
|
},
|
||||||
|
|
||||||
|
registerRegistryFunctions: function(aBroadcaster, aIdGetter) {
|
||||||
|
this._broadcaster = aBroadcaster;
|
||||||
|
this._appIdFromManifestURL = aIdGetter;
|
||||||
|
},
|
||||||
|
|
||||||
|
receiveMessage: function(aMessage) {
|
||||||
|
let data = aMessage.data;
|
||||||
|
let mm = aMessage.target;
|
||||||
|
switch (aMessage.name) {
|
||||||
|
case "Webapps:GetLocalizationResource":
|
||||||
|
this.getLocalizationResource(data, mm);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
debug("Unexpected message: " + aMessage.name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getAdditionalLanguages: function(aManifestURL) {
|
||||||
|
debug("getAdditionalLanguages " + aManifestURL);
|
||||||
|
let res = { langs: {} };
|
||||||
|
let langs = res.langs;
|
||||||
|
if (this._data[aManifestURL]) {
|
||||||
|
res.appId = this._data[aManifestURL].appId;
|
||||||
|
for (let lang in this._data[aManifestURL].langs) {
|
||||||
|
if (!langs[lang]) {
|
||||||
|
langs[lang] = [];
|
||||||
|
}
|
||||||
|
let current = this._data[aManifestURL].langs[lang];
|
||||||
|
langs[lang].push({
|
||||||
|
version: current.version,
|
||||||
|
name: current.name,
|
||||||
|
target: current.target
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug("Languages found: " + uneval(res));
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
|
sendAppUpdate: function(aManifestURL) {
|
||||||
|
debug("sendAppUpdate " + aManifestURL);
|
||||||
|
if (!this._broadcaster) {
|
||||||
|
debug("No broadcaster!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = this.getAdditionalLanguages(aManifestURL);
|
||||||
|
let message = {
|
||||||
|
id: res.appId,
|
||||||
|
app: {
|
||||||
|
additionalLanguages: res.langs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._broadcaster("Webapps:UpdateState", message);
|
||||||
|
},
|
||||||
|
|
||||||
|
getLocalizationResource: function(aData, aMm) {
|
||||||
|
debug("getLocalizationResource " + uneval(aData));
|
||||||
|
|
||||||
|
function sendError(aMsg, aCode) {
|
||||||
|
debug(aMsg);
|
||||||
|
aMm.sendAsyncMessage("Webapps:GetLocalizationResource:Return",
|
||||||
|
{ requestID: aData.requestID, oid: aData.oid, error: aCode });
|
||||||
|
}
|
||||||
|
|
||||||
|
// No langpack available for this app.
|
||||||
|
if (!this._data[aData.manifestURL]) {
|
||||||
|
return sendError("No langpack for this app.", "NoLangpack");
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have langpack(s) for this app, but not for this language.
|
||||||
|
if (!this._data[aData.manifestURL].langs[aData.lang]) {
|
||||||
|
return sendError("No language " + aData.lang + " for this app.",
|
||||||
|
"UnavailableLanguage");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that we have the right version.
|
||||||
|
let item = this._data[aData.manifestURL].langs[aData.lang];
|
||||||
|
if (item.target != aData.version) {
|
||||||
|
return sendError("No version " + aData.version + " for this app.",
|
||||||
|
"UnavailableVersion");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The path can't be an absolute uri.
|
||||||
|
if (isAbsoluteURI(aData.path)) {
|
||||||
|
return sendError("url can't be absolute.", "BadUrl");
|
||||||
|
}
|
||||||
|
|
||||||
|
let href = item.url + aData.path;
|
||||||
|
debug("Will load " + href);
|
||||||
|
|
||||||
|
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||||
|
.createInstance(Ci.nsIXMLHttpRequest);
|
||||||
|
xhr.mozBackgroundRequest = true;
|
||||||
|
xhr.open("GET", href);
|
||||||
|
|
||||||
|
// Default to text response type, but the webidl binding takes care of
|
||||||
|
// validating the dataType value.
|
||||||
|
xhr.responseType = "text";
|
||||||
|
if (aData.dataType === "json") {
|
||||||
|
xhr.responseType = "json";
|
||||||
|
} else if (aData.dataType === "binary") {
|
||||||
|
xhr.responseType = "blob";
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.addEventListener("load", function() {
|
||||||
|
debug("Success loading " + href);
|
||||||
|
if (xhr.status >= 200 && xhr.status < 400) {
|
||||||
|
aMm.sendAsyncMessage("Webapps:GetLocalizationResource:Return",
|
||||||
|
{ requestID: aData.requestID, oid: aData.oid, data: xhr.response });
|
||||||
|
} else {
|
||||||
|
sendError("Error loading " + href, "UnavailableResource");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
xhr.addEventListener("error", function() {
|
||||||
|
sendError("Error loading " + href, "UnavailableResource");
|
||||||
|
});
|
||||||
|
xhr.send(null);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Validates the langpack part of a manifest.
|
||||||
|
checkManifest: function(aManifest) {
|
||||||
|
if (!("languages-target" in aManifest)) {
|
||||||
|
debug("Error: no 'languages-target' property.")
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!("languages-provided" in aManifest)) {
|
||||||
|
debug("Error: no 'languages-provided' property.")
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let lang in aManifest["languages-provided"]) {
|
||||||
|
let item = aManifest["languages-provided"][lang];
|
||||||
|
|
||||||
|
if (!item.version) {
|
||||||
|
debug("Error: missing 'version' in languages-provided." + lang);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof item.version !== "number") {
|
||||||
|
debug("Error: languages-provided." + lang +
|
||||||
|
".version must be a number but is a " + (typeof item.version));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item.apps) {
|
||||||
|
debug("Error: missing 'apps' in languages-provided." + lang);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let app in item.apps) {
|
||||||
|
// Keys should be manifest urls, ie. absolute urls.
|
||||||
|
if (!isAbsoluteURI(app)) {
|
||||||
|
debug("Error: languages-provided." + lang + "." + app +
|
||||||
|
" must be an absolute manifest url.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof item.apps[app] !== "string") {
|
||||||
|
debug("Error: languages-provided." + lang + ".apps." + app +
|
||||||
|
" value must be a string but is " + (typeof item.apps[app]) +
|
||||||
|
" : " + item.apps[app]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Check if this app is a langpack and update registration if needed.
|
||||||
|
register: function(aApp, aManifest) {
|
||||||
|
debug("register app " + aApp.manifestURL + " role=" + aApp.role);
|
||||||
|
|
||||||
|
if (aApp.role !== "langpack") {
|
||||||
|
debug("Not a langpack.");
|
||||||
|
// Not a langpack, but that's fine.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.checkManifest(aManifest)) {
|
||||||
|
debug("Invalid langpack manifest.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let platformVersion = aManifest["languages-target"]
|
||||||
|
["app://*.gaiamobile.org/manifest.webapp"];
|
||||||
|
let origin = Services.io.newURI(aApp.origin, null, null);
|
||||||
|
|
||||||
|
for (let lang in aManifest["languages-provided"]) {
|
||||||
|
let item = aManifest["languages-provided"][lang];
|
||||||
|
let version = item.version; // The langpack version, not the platform.
|
||||||
|
let name = item.name || lang; // If no name specified, default to lang.
|
||||||
|
for (let app in item.apps) {
|
||||||
|
let sendEvent = false;
|
||||||
|
if (!this._data[app] ||
|
||||||
|
!this._data[app].langs[lang] ||
|
||||||
|
this._data[app].langs[lang].version > version) {
|
||||||
|
if (!this._data[app]) {
|
||||||
|
this._data[app] = {
|
||||||
|
appId: this._appIdFromManifestURL(app),
|
||||||
|
langs: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this._data[app].langs[lang] = {
|
||||||
|
version: version,
|
||||||
|
target: platformVersion,
|
||||||
|
name: name,
|
||||||
|
url: origin.resolve(item.apps[app]),
|
||||||
|
from: aApp.manifestURL
|
||||||
|
}
|
||||||
|
sendEvent = true;
|
||||||
|
debug("Registered " + app + " -> " + uneval(this._data[app].langs[lang]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire additionallanguageschange event.
|
||||||
|
// This will only be dispatched to documents using the langpack api.
|
||||||
|
if (sendEvent) {
|
||||||
|
this.sendAppUpdate(app);
|
||||||
|
ppmm.broadcastAsyncMessage(
|
||||||
|
"Webapps:AdditionalLanguageChange",
|
||||||
|
{ manifestURL: app,
|
||||||
|
languages: this.getAdditionalLanguages(app).langs });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Check if this app is a langpack and update registration by removing all
|
||||||
|
// the entries from this app.
|
||||||
|
unregister: function(aApp, aManifest) {
|
||||||
|
debug("unregister app " + aApp.manifestURL + " role=" + aApp.role);
|
||||||
|
|
||||||
|
if (aApp.role !== "langpack") {
|
||||||
|
debug("Not a langpack.");
|
||||||
|
// Not a langpack, but that's fine.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let app in this._data) {
|
||||||
|
let sendEvent = false;
|
||||||
|
for (let lang in this._data[app].langs) {
|
||||||
|
if (this._data[app].langs[lang].from == aApp.manifestURL) {
|
||||||
|
sendEvent = true;
|
||||||
|
delete this._data[app].langs[lang];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fire additionallanguageschange event.
|
||||||
|
// This will only be dispatched to documents using the langpack api.
|
||||||
|
if (sendEvent) {
|
||||||
|
this.sendAppUpdate(app);
|
||||||
|
ppmm.broadcastAsyncMessage(
|
||||||
|
"Webapps:AdditionalLanguageChange",
|
||||||
|
{ manifestURL: app,
|
||||||
|
languages: this.getAdditionalLanguages(app).langs });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Langpacks.init();
|
|
@ -44,11 +44,23 @@ WebappsRegistry.prototype = {
|
||||||
|
|
||||||
receiveMessage: function(aMessage) {
|
receiveMessage: function(aMessage) {
|
||||||
let msg = aMessage.json;
|
let msg = aMessage.json;
|
||||||
if (msg.oid != this._id)
|
let req;
|
||||||
return
|
if (aMessage.name != "Webapps:AdditionalLanguageChange") {
|
||||||
let req = this.getRequest(msg.requestID);
|
if (msg.oid != this._id) {
|
||||||
if (!req)
|
return
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
if (aMessage.name == "Webapps:GetAdditionalLanguages:Return" ||
|
||||||
|
aMessage.name == "Webapps:GetLocalizationResource:Return") {
|
||||||
|
req = this.takePromiseResolver(msg.requestID);
|
||||||
|
} else {
|
||||||
|
req = this.getRequest(msg.requestID);
|
||||||
|
}
|
||||||
|
if (!req) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let app = msg.app;
|
let app = msg.app;
|
||||||
switch (aMessage.name) {
|
switch (aMessage.name) {
|
||||||
case "Webapps:Install:Return:OK":
|
case "Webapps:Install:Return:OK":
|
||||||
|
@ -78,6 +90,26 @@ WebappsRegistry.prototype = {
|
||||||
this.removeMessageListeners(aMessage.name);
|
this.removeMessageListeners(aMessage.name);
|
||||||
Services.DOMRequest.fireSuccess(req, convertAppsArray(msg.apps, this._window));
|
Services.DOMRequest.fireSuccess(req, convertAppsArray(msg.apps, this._window));
|
||||||
break;
|
break;
|
||||||
|
case "Webapps:AdditionalLanguageChange":
|
||||||
|
// Check if the current page is from the app receiving the event.
|
||||||
|
let manifestURL = AppsUtils.getAppManifestURLFromWindow(this._window);
|
||||||
|
if (manifestURL && manifestURL == msg.manifestURL) {
|
||||||
|
// Let's dispatch an "additionallanguageschange" event on the document.
|
||||||
|
let doc = this._window.document;
|
||||||
|
let event = doc.createEvent("CustomEvent");
|
||||||
|
event.initCustomEvent("additionallanguageschange", true, true,
|
||||||
|
Cu.cloneInto(msg.languages, this._window));
|
||||||
|
doc.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Webapps:GetLocalizationResource:Return":
|
||||||
|
this.removeMessageListeners(["Webapps:GetLocalizationResource:Return"]);
|
||||||
|
if (msg.error) {
|
||||||
|
req.reject(new this._window.DOMError(msg.error));
|
||||||
|
} else {
|
||||||
|
req.resolve(Cu.cloneInto(msg.data, this._window));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
this.removeRequest(msg.requestID);
|
this.removeRequest(msg.requestID);
|
||||||
},
|
},
|
||||||
|
@ -231,7 +263,8 @@ WebappsRegistry.prototype = {
|
||||||
uninit: function() {
|
uninit: function() {
|
||||||
this._mgmt = null;
|
this._mgmt = null;
|
||||||
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
|
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
|
||||||
["Webapps:Install:Return:OK"]);
|
["Webapps:Install:Return:OK",
|
||||||
|
"Webapps:AdditionalLanguageChange"]);
|
||||||
},
|
},
|
||||||
|
|
||||||
installPackage: function(aURL, aParams) {
|
installPackage: function(aURL, aParams) {
|
||||||
|
@ -248,19 +281,69 @@ WebappsRegistry.prototype = {
|
||||||
return request;
|
return request;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getCurrentAppManifestURL: function() {
|
||||||
|
let appId = this._window.document.nodePrincipal.appId;
|
||||||
|
if (appId === Ci.nsIScriptSecurityManager.NO_APP_ID) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return appsService.getManifestURLByLocalId(appId);
|
||||||
|
},
|
||||||
|
|
||||||
|
getAdditionalLanguages: function() {
|
||||||
|
let manifestURL = AppsUtils.getAppManifestURLFromWindow(this._window);
|
||||||
|
|
||||||
|
return new this._window.Promise((aResolve, aReject) => {
|
||||||
|
if (!manifestURL) {
|
||||||
|
aReject("NotInApp");
|
||||||
|
} else {
|
||||||
|
let langs = DOMApplicationRegistry.getAdditionalLanguages(manifestURL);
|
||||||
|
aResolve(Cu.cloneInto(langs, this._window));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getLocalizationResource: function(aLanguage, aVersion, aPath, aType) {
|
||||||
|
let manifestURL = AppsUtils.getAppManifestURLFromWindow(this._window);
|
||||||
|
|
||||||
|
if (!manifestURL) {
|
||||||
|
return new Promise((aResolve, aReject) => {
|
||||||
|
aReject("NotInApp");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addMessageListeners(["Webapps:GetLocalizationResource:Return"]);
|
||||||
|
return this.createPromise((aResolve, aReject) => {
|
||||||
|
cpmm.sendAsyncMessage("Webapps:GetLocalizationResource", {
|
||||||
|
manifestURL: manifestURL,
|
||||||
|
lang: aLanguage,
|
||||||
|
version: aVersion,
|
||||||
|
path: aPath,
|
||||||
|
dataType: aType,
|
||||||
|
oid: this._id,
|
||||||
|
requestID: this.getPromiseResolverId({
|
||||||
|
resolve: aResolve,
|
||||||
|
reject: aReject
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// nsIDOMGlobalPropertyInitializer implementation
|
// nsIDOMGlobalPropertyInitializer implementation
|
||||||
init: function(aWindow) {
|
init: function(aWindow) {
|
||||||
const prefs = new Preferences();
|
const prefs = new Preferences();
|
||||||
|
|
||||||
this._window = aWindow;
|
this._window = aWindow;
|
||||||
|
|
||||||
this.initDOMRequestHelper(aWindow, "Webapps:Install:Return:OK");
|
this.initDOMRequestHelper(aWindow, ["Webapps:Install:Return:OK",
|
||||||
|
"Webapps:AdditionalLanguageChange"]);
|
||||||
|
|
||||||
let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
|
let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
.getInterface(Ci.nsIDOMWindowUtils);
|
.getInterface(Ci.nsIDOMWindowUtils);
|
||||||
this._id = util.outerWindowID;
|
this._id = util.outerWindowID;
|
||||||
cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
|
cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
|
||||||
{ messages: ["Webapps:Install:Return:OK"]});
|
{ messages: ["Webapps:Install:Return:OK",
|
||||||
|
"Webapps:AdditionalLanguageChange"]});
|
||||||
|
|
||||||
let principal = aWindow.document.nodePrincipal;
|
let principal = aWindow.document.nodePrincipal;
|
||||||
let appId = principal.appId;
|
let appId = principal.appId;
|
||||||
|
|
|
@ -81,6 +81,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "ScriptPreloader",
|
XPCOMUtils.defineLazyModuleGetter(this, "ScriptPreloader",
|
||||||
"resource://gre/modules/ScriptPreloader.jsm");
|
"resource://gre/modules/ScriptPreloader.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "Langpacks",
|
||||||
|
"resource://gre/modules/Langpacks.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "TrustedHostedAppsUtils",
|
XPCOMUtils.defineLazyModuleGetter(this, "TrustedHostedAppsUtils",
|
||||||
"resource://gre/modules/TrustedHostedAppsUtils.jsm");
|
"resource://gre/modules/TrustedHostedAppsUtils.jsm");
|
||||||
|
|
||||||
|
@ -243,6 +246,9 @@ this.DOMApplicationRegistry = {
|
||||||
["webapps", "webapps.json"], true).path;
|
["webapps", "webapps.json"], true).path;
|
||||||
|
|
||||||
this.loadAndUpdateApps();
|
this.loadAndUpdateApps();
|
||||||
|
|
||||||
|
Langpacks.registerRegistryFunctions(this.broadcastMessage.bind(this),
|
||||||
|
this._appIdForManifestURL.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
// loads the current registry, that could be empty on first run.
|
// loads the current registry, that could be empty on first run.
|
||||||
|
@ -424,6 +430,7 @@ this.DOMApplicationRegistry = {
|
||||||
}
|
}
|
||||||
app.kind = this.appKind(app, aResult.manifest);
|
app.kind = this.appKind(app, aResult.manifest);
|
||||||
UserCustomizations.register(aResult.manifest, app);
|
UserCustomizations.register(aResult.manifest, app);
|
||||||
|
Langpacks.register(app, aResult.manifest);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Nothing else to do but notifying we're ready.
|
// Nothing else to do but notifying we're ready.
|
||||||
|
@ -1149,6 +1156,7 @@ this.DOMApplicationRegistry = {
|
||||||
this._registerInterAppConnections(manifest, app);
|
this._registerInterAppConnections(manifest, app);
|
||||||
appsToRegister.push({ manifest: manifest, app: app });
|
appsToRegister.push({ manifest: manifest, app: app });
|
||||||
UserCustomizations.register(manifest, app);
|
UserCustomizations.register(manifest, app);
|
||||||
|
Langpacks.register(app, manifest);
|
||||||
});
|
});
|
||||||
this._safeToClone.resolve();
|
this._safeToClone.resolve();
|
||||||
this._registerActivitiesForApps(appsToRegister, aRunUpdate);
|
this._registerActivitiesForApps(appsToRegister, aRunUpdate);
|
||||||
|
@ -1520,6 +1528,8 @@ this.DOMApplicationRegistry = {
|
||||||
this.safeToClone.then( () => {
|
this.safeToClone.then( () => {
|
||||||
for (let id in this.webapps) {
|
for (let id in this.webapps) {
|
||||||
tmp.push({ id: id });
|
tmp.push({ id: id });
|
||||||
|
this.webapps[id].additionalLanguages =
|
||||||
|
Langpacks.getAdditionalLanguages(this.webapps[id].manifestURL).langs;
|
||||||
}
|
}
|
||||||
this._readManifests(tmp).then(
|
this._readManifests(tmp).then(
|
||||||
function(manifests) {
|
function(manifests) {
|
||||||
|
@ -1964,6 +1974,10 @@ this.DOMApplicationRegistry = {
|
||||||
|
|
||||||
// Update the asm.js scripts we need to compile.
|
// Update the asm.js scripts we need to compile.
|
||||||
yield ScriptPreloader.preload(app, newManifest);
|
yield ScriptPreloader.preload(app, newManifest);
|
||||||
|
|
||||||
|
// Update langpack information.
|
||||||
|
Langpacks.register(app, newManifest);
|
||||||
|
|
||||||
yield this._saveApps();
|
yield this._saveApps();
|
||||||
// Update the handlers and permissions for this app.
|
// Update the handlers and permissions for this app.
|
||||||
this.updateAppHandlers(oldManifest, newManifest, app);
|
this.updateAppHandlers(oldManifest, newManifest, app);
|
||||||
|
@ -2081,11 +2095,13 @@ this.DOMApplicationRegistry = {
|
||||||
this.notifyAppsRegistryReady();
|
this.notifyAppsRegistryReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update user customizations.
|
// Update user customizations and langpacks.
|
||||||
if (aOldManifest) {
|
if (aOldManifest) {
|
||||||
UserCustomizations.unregister(aOldManifest, aApp);
|
UserCustomizations.unregister(aOldManifest, aApp);
|
||||||
|
Langpacks.unregister(aApp, aOldManifest);
|
||||||
}
|
}
|
||||||
UserCustomizations.register(aNewManifest, aApp);
|
UserCustomizations.register(aNewManifest, aApp);
|
||||||
|
Langpacks.register(aApp, aNewManifest);
|
||||||
},
|
},
|
||||||
|
|
||||||
checkForUpdate: function(aData, aMm) {
|
checkForUpdate: function(aData, aMm) {
|
||||||
|
@ -3185,6 +3201,9 @@ this.DOMApplicationRegistry = {
|
||||||
// Check if we have asm.js code to preload for this application.
|
// Check if we have asm.js code to preload for this application.
|
||||||
yield ScriptPreloader.preload(aNewApp, aManifest);
|
yield ScriptPreloader.preload(aNewApp, aManifest);
|
||||||
|
|
||||||
|
// Update langpack information.
|
||||||
|
yield Langpacks.register(aNewApp, aManifest);
|
||||||
|
|
||||||
this.broadcastMessage("Webapps:FireEvent", {
|
this.broadcastMessage("Webapps:FireEvent", {
|
||||||
eventType: ["downloadsuccess", "downloadapplied"],
|
eventType: ["downloadsuccess", "downloadapplied"],
|
||||||
manifestURL: aNewApp.manifestURL
|
manifestURL: aNewApp.manifestURL
|
||||||
|
@ -4094,6 +4113,7 @@ this.DOMApplicationRegistry = {
|
||||||
this._unregisterActivities(aApp.manifest, aApp);
|
this._unregisterActivities(aApp.manifest, aApp);
|
||||||
}
|
}
|
||||||
UserCustomizations.unregister(aApp.manifest, aApp);
|
UserCustomizations.unregister(aApp.manifest, aApp);
|
||||||
|
Langpacks.unregister(aApp, aApp.manifest);
|
||||||
|
|
||||||
let dir = this._getAppDir(id);
|
let dir = this._getAppDir(id);
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -34,6 +34,7 @@ EXTRA_JS_MODULES += [
|
||||||
'AppsServiceChild.jsm',
|
'AppsServiceChild.jsm',
|
||||||
'FreeSpaceWatcher.jsm',
|
'FreeSpaceWatcher.jsm',
|
||||||
'InterAppCommService.jsm',
|
'InterAppCommService.jsm',
|
||||||
|
'Langpacks.jsm',
|
||||||
'OfflineCacheInstaller.jsm',
|
'OfflineCacheInstaller.jsm',
|
||||||
'PermissionsInstaller.jsm',
|
'PermissionsInstaller.jsm',
|
||||||
'PermissionsTable.jsm',
|
'PermissionsTable.jsm',
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Langpack Test : event</title>
|
||||||
|
<script>
|
||||||
|
var baseURL = "http://mochi.test:8888/tests/dom/apps/tests/langpack/";
|
||||||
|
var eventCount = 0;
|
||||||
|
|
||||||
|
function languageChanged(evt) {
|
||||||
|
eventCount++;
|
||||||
|
alert(JSON.stringify(evt.detail));
|
||||||
|
if (eventCount == 1) {
|
||||||
|
var req = navigator.mozApps.install(baseURL + "lang2.webapp");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the event handler, and install an app.
|
||||||
|
function run() {
|
||||||
|
document.addEventListener("additionallanguageschange", languageChanged);
|
||||||
|
|
||||||
|
navigator.mozApps.install(baseURL + "lang1.webapp");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="run()">
|
||||||
|
<h1>Langpack Test : event</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1 @@
|
||||||
|
{ "hello" : "Bonjour" }
|
|
@ -0,0 +1 @@
|
||||||
|
hello=Bonjour
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Langpack Test : getAdditionalLanguages()</title>
|
||||||
|
<script>
|
||||||
|
function run() {
|
||||||
|
navigator.mozApps.getAdditionalLanguages().then(languages => {
|
||||||
|
alert(JSON.stringify(languages));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="run()">
|
||||||
|
<h1>Langpack Test : getAdditionalLanguages()</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"name": "French locale",
|
||||||
|
"languages-target" : { "app://*.gaiamobile.org/manifest.webapp": "2.2" },
|
||||||
|
"languages-provided": {
|
||||||
|
"fr": {
|
||||||
|
"version": 201411051234,
|
||||||
|
"name": "Français",
|
||||||
|
"apps": {
|
||||||
|
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/fr/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"role" : "langpack"
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Content-Type: application/manifest+json
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "German an Polish locales",
|
||||||
|
"languages-target" : { "app://*.gaiamobile.org/manifest.webapp": "2.2" },
|
||||||
|
"languages-provided": {
|
||||||
|
"de": {
|
||||||
|
"version": 201411051234,
|
||||||
|
"name": "Deutsch",
|
||||||
|
"apps": {
|
||||||
|
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/de/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pl": {
|
||||||
|
"version": 201411051234,
|
||||||
|
"name": "Polski",
|
||||||
|
"apps": {
|
||||||
|
"http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/pl/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"role" : "langpack"
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Content-Type: application/manifest+json
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"name": "Localization test app"
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Content-Type: application/manifest+json
|
|
@ -0,0 +1,92 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Langpack Test : resources</title>
|
||||||
|
<script>
|
||||||
|
function success(data) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
if (typeof data === "object") {
|
||||||
|
// Read what's inside the blob.
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
alert(e.target.result);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
reader.readAsText(data);
|
||||||
|
} else {
|
||||||
|
alert(data);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function successJSON(data) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
alert(JSON.stringify(data));
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function error(domError) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
alert(domError.name);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error: Bad resource.
|
||||||
|
function test1() {
|
||||||
|
return navigator.mozApps.getLocalizationResource("fr", "2.2", "./foo.html", "binary")
|
||||||
|
.then(success, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error: Unknown locale.
|
||||||
|
function test2() {
|
||||||
|
return navigator.mozApps.getLocalizationResource("es", "2.2", "./foo.html", "binary")
|
||||||
|
.then(success, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error: Bad version.
|
||||||
|
function test3() {
|
||||||
|
return navigator.mozApps.getLocalizationResource("fr", "2.0", "./foo.html", "binary")
|
||||||
|
.then(success, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error: Absolute url.
|
||||||
|
function test4() {
|
||||||
|
return navigator.mozApps.getLocalizationResource("fr", "2.2", "http://example.com/foo.html", "binary")
|
||||||
|
.then(success, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok, binary data.
|
||||||
|
function test5() {
|
||||||
|
return navigator.mozApps.getLocalizationResource("fr", "2.2", "./app.properties", "binary")
|
||||||
|
.then(success, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok, text data.
|
||||||
|
function test6() {
|
||||||
|
return navigator.mozApps.getLocalizationResource("fr", "2.2", "./app.properties", "text")
|
||||||
|
.then(success, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok, json data.
|
||||||
|
function test7() {
|
||||||
|
return navigator.mozApps.getLocalizationResource("fr", "2.2", "./app.json", "json")
|
||||||
|
.then(successJSON, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
test1().then(test2)
|
||||||
|
.then(test3)
|
||||||
|
.then(test4)
|
||||||
|
.then(test5)
|
||||||
|
.then(test6)
|
||||||
|
.then(test7);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="run()">
|
||||||
|
<h1>Langpack Test : resources</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -22,6 +22,7 @@ support-files =
|
||||||
file_widget_app.template.webapp
|
file_widget_app.template.webapp
|
||||||
file_widget_app.template.html
|
file_widget_app.template.html
|
||||||
file_test_widget.js
|
file_test_widget.js
|
||||||
|
langpack/*
|
||||||
signed_app.sjs
|
signed_app.sjs
|
||||||
signed_app_template.webapp
|
signed_app_template.webapp
|
||||||
signed/*
|
signed/*
|
||||||
|
@ -38,6 +39,8 @@ skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in moch
|
||||||
[test_import_export.html]
|
[test_import_export.html]
|
||||||
[test_install_multiple_apps_origin.html]
|
[test_install_multiple_apps_origin.html]
|
||||||
[test_install_receipts.html]
|
[test_install_receipts.html]
|
||||||
|
[test_langpacks.html]
|
||||||
|
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
|
||||||
[test_marketplace_pkg_install.html]
|
[test_marketplace_pkg_install.html]
|
||||||
skip-if = buildapp == "b2g" || toolkit == "android" # see bug 989806
|
skip-if = buildapp == "b2g" || toolkit == "android" # see bug 989806
|
||||||
[test_packaged_app_install.html]
|
[test_packaged_app_install.html]
|
||||||
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
<!DOCTYPE HTML><!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1108096
|
||||||
|
-->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 1108096 - Langpack support</title>
|
||||||
|
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
<script type="application/javascript;version=1.7">
|
||||||
|
/**
|
||||||
|
* Test for Bug 1108096
|
||||||
|
* This file covers testing langpacks.
|
||||||
|
*
|
||||||
|
* The setup is as follows:
|
||||||
|
* - app is the localizable application.
|
||||||
|
* - langpack1 provides the French locale.
|
||||||
|
* - langpack2 provides the German and Polish locales.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
const uriPrefix = "http://mochi.test:8888/tests/dom/apps/tests/langpack/";
|
||||||
|
|
||||||
|
let appManifestURL = uriPrefix + "manifest.webapp";
|
||||||
|
let lang1ManifestURL = uriPrefix + "lang1.webapp";
|
||||||
|
let lang2ManifestURL = uriPrefix + "lang2.webapp";
|
||||||
|
|
||||||
|
let gGenerator = runTest();
|
||||||
|
|
||||||
|
function go() {
|
||||||
|
gGenerator.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
function continueTest() {
|
||||||
|
try {
|
||||||
|
gGenerator.next();
|
||||||
|
} catch (e if e instanceof StopIteration) {
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mozAppsError() {
|
||||||
|
ok(false, "mozApps error: " + this.error.name);
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggers one navigation test to the given page.
|
||||||
|
// Waits for alert() messages before tearing down the iframe.
|
||||||
|
function openPage(pageURL, messages) {
|
||||||
|
info("Navigating to " + pageURL);
|
||||||
|
let ifr = document.createElement("iframe");
|
||||||
|
let listener = function(event) {
|
||||||
|
let message = messages.shift();
|
||||||
|
is(event.detail.message, message, "Checking alert message for " + pageURL);
|
||||||
|
if (messages.length == 0) {
|
||||||
|
ifr.removeEventListener("mozbrowsershowmodalprompt", listener);
|
||||||
|
ifr.parentNode.removeChild(ifr);
|
||||||
|
continueTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ifr.addEventListener("mozbrowsershowmodalprompt", listener, false);
|
||||||
|
|
||||||
|
// Open the app url in an iframe.
|
||||||
|
ifr.setAttribute("mozapp", appManifestURL);
|
||||||
|
ifr.setAttribute("mozbrowser", "true");
|
||||||
|
ifr.setAttribute("src", uriPrefix + pageURL);
|
||||||
|
document.getElementById("container").appendChild(ifr);
|
||||||
|
}
|
||||||
|
|
||||||
|
let apps = [];
|
||||||
|
|
||||||
|
function installApp(manifestURL) {
|
||||||
|
info("About to install app at " + manifestURL);
|
||||||
|
let req = navigator.mozApps.install(manifestURL);
|
||||||
|
req.onsuccess = function() {
|
||||||
|
is(req.result.manifestURL, manifestURL, "app installed");
|
||||||
|
if (req.result.installState == "installed") {
|
||||||
|
is(req.result.installState, "installed", "app downloaded");
|
||||||
|
continueTest();
|
||||||
|
} else {
|
||||||
|
req.result.ondownloadapplied = function() {
|
||||||
|
is(req.result.installState, "installed", "app downloaded");
|
||||||
|
continueTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.onerror = mozAppsError;
|
||||||
|
}
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
// Set up.
|
||||||
|
SpecialPowers.setAllAppsLaunchable(true);
|
||||||
|
SpecialPowers.pushPrefEnv({'set': [
|
||||||
|
["dom.mozBrowserFramesEnabled", true],
|
||||||
|
["dom.apps.allow_unsigned_langpacks", true] ]},continueTest);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
SpecialPowers.pushPermissions(
|
||||||
|
[{ "type": "webapps-manage", "allow": 1, "context": document },
|
||||||
|
{ "type": "embed-apps", "allow": 1, "context": document },
|
||||||
|
{ "type": "browser", "allow": 1, "context": document } ],
|
||||||
|
continueTest);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
navigator.mozApps.mgmt.oninstall = function(evt) {
|
||||||
|
apps.push(evt.application);
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = JSON.stringify;
|
||||||
|
|
||||||
|
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
// Install test app.
|
||||||
|
installApp(appManifestURL);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
// Opens the iframe to the test page, initial state.
|
||||||
|
// No locale is available.
|
||||||
|
openPage("index.html", [_({})]);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
// Install the fr langpack.
|
||||||
|
installApp(lang1ManifestURL);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
// Opens the iframe to the test page.
|
||||||
|
// Only the French locale is available.
|
||||||
|
openPage("index.html",
|
||||||
|
[_({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}]})]);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
// Install the de and pl langpack.
|
||||||
|
installApp(lang2ManifestURL);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
// Opens the iframe to the test page.
|
||||||
|
// French, German and Polish locales are available.
|
||||||
|
openPage("index.html",
|
||||||
|
[_({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}],"de":[{"version":201411051234,"name":"Deutsch","target":"2.2"}],"pl":[{"version":201411051234,"name":"Polski","target":"2.2"}]})]);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
// Uninstall the second langpack.
|
||||||
|
{
|
||||||
|
let app = apps.pop();
|
||||||
|
info("Uninstalling " + app.manifestURL);
|
||||||
|
req = navigator.mozApps.mgmt.uninstall(app);
|
||||||
|
req.onsuccess = continueTest;
|
||||||
|
req.onerror = mozAppsError;
|
||||||
|
yield undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opens the iframe to the test page.
|
||||||
|
// Only the French locale is available.
|
||||||
|
openPage("index.html",
|
||||||
|
[_({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}]})]);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
// Uninstall the first langpack.
|
||||||
|
{
|
||||||
|
let app = apps.pop();
|
||||||
|
info("Uninstalling " + app.manifestURL);
|
||||||
|
req = navigator.mozApps.mgmt.uninstall(app);
|
||||||
|
req.onsuccess = continueTest;
|
||||||
|
req.onerror = mozAppsError;
|
||||||
|
yield undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opens the iframe to the test page, initial state.
|
||||||
|
// No locale is available.
|
||||||
|
openPage("index.html",
|
||||||
|
["{}"]);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
// Opens the iframe to the event test page.
|
||||||
|
// Will get additionallanguageschange events.
|
||||||
|
openPage("event.html",
|
||||||
|
[_({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}]}),
|
||||||
|
_({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}],"de":[{"version":201411051234,"name":"Deutsch","target":"2.2"}]}),
|
||||||
|
_({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}],"de":[{"version":201411051234,"name":"Deutsch","target":"2.2"}],"pl":[{"version":201411051234,"name":"Polski","target":"2.2"}]})]);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
// Opens the iframe to the resource test page.
|
||||||
|
openPage("resources.html",
|
||||||
|
["UnavailableResource",
|
||||||
|
"UnavailableLanguage",
|
||||||
|
"UnavailableVersion",
|
||||||
|
"BadUrl",
|
||||||
|
"hello=Bonjour",
|
||||||
|
"hello=Bonjour",
|
||||||
|
_({"hello":"Bonjour"})]);
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
|
// Clean up after ourselves by uninstalling apps.
|
||||||
|
info(apps.length + " applications to uninstall.");
|
||||||
|
while (apps.length) {
|
||||||
|
let app = apps.pop();
|
||||||
|
req = navigator.mozApps.mgmt.uninstall(app);
|
||||||
|
req.onsuccess = continueTest;
|
||||||
|
req.onerror = mozAppsError;
|
||||||
|
yield undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="go()">
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
</pre>
|
||||||
|
<div id="container"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -20,7 +20,9 @@
|
||||||
|
|
||||||
var props = {
|
var props = {
|
||||||
checkInstalled: "function",
|
checkInstalled: "function",
|
||||||
|
getAdditionalLanguages: "function",
|
||||||
getInstalled: "function",
|
getInstalled: "function",
|
||||||
|
getLocalizationResource: "function",
|
||||||
getSelf: "function",
|
getSelf: "function",
|
||||||
install: "function",
|
install: "function",
|
||||||
installPackage: "function",
|
installPackage: "function",
|
||||||
|
|
|
@ -9,6 +9,18 @@ dictionary InstallParameters {
|
||||||
sequence<DOMString> categories = [];
|
sequence<DOMString> categories = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dictionary LanguageDesc {
|
||||||
|
DOMString target;
|
||||||
|
DOMString version;
|
||||||
|
DOMString name;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LocaleResourceType {
|
||||||
|
"binary",
|
||||||
|
"json",
|
||||||
|
"text"
|
||||||
|
};
|
||||||
|
|
||||||
[NoInterfaceObject, NavigatorProperty="mozApps",
|
[NoInterfaceObject, NavigatorProperty="mozApps",
|
||||||
JSImplementation="@mozilla.org/webapps;1"]
|
JSImplementation="@mozilla.org/webapps;1"]
|
||||||
interface DOMApplicationsRegistry {
|
interface DOMApplicationsRegistry {
|
||||||
|
@ -19,6 +31,17 @@ interface DOMApplicationsRegistry {
|
||||||
DOMRequest getSelf();
|
DOMRequest getSelf();
|
||||||
DOMRequest getInstalled();
|
DOMRequest getInstalled();
|
||||||
DOMRequest checkInstalled(DOMString manifestUrl);
|
DOMRequest checkInstalled(DOMString manifestUrl);
|
||||||
|
|
||||||
|
// Language pack API.
|
||||||
|
// These promises will be rejected if the page is not in an app context,
|
||||||
|
// i.e. they are implicitely acting on getSelf().
|
||||||
|
Promise<MozMap<sequence<LanguageDesc>>> getAdditionalLanguages();
|
||||||
|
// Resolves to a different object depending on the dataType value.
|
||||||
|
Promise<any>
|
||||||
|
getLocalizationResource(DOMString language,
|
||||||
|
DOMString version,
|
||||||
|
DOMString path,
|
||||||
|
LocaleResourceType dataType);
|
||||||
};
|
};
|
||||||
|
|
||||||
[JSImplementation="@mozilla.org/webapps/application;1", ChromeOnly]
|
[JSImplementation="@mozilla.org/webapps/application;1", ChromeOnly]
|
||||||
|
@ -71,18 +94,18 @@ interface DOMApplication : EventTarget {
|
||||||
* https://wiki.mozilla.org/WebAPI/Inter_App_Communication_Alt_proposal
|
* https://wiki.mozilla.org/WebAPI/Inter_App_Communication_Alt_proposal
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
Promise<MozInterAppConnection> connect(DOMString keyword, optional any rules);
|
Promise<MozInterAppConnection> connect(DOMString keyword, optional any rules);
|
||||||
|
|
||||||
Promise<sequence<MozInterAppMessagePort>> getConnections();
|
Promise<sequence<MozInterAppMessagePort>> getConnections();
|
||||||
|
|
||||||
// Receipts handling functions.
|
// Receipts handling functions.
|
||||||
DOMRequest addReceipt(optional DOMString receipt);
|
DOMRequest addReceipt(optional DOMString receipt);
|
||||||
DOMRequest removeReceipt(optional DOMString receipt);
|
DOMRequest removeReceipt(optional DOMString receipt);
|
||||||
DOMRequest replaceReceipt(optional DOMString oldReceipt,
|
DOMRequest replaceReceipt(optional DOMString oldReceipt,
|
||||||
optional DOMString newReceipt);
|
optional DOMString newReceipt);
|
||||||
|
|
||||||
// Export this app as a shareable Blob.
|
// Export this app as a shareable Blob.
|
||||||
Promise<Blob> export();
|
Promise<Blob> export();
|
||||||
};
|
};
|
||||||
|
|
||||||
[JSImplementation="@mozilla.org/webapps/manager;1",
|
[JSImplementation="@mozilla.org/webapps/manager;1",
|
||||||
|
|
Загрузка…
Ссылка в новой задаче