Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Update add-on to implement new mozApps API (semi-complete, 33/47 tests)

  • Loading branch information...
commit 9ae3a631138296d9bec1b18148af0c419c8b5f78 1 parent 5e14674
@anantn anantn authored
View
111 addons/jetpack/data/mgmtapi.js
@@ -1,13 +1,11 @@
-
-
var callid = 0;
function _makeCall(msg, args, callback, errcb) {
let data = {
location: location.href,
data: args
- }
+ };
callid++;
if (callback) {
data.success = msg+".success."+callid;
@@ -30,44 +28,107 @@ function _makeCall(msg, args, callback, errcb) {
self.port.emit(msg, data);
}
-let _watches = [];
+let _watches = {
+ "install": [],
+ "uninstall": []
+};
+
function _updateWatchers(args) {
+ let _watchers = null;
+ if (args[0] == "add") _watchers = _watches["install"];
+ else if (args[0] == "remove") _watchers = _watches["uninstall"];
+
for (var i=0; i < _watches.length; i++) {
- _watches[i](args[0], args[1]);
+ _watches[i]({applicaton: args[1][0]});
}
}
-function _clearWatcher(fn) {
- let idx = _watches.indexOf(fn);
+
+function _clearWatcher(type, fn) {
+ let idx = _watches[type].indexOf(fn);
if (idx >= 0) {
- _watches.splice(idx, 1);
+ _watches[type].splice(idx, 1);
}
}
-unsafeWindow.navigator.wrappedJSObject.mozApps.mgmt = {
- launch: function(args) {
- // no return, just emit the message
- _makeCall('owa.mgmt.launch', args);
- },
- list: function(callback) {
- _makeCall('owa.mgmt.list', null, callback);
+// A helper function to make an 'app object' that implements
+// both launch() & uninstall() from an app record. Similar to
+// what's in api.js, but uses _makeCall instead of FFRepoImplService
+function appObject(apprec) {
+ // FIXME: Any better way to do this?
+ let props = ["manifest", "manifestURL", "origin", "installOrigin", "installTime"];
+ for (let i = 0; i < props.length; i++) {
+ this[props[i]] = apprec[props[i]];
+ }
+ this.receipts = null;
+ if ('installData' in apprec && 'receipts' in apprec.installData) {
+ this.receipts = apprec.installData.receipts;
+ }
+}
+appObject.prototype = {
+ launch: function() {
+ _makeCall('owa.mgmt.launch', this.origin);
},
- uninstall: function(key, callback, onerror) {
- _makeCall('owa.mgmt.uninstall', key, callback, onerror);
+ uninstall: function() {
+ let pendingUninstall = {};
+ _makeCall('owa.mgmt.uninstall', this.origin,
+ function(e) {
+ if (pendingUninstall.onsuccess) pendingUninstall.onsuccess(e);
+ },
+ function(e) {
+ if (pendingUninstall.onerror) pendingUninstall.onerror(e);
+ }
+ );
+ return pendingUninstall;
+ }
+};
+
+
+// We are mapping the new API to the old ones, so addEventListener
+// and removeEventListener are built on top of updateWatcher & clearWatch.
+// Additionally, getAll implements the pendingGetAll object in place to
+// conform with the new API.
+//
+// We don't implement these mgmt calls either in api.js or repo.js because
+// pageMod is used to inject these privileged functions only to certain
+// origins, listed in the 'allowedOrigins' array in main.js
+unsafeWindow.navigator.wrappedJSObject.mozApps.mgmt = {
+ getAll: function() {
+ let pendingGetAll = {
+ onsuccess: function(e) {
+ console.log("default getAll: " + JSON.stringify(pendingGetAll.result));
+ },
+ // FIXME: When is onerror called?
+ onerror: function(e) {
+ console.log("default getAll error: " + JSON.stringify(e));
+ },
+ result: undefined
+ };
+
+ _makeCall('owa.mgmt.getAll', null, function(apps) {
+ let appObjs = [];
+ for (var i = 0; i < apps.length; i++) {
+ appObjs.push(new appObject(apps[i]));
+ }
+ pendingGetAll.result = appObjs;
+ pendingGetAll.onsuccess(appObjs);
+ });
+
+ return pendingGetAll;
},
- watchUpdates: function(callback) {
- _watches.push(callback);
- let idx = _watches.indexOf(callback);
+ addEventListener: function(type, callback) {
+ _watches[type].push(callback);
+ let idx = _watches[type].indexOf(callback);
if (idx == 0) {
self.port.on("owa.mgmt.update", _updateWatchers);
_makeCall('owa.mgmt.watchUpdates');
}
},
- clearWatch: function(callback) {
- _clearWatcher(callback);
- if (_watches.length < 1) {
+ removeEventListener: function(type, callback) {
+ _clearWatcher(type, callback);
+ if (_watches["install"].length < 1 &&
+ _watches["uninstall"].length < 1) {
_makeCall('owa.mgmt.clearWatch');
self.port.removeListener("owa.mgmt.update", _updateWatchers);
}
}
-}
-
+};
View
140 addons/jetpack/lib/api.js
@@ -52,6 +52,53 @@ var { URLParse } = require("./urlmatch");
var { NativeShell } = require("./nativeshell");
var { TypedStorage } = require("typed_storage");
+// Typical 'pending' object
+function pendingOperation(type) {
+ this._type = type;
+}
+pendingOperation.prototype = {
+ onsuccess: function() {
+ console.log("default onsuccess called for " + this._type);
+ },
+ onerror: function() {
+ console.log("default onerror called for " + this._type);
+ },
+ result: undefined,
+ error: undefined
+};
+
+// A helper function to make an 'app object' that implements
+// both launch() & uninstall() from an app record
+function appObject(apprec) {
+ // FIXME: Any better way to do this?
+ let props = ["manifest", "manifestURL", "origin", "installOrigin", "installTime"];
+ for (let i = 0; i < props.length; i++) {
+ this[props[i]] = apprec[props[i]];
+ }
+ this.receipts = null;
+ if ('installData' in apprec && 'receipts' in apprec.installData) {
+ this.receipts = apprec.installData.receipts;
+ }
+}
+appObject.prototype.launch = function() {
+ FFRepoImplService.launch(this.origin);
+};
+appObject.prototype.uninstall = function() {
+ let pendingUninstall = new pendingOperation("uninstall");
+ FFRepoImplService.uninstall(
+ this.origin,
+ function(e) {
+ pendingUninstall.result = e;
+ if (pendingUninstall.onsuccess) pendingUninstall.onsuccess(e);
+ },
+ function(e) {
+ pendingUninstall.error = e;
+ if (pendingUninstall.onerror) pendingUninstall.onerror(e);
+ }
+ );
+ return pendingUninstall;
+};
+
// We want to use as much from the cross-platform repo implementation
// as possible, but we do need to override a few methods.
var { Repo } = require("repo");
@@ -121,6 +168,42 @@ FFRepoImpl.prototype = {
}
},
+ // Implement getSelf, getInstalled to use repo.js;
+ // *but* wrap them in an appobject (which exposes launch & uninstall)
+ // Can't do this for getAll since mgmt functions are implement using
+ // worker.emit and pageMods. The equivalent logic for the following two
+ // functions for getAll lives in mgmtapi.js
+ getSelf: function(origin) {
+ let pendingGetSelf = new pendingOperation("getSelf");
+ Repo.getSelf(origin, function(app) {
+ // FIXME: what's the error case?
+ if (pendingGetSelf.onsuccess) {
+ let appObj = null;
+ if (app) {
+ appObj = new appObject(app);
+ }
+ pendingGetSelf.result = appObj;
+ pendingGetSelf.onsuccess(appObj);
+ }
+ });
+ return pendingGetSelf;
+ },
+
+ getInstalled: function(origin) {
+ let pendingGetInstalled = new pendingOperation("getInstalled");
+ Repo.getInstalled(origin, function(apps) {
+ if (pendingGetInstalled.onsuccess) {
+ let appObjs = [];
+ for (let i = 0; i < apps.length; i++) {
+ appObjs.push(new appObject(apps[i]));
+ }
+ pendingGetInstalled.result = appObjs;
+ pendingGetInstalled.onsuccess(appObjs);
+ }
+ });
+ return pendingGetInstalled;
+ },
+
// An application added to the local repo *without*
// user prompt. Used by sync, could be used by tests
// Do not expose to navigator.mozApps!
@@ -181,9 +264,15 @@ FFRepoImpl.prototype = {
},
+ // FIXME: return pendingAppInstall object, remove onsuccess, onerror
install: function _install(location, args, window) {
let self = this;
+ // Check if manifest is provided
+ if (!args.url) {
+ throw "install missing required url argument";
+ }
+
// added a quick hack to forgo the prompt if a special argument is
// sent in, to make it easy to install app straight from the lower-right prompt.
var autoInstall = args._autoInstall;
@@ -290,11 +379,13 @@ FFRepoImpl.prototype = {
args.url = args.origin;
}
- return Repo.install(location, args, displayPrompt, fetcher, function(result) {
+ let pendingAppInstall = new pendingOperation("appInstall");
+
+ Repo.install(location, args, displayPrompt, fetcher, function(result) {
//dump(" APPS | jetpack.install | Repo install returned to callback; result is " + result + "\n");
// install is complete
- if (result !== true) {
- if (args.onerror) {
+ if (result.error !== undefined) {
+ if (pendingAppInstall.onerror) {
let errorResult;
if (result.error.length == 2) {
// Then it's [code, error]
@@ -305,35 +396,36 @@ FFRepoImpl.prototype = {
} else {
errorResult = result.error;
}
- // Note, here and below we use (1,...) to force this to be
- // window (instead of args):
- (1, args.onerror)(errorResult);
+ pendingAppInstall.error = errorResult;
+ pendingAppInstall.onerror(errorResult);
}
} else {
let origin = URLParse(args.url).normalize().originOnly().toString();
- Repo.getAppById(origin, function(app) {
- self._observer.notifyObservers(
- null, "openwebapp-installed", JSON.stringify({
- origin: origin,
- skipPostInstallDashboard: args.skipPostInstallDashboard ? args.skipPostInstallDashboard : false
- }));
- self._callWatchers("add", [app]);
-
- // create OS-local application
- if (_makeNativeApp) {
- try {
- NativeShell.CreateNativeShell(app);
- } catch (e) {
- console.log("APPS | NativeShell | Aborted: " + e);
- }
+ self._observer.notifyObservers(
+ null, "openwebapp-installed", JSON.stringify({
+ origin: origin,
+ skipPostInstallDashboard: args.skipPostInstallDashboard ? args.skipPostInstallDashboard : false
+ }));
+ self._callWatchers("add", [result]);
+
+ // create OS-local application
+ if (_makeNativeApp) {
+ try {
+ NativeShell.CreateNativeShell(app);
+ } catch (e) {
+ console.log("APPS | NativeShell | Aborted: " + e);
}
- });
+ }
- if (args.onsuccess) {
- (1, args.onsuccess)();
+ if (pendingAppInstall.onsuccess) {
+ let appObj = new appObject(result);
+ pendingAppInstall.result = appObj;
+ pendingAppInstall.onsuccess(appObj);
}
}
});
+
+ return pendingAppInstall;
},
uninstall: function(key, onsuccess, onerror) {
View
32 addons/jetpack/lib/main.js
@@ -160,8 +160,8 @@ openwebapps.prototype = {
worker.port.on("owa.mgmt.launch", function(msg) {
repo.launch(msg.data);
});
- worker.port.on("owa.mgmt.list", function(msg) {
- repo.list(function(apps) {
+ worker.port.on("owa.mgmt.getAll", function(msg) {
+ repo.getAll(function(apps) {
worker.port.emit(msg.success, apps)
});
});
@@ -178,12 +178,10 @@ openwebapps.prototype = {
});
worker.port.on("owa.mgmt.clearWatch", function(msg) {
repo.clearWatch(worker);
- });
+ });
}
- });
+ });
}
-
-
};
//----- navigator.mozApps api implementation
@@ -227,25 +225,24 @@ MozAppsAPI.prototype = {
let repo = tmp.FFRepoImplService;
return {
// window.console API
- install: function(origin, data, onsuccess, onerror) {
+ install: function(origin, data) {
let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
let recentWindow = wm.getMostRecentWindow("navigator:browser");
let args = {
- url: origin, install_data: data,
- onsuccess: onsuccess, onerror: onerror
+ url: origin, installData: data
};
- repo.install(aWindow.location, args, recentWindow);
+ return repo.install(aWindow.location, args, recentWindow);
},
- amInstalled: function(callback) {
- repo.amInstalled(aWindow.location, callback);
+ getSelf: function() {
+ return repo.getSelf(aWindow.location);
},
- getInstalledBy: function(callback) {
- repo.getInstalledBy(aWindow.location, callback);
+ getInstalled: function() {
+ return repo.getInstalled(aWindow.location);
},
__exposedProps__: {
install: "r",
- amInstalled: "r",
- getInstalledBy: "r"
+ getSelf: "r",
+ getInstalled: "r"
}
};
}
@@ -545,7 +542,8 @@ function startup(getUrlCB) { /* Initialize simple storage */
Services.obs.notifyObservers(tmp.FFRepoImplService, "openwebapps-startup-complete", "");
// initialize the injector if we are <fx9
- require("./injector").init();
+ // we don't need to support fx<9 anymore, TODO: remove injector.js
+ // require("./injector").init();
}
function shutdown(why) {
View
1  jslibs/README
@@ -0,0 +1 @@
+THIS DIRECTORY IS OBSOLETE
Please sign in to comment.
Something went wrong with that request. Please try again.