mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 03:35:33 +00:00
5dec0e0beb
This patch was autogenerated by my decomponents.py It covers almost every file with the extension js, jsm, html, py, xhtml, or xul. It removes blank lines after removed lines, when the removed lines are preceded by either blank lines or the start of a new block. The "start of a new block" is defined fairly hackily: either the line starts with //, ends with */, ends with {, <![CDATA[, """ or '''. The first two cover comments, the third one covers JS, the fourth covers JS embedded in XUL, and the final two cover JS embedded in Python. This also applies if the removed line was the first line of the file. It covers the pattern matching cases like "var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;". It'll remove the entire thing if they are all either Ci, Cr, Cc or Cu, or it will remove the appropriate ones and leave the residue behind. If there's only one behind, then it will turn it into a normal, non-pattern matching variable definition. (For instance, "const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components" becomes "const CC = Components.Constructor".) MozReview-Commit-ID: DeSHcClQ7cG --HG-- extra : rebase_source : d9c41878036c1ef7766ef5e91a7005025bc1d72b
227 lines
6.4 KiB
JavaScript
227 lines
6.4 KiB
JavaScript
/*
|
|
* Manifest.jsm is the top level api for managing installed web applications
|
|
* https://www.w3.org/TR/appmanifest/
|
|
*
|
|
* It is used to trigger the installation of a web application via .install()
|
|
* and to access the manifest data (including icons).
|
|
*
|
|
* TODO:
|
|
* - Trigger appropriate app installed events
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
const { ManifestObtainer } =
|
|
ChromeUtils.import("resource://gre/modules/ManifestObtainer.jsm", {});
|
|
const { ManifestIcons } =
|
|
ChromeUtils.import("resource://gre/modules/ManifestIcons.jsm", {});
|
|
|
|
ChromeUtils.defineModuleGetter(this, "OS",
|
|
"resource://gre/modules/osfile.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "JSONFile",
|
|
"resource://gre/modules/JSONFile.jsm");
|
|
|
|
/**
|
|
* Generates an hash for the given string.
|
|
*
|
|
* @note The generated hash is returned in base64 form. Mind the fact base64
|
|
* is case-sensitive if you are going to reuse this code.
|
|
*/
|
|
function generateHash(aString) {
|
|
const cryptoHash = Cc["@mozilla.org/security/hash;1"]
|
|
.createInstance(Ci.nsICryptoHash);
|
|
cryptoHash.init(Ci.nsICryptoHash.MD5);
|
|
const stringStream = Cc["@mozilla.org/io/string-input-stream;1"]
|
|
.createInstance(Ci.nsIStringInputStream);
|
|
stringStream.data = aString;
|
|
cryptoHash.updateFromStream(stringStream, -1);
|
|
// base64 allows the '/' char, but we can't use it for filenames.
|
|
return cryptoHash.finish(true).replace(/\//g, "-");
|
|
}
|
|
|
|
/**
|
|
* Trims the query paramters from a url
|
|
*/
|
|
function stripQuery(url) {
|
|
return url.split("?")[0];
|
|
}
|
|
|
|
// Folder in which we store the manifest files
|
|
const MANIFESTS_DIR = OS.Path.join(OS.Constants.Path.profileDir, "manifests");
|
|
|
|
// We maintain a list of scopes for installed webmanifests so we can determine
|
|
// whether a given url is within the scope of a previously installed manifest
|
|
const MANIFESTS_FILE = "manifest-scopes.json";
|
|
|
|
/**
|
|
* Manifest object
|
|
*/
|
|
|
|
class Manifest {
|
|
|
|
constructor(browser, manifestUrl) {
|
|
this._manifestUrl = manifestUrl;
|
|
// The key for this is the manifests URL that is required to be unique.
|
|
// However arbitrary urls are not safe file paths so lets hash it.
|
|
const fileName = generateHash(manifestUrl) + ".json";
|
|
this._path = OS.Path.join(MANIFESTS_DIR, fileName);
|
|
this._browser = browser;
|
|
}
|
|
|
|
async initialise() {
|
|
this._store = new JSONFile({path: this._path, saveDelayMs: 100});
|
|
await this._store.load();
|
|
}
|
|
|
|
async prefetch(browser) {
|
|
const manifestData = await ManifestObtainer.browserObtainManifest(browser);
|
|
const icon = await ManifestIcons.browserFetchIcon(browser, manifestData, 192);
|
|
const data = {
|
|
installed: false,
|
|
manifest: manifestData,
|
|
cached_icon: icon
|
|
};
|
|
return data;
|
|
}
|
|
|
|
async install() {
|
|
const manifestData = await ManifestObtainer.browserObtainManifest(this._browser);
|
|
this._store.data = {
|
|
installed: true,
|
|
manifest: manifestData
|
|
};
|
|
Manifests.manifestInstalled(this);
|
|
this._store.saveSoon();
|
|
}
|
|
|
|
async icon(expectedSize) {
|
|
if ('cached_icon' in this._store.data) {
|
|
return this._store.data.cached_icon;
|
|
}
|
|
const icon = await ManifestIcons
|
|
.browserFetchIcon(this._browser, this._store.data.manifest, expectedSize);
|
|
// Cache the icon so future requests do not go over the network
|
|
this._store.data.cached_icon = icon;
|
|
this._store.saveSoon();
|
|
return icon;
|
|
}
|
|
|
|
get scope() {
|
|
const scope = this._store.data.manifest.scope ||
|
|
this._store.data.manifest.start_url;
|
|
return stripQuery(scope);
|
|
}
|
|
|
|
get name() {
|
|
return this._store.data.manifest.short_name ||
|
|
this._store.data.manifest.name ||
|
|
this._store.data.manifest.short_url;
|
|
}
|
|
|
|
get url() {
|
|
return this._manifestUrl;
|
|
}
|
|
|
|
get installed() {
|
|
return this._store.data && this._store.data.installed || false;
|
|
}
|
|
|
|
get start_url() {
|
|
return this._store.data.manifest.start_url;
|
|
}
|
|
|
|
get path() {
|
|
return this._path;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Manifests maintains the list of installed manifests
|
|
*/
|
|
var Manifests = {
|
|
|
|
async initialise () {
|
|
|
|
if (this.started) {
|
|
return this.started;
|
|
}
|
|
|
|
this.started = (async () => {
|
|
|
|
// Make sure the manifests have the folder needed to save into
|
|
await OS.File.makeDir(MANIFESTS_DIR, {ignoreExisting: true});
|
|
|
|
// Ensure any existing scope data we have about manifests is loaded
|
|
this._path = OS.Path.join(OS.Constants.Path.profileDir, MANIFESTS_FILE);
|
|
this._store = new JSONFile({path: this._path});
|
|
await this._store.load();
|
|
|
|
// If we dont have any existing data, initialise empty
|
|
if (!this._store.data.hasOwnProperty("scopes")) {
|
|
this._store.data.scopes = new Map();
|
|
}
|
|
|
|
// Cache the Manifest objects creates as they are references to files
|
|
// and we do not want multiple file handles
|
|
this.manifestObjs = {};
|
|
|
|
})();
|
|
|
|
return this.started;
|
|
},
|
|
|
|
// When a manifest is installed, we save its scope so we can determine if
|
|
// fiture visits fall within this manifests scope
|
|
manifestInstalled(manifest) {
|
|
this._store.data.scopes[manifest.scope] = manifest.url;
|
|
this._store.saveSoon();
|
|
},
|
|
|
|
// Given a url, find if it is within an installed manifests scope and if so
|
|
// return that manifests url
|
|
findManifestUrl(url) {
|
|
for (let scope in this._store.data.scopes) {
|
|
if (url.startsWith(scope)) {
|
|
return this._store.data.scopes[scope];
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
|
|
// Get the manifest given a url, or if not look for a manifest that is
|
|
// tied to the current page
|
|
async getManifest(browser, manifestUrl) {
|
|
|
|
// Ensure we have all started up
|
|
await this.initialise();
|
|
|
|
// If the client does not already know its manifestUrl, we take the
|
|
// url of the client and see if it matches the scope of any installed
|
|
// manifests
|
|
if (!manifestUrl) {
|
|
const url = stripQuery(browser.currentURI.spec);
|
|
manifestUrl = this.findManifestUrl(url);
|
|
}
|
|
|
|
// No matches so no manifest
|
|
if (manifestUrl === null) {
|
|
return null;
|
|
}
|
|
|
|
// If we have already created this manifest return cached
|
|
if (manifestUrl in this.manifestObjs) {
|
|
return this.manifestObjs[manifestUrl];
|
|
}
|
|
|
|
// Otherwise create a new manifest object
|
|
this.manifestObjs[manifestUrl] = new Manifest(browser, manifestUrl);
|
|
await this.manifestObjs[manifestUrl].initialise();
|
|
return this.manifestObjs[manifestUrl];
|
|
}
|
|
|
|
};
|
|
|
|
this.EXPORTED_SYMBOLS = ["Manifests"]; // jshint ignore:line
|