зеркало из https://github.com/mozilla/gecko-dev.git
376 строки
11 KiB
JavaScript
376 строки
11 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/. */
|
|
|
|
"use strict";
|
|
|
|
this.EXPORTED_SYMBOLS = ["PlacesWrapper"];
|
|
|
|
const {interfaces: Ci, utils: Cu} = Components;
|
|
const REASON_ERROR = Ci.mozIStorageStatementCallback.REASON_ERROR;
|
|
|
|
Cu.import("resource://gre/modules/Promise.jsm");
|
|
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
|
Cu.import("resource:///modules/PlacesUIUtils.jsm");
|
|
Cu.import("resource://services-common/utils.js");
|
|
|
|
var PlacesQueries = function () {
|
|
}
|
|
|
|
PlacesQueries.prototype = {
|
|
cachedStmts: {},
|
|
|
|
getQuery: function (queryString) {
|
|
if (queryString in this.cachedStmts) {
|
|
return this.cachedStmts[queryString];
|
|
}
|
|
|
|
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
|
|
return this.cachedStmts[queryString] = db.createAsyncStatement(queryString);
|
|
}
|
|
};
|
|
|
|
var PlacesWrapper = function () {
|
|
}
|
|
|
|
PlacesWrapper.prototype = {
|
|
placesQueries: new PlacesQueries(),
|
|
|
|
guidToLocalId: function (guid) {
|
|
let deferred = Promise.defer();
|
|
|
|
let stmt = "SELECT id AS item_id " +
|
|
"FROM moz_bookmarks " +
|
|
"WHERE guid = :guid";
|
|
let query = this.placesQueries.getQuery(stmt);
|
|
|
|
function getLocalId(results) {
|
|
let result = results[0] && results[0]["item_id"];
|
|
return Promise.resolve(result);
|
|
}
|
|
|
|
query.params.guid = guid.toString();
|
|
|
|
this.asyncQuery(query, ["item_id"])
|
|
.then(getLocalId, deferred.reject)
|
|
.then(deferred.resolve, deferred.reject);
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
localIdToGuid: function (id) {
|
|
let deferred = Promise.defer();
|
|
|
|
let stmt = "SELECT guid " +
|
|
"FROM moz_bookmarks " +
|
|
"WHERE id = :item_id";
|
|
let query = this.placesQueries.getQuery(stmt);
|
|
|
|
function getGuid(results) {
|
|
let result = results[0] && results[0]["guid"];
|
|
return Promise.resolve(result);
|
|
}
|
|
|
|
query.params.item_id = id;
|
|
|
|
this.asyncQuery(query, ["guid"])
|
|
.then(getGuid, deferred.reject)
|
|
.then(deferred.resolve, deferred.reject);
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
getItemsById: function (ids, types) {
|
|
let deferred = Promise.defer();
|
|
let stmt = "SELECT b.id, b.type, b.parent, b.position, b.title, b.guid, b.dateAdded, b.lastModified, p.url " +
|
|
"FROM moz_bookmarks b " +
|
|
"LEFT JOIN moz_places p ON b.fk = p.id " +
|
|
"WHERE b.id in (" + ids.join(",") + ") AND b.type in (" + types.join(",") + ")";
|
|
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
|
|
let query = db.createAsyncStatement(stmt);
|
|
|
|
this.asyncQuery(query, ["id", "type", "parent", "position", "title", "guid", "dateAdded", "lastModified", "url"])
|
|
.then(deferred.resolve, deferred.reject);
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
getItemsByParentId: function (parents, types) {
|
|
let deferred = Promise.defer();
|
|
let stmt = "SELECT b.id, b.type, b.parent, b.position, b.title, b.guid, b.dateAdded, b.lastModified, p.url " +
|
|
"FROM moz_bookmarks b " +
|
|
"LEFT JOIN moz_places p ON b.fk = p.id " +
|
|
"WHERE b.parent in (" + parents.join(",") + ") AND b.type in (" + types.join(",") + ")";
|
|
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
|
|
let query = db.createAsyncStatement(stmt);
|
|
|
|
this.asyncQuery(query, ["id", "type", "parent", "position", "title", "guid", "dateAdded", "lastModified", "url"])
|
|
.then(deferred.resolve, deferred.reject);
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
getItemsByGuid: function (guids, types) {
|
|
let deferred = Promise.defer();
|
|
guids = guids.map(JSON.stringify);
|
|
let stmt = "SELECT b.id, b.type, b.parent, b.position, b.title, b.guid, b.dateAdded, b.lastModified, p.url " +
|
|
"FROM moz_bookmarks b " +
|
|
"LEFT JOIN moz_places p ON b.fk = p.id " +
|
|
"WHERE b.guid in (" + guids.join(",") + ") AND b.type in (" + types.join(",") + ")";
|
|
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
|
|
let query = db.createAsyncStatement(stmt);
|
|
|
|
this.asyncQuery(query, ["id", "type", "parent", "position", "title", "guid", "dateAdded", "lastModified", "url"])
|
|
.then(deferred.resolve, deferred.reject);
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
updateCachedFolderIds: function (folderCache, folder) {
|
|
let deferred = Promise.defer();
|
|
let stmt = "SELECT id, guid " +
|
|
"FROM moz_bookmarks " +
|
|
"WHERE parent = :parent_id AND type = :item_type";
|
|
let query = this.placesQueries.getQuery(stmt);
|
|
|
|
query.params.parent_id = folder;
|
|
query.params.item_type = PlacesUtils.bookmarks.TYPE_FOLDER;
|
|
|
|
this.asyncQuery(query, ["id", "guid"]).then(
|
|
function (items) {
|
|
let previousIds = folderCache.getChildren(folder);
|
|
let currentIds = new Set();
|
|
for (let item of items) {
|
|
currentIds.add(item.id);
|
|
}
|
|
let newIds = new Set();
|
|
let missingIds = new Set();
|
|
|
|
for (let currentId of currentIds) {
|
|
if (!previousIds.has(currentId)) {
|
|
newIds.add(currentId);
|
|
}
|
|
}
|
|
for (let previousId of previousIds) {
|
|
if (!currentIds.has(previousId)) {
|
|
missingIds.add(previousId);
|
|
}
|
|
}
|
|
|
|
folderCache.setChildren(folder, currentIds);
|
|
|
|
let promises = [];
|
|
for (let newId of newIds) {
|
|
promises.push(this.updateCachedFolderIds(folderCache, newId));
|
|
}
|
|
Promise.all(promises)
|
|
.then(deferred.resolve, deferred.reject);
|
|
|
|
for (let missingId of missingIds) {
|
|
folderCache.remove(missingId);
|
|
}
|
|
}.bind(this)
|
|
);
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
getLocalIdsWithAnnotation: function (anno) {
|
|
let deferred = Promise.defer();
|
|
let stmt = "SELECT a.item_id " +
|
|
"FROM moz_anno_attributes n " +
|
|
"JOIN moz_items_annos a ON n.id = a.anno_attribute_id " +
|
|
"WHERE n.name = :anno_name";
|
|
let query = this.placesQueries.getQuery(stmt);
|
|
|
|
query.params.anno_name = anno.toString();
|
|
|
|
this.asyncQuery(query, ["item_id"])
|
|
.then(function (items) {
|
|
let results = [];
|
|
for (let item of items) {
|
|
results.push(item.item_id);
|
|
}
|
|
deferred.resolve(results);
|
|
},
|
|
deferred.reject);
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
getItemAnnotationsForLocalId: function (id) {
|
|
let deferred = Promise.defer();
|
|
let stmt = "SELECT a.name, b.content " +
|
|
"FROM moz_anno_attributes a " +
|
|
"JOIN moz_items_annos b ON a.id = b.anno_attribute_id " +
|
|
"WHERE b.item_id = :item_id";
|
|
let query = this.placesQueries.getQuery(stmt);
|
|
|
|
query.params.item_id = id;
|
|
|
|
this.asyncQuery(query, ["name", "content"])
|
|
.then(function (results) {
|
|
let annos = {};
|
|
for (let result of results) {
|
|
annos[result.name] = result.content;
|
|
}
|
|
deferred.resolve(annos);
|
|
},
|
|
deferred.reject);
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
insertBookmark: function (parent, uri, index, title, guid) {
|
|
let parsedURI;
|
|
try {
|
|
parsedURI = CommonUtils.makeURI(uri)
|
|
} catch (e) {
|
|
return Promise.reject("unable to parse URI '" + uri + "': " + e);
|
|
}
|
|
|
|
try {
|
|
let id = PlacesUtils.bookmarks.insertBookmark(parent, parsedURI, index, title, guid);
|
|
return Promise.resolve(id);
|
|
} catch (e) {
|
|
return Promise.reject("unable to insert bookmark " + JSON.stringify(arguments) + ": " + e);
|
|
}
|
|
},
|
|
|
|
setItemAnnotation: function (item, anno, value, flags, exp) {
|
|
try {
|
|
return Promise.resolve(PlacesUtils.annotations.setItemAnnotation(item, anno, value, flags, exp));
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
},
|
|
|
|
itemHasAnnotation: function (item, anno) {
|
|
try {
|
|
return Promise.resolve(PlacesUtils.annotations.itemHasAnnotation(item, anno));
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
},
|
|
|
|
createFolder: function (parent, name, index, guid) {
|
|
try {
|
|
return Promise.resolve(PlacesUtils.bookmarks.createFolder(parent, name, index, guid));
|
|
} catch (e) {
|
|
return Promise.reject("unable to create folder ['" + name + "']: " + e);
|
|
}
|
|
},
|
|
|
|
removeFolderChildren: function (folder) {
|
|
try {
|
|
PlacesUtils.bookmarks.removeFolderChildren(folder);
|
|
return Promise.resolve();
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
},
|
|
|
|
insertSeparator: function (parent, index, guid) {
|
|
try {
|
|
return Promise.resolve(PlacesUtils.bookmarks.insertSeparator(parent, index, guid));
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
},
|
|
|
|
removeItem: function (item) {
|
|
try {
|
|
return Promise.resolve(PlacesUtils.bookmarks.removeItem(item));
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
},
|
|
|
|
setItemDateAdded: function (item, dateAdded) {
|
|
try {
|
|
return Promise.resolve(PlacesUtils.bookmarks.setItemDateAdded(item, dateAdded));
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
},
|
|
|
|
setItemLastModified: function (item, lastModified) {
|
|
try {
|
|
return Promise.resolve(PlacesUtils.bookmarks.setItemLastModified(item, lastModified));
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
},
|
|
|
|
setItemTitle: function (item, title) {
|
|
try {
|
|
return Promise.resolve(PlacesUtils.bookmarks.setItemTitle(item, title));
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
},
|
|
|
|
changeBookmarkURI: function (item, uri) {
|
|
try {
|
|
uri = CommonUtils.makeURI(uri);
|
|
return Promise.resolve(PlacesUtils.bookmarks.changeBookmarkURI(item, uri));
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
},
|
|
|
|
moveItem: function (item, parent, index) {
|
|
try {
|
|
return Promise.resolve(PlacesUtils.bookmarks.moveItem(item, parent, index));
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
},
|
|
|
|
setItemIndex: function (item, index) {
|
|
try {
|
|
return Promise.resolve(PlacesUtils.bookmarks.setItemIndex(item, index));
|
|
} catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
},
|
|
|
|
asyncQuery: function (query, names) {
|
|
let deferred = Promise.defer();
|
|
let storageCallback = {
|
|
results: [],
|
|
handleResult: function (results) {
|
|
if (!names) {
|
|
return;
|
|
}
|
|
|
|
let row;
|
|
while ((row = results.getNextRow()) != null) {
|
|
let item = {};
|
|
for (let name of names) {
|
|
item[name] = row.getResultByName(name);
|
|
}
|
|
this.results.push(item);
|
|
}
|
|
},
|
|
|
|
handleError: function (error) {
|
|
deferred.reject(error);
|
|
},
|
|
|
|
handleCompletion: function (reason) {
|
|
if (REASON_ERROR == reason) {
|
|
return;
|
|
}
|
|
|
|
deferred.resolve(this.results);
|
|
}
|
|
};
|
|
|
|
query.executeAsync(storageCallback);
|
|
return deferred.promise;
|
|
},
|
|
};
|
|
|
|
this.PlacesWrapper = new PlacesWrapper();
|