mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
d241b9b5ea
--HG-- extra : transplant_source : %07gE1%BDt%10%5B%F6G%84%E6r%05%07%BB%83%E6%C8%20
246 lines
7.6 KiB
JavaScript
246 lines
7.6 KiB
JavaScript
const {Cc,Ci,Cu,Cr} = require("chrome");
|
||
const ObservableObject = require("devtools/shared/observable-object");
|
||
const promise = require("devtools/toolkit/deprecated-sync-thenables");
|
||
|
||
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
||
const {generateUUID} = Cc['@mozilla.org/uuid-generator;1'].getService(Ci.nsIUUIDGenerator);
|
||
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
|
||
const { indexedDB } = require("sdk/indexed-db");
|
||
|
||
/**
|
||
* 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 () {
|
||
let deferred = promise.defer();
|
||
|
||
let request = indexedDB.open(IDB.databaseName, 5);
|
||
request.onerror = function(event) {
|
||
deferred.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(() => {
|
||
deferred.resolve(projects);
|
||
});
|
||
}
|
||
};
|
||
};
|
||
|
||
return deferred.promise;
|
||
},
|
||
|
||
add: function(project) {
|
||
let deferred = promise.defer();
|
||
|
||
if (!project.location) {
|
||
// We need to make sure this object has a `.location` property.
|
||
deferred.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) {
|
||
deferred.reject("Unable to add project to the AppProjects indexedDB: " +
|
||
this.error.name + " - " + this.error.message );
|
||
};
|
||
request.onsuccess = function() {
|
||
deferred.resolve();
|
||
};
|
||
}
|
||
|
||
return deferred.promise;
|
||
},
|
||
|
||
update: function(project) {
|
||
let deferred = promise.defer();
|
||
|
||
// Clone object to make it storable by IndexedDB.
|
||
// Projects are proxified objects (for the template
|
||
// mechanismn in the first version of the App Manager).
|
||
// This will change in the future.
|
||
project = JSON.parse(JSON.stringify(project));
|
||
|
||
var transaction = IDB._db.transaction(["projects"], "readwrite");
|
||
var objectStore = transaction.objectStore("projects");
|
||
var request = objectStore.put(project);
|
||
request.onerror = function(event) {
|
||
deferred.reject("Unable to update project to the AppProjects indexedDB: " +
|
||
this.error.name + " - " + this.error.message );
|
||
};
|
||
request.onsuccess = function() {
|
||
deferred.resolve();
|
||
};
|
||
|
||
return deferred.promise;
|
||
},
|
||
|
||
remove: function(location) {
|
||
let deferred = promise.defer();
|
||
|
||
let request = IDB._db.transaction(["projects"], "readwrite")
|
||
.objectStore("projects")
|
||
.delete(location);
|
||
request.onsuccess = function(event) {
|
||
deferred.resolve();
|
||
};
|
||
request.onerror = function() {
|
||
deferred.reject("Unable to delete project to the AppProjects indexedDB: " +
|
||
this.error.name + " - " + this.error.message );
|
||
};
|
||
|
||
return deferred.promise;
|
||
}
|
||
};
|
||
|
||
const store = new ObservableObject({ projects:[] });
|
||
|
||
let loadDeferred = promise.defer();
|
||
|
||
loadDeferred.resolve(IDB.open().then(function (projects) {
|
||
store.object.projects = projects;
|
||
AppProjects.emit("ready", store.object.projects);
|
||
}));
|
||
|
||
const AppProjects = {
|
||
load: function() {
|
||
return loadDeferred.promise;
|
||
},
|
||
|
||
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(function () {
|
||
store.object.projects.push(project);
|
||
// return the added objects (proxified)
|
||
return store.object.projects[store.object.projects.length - 1];
|
||
});
|
||
},
|
||
|
||
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(function () {
|
||
store.object.projects.push(project);
|
||
// return the added objects (proxified)
|
||
return store.object.projects[store.object.projects.length - 1];
|
||
});
|
||
},
|
||
|
||
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(function () {
|
||
let projects = store.object.projects;
|
||
for (let i = 0; i < projects.length; i++) {
|
||
if (projects[i].location == location) {
|
||
projects.splice(i, 1);
|
||
return;
|
||
}
|
||
}
|
||
throw new Error("Unable to find project in AppProjects store");
|
||
});
|
||
},
|
||
|
||
get: function(location) {
|
||
let projects = store.object.projects;
|
||
for (let i = 0; i < projects.length; i++) {
|
||
if (projects[i].location == location) {
|
||
return projects[i];
|
||
}
|
||
}
|
||
return null;
|
||
},
|
||
|
||
store: store
|
||
};
|
||
|
||
EventEmitter.decorate(AppProjects);
|
||
|
||
exports.AppProjects = AppProjects;
|