fune/devtools/client/webide/modules/app-projects.js
Mark Banner d226fcc86a Bug 1453383 - Enable ESLint for devtools/client/{webaudioeditor,webide}/. r=jdescottes
MozReview-Commit-ID: Gm77Z0T3oJq

--HG--
extra : rebase_source : 9a23baa102558d30302baf5044da207b7d79f3b6
2018-04-11 16:10:35 +01:00

222 lines
6.9 KiB
JavaScript

/* 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/. */
const {Cc, Ci, Cr} = require("chrome");
const EventEmitter = require("devtools/shared/event-emitter");
const {generateUUID} = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
const {FileUtils} = require("resource://gre/modules/FileUtils.jsm");
/**
* IndexedDB wrapper that just save project objects
*
* The only constraint is that project objects have to have
* a unique `location` object.
*/
const IDB = {
_db: null,
databaseName: "AppProjects",
open: function() {
return new Promise((resolve, reject) => {
let request = indexedDB.open(IDB.databaseName, 5);
request.onerror = function(event) {
reject("Unable to open AppProjects indexedDB: " +
this.error.name + " - " + this.error.message);
};
request.onupgradeneeded = function(event) {
let db = event.target.result;
db.createObjectStore("projects", { keyPath: "location" });
};
request.onsuccess = function() {
let db = IDB._db = request.result;
let objectStore = db.transaction("projects").objectStore("projects");
let projects = [];
let toRemove = [];
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
if (cursor.value.location) {
// We need to make sure this object has a `.location` property.
// The UI depends on this property.
// This should not be needed as we make sure to register valid
// projects, but in the past (before bug 924568), we might have
// registered invalid objects.
// We also want to make sure the location is valid.
// If the location doesn't exist, we remove the project.
try {
let file = FileUtils.File(cursor.value.location);
if (file.exists()) {
projects.push(cursor.value);
} else {
toRemove.push(cursor.value.location);
}
} catch (e) {
if (e.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH) {
// A URL
projects.push(cursor.value);
}
}
}
cursor.continue();
} else {
let removePromises = [];
for (let location of toRemove) {
removePromises.push(IDB.remove(location));
}
Promise.all(removePromises).then(() => {
resolve(projects);
});
}
};
};
});
},
add: function(project) {
return new Promise((resolve, reject) => {
if (!project.location) {
// We need to make sure this object has a `.location` property.
reject("Missing location property on project object.");
} else {
let transaction = IDB._db.transaction(["projects"], "readwrite");
let objectStore = transaction.objectStore("projects");
let request = objectStore.add(project);
request.onerror = function(event) {
reject("Unable to add project to the AppProjects indexedDB: " +
this.error.name + " - " + this.error.message);
};
request.onsuccess = function() {
resolve();
};
}
});
},
update: function(project) {
return new Promise((resolve, reject) => {
let transaction = IDB._db.transaction(["projects"], "readwrite");
let objectStore = transaction.objectStore("projects");
let request = objectStore.put(project);
request.onerror = function(event) {
reject("Unable to update project to the AppProjects indexedDB: " +
this.error.name + " - " + this.error.message);
};
request.onsuccess = function() {
resolve();
};
});
},
remove: function(location) {
return new Promise((resolve, reject) => {
let request = IDB._db.transaction(["projects"], "readwrite")
.objectStore("projects")
.delete(location);
request.onsuccess = function(event) {
resolve();
};
request.onerror = function() {
reject("Unable to delete project to the AppProjects indexedDB: " +
this.error.name + " - " + this.error.message);
};
});
}
};
var loadDeferred = IDB.open().then(function(projects) {
AppProjects.projects = projects;
AppProjects.emit("ready", projects);
});
const AppProjects = {
load: function() {
return loadDeferred;
},
addPackaged: function(folder) {
let file = FileUtils.File(folder.path);
if (!file.exists()) {
return Promise.reject("path doesn't exist");
}
let existingProject = this.get(folder.path);
if (existingProject) {
return Promise.reject("Already added");
}
let project = {
type: "packaged",
location: folder.path,
// We need a unique id, that is the app origin,
// in order to identify the app when being installed on the device.
// The packaged app local path is a valid id, but only on the client.
// This origin will be used to generate the true id of an app:
// its manifest URL.
// If the app ends up specifying an explicit origin in its manifest,
// we will override this random UUID on app install.
packagedAppOrigin: generateUUID().toString().slice(1, -1)
};
return IDB.add(project).then(() => {
this.projects.push(project);
return project;
});
},
addHosted: function(manifestURL) {
let existingProject = this.get(manifestURL);
if (existingProject) {
return Promise.reject("Already added");
}
let project = {
type: "hosted",
location: manifestURL
};
return IDB.add(project).then(() => {
this.projects.push(project);
return project;
});
},
update: function(project) {
return IDB.update(project);
},
updateLocation: function(project, newLocation) {
return IDB.remove(project.location)
.then(() => {
project.location = newLocation;
return IDB.add(project);
});
},
remove: function(location) {
return IDB.remove(location).then(() => {
for (let i = 0; i < this.projects.length; i++) {
if (this.projects[i].location == location) {
this.projects.splice(i, 1);
return;
}
}
throw new Error("Unable to find project in AppProjects store");
});
},
get: function(location) {
for (let i = 0; i < this.projects.length; i++) {
if (this.projects[i].location == location) {
return this.projects[i];
}
}
return null;
},
projects: []
};
EventEmitter.decorate(AppProjects);
exports.AppProjects = AppProjects;