commit e4451d90025ad6c8a40c400fed43510d7846b7e8
parent efa8346d373525fcd6af7104da453f024e24513e
Author: Dan Stillman <dstillman@zotero.org>
Date: Thu, 30 Oct 2014 01:47:49 -0400
Merge pull request #575 from aurimasv/async_db-av
Async DB tweaks (attempt 2)
Diffstat:
7 files changed, 125 insertions(+), 78 deletions(-)
diff --git a/chrome/content/zotero/xpcom/data/collection.js b/chrome/content/zotero/xpcom/data/collection.js
@@ -24,12 +24,7 @@
*/
Zotero.Collection = function() {
- let dataTypes = [
- 'primaryData',
- 'childCollections',
- 'childItems'
- ];
- Zotero.DataObject.apply(this, ['collection', dataTypes]);
+ Zotero.Collection._super.apply(this);
this._name = null;
this._parentID = null;
@@ -42,9 +37,17 @@ Zotero.Collection = function() {
this._childItems = [];
}
-Zotero.Collection.prototype = Object.create(Zotero.DataObject.prototype);
+Zotero.Collection._super = Zotero.DataObject;
+Zotero.Collection.prototype = Object.create(Zotero.Collection._super.prototype);
Zotero.Collection.constructor = Zotero.Collection;
+Zotero.Collection.prototype._objectType = 'collection';
+Zotero.Collection.prototype._dataTypes = Zotero.Collection._super.prototype._dataTypes.concat([
+ 'primaryData',
+ 'childCollections',
+ 'childItems'
+]);
+
Zotero.Collection.prototype.__defineGetter__('id', function () { return this._get('id'); });
Zotero.Collection.prototype.__defineSetter__('id', function (val) { this._set('id', val); });
Zotero.Collection.prototype.__defineGetter__('libraryID', function () { return this._get('libraryID'); });
diff --git a/chrome/content/zotero/xpcom/data/dataObject.js b/chrome/content/zotero/xpcom/data/dataObject.js
@@ -24,21 +24,16 @@
*/
/**
- *
- * @param {String} objectType
- * @param {String[]} dataTypes A set of data types that can be loaded for this data object
- *
* @property {String} (readOnly) objectType
* @property {String} (readOnly) libraryKey
* @property {String|null} parentKey Null if no parent
* @property {Integer|false|undefined} parentID False if no parent. Undefined if not applicable (e.g. search objects)
*/
-Zotero.DataObject = function (objectType, dataTypes) {
- this._objectType = objectType;
+Zotero.DataObject = function () {
+ let objectType = this._objectType;
this._ObjectType = objectType[0].toUpperCase() + objectType.substr(1);
this._objectTypePlural = Zotero.DataObjectUtilities.getObjectTypePlural(objectType);
- this._dataTypes = dataTypes;
this._id = null;
this._libraryID = null;
@@ -57,27 +52,26 @@ Zotero.DataObject = function (objectType, dataTypes) {
this._clearChanged();
};
-Zotero.Utilities.Internal.defineProperty(Zotero.DataObject, 'objectType', {
+Zotero.DataObject.prototype._objectType = 'dataObject';
+Zotero.DataObject.prototype._dataTypes = [];
+
+Zotero.Utilities.Internal.defineProperty(Zotero.DataObject.prototype, 'objectType', {
get: function() this._objectType
});
-Zotero.Utilities.Internal.defineProperty(Zotero.DataObject, 'libraryKey', {
+Zotero.Utilities.Internal.defineProperty(Zotero.DataObject.prototype, 'libraryKey', {
get: function() this._libraryID + "/" + this._key
});
-Zotero.Utilities.Internal.defineProperty(Zotero.DataObject, 'parentKey', {
+Zotero.Utilities.Internal.defineProperty(Zotero.DataObject.prototype, 'parentKey', {
get: function() this._parentKey,
set: function(v) this._setParentKey(v)
});
-Zotero.Utilities.Internal.defineProperty(Zotero.DataObject, 'parentID', {
+Zotero.Utilities.Internal.defineProperty(Zotero.DataObject.prototype, 'parentID', {
get: function() this._getParentID(),
set: function(v) this._setParentID(v)
});
Zotero.DataObject.prototype._get = function (field) {
- if (this._objectType == 'item') {
- throw new Error("_get is not valid for items");
- }
-
if (this['_' + field] !== null) {
return this['_' + field];
}
@@ -166,11 +160,6 @@ Zotero.DataObject.prototype._setParentID = function (id) {
* @return {Boolean} True if changed, false if stayed the same
*/
Zotero.DataObject.prototype._setParentKey = function(key) {
- if (this._objectType == 'item') {
- if (!this.isNote() && !this.isAttachment()) {
- throw new Error("_setParentKey() can only be called on items of type 'note' or 'attachment'");
- }
- }
key = Zotero.DataObjectUtilities.checkKey(key);
if (this._parentKey == key) {
diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js
@@ -32,18 +32,7 @@ Zotero.Item = function(itemTypeOrID) {
throw ("Zotero.Item constructor only takes one parameter");
}
- var dataTypes = [
- 'primaryData',
- 'itemData',
- 'note',
- 'creators',
- 'childItems',
- 'relatedItems', // TODO: remove
- 'tags',
- 'collections',
- 'relations'
- ];
- Zotero.DataObject.apply(this, ['item', dataTypes]);
+ Zotero.Item._super.apply(this);
this._disabled = false;
@@ -100,10 +89,23 @@ Zotero.Item = function(itemTypeOrID) {
}
}
-Zotero.Item.prototype = Object.create(Zotero.DataObject.prototype);
+Zotero.Item._super = Zotero.DataObject;
+Zotero.Item.prototype = Object.create(Zotero.Item._super.prototype);
Zotero.Item.constructor = Zotero.Item;
-Zotero.Item.prototype.__defineGetter__('objectType', function () { return 'item'; });
+Zotero.Item.prototype._objectType = 'item';
+Zotero.Item.prototype._dataTypes = Zotero.Item._super.prototype._dataTypes.concat([
+ 'primaryData',
+ 'itemData',
+ 'note',
+ 'creators',
+ 'childItems',
+ 'relatedItems', // TODO: remove
+ 'tags',
+ 'collections',
+ 'relations'
+]);
+
Zotero.Item.prototype.__defineGetter__('id', function () this._id);
Zotero.Item.prototype.__defineGetter__('itemID', function () {
Zotero.debug("Item.itemID is deprecated -- use Item.id");
@@ -149,6 +151,17 @@ Zotero.Item.prototype.isPrimaryField = function (fieldName) {
return Zotero.Items.isPrimaryField(fieldName);
}
+Zotero.Item.prototype._get = function (fieldName) {
+ throw new Error("_get is not valid for items");
+}
+
+Zotero.Item.prototype._setParentKey = function() {
+ if (!this.isNote() && !this.isAttachment()) {
+ throw new Error("_setParentKey() can only be called on items of type 'note' or 'attachment'");
+ }
+
+ Zotero.Item._super.prototype._setParentKey.apply(this, arguments);
+}
//////////////////////////////////////////////////////////////////////////////
//
diff --git a/chrome/content/zotero/xpcom/data/libraries.js b/chrome/content/zotero/xpcom/data/libraries.js
@@ -24,7 +24,18 @@
*/
Zotero.Libraries = new function () {
- var _libraryData = {};
+ let _libraryData = {},
+ _userLibraryID,
+ _libraryDataLoaded = false;
+
+ Zotero.Utilities.Internal.defineProperty(this, 'userLibraryID', {
+ get: function() {
+ if (!_libraryDataLoaded) {
+ throw new Error("Library data not yet loaded");
+ }
+ return _userLibraryID;
+ }
+ });
this.init = Zotero.Promise.coroutine(function* () {
// Library data
@@ -36,25 +47,28 @@ Zotero.Libraries = new function () {
type: row.libraryType,
version: row.version
};
+ if (row.libraryType == 'user') {
+ _userLibraryID = row.libraryID;
+ }
}
+ _libraryDataLoaded = true;
});
+ function _getLibraryDataFromDB (libraryID) {
+ var sql = "SELECT * FROM libraries WHERE libraryID=?";
+ return Zotero.DB.queryAsync(sql, [libraryID])
+ .then(function(rows) {
+ return rows[0];
+ });
+ }
+
+
this.exists = function (libraryID) {
- // Until there are other library types, this can just check groups,
- // which already preload ids at startup
- try {
- return !!Zotero.Groups.getGroupIDFromLibraryID(libraryID);
- }
- catch (e) {
- if (e.getMessage().indexOf("does not exist") != -1) {
- return false;
- }
- throw e;
- }
+ return _libraryData[libraryID] !== undefined;
}
- this.add = function (libraryID, type) {
+ this.add = Zotero.Promise.coroutine(function* (libraryID, type) {
switch (type) {
case 'group':
break;
@@ -64,9 +78,16 @@ Zotero.Libraries = new function () {
}
var sql = "INSERT INTO libraries (libraryID, libraryType) VALUES (?, ?)";
- Zotero.DB.query(sql, [libraryID, type]);
- }
-
+ yield Zotero.DB.queryAsync(sql, [libraryID, type]);
+ // Re-fetch from DB to get auto-filled defaults
+ var newData = yield _getLibraryDataFromDB(libraryID);
+ _libraryData[newData.libraryID] = {
+ type: newData.libraryType,
+ version: newData.version
+ };
+
+ return newData;
+ });
this.dbLibraryID = function (libraryID) {
return (libraryID == Zotero.Users.getCurrentLibraryID()) ? 0 : libraryID;
@@ -74,12 +95,10 @@ Zotero.Libraries = new function () {
this.getName = function (libraryID) {
- if (!libraryID) {
- return Zotero.getString('pane.collections.library');
- }
-
var type = this.getType(libraryID);
switch (type) {
+ case 'user':
+ return Zotero.getString('pane.collections.library');
case 'group':
var groupID = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
var group = Zotero.Groups.get(groupID);
@@ -92,10 +111,10 @@ Zotero.Libraries = new function () {
this.getType = function (libraryID) {
- if (this.dbLibraryID(libraryID) === 0) {
+ if (libraryID === Zotero.Libraries.userLibraryID) {
return 'user';
}
- if (!_libraryData[libraryID]) {
+ if (!this.exists(libraryID)) {
throw new Error("Library data not loaded for library " + libraryID);
}
return _libraryData[libraryID].type;
@@ -106,7 +125,7 @@ Zotero.Libraries = new function () {
* @return {Integer}
*/
this.getVersion = function (libraryID) {
- if (!_libraryData[libraryID]) {
+ if (!this.exists(libraryID)) {
throw new Error("Library data not loaded for library " + libraryID);
}
return _libraryData[libraryID].version;
@@ -122,7 +141,7 @@ Zotero.Libraries = new function () {
version = parseInt(version);
var sql = "UPDATE libraries SET version=? WHERE libraryID=?";
yield Zotero.DB.queryAsync(sql, [version, libraryID]);
- _libraryData[libraryID] = version;
+ _libraryData[libraryID].version = version;
});
diff --git a/chrome/content/zotero/xpcom/search.js b/chrome/content/zotero/xpcom/search.js
@@ -24,11 +24,7 @@
*/
Zotero.Search = function() {
- var dataTypes = [
- 'primaryData',
- 'conditions'
- ];
- Zotero.DataObject.apply(this, ['search', dataTypes]);
+ Zotero.Search._super.apply(this);
this._name = null;
@@ -41,9 +37,16 @@ Zotero.Search = function() {
this._hasPrimaryConditions = false;
}
-Zotero.Search.prototype = Object.create(Zotero.DataObject.prototype);
+Zotero.Search._super = Zotero.DataObject;
+Zotero.Search.prototype = Object.create(Zotero.Search._super.prototype);
Zotero.Search.constructor = Zotero.Search;
+Zotero.Search.prototype._objectType = 'search';
+Zotero.Search.prototype._dataTypes = Zotero.Search._super.prototype._dataTypes.concat([
+ 'primaryData',
+ 'conditions'
+]);
+
Zotero.Search.prototype.getID = function(){
Zotero.debug('Zotero.Search.getName() is deprecated -- use Search.id');
return this._id;
diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js
@@ -411,11 +411,7 @@ Zotero.Utilities = {
// Create a node and use the textContent property to do unescaping where
// possible, because this approach preserves line endings in the HTML
if(node === undefined) {
- var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
- .createInstance(Components.interfaces.nsIDOMParser);
- var domDocument = parser.parseFromString("<!DOCTYPE html><html></html>",
- "text/html");
- node = domDocument.createElement("div");
+ node = Zotero.Utilities.Internal.getDOMDocument().createElement("div");
}
node.innerHTML = str;
@@ -441,6 +437,20 @@ Zotero.Utilities = {
},
/**
+ * Converts text inside a DOM object to plain text preserving text formatting
+ * appropriate for given field
+ *
+ * @param {DOMNode} rootNode Node containing all the text that needs to be extracted
+ * @param {String} targetField Zotero item field that the text is meant for
+ *
+ * @return {String} Zotero formatted string
+ */
+ "dom2text": function(rootNode, targetField) {
+ // TODO: actually do this
+ return Zotero.Utilities.trimInternal(rootNode.textContent);
+ },
+
+ /**
* Wrap URLs and DOIs in <a href=""> links in plain text
*
* Ignore URLs preceded by '>', just in case there are already links
diff --git a/chrome/content/zotero/xpcom/utilities_internal.js b/chrome/content/zotero/xpcom/utilities_internal.js
@@ -346,6 +346,16 @@ Zotero.Utilities.Internal = {
/**
+ * Returns a DOMDocument object not attached to any window
+ */
+ "getDOMDocument": function() {
+ return Components.classes["@mozilla.org/xmlextras/domparser;1"]
+ .createInstance(Components.interfaces.nsIDOMParser)
+ .parseFromString("<!DOCTYPE html><html></html>", "text/html");
+ },
+
+
+ /**
* A generator that yields promises that delay for the given intervals
*
* @param {Array<Integer>} intervals An array of intervals in milliseconds
@@ -486,7 +496,7 @@ Zotero.Utilities.Internal = {
},
/**
- * Defines property on the object's prototype.
+ * Defines property on the object
* More compact way to do Object.defineProperty
*
* @param {Object} obj Target object
@@ -500,7 +510,7 @@ Zotero.Utilities.Internal = {
if (!desc.hasOwnProperty(p)) continue;
d[p] = desc[p];
}
- Object.defineProperty(obj.prototype, prop, d);
+ Object.defineProperty(obj, prop, d);
}
}