[\s\S]*<\/div>$/)) {
- // Keep consistent with getNote()
- noteText = '
' + noteText + '
';
- }
-
- let params = [
- parent ? parent : null,
- noteText,
- this._noteTitle ? this._noteTitle : ''
- ];
- let sql = "SELECT COUNT(*) FROM itemNotes WHERE itemID=?";
- if (yield Zotero.DB.valueQueryAsync(sql, itemID)) {
- sql = "UPDATE itemNotes SET parentItemID=?, note=?, title=? WHERE itemID=?";
- params.push(itemID);
- }
- else {
- sql = "INSERT INTO itemNotes "
- + "(itemID, parentItemID, note, title) VALUES (?,?,?,?)";
- params.unshift(itemID);
- }
- yield Zotero.DB.queryAsync(sql, params);
-
- if (parentItem) {
- reloadParentChildItems[parentItem.id] = true;
- }
- }
-
- //
- // Attachment
- //
- if (!isNew) {
- // If attachment title changes, update parent attachments
- if (this._changed.itemData && this._changed.itemData[110] && this.isAttachment() && parentItem) {
- reloadParentChildItems[parentItem.id] = true;
- }
- }
-
- if (this.isAttachment() || this._changed.attachmentData) {
- let sql = "REPLACE INTO itemAttachments (itemID, parentItemID, linkMode, "
- + "contentType, charsetID, path, syncState) VALUES (?,?,?,?,?,?,?)";
- let parent = this.parentID;
- let linkMode = this.attachmentLinkMode;
- let contentType = this.attachmentContentType;
- let charsetID = Zotero.CharacterSets.getID(this.attachmentCharset);
- let path = this.attachmentPath;
- let syncState = this.attachmentSyncState;
-
- if (this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE) {
- // Save attachment within attachment base directory as relative path
- if (Zotero.Prefs.get('saveRelativeAttachmentPath')) {
- path = Zotero.Attachments.getBaseDirectoryRelativePath(path);
- }
- // If possible, convert relative path to absolute
- else {
- let file = Zotero.Attachments.resolveRelativePath(path);
- if (file) {
- path = file.persistentDescriptor;
- }
- }
- }
-
- let params = [
- itemID,
- parent ? parent : null,
- { int: linkMode },
- contentType ? { string: contentType } : null,
- charsetID ? { int: charsetID } : null,
- path ? { string: path } : null,
- syncState ? { int: syncState } : 0
- ];
- yield Zotero.DB.queryAsync(sql, params);
-
- // Clear cached child attachments of the parent
- if (!isNew && parentItem) {
- reloadParentChildItems[parentItem.id] = true;
- }
- }
-
- // Tags
- if (this._changed.tags) {
- let oldTags = this._previousData.tags;
- let newTags = this._tags;
-
- // Convert to individual JSON objects, diff, and convert back
- let oldTagsJSON = oldTags.map(function (x) JSON.stringify(x));
- let newTagsJSON = newTags.map(function (x) JSON.stringify(x));
- let toAdd = Zotero.Utilities.arrayDiff(newTagsJSON, oldTagsJSON)
- .map(function (x) JSON.parse(x));
- let toRemove = Zotero.Utilities.arrayDiff(oldTagsJSON, newTagsJSON)
- .map(function (x) JSON.parse(x));;
-
- for (let i=0; i
wrapper if not present
+ if (!noteText.match(/^[\s\S]*<\/div>$/)) {
+ // Keep consistent with getNote()
+ noteText = '
' + noteText + '
';
+ }
+
+ let params = [
+ parent ? parent : null,
+ noteText,
+ this._noteTitle ? this._noteTitle : ''
+ ];
+ let sql = "SELECT COUNT(*) FROM itemNotes WHERE itemID=?";
+ if (yield Zotero.DB.valueQueryAsync(sql, itemID)) {
+ sql = "UPDATE itemNotes SET parentItemID=?, note=?, title=? WHERE itemID=?";
+ params.push(itemID);
+ }
+ else {
+ sql = "INSERT INTO itemNotes "
+ + "(itemID, parentItemID, note, title) VALUES (?,?,?,?)";
+ params.unshift(itemID);
+ }
+ yield Zotero.DB.queryAsync(sql, params);
+
+ if (parentItem) {
+ reloadParentChildItems[parentItem.id] = true;
+ }
+ }
+
+ //
+ // Attachment
+ //
+ if (!isNew) {
+ // If attachment title changes, update parent attachments
+ if (this._changed.itemData && this._changed.itemData[110] && this.isAttachment() && parentItem) {
+ reloadParentChildItems[parentItem.id] = true;
+ }
+ }
+
+ if (this.isAttachment() || this._changed.attachmentData) {
+ let sql = "REPLACE INTO itemAttachments (itemID, parentItemID, linkMode, "
+ + "contentType, charsetID, path, syncState) VALUES (?,?,?,?,?,?,?)";
+ let parent = this.parentID;
+ let linkMode = this.attachmentLinkMode;
+ let contentType = this.attachmentContentType;
+ let charsetID = Zotero.CharacterSets.getID(this.attachmentCharset);
+ let path = this.attachmentPath;
+ let syncState = this.attachmentSyncState;
+
+ if (this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE) {
+ // Save attachment within attachment base directory as relative path
+ if (Zotero.Prefs.get('saveRelativeAttachmentPath')) {
+ path = Zotero.Attachments.getBaseDirectoryRelativePath(path);
+ }
+ // If possible, convert relative path to absolute
+ else {
+ let file = Zotero.Attachments.resolveRelativePath(path);
+ if (file) {
+ path = file.persistentDescriptor;
+ }
+ }
+ }
+
+ let params = [
+ itemID,
+ parent ? parent : null,
+ { int: linkMode },
+ contentType ? { string: contentType } : null,
+ charsetID ? { int: charsetID } : null,
+ path ? { string: path } : null,
+ syncState ? { int: syncState } : 0
+ ];
+ yield Zotero.DB.queryAsync(sql, params);
+
+ // Clear cached child attachments of the parent
+ if (!isNew && parentItem) {
+ reloadParentChildItems[parentItem.id] = true;
+ }
+ }
+
+ // Tags
+ if (this._changed.tags) {
+ let oldTags = this._previousData.tags;
+ let newTags = this._tags;
+
+ // Convert to individual JSON objects, diff, and convert back
+ let oldTagsJSON = oldTags.map(function (x) JSON.stringify(x));
+ let newTagsJSON = newTags.map(function (x) JSON.stringify(x));
+ let toAdd = Zotero.Utilities.arrayDiff(newTagsJSON, oldTagsJSON)
+ .map(function (x) JSON.parse(x));
+ let toRemove = Zotero.Utilities.arrayDiff(oldTagsJSON, newTagsJSON)
+ .map(function (x) JSON.parse(x));;
+
+ for (let i=0; i
{
+ var aTitle = this.ObjectsClass.getSortTitle(a.title);
+ var bTitle = this.ObjectsClass.getSortTitle(b.title);
return collation.compareString(1, aTitle, bTitle);
});
}
@@ -2483,7 +2428,7 @@ Zotero.Item.prototype._updateAttachmentStates = function (exists) {
}
try {
- var item = Zotero.Items.getByLibraryAndKey(this.libraryID, parentKey);
+ var item = this.ObjectsClass.getByLibraryAndKey(this.libraryID, parentKey);
}
catch (e) {
if (e instanceof Zotero.Exception.UnloadedDataException) {
@@ -2688,39 +2633,39 @@ Zotero.Item.prototype.getAttachmentLinkMode = function() {
* Possible values specified as constants in Zotero.Attachments
* (e.g. Zotero.Attachments.LINK_MODE_LINKED_FILE)
*/
-Zotero.Item.prototype.__defineGetter__('attachmentLinkMode', function () {
- if (!this.isAttachment()) {
- return undefined;
+Zotero.defineProperty(Zotero.Item.prototype, 'attachmentLinkMode', {
+ get: function() {
+ if (!this.isAttachment()) {
+ return undefined;
+ }
+ return this._attachmentLinkMode;
+ },
+ set: function(val) {
+ if (!this.isAttachment()) {
+ throw (".attachmentLinkMode can only be set for attachment items");
+ }
+
+ switch (val) {
+ case Zotero.Attachments.LINK_MODE_IMPORTED_FILE:
+ case Zotero.Attachments.LINK_MODE_IMPORTED_URL:
+ case Zotero.Attachments.LINK_MODE_LINKED_FILE:
+ case Zotero.Attachments.LINK_MODE_LINKED_URL:
+ break;
+
+ default:
+ throw ("Invalid attachment link mode '" + val
+ + "' in Zotero.Item.attachmentLinkMode setter");
+ }
+
+ if (val === this.attachmentLinkMode) {
+ return;
+ }
+ if (!this._changed.attachmentData) {
+ this._changed.attachmentData = {};
+ }
+ this._changed.attachmentData.linkMode = true;
+ this._attachmentLinkMode = val;
}
- return this._attachmentLinkMode;
-});
-
-
-Zotero.Item.prototype.__defineSetter__('attachmentLinkMode', function (val) {
- if (!this.isAttachment()) {
- throw (".attachmentLinkMode can only be set for attachment items");
- }
-
- switch (val) {
- case Zotero.Attachments.LINK_MODE_IMPORTED_FILE:
- case Zotero.Attachments.LINK_MODE_IMPORTED_URL:
- case Zotero.Attachments.LINK_MODE_LINKED_FILE:
- case Zotero.Attachments.LINK_MODE_LINKED_URL:
- break;
-
- default:
- throw ("Invalid attachment link mode '" + val
- + "' in Zotero.Item.attachmentLinkMode setter");
- }
-
- if (val === this.attachmentLinkMode) {
- return;
- }
- if (!this._changed.attachmentData) {
- this._changed.attachmentData = {};
- }
- this._changed.attachmentData.linkMode = true;
- this._attachmentLinkMode = val;
});
@@ -2729,40 +2674,42 @@ Zotero.Item.prototype.getAttachmentMIMEType = function() {
return this.attachmentContentType;
};
-Zotero.Item.prototype.__defineGetter__('attachmentMIMEType', function () {
- Zotero.debug(".attachmentMIMEType deprecated -- use .attachmentContentType");
- return this.attachmentContentType;
+Zotero.defineProperty(Zotero.Item.prototype, 'attachmentMIMEType', {
+ get: function() {
+ Zotero.debug(".attachmentMIMEType deprecated -- use .attachmentContentType");
+ return this.attachmentContentType;
+ }
});
/**
* Content type of an attachment (e.g. 'text/plain')
*/
-Zotero.Item.prototype.__defineGetter__('attachmentContentType', function () {
- if (!this.isAttachment()) {
- return undefined;
+Zotero.defineProperty(Zotero.Item.prototype, 'attachmentContentType', {
+ get: function() {
+ if (!this.isAttachment()) {
+ return undefined;
+ }
+ return this._attachmentContentType;
+ },
+ set: function(val) {
+ if (!this.isAttachment()) {
+ throw (".attachmentContentType can only be set for attachment items");
+ }
+
+ if (!val) {
+ val = '';
+ }
+
+ if (val == this.attachmentContentType) {
+ return;
+ }
+
+ if (!this._changed.attachmentData) {
+ this._changed.attachmentData = {};
+ }
+ this._changed.attachmentData.contentType = true;
+ this._attachmentContentType = val;
}
- return this._attachmentContentType;
-});
-
-
-Zotero.Item.prototype.__defineSetter__('attachmentContentType', function (val) {
- if (!this.isAttachment()) {
- throw (".attachmentContentType can only be set for attachment items");
- }
-
- if (!val) {
- val = '';
- }
-
- if (val == this.attachmentContentType) {
- return;
- }
-
- if (!this._changed.attachmentData) {
- this._changed.attachmentData = {};
- }
- this._changed.attachmentData.contentType = true;
- this._attachmentContentType = val;
});
@@ -2775,76 +2722,75 @@ Zotero.Item.prototype.getAttachmentCharset = function() {
/**
* Character set of an attachment
*/
-Zotero.Item.prototype.__defineGetter__('attachmentCharset', function () {
- if (!this.isAttachment()) {
- return undefined;
+Zotero.defineProperty(Zotero.Item.prototype, 'attachmentCharset', {
+ get: function() {
+ if (!this.isAttachment()) {
+ return undefined;
+ }
+ return this._attachmentCharset
+ },
+ set: function(val) {
+ if (!this.isAttachment()) {
+ throw (".attachmentCharset can only be set for attachment items");
+ }
+
+ var oldVal = this.attachmentCharset;
+ if (oldVal) {
+ oldVal = Zotero.CharacterSets.getID(oldVal);
+ }
+ if (!oldVal) {
+ oldVal = null;
+ }
+
+ if (val) {
+ val = Zotero.CharacterSets.getID(val);
+ }
+ if (!val) {
+ val = null;
+ }
+
+ if (val == oldVal) {
+ return;
+ }
+
+ if (!this._changed.attachmentData) {
+ this._changed.attachmentData= {};
+ }
+ this._changed.attachmentData.charset = true;
+ this._attachmentCharset = val;
}
- return this._attachmentCharset
});
-
-Zotero.Item.prototype.__defineSetter__('attachmentCharset', function (val) {
- if (!this.isAttachment()) {
- throw (".attachmentCharset can only be set for attachment items");
+Zotero.defineProperty(Zotero.Item.prototype, 'attachmentPath', {
+ get: function() {
+ if (!this.isAttachment()) {
+ return undefined;
+ }
+ return this._attachmentPath;
+ },
+ set: function(val) {
+ if (!this.isAttachment()) {
+ throw (".attachmentPath can only be set for attachment items");
+ }
+
+ if (this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_URL) {
+ throw ('attachmentPath cannot be set for link attachments');
+ }
+
+ if (!val) {
+ val = '';
+ }
+
+ if (val == this.attachmentPath) {
+ return;
+ }
+
+ if (!this._changed.attachmentData) {
+ this._changed.attachmentData = {};
+ }
+ this._changed.attachmentData.path = true;
+ this._attachmentPath = val;
}
-
- var oldVal = this.attachmentCharset;
- if (oldVal) {
- oldVal = Zotero.CharacterSets.getID(oldVal);
- }
- if (!oldVal) {
- oldVal = null;
- }
-
- if (val) {
- val = Zotero.CharacterSets.getID(val);
- }
- if (!val) {
- val = null;
- }
-
- if (val == oldVal) {
- return;
- }
-
- if (!this._changed.attachmentData) {
- this._changed.attachmentData= {};
- }
- this._changed.attachmentData.charset = true;
- this._attachmentCharset = val;
-});
-
-
-Zotero.Item.prototype.__defineGetter__('attachmentPath', function () {
- if (!this.isAttachment()) {
- return undefined;
- }
- return this._attachmentPath;
-});
-
-
-Zotero.Item.prototype.__defineSetter__('attachmentPath', function (val) {
- if (!this.isAttachment()) {
- throw (".attachmentPath can only be set for attachment items");
- }
-
- if (this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_URL) {
- throw ('attachmentPath cannot be set for link attachments');
- }
-
- if (!val) {
- val = '';
- }
-
- if (val == this.attachmentPath) {
- return;
- }
-
- if (!this._changed.attachmentData) {
- this._changed.attachmentData = {};
- }
- this._changed.attachmentData.path = true;
- this._attachmentPath = val;
});
@@ -2865,51 +2811,51 @@ Zotero.Item.prototype.updateAttachmentPath = function () {
};
-Zotero.Item.prototype.__defineGetter__('attachmentSyncState', function () {
- if (!this.isAttachment()) {
- return undefined;
+Zotero.defineProperty(Zotero.Item.prototype, 'attachmentSyncState', {
+ get: function() {
+ if (!this.isAttachment()) {
+ return undefined;
+ }
+ return this._attachmentSyncState;
+ },
+ set: function(val) {
+ if (!this.isAttachment()) {
+ throw ("attachmentSyncState can only be set for attachment items");
+ }
+
+ switch (this.attachmentLinkMode) {
+ case Zotero.Attachments.LINK_MODE_IMPORTED_URL:
+ case Zotero.Attachments.LINK_MODE_IMPORTED_FILE:
+ break;
+
+ default:
+ throw ("attachmentSyncState can only be set for snapshots and "
+ + "imported files");
+ }
+
+ switch (val) {
+ case Zotero.Sync.Storage.SYNC_STATE_TO_UPLOAD:
+ case Zotero.Sync.Storage.SYNC_STATE_TO_DOWNLOAD:
+ case Zotero.Sync.Storage.SYNC_STATE_IN_SYNC:
+ case Zotero.Sync.Storage.SYNC_STATE_FORCE_UPLOAD:
+ case Zotero.Sync.Storage.SYNC_STATE_FORCE_DOWNLOAD:
+ break;
+
+ default:
+ throw ("Invalid sync state '" + val
+ + "' in Zotero.Item.attachmentSyncState setter");
+ }
+
+ if (val == this.attachmentSyncState) {
+ return;
+ }
+
+ if (!this._changed.attachmentData) {
+ this._changed.attachmentData = {};
+ }
+ this._changed.attachmentData.syncState = true;
+ this._attachmentSyncState = val;
}
- return this._attachmentSyncState;
-});
-
-
-Zotero.Item.prototype.__defineSetter__('attachmentSyncState', function (val) {
- if (!this.isAttachment()) {
- throw ("attachmentSyncState can only be set for attachment items");
- }
-
- switch (this.attachmentLinkMode) {
- case Zotero.Attachments.LINK_MODE_IMPORTED_URL:
- case Zotero.Attachments.LINK_MODE_IMPORTED_FILE:
- break;
-
- default:
- throw ("attachmentSyncState can only be set for snapshots and "
- + "imported files");
- }
-
- switch (val) {
- case Zotero.Sync.Storage.SYNC_STATE_TO_UPLOAD:
- case Zotero.Sync.Storage.SYNC_STATE_TO_DOWNLOAD:
- case Zotero.Sync.Storage.SYNC_STATE_IN_SYNC:
- case Zotero.Sync.Storage.SYNC_STATE_FORCE_UPLOAD:
- case Zotero.Sync.Storage.SYNC_STATE_FORCE_DOWNLOAD:
- break;
-
- default:
- throw ("Invalid sync state '" + val
- + "' in Zotero.Item.attachmentSyncState setter");
- }
-
- if (val == this.attachmentSyncState) {
- return;
- }
-
- if (!this._changed.attachmentData) {
- this._changed.attachmentData = {};
- }
- this._changed.attachmentData.syncState = true;
- this._attachmentSyncState = val;
});
@@ -2922,29 +2868,31 @@ Zotero.Item.prototype.__defineSetter__('attachmentSyncState', function (val) {
* @return {Promise} File modification time as timestamp in milliseconds,
* or undefined if no file
*/
-Zotero.Item.prototype.__defineGetter__('attachmentModificationTime', Zotero.Promise.coroutine(function* () {
- if (!this.isAttachment()) {
- return undefined;
- }
-
- if (!this.id) {
- return undefined;
- }
-
- var path = yield this.getFilePathAsync();
- if (!path) {
- return undefined;
- }
-
- var fmtime = OS.File.stat(path).lastModificationDate;
-
- if (fmtime < 1) {
- Zotero.debug("File mod time " + fmtime + " is less than 1 -- interpreting as 1", 2);
- fmtime = 1;
- }
-
- return fmtime;
-}));
+Zotero.defineProperty(Zotero.Item.prototype, 'attachmentModificationTime', {
+ get: Zotero.Promise.coroutine(function* () {
+ if (!this.isAttachment()) {
+ return undefined;
+ }
+
+ if (!this.id) {
+ return undefined;
+ }
+
+ var path = yield this.getFilePathAsync();
+ if (!path) {
+ return undefined;
+ }
+
+ var fmtime = OS.File.stat(path).lastModificationDate;
+
+ if (fmtime < 1) {
+ Zotero.debug("File mod time " + fmtime + " is less than 1 -- interpreting as 1", 2);
+ fmtime = 1;
+ }
+
+ return fmtime;
+ })
+});
/**
@@ -2955,21 +2903,23 @@ Zotero.Item.prototype.__defineGetter__('attachmentModificationTime', Zotero.Prom
*
* @return {String} MD5 hash of file as hex string
*/
-Zotero.Item.prototype.__defineGetter__('attachmentHash', function () {
- if (!this.isAttachment()) {
- return undefined;
+Zotero.defineProperty(Zotero.Item.prototype, 'attachmentHash', {
+ get: function () {
+ if (!this.isAttachment()) {
+ return undefined;
+ }
+
+ if (!this.id) {
+ return undefined;
+ }
+
+ var file = this.getFile();
+ if (!file) {
+ return undefined;
+ }
+
+ return Zotero.Utilities.Internal.md5(file) || undefined;
}
-
- if (!this.id) {
- return undefined;
- }
-
- var file = this.getFile();
- if (!file) {
- return undefined;
- }
-
- return Zotero.Utilities.Internal.md5(file) || undefined;
});
@@ -2982,84 +2932,86 @@ Zotero.Item.prototype.__defineGetter__('attachmentHash', function () {
*
* @return {Promise} - A promise for attachment text or empty string if unavailable
*/
-Zotero.Item.prototype.__defineGetter__('attachmentText', Zotero.Promise.coroutine(function* () {
- if (!this.isAttachment()) {
- return undefined;
- }
-
- if (!this.id) {
- return null;
- }
-
- var file = this.getFile();
-
- if (!(yield OS.File.exists(file.path))) {
- file = false;
- }
-
- var cacheFile = Zotero.Fulltext.getItemCacheFile(this);
- if (!file) {
- if (cacheFile.exists()) {
- var str = yield Zotero.File.getContentsAsync(cacheFile);
-
- return str.trim();
- }
- return '';
- }
-
- var contentType = this.attachmentContentType;
- if (!contentType) {
- contentType = yield Zotero.MIME.getMIMETypeFromFile(file);
- if (contentType) {
- this.attachmentContentType = contentType;
- yield this.save();
- }
- }
-
- var str;
- if (Zotero.Fulltext.isCachedMIMEType(contentType)) {
- var reindex = false;
-
- if (!cacheFile.exists()) {
- Zotero.debug("Regenerating item " + this.id + " full-text cache file");
- reindex = true;
- }
- // Fully index item if it's not yet
- else if (!(yield Zotero.Fulltext.isFullyIndexed(this))) {
- Zotero.debug("Item " + this.id + " is not fully indexed -- caching now");
- reindex = true;
+Zotero.defineProperty(Zotero.Item.prototype, 'attachmentText', {
+ get: Zotero.Promise.coroutine(function* () {
+ if (!this.isAttachment()) {
+ return undefined;
}
- if (reindex) {
- if (!Zotero.Fulltext.pdfConverterIsRegistered()) {
- Zotero.debug("PDF converter is unavailable -- returning empty .attachmentText", 3);
- return '';
+ if (!this.id) {
+ return null;
+ }
+
+ var file = this.getFile();
+
+ if (!(yield OS.File.exists(file.path))) {
+ file = false;
+ }
+
+ var cacheFile = Zotero.Fulltext.getItemCacheFile(this);
+ if (!file) {
+ if (cacheFile.exists()) {
+ var str = yield Zotero.File.getContentsAsync(cacheFile);
+
+ return str.trim();
}
- yield Zotero.Fulltext.indexItems(this.id, false);
- }
-
- if (!cacheFile.exists()) {
- Zotero.debug("Cache file doesn't exist after indexing -- returning empty .attachmentText");
return '';
}
- str = yield Zotero.File.getContentsAsync(cacheFile);
- }
-
- else if (contentType == 'text/html') {
- str = yield Zotero.File.getContentsAsync(file);
- str = Zotero.Utilities.unescapeHTML(str);
- }
-
- else if (contentType == 'text/plain') {
- str = yield Zotero.File.getContentsAsync(file);
- }
-
- else {
- return '';
- }
-
- return str.trim();
-}));
+
+ var contentType = this.attachmentContentType;
+ if (!contentType) {
+ contentType = yield Zotero.MIME.getMIMETypeFromFile(file);
+ if (contentType) {
+ this.attachmentContentType = contentType;
+ yield this.save();
+ }
+ }
+
+ var str;
+ if (Zotero.Fulltext.isCachedMIMEType(contentType)) {
+ var reindex = false;
+
+ if (!cacheFile.exists()) {
+ Zotero.debug("Regenerating item " + this.id + " full-text cache file");
+ reindex = true;
+ }
+ // Fully index item if it's not yet
+ else if (!(yield Zotero.Fulltext.isFullyIndexed(this))) {
+ Zotero.debug("Item " + this.id + " is not fully indexed -- caching now");
+ reindex = true;
+ }
+
+ if (reindex) {
+ if (!Zotero.Fulltext.pdfConverterIsRegistered()) {
+ Zotero.debug("PDF converter is unavailable -- returning empty .attachmentText", 3);
+ return '';
+ }
+ yield Zotero.Fulltext.indexItems(this.id, false);
+ }
+
+ if (!cacheFile.exists()) {
+ Zotero.debug("Cache file doesn't exist after indexing -- returning empty .attachmentText");
+ return '';
+ }
+ str = yield Zotero.File.getContentsAsync(cacheFile);
+ }
+
+ else if (contentType == 'text/html') {
+ str = yield Zotero.File.getContentsAsync(file);
+ str = Zotero.Utilities.unescapeHTML(str);
+ }
+
+ else if (contentType == 'text/plain') {
+ str = yield Zotero.File.getContentsAsync(file);
+ }
+
+ else {
+ return '';
+ }
+
+ return str.trim();
+ })
+});
@@ -3136,7 +3088,7 @@ Zotero.Item.prototype.getBestAttachments = Zotero.Promise.coroutine(function* ()
+ "AND IA.itemID NOT IN (SELECT itemID FROM deletedItems) "
+ "ORDER BY contentType='application/pdf' DESC, value=? DESC, dateAdded ASC";
var itemIDs = yield Zotero.DB.columnQueryAsync(sql, [this.id, Zotero.Attachments.LINK_MODE_LINKED_URL, url]);
- return Zotero.Items.get(itemIDs);
+ return this.ObjectsClass.get(itemIDs);
});
@@ -3392,7 +3344,7 @@ Zotero.Item.prototype.setCollections = function (collectionIDsOrKeys) {
var collectionIDs = collectionIDsOrKeys.map(function (val) {
return parseInt(val) == val
? parseInt(val)
- : Zotero.Collections.getIDFromLibraryAndKey(this.libraryID, val);
+ : this.ContainerObjectsClass.getIDFromLibraryAndKey(this.libraryID, val);
}.bind(this));
collectionIDs = Zotero.Utilities.arrayUnique(collectionIDs);
@@ -3417,7 +3369,7 @@ Zotero.Item.prototype.setCollections = function (collectionIDsOrKeys) {
Zotero.Item.prototype.addToCollection = function (collectionIDOrKey) {
var collectionID = parseInt(collectionIDOrKey) == collectionIDOrKey
? parseInt(collectionIDOrKey)
- : Zotero.Collections.getIDFromLibraryAndKey(this.libraryID, collectionIDOrKey)
+ : this.ContainerObjectsClass.getIDFromLibraryAndKey(this.libraryID, collectionIDOrKey)
if (!collectionID) {
throw new Error("Invalid collection '" + collectionIDOrKey + "'");
@@ -3442,7 +3394,7 @@ Zotero.Item.prototype.addToCollection = function (collectionIDOrKey) {
Zotero.Item.prototype.removeFromCollection = function (collectionIDOrKey) {
var collectionID = parseInt(collectionIDOrKey) == collectionIDOrKey
? parseInt(collectionIDOrKey)
- : Zotero.Collections.getIDFromLibraryAndKey(this.libraryID, collectionIDOrKey)
+ : this.ContainerObjectsClass.getIDFromLibraryAndKey(this.libraryID, collectionIDOrKey)
if (!collectionID) {
throw new Error("Invalid collection '" + collectionIDOrKey + "'");
@@ -3591,7 +3543,7 @@ Zotero.Item.prototype.diff = function (item, includeMatches, ignoreFields) {
var thisData = this.serialize();
var otherData = item.serialize();
- var numDiffs = Zotero.Items.diff(thisData, otherData, diff, includeMatches);
+ var numDiffs = this.ObjectsClass.diff(thisData, otherData, diff, includeMatches);
diff[0].creators = [];
diff[1].creators = [];
@@ -3727,7 +3679,7 @@ Zotero.Item.prototype.multiDiff = Zotero.Promise.coroutine(function* (otherItems
let otherItem = otherItems[i];
let diff = [];
let otherData = yield otherItem.toJSON();
- let numDiffs = Zotero.Items.diff(thisData, otherData, diff);
+ let numDiffs = this.ObjectsClass.diff(thisData, otherData, diff);
if (numDiffs) {
for (let field in diff[1]) {
@@ -3778,6 +3730,7 @@ Zotero.Item.prototype.clone = function(libraryID, skipTags) {
var sameLibrary = libraryID == this.libraryID;
var newItem = new Zotero.Item;
+ newItem.libraryID = libraryID;
newItem.setType(this.itemTypeID);
var fieldIDs = this.getUsedFields();
@@ -3838,99 +3791,89 @@ Zotero.Item.prototype.copy = Zotero.Promise.coroutine(function* () {
});;
-/**
- * Delete item from database and clear from Zotero.Items internal array
- *
- * Items.erase() should be used for multiple items
- */
-Zotero.Item.prototype.erase = Zotero.Promise.coroutine(function* () {
- if (!this.id) {
- return false;
+Zotero.Item.prototype._eraseInit = Zotero.Promise.coroutine(function* (env) {
+ var proceed = yield Zotero.Item._super.prototype._eraseInit.apply(this, arguments);
+ if (!proceed) return false;
+
+ env.deletedItemNotifierData = {};
+ env.deletedItemNotifierData[this.id] = { old: this.toJSON() };
+
+ return true;
+});
+
+Zotero.Item.prototype._eraseData = Zotero.Promise.coroutine(function* (env) {
+ // Remove item from parent collections
+ var parentCollectionIDs = this.collections;
+ if (parentCollectionIDs) {
+ for (var i=0; i {
if (topic == 'idle' || topic == 'timer-callback') {
var days = Zotero.Prefs.get('trashAutoEmptyDays');
if (!days) {
@@ -620,20 +550,20 @@ Zotero.Items = new function() {
// TODO: increase number after dealing with slow
// tag.getLinkedItems() call during deletes
var num = 10;
- Zotero.Items.emptyTrash(null, days, num)
- .then(function (deleted) {
+ this.emptyTrash(null, days, num)
+ .then(deleted => {
if (!deleted) {
- _emptyTrashTimer = null;
+ this._emptyTrashTimer = null;
return;
}
// Set a timer to do more every few seconds
- if (!_emptyTrashTimer) {
- _emptyTrashTimer = Components.classes["@mozilla.org/timer;1"]
+ if (!this._emptyTrashTimer) {
+ this._emptyTrashTimer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
}
- _emptyTrashTimer.init(
- _emptyTrashIdleObserver.observe,
+ this._emptyTrashTimer.init(
+ this._emptyTrashIdleObserver.observe,
5 * 1000,
Components.interfaces.nsITimer.TYPE_ONE_SHOT
);
@@ -641,8 +571,8 @@ Zotero.Items = new function() {
}
// When no longer idle, cancel timer
else if (topic == 'back') {
- if (_emptyTrashTimer) {
- _emptyTrashTimer.cancel();
+ if (this._emptyTrashTimer) {
+ this._emptyTrashTimer.cancel();
}
}
}
@@ -650,7 +580,7 @@ Zotero.Items = new function() {
var idleService = Components.classes["@mozilla.org/widget/idleservice;1"].
getService(Components.interfaces.nsIIdleService);
- idleService.addIdleObserver(_emptyTrashIdleObserver, 305);
+ idleService.addIdleObserver(this._emptyTrashIdleObserver, 305);
}
@@ -693,28 +623,12 @@ Zotero.Items = new function() {
});
- this.getPrimaryDataSQL = function () {
- return "SELECT "
- + Object.keys(this._primaryDataSQLParts).map((val) => this._primaryDataSQLParts[val]).join(', ')
- + this.primaryDataSQLFrom;
- };
-
-
- this.primaryDataSQLFrom = " FROM items O "
- + "LEFT JOIN itemAttachments IA USING (itemID) "
- + "LEFT JOIN items IAP ON (IA.parentItemID=IAP.itemID) "
- + "LEFT JOIN itemNotes INo ON (O.itemID=INo.itemID) "
- + "LEFT JOIN items INoP ON (INo.parentItemID=INoP.itemID) "
- + "LEFT JOIN deletedItems DI ON (O.itemID=DI.itemID) "
- + "WHERE 1";
-
-
this._postLoad = function (libraryID, ids) {
if (!ids) {
- if (!_cachedFields[libraryID]) {
- _cachedFields[libraryID] = [];
+ if (!this._cachedFields[libraryID]) {
+ this._cachedFields[libraryID] = [];
}
- _cachedFields[libraryID] = this.primaryFields.concat();
+ this._cachedFields[libraryID] = this.primaryFields.concat();
}
}
@@ -724,6 +638,7 @@ Zotero.Items = new function() {
*
* Why do we do this entirely in SQL? Because we're crazy. Crazy like foxes.
*/
+ var _firstCreatorSQL = '';
function _getFirstCreatorSQL() {
if (_firstCreatorSQL) {
return _firstCreatorSQL;
@@ -828,6 +743,7 @@ Zotero.Items = new function() {
/*
* Generate SQL to retrieve sortCreator field
*/
+ var _sortCreatorSQL = '';
function _getSortCreatorSQL() {
if (_sortCreatorSQL) {
return _sortCreatorSQL;
@@ -947,7 +863,7 @@ Zotero.Items = new function() {
}
- function getSortTitle(title) {
+ this.getSortTitle = function(title) {
if (title === false || title === undefined) {
return '';
}
@@ -956,4 +872,8 @@ Zotero.Items = new function() {
}
return title.replace(/^[\[\'\"](.*)[\'\"\]]?$/, '$1')
}
-}
+
+ Zotero.DataObjects.call(this);
+
+ return this;
+}.bind(Object.create(Zotero.DataObjects.prototype))();
diff --git a/chrome/content/zotero/xpcom/data/libraries.js b/chrome/content/zotero/xpcom/data/libraries.js
index 8234f2083..9fdc5a827 100644
--- a/chrome/content/zotero/xpcom/data/libraries.js
+++ b/chrome/content/zotero/xpcom/data/libraries.js
@@ -28,7 +28,7 @@ Zotero.Libraries = new function () {
_userLibraryID,
_libraryDataLoaded = false;
- Zotero.Utilities.Internal.defineProperty(this, 'userLibraryID', {
+ Zotero.defineProperty(this, 'userLibraryID', {
get: function() {
if (!_libraryDataLoaded) {
throw new Error("Library data not yet loaded");
@@ -177,4 +177,12 @@ Zotero.Libraries = new function () {
throw new Error("Unsupported library type '" + type + "' in Zotero.Libraries.getName()");
}
}
-}
+
+ this.isGroupLibrary = function (libraryID) {
+ if (!_libraryDataLoaded) {
+ throw new Error("Library data not yet loaded");
+ }
+
+ return this.getType(libraryID) == 'group';
+ }
+}
\ No newline at end of file
diff --git a/chrome/content/zotero/xpcom/data/relations.js b/chrome/content/zotero/xpcom/data/relations.js
index 310f39e97..de60de528 100644
--- a/chrome/content/zotero/xpcom/data/relations.js
+++ b/chrome/content/zotero/xpcom/data/relations.js
@@ -23,18 +23,15 @@
***** END LICENSE BLOCK *****
*/
-Zotero.Relations = new function () {
- Zotero.DataObjects.apply(this, ['relation']);
- this.constructor.prototype = new Zotero.DataObjects();
+Zotero.Relations = function () {
+ this.constructor = null;
- this.__defineGetter__('relatedItemPredicate', function () "dc:relation");
- this.__defineGetter__('linkedObjectPredicate', function () "owl:sameAs");
- this.__defineGetter__('deletedItemPredicate', function () 'dc:isReplacedBy');
+ this._ZDO_object = 'relation';
+ this._ZDO_idOnly = true;
- var _namespaces = {
- dc: 'http://purl.org/dc/elements/1.1/',
- owl: 'http://www.w3.org/2002/07/owl#'
- };
+ Zotero.defineProperty(this, 'relatedItemPredicate', {value: 'dc:relation'});
+ Zotero.defineProperty(this, 'linkedObjectPredicate', {value: 'owl:sameAs'});
+ Zotero.defineProperty(this, 'deletedItemPredicate', {value: 'dc:isReplacedBy'});
this.get = function (id) {
if (typeof id != 'number') {
@@ -52,7 +49,7 @@ Zotero.Relations = new function () {
*/
this.getByURIs = Zotero.Promise.coroutine(function* (subject, predicate, object) {
if (predicate) {
- predicate = _getPrefixAndValue(predicate).join(':');
+ predicate = this._getPrefixAndValue(predicate).join(':');
}
if (!subject && !predicate && !object) {
@@ -141,7 +138,7 @@ Zotero.Relations = new function () {
this.add = Zotero.Promise.coroutine(function* (libraryID, subject, predicate, object) {
- predicate = _getPrefixAndValue(predicate).join(':');
+ predicate = this._getPrefixAndValue(predicate).join(':');
var relation = new Zotero.Relation;
if (!libraryID) {
@@ -272,11 +269,15 @@ Zotero.Relations = new function () {
return relation;
}
+ this._namespaces = {
+ dc: 'http://purl.org/dc/elements/1.1/',
+ owl: 'http://www.w3.org/2002/07/owl#'
+ };
- function _getPrefixAndValue(uri) {
+ this._getPrefixAndValue = function(uri) {
var [prefix, value] = uri.split(':');
if (prefix && value) {
- if (!_namespaces[prefix]) {
+ if (!this._namespaces[prefix]) {
throw ("Invalid prefix '" + prefix + "' in Zotero.Relations._getPrefixAndValue()");
}
return [prefix, value];
@@ -290,4 +291,8 @@ Zotero.Relations = new function () {
}
throw ("Invalid namespace in URI '" + uri + "' in Zotero.Relations._getPrefixAndValue()");
}
-}
+
+ Zotero.DataObjects.call(this);
+
+ return this;
+}.bind(Object.create(Zotero.DataObjects.prototype))();
\ No newline at end of file
diff --git a/chrome/content/zotero/xpcom/search.js b/chrome/content/zotero/xpcom/search.js
index 0166666ad..cee68a6aa 100644
--- a/chrome/content/zotero/xpcom/search.js
+++ b/chrome/content/zotero/xpcom/search.js
@@ -37,13 +37,10 @@ Zotero.Search = function() {
this._hasPrimaryConditions = false;
}
-Zotero.Search._super = Zotero.DataObject;
-Zotero.Search.prototype = Object.create(Zotero.Search._super.prototype);
-Zotero.Search.constructor = Zotero.Search;
+Zotero.extendClass(Zotero.DataObject, Zotero.Search);
Zotero.Search.prototype._objectType = 'search';
Zotero.Search.prototype._dataTypes = Zotero.Search._super.prototype._dataTypes.concat([
- 'primaryData',
'conditions'
]);
@@ -62,21 +59,33 @@ Zotero.Search.prototype.setName = function(val) {
this.name = val;
}
-
-Zotero.Search.prototype.__defineGetter__('id', function () { return this._get('id'); });
-Zotero.Search.prototype.__defineSetter__('id', function (val) { this._set('id', val); });
-Zotero.Search.prototype.__defineGetter__('libraryID', function () { return this._get('libraryID'); });
-Zotero.Search.prototype.__defineSetter__('libraryID', function (val) { return this._set('libraryID', val); });
-Zotero.Search.prototype.__defineGetter__('key', function () { return this._get('key'); });
-Zotero.Search.prototype.__defineSetter__('key', function (val) { this._set('key', val) });
-Zotero.Search.prototype.__defineGetter__('name', function () { return this._get('name'); });
-Zotero.Search.prototype.__defineSetter__('name', function (val) { this._set('name', val); });
-Zotero.Search.prototype.__defineGetter__('version', function () { return this._get('version'); });
-Zotero.Search.prototype.__defineSetter__('version', function (val) { this._set('version', val); });
-Zotero.Search.prototype.__defineGetter__('synced', function () { return this._get('synced'); });
-Zotero.Search.prototype.__defineSetter__('synced', function (val) { this._set('synced', val); });
-
-Zotero.Search.prototype.__defineGetter__('conditions', function (arr) { this.getSearchConditions(); });
+Zotero.defineProperty(Zotero.Search.prototype, 'id', {
+ get: function() this._get('id'),
+ set: function(val) this._set('id', val)
+});
+Zotero.defineProperty(Zotero.Search.prototype, 'libraryID', {
+ get: function() this._get('libraryID'),
+ set: function(val) this._set('libraryID', val)
+});
+Zotero.defineProperty(Zotero.Search.prototype, 'key', {
+ get: function() this._get('key'),
+ set: function(val) this._set('key', val)
+});
+Zotero.defineProperty(Zotero.Search.prototype, 'name', {
+ get: function() this._get('name'),
+ set: function(val) this._set('name', val)
+});
+Zotero.defineProperty(Zotero.Search.prototype, 'version', {
+ get: function() this._get('version'),
+ set: function(val) this._set('version', val)
+});
+Zotero.defineProperty(Zotero.Search.prototype, 'synced', {
+ get: function() this._get('synced'),
+ set: function(val) this._set('synced', val)
+});
+Zotero.defineProperty(Zotero.Search.prototype, 'conditions', {
+ get: function() this.getSearchConditions()
+});
Zotero.Search.prototype._set = function (field, value) {
if (field == 'id' || field == 'libraryID' || field == 'key') {
@@ -161,152 +170,115 @@ Zotero.Search.prototype.loadFromRow = function (row) {
this._identified = true;
}
+Zotero.Search.prototype._initSave = Zotero.Promise.coroutine(function* (env) {
+ if (!this.name) {
+ throw('Name not provided for saved search');
+ }
+
+ return Zotero.Search._super.prototype._initSave.apply(this, arguments);
+});
-/*
- * Save the search to the DB and return a savedSearchID
- *
- * If there are gaps in the searchConditionIDs, |fixGaps| must be true
- * and the caller must dispose of the search or reload the condition ids,
- * which may change after the save.
- *
- * For new searches, name must be set called before saving
- */
-Zotero.Search.prototype.save = Zotero.Promise.coroutine(function* (fixGaps) {
- try {
- Zotero.Searches.editCheck(this);
-
- if (!this.name) {
- throw('Name not provided for saved search');
- }
-
- var isNew = !this.id;
-
- // Register this item's identifiers in Zotero.DataObjects on transaction commit,
- // before other callbacks run
- var searchID, libraryID, key;
- if (isNew) {
- var transactionOptions = {
- onCommit: function () {
- Zotero.Searches.registerIdentifiers(searchID, libraryID, key);
- }
- };
- }
- else {
- var transactionOptions = null;
- }
-
- return Zotero.DB.executeTransaction(function* () {
- searchID = this._id = this.id ? this.id : yield Zotero.ID.get('savedSearches');
- libraryID = this.libraryID;
- key = this._key = this.key ? this.key : this._generateKey();
-
- Zotero.debug("Saving " + (isNew ? 'new ' : '') + "search " + this.id);
-
- var columns = [
- 'savedSearchID',
- 'savedSearchName',
- 'clientDateModified',
- 'libraryID',
- 'key',
- 'version',
- 'synced'
- ];
- var placeholders = columns.map(function () '?').join();
- var sqlValues = [
- searchID ? { int: searchID } : null,
- { string: this.name },
- Zotero.DB.transactionDateTime,
- this.libraryID ? this.libraryID : 0,
- key,
- this.version ? this.version : 0,
- this.synced ? 1 : 0
- ];
-
- var sql = "REPLACE INTO savedSearches (" + columns.join(', ') + ") "
- + "VALUES (" + placeholders + ")";
- var insertID = yield Zotero.DB.queryAsync(sql, sqlValues);
- if (!searchID) {
- searchID = insertID;
- }
-
- if (!isNew) {
- var sql = "DELETE FROM savedSearchConditions WHERE savedSearchID=?";
- yield Zotero.DB.queryAsync(sql, this.id);
- }
-
- // Close gaps in savedSearchIDs
- var saveConditions = {};
- var i = 1;
- for (var id in this._conditions) {
- if (!fixGaps && id != i) {
- Zotero.DB.rollbackTransaction();
- throw ('searchConditionIDs not contiguous and |fixGaps| not set in save() of saved search ' + this._id);
- }
- saveConditions[i] = this._conditions[id];
- i++;
- }
-
- this._conditions = saveConditions;
-
- for (var i in this._conditions){
- var sql = "INSERT INTO savedSearchConditions (savedSearchID, "
- + "searchConditionID, condition, operator, value, required) "
- + "VALUES (?,?,?,?,?,?)";
-
- // Convert condition and mode to "condition[/mode]"
- var condition = this._conditions[i].mode ?
- this._conditions[i].condition + '/' + this._conditions[i].mode :
- this._conditions[i].condition
-
- var sqlParams = [
- searchID,
- i,
- condition,
- this._conditions[i].operator ? this._conditions[i].operator : null,
- this._conditions[i].value ? this._conditions[i].value : null,
- this._conditions[i].required ? 1 : null
- ];
- yield Zotero.DB.queryAsync(sql, sqlParams);
- }
-
-
- if (isNew) {
- Zotero.Notifier.trigger('add', 'search', this.id);
- }
- else {
- Zotero.Notifier.trigger('modify', 'search', this.id, this._previousData);
- }
-
- if (isNew && this.libraryID) {
- var groupID = Zotero.Groups.getGroupIDFromLibraryID(this.libraryID);
- var group = yield Zotero.Groups.get(groupID);
- group.clearSearchCache();
- }
-
- if (isNew) {
- var id = this.id;
- this._disabled = true;
- return id;
- }
-
- yield this.reload();
- this._clearChanged();
-
- return isNew ? this.id : true;
- }.bind(this), transactionOptions);
+Zotero.Search.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
+ var fixGaps = env.options.fixGaps;
+ var isNew = env.isNew;
+
+ var searchID = env.id = this._id = this.id ? this.id : yield Zotero.ID.get('savedSearches');
+ var libraryID = env.libraryID = this.libraryID;
+ var key = env.key = this._key = this.key ? this.key : this._generateKey();
+
+ var columns = [
+ 'savedSearchID',
+ 'savedSearchName',
+ 'clientDateModified',
+ 'libraryID',
+ 'key',
+ 'version',
+ 'synced'
+ ];
+ var placeholders = columns.map(function () '?').join();
+ var sqlValues = [
+ searchID ? { int: searchID } : null,
+ { string: this.name },
+ Zotero.DB.transactionDateTime,
+ this.libraryID ? this.libraryID : 0,
+ key,
+ this.version ? this.version : 0,
+ this.synced ? 1 : 0
+ ];
+
+ var sql = "REPLACE INTO savedSearches (" + columns.join(', ') + ") "
+ + "VALUES (" + placeholders + ")";
+ var insertID = yield Zotero.DB.queryAsync(sql, sqlValues);
+ if (!searchID) {
+ searchID = env.id = insertID;
}
- catch (e) {
- try {
- yield this.reload();
- this._clearChanged();
- }
- catch (e2) {
- Zotero.debug(e2, 1);
- }
-
- Zotero.debug(e, 1);
- throw e;
+
+ if (!isNew) {
+ var sql = "DELETE FROM savedSearchConditions WHERE savedSearchID=?";
+ yield Zotero.DB.queryAsync(sql, this.id);
}
+
+ // Close gaps in savedSearchIDs
+ var saveConditions = {};
+ var i = 1;
+ for (var id in this._conditions) {
+ if (!fixGaps && id != i) {
+ Zotero.DB.rollbackTransaction();
+ throw ('searchConditionIDs not contiguous and |fixGaps| not set in save() of saved search ' + this._id);
+ }
+ saveConditions[i] = this._conditions[id];
+ i++;
+ }
+
+ this._conditions = saveConditions;
+
+ for (var i in this._conditions){
+ var sql = "INSERT INTO savedSearchConditions (savedSearchID, "
+ + "searchConditionID, condition, operator, value, required) "
+ + "VALUES (?,?,?,?,?,?)";
+
+ // Convert condition and mode to "condition[/mode]"
+ var condition = this._conditions[i].mode ?
+ this._conditions[i].condition + '/' + this._conditions[i].mode :
+ this._conditions[i].condition
+
+ var sqlParams = [
+ searchID,
+ i,
+ condition,
+ this._conditions[i].operator ? this._conditions[i].operator : null,
+ this._conditions[i].value ? this._conditions[i].value : null,
+ this._conditions[i].required ? 1 : null
+ ];
+ yield Zotero.DB.queryAsync(sql, sqlParams);
+ }
+});
+
+Zotero.Search.prototype._finalizeSave = Zotero.Promise.coroutine(function* (env) {
+ var isNew = env.isNew;
+ if (isNew) {
+ Zotero.Notifier.trigger('add', 'search', this.id);
+ }
+ else {
+ Zotero.Notifier.trigger('modify', 'search', this.id, this._previousData);
+ }
+
+ if (isNew && Zotero.Libraries.isGroupLibrary(this.libraryID)) {
+ var groupID = Zotero.Groups.getGroupIDFromLibraryID(this.libraryID);
+ var group = yield Zotero.Groups.get(groupID);
+ group.clearSearchCache();
+ }
+
+ if (isNew) {
+ var id = this.id;
+ this._disabled = true;
+ return id;
+ }
+
+ yield this.reload();
+ this._clearChanged();
+
+ return isNew ? this.id : true;
});
@@ -1189,7 +1161,7 @@ Zotero.Search.prototype._buildQuery = Zotero.Promise.coroutine(function* () {
let objLibraryID;
let objKey = condition.value;
let objectType = condition.name == 'collection' ? 'collection' : 'search';
- let objectTypeClass = Zotero.DataObjectUtilities.getClassForObjectType(objectType);
+ let objectTypeClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(objectType);
// Old-style library-key hash
if (objKey.contains('_')) {
@@ -1665,29 +1637,25 @@ Zotero.Search.prototype._buildQuery = Zotero.Promise.coroutine(function* () {
this._sqlParams = sqlParams.length ? sqlParams : false;
});
-Zotero.Searches = new function(){
- Zotero.DataObjects.apply(this, ['search', 'searches', 'savedSearch', 'savedSearches']);
- this.constructor.prototype = new Zotero.DataObjects();
+Zotero.Searches = function() {
+ this.constructor = null;
- Object.defineProperty(this, "_primaryDataSQLParts", {
- get: function () {
- return _primaryDataSQLParts ? _primaryDataSQLParts : (_primaryDataSQLParts = {
- savedSearchID: "O.savedSearchID",
- name: "O.savedSearchName",
- libraryID: "O.libraryID",
- key: "O.key",
- version: "O.version",
- synced: "O.synced"
- });
- }
- });
+ this._ZDO_object = 'search';
+ this._ZDO_id = 'savedSearch';
+ this._ZDO_table = 'savedSearches';
-
- var _primaryDataSQLParts;
+ this._primaryDataSQLParts = {
+ savedSearchID: "O.savedSearchID",
+ name: "O.savedSearchName",
+ libraryID: "O.libraryID",
+ key: "O.key",
+ version: "O.version",
+ synced: "O.synced"
+ }
this.init = Zotero.Promise.coroutine(function* () {
- yield this.constructor.prototype.init.apply(this);
+ yield Zotero.DataObjects.prototype.init.apply(this);
yield Zotero.SearchConditions.init();
});
@@ -1735,6 +1703,8 @@ Zotero.Searches = new function(){
let id = ids[i];
var search = new Zotero.Search;
search.id = id;
+ yield search.loadPrimaryData();
+ yield search.loadConditions();
notifierData[id] = { old: search.serialize() };
var sql = "DELETE FROM savedSearchConditions WHERE savedSearchID=?";
@@ -1756,7 +1726,11 @@ Zotero.Searches = new function(){
+ Object.keys(this._primaryDataSQLParts).map(key => this._primaryDataSQLParts[key]).join(", ") + " "
+ "FROM savedSearches O WHERE 1";
}
-}
+
+ Zotero.DataObjects.call(this);
+
+ return this;
+}.bind(Object.create(Zotero.DataObjects.prototype))();
diff --git a/chrome/content/zotero/xpcom/utilities_internal.js b/chrome/content/zotero/xpcom/utilities_internal.js
index f88c08f75..bbe1767c0 100644
--- a/chrome/content/zotero/xpcom/utilities_internal.js
+++ b/chrome/content/zotero/xpcom/utilities_internal.js
@@ -493,24 +493,6 @@ Zotero.Utilities.Internal = {
}, 0, 0, null);
return pipe.inputStream;
- },
-
- /**
- * Defines property on the object
- * More compact way to do Object.defineProperty
- *
- * @param {Object} obj Target object
- * @param {String} prop Property to be defined
- * @param {Object} desc Propery descriptor. If not overriden, "enumerable" is true
- */
- "defineProperty": function(obj, prop, desc) {
- if (typeof prop != 'string') throw new Error("Property must be a string");
- var d = { __proto__: null, enumerable: true }; // Enumerable by default
- for (let p in desc) {
- if (!desc.hasOwnProperty(p)) continue;
- d[p] = desc[p];
- }
- Object.defineProperty(obj, prop, d);
}
}
diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js
index cdd4bd080..3501acb3b 100644
--- a/chrome/content/zotero/xpcom/zotero.js
+++ b/chrome/content/zotero/xpcom/zotero.js
@@ -1400,6 +1400,40 @@ Components.utils.import("resource://gre/modules/osfile.jsm");
}
+ /**
+ * Defines property on the object
+ * More compact way to do Object.defineProperty
+ *
+ * @param {Object} obj Target object
+ * @param {String} prop Property to be defined
+ * @param {Object} desc Propery descriptor. If not overriden, "enumerable" is true
+ * @param {Object} opts Options:
+ * lazy {Boolean} If true, the _getter_ is intended for late
+ * initialization of the property. The getter is replaced with a simple
+ * property once initialized.
+ */
+ this.defineProperty = function(obj, prop, desc, opts) {
+ if (typeof prop != 'string') throw new Error("Property must be a string");
+ var d = { __proto__: null, enumerable: true, configurable: true }; // Enumerable by default
+ for (let p in desc) {
+ if (!desc.hasOwnProperty(p)) continue;
+ d[p] = desc[p];
+ }
+
+ if (opts) {
+ if (opts.lazy && d.get) {
+ let getter = d.get;
+ d.get = function() {
+ var val = getter.call(this);
+ this[prop] = val; // Replace getter with value
+ return val;
+ }
+ }
+ }
+
+ Object.defineProperty(obj, prop, d);
+ }
+
/*
* This function should be removed
*
@@ -1497,6 +1531,12 @@ Components.utils.import("resource://gre/modules/osfile.jsm");
};
}
+ this.defineProperty(this, "localeCompare", {
+ get: function() {
+ var collation = this.getLocaleCollation();
+ return collation.compareString.bind(collation, 1);
+ }
+ }, {lazy: true});
/*
* Sets font size based on prefs -- intended for use on root element
@@ -1579,6 +1619,46 @@ Components.utils.import("resource://gre/modules/osfile.jsm");
}
+ /**
+ * Defines property on the object
+ * More compact way to do Object.defineProperty
+ *
+ * @param {Object} obj Target object
+ * @param {String} prop Property to be defined
+ * @param {Object} desc Propery descriptor. If not overriden, "enumerable" is true
+ * @param {Object} opts Options:
+ * lateInit {Boolean} If true, the _getter_ is intended for late
+ * initialization of the property. The getter is replaced with a simple
+ * property once initialized.
+ */
+ this.defineProperty = function(obj, prop, desc, opts) {
+ if (typeof prop != 'string') throw new Error("Property must be a string");
+ var d = { __proto__: null, enumerable: true, configurable: true }; // Enumerable by default
+ for (let p in desc) {
+ if (!desc.hasOwnProperty(p)) continue;
+ d[p] = desc[p];
+ }
+
+ if (opts) {
+ if (opts.lateInit && d.get) {
+ let getter = d.get;
+ d.get = function() {
+ var val = getter.call(this);
+ this[prop] = val; // Replace getter with value
+ return val;
+ }
+ }
+ }
+
+ Object.defineProperty(obj, prop, d);
+ }
+
+ this.extendClass = function(superClass, newClass) {
+ newClass._super = superClass;
+ newClass.prototype = Object.create(superClass.prototype);
+ newClass.prototype.constructor = newClass;
+ }
+
/**
* Allow other events (e.g., UI updates) on main thread to be processed if necessary
*
diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js
index 01c6918c8..09c7c28e3 100644
--- a/chrome/content/zotero/zoteroPane.js
+++ b/chrome/content/zotero/zoteroPane.js
@@ -1971,6 +1971,7 @@ var ZoteroPane = new function()
}
var self = this;
+ var deferred = Zotero.Promise.defer();
this.collectionsView.addEventListener('load', function () {
Zotero.spawn(function* () {
var currentLibraryID = self.getSelectedLibraryID();
@@ -1993,15 +1994,22 @@ var ZoteroPane = new function()
yield self.collectionsView.selectLibrary(item.libraryID);
yield self.itemsView.selectItem(itemID, expand);
}
+ deferred.resolve(true);
+ })
+ .catch(function(e) {
+ deferred.reject(e);
});
});
+ })
+ .catch(function(e) {
+ deferred.reject(e);
});
});
// open Zotero pane
this.show();
- return true;
+ return deferred.promise;
});