Load reverse relations mappings at startup
This allows Zotero.Relations.getByPredicateAndObject()/getByObject() and Zotero.Item::getLinkedItem()/Zotero.Collection::getLinkedCollection() to be synchronous, which is necessary for word processor integration.
This commit is contained in:
parent
5d3e7f555c
commit
da45df06cc
|
@ -1517,7 +1517,7 @@ Zotero.CollectionTreeView.prototype.canDropCheckAsync = Zotero.Promise.coroutine
|
||||||
|
|
||||||
// Cross-library drag
|
// Cross-library drag
|
||||||
if (treeRow.ref.libraryID != item.libraryID) {
|
if (treeRow.ref.libraryID != item.libraryID) {
|
||||||
let linkedItem = yield item.getLinkedItem(treeRow.ref.libraryID, true);
|
let linkedItem = item.getLinkedItem(treeRow.ref.libraryID, true);
|
||||||
if (linkedItem && !linkedItem.deleted) {
|
if (linkedItem && !linkedItem.deleted) {
|
||||||
// For drag to root, skip if linked item exists
|
// For drag to root, skip if linked item exists
|
||||||
if (treeRow.isLibrary(true)) {
|
if (treeRow.isLibrary(true)) {
|
||||||
|
@ -1623,7 +1623,7 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
||||||
var targetLibraryType = Zotero.Libraries.get(targetLibraryID).libraryType;
|
var targetLibraryType = Zotero.Libraries.get(targetLibraryID).libraryType;
|
||||||
|
|
||||||
// Check if there's already a copy of this item in the library
|
// Check if there's already a copy of this item in the library
|
||||||
var linkedItem = yield item.getLinkedItem(targetLibraryID, true);
|
var linkedItem = item.getLinkedItem(targetLibraryID, true);
|
||||||
if (linkedItem) {
|
if (linkedItem) {
|
||||||
// If linked item is in the trash, undelete it and remove it from collections
|
// If linked item is in the trash, undelete it and remove it from collections
|
||||||
// (since it shouldn't be restored to previous collections)
|
// (since it shouldn't be restored to previous collections)
|
||||||
|
|
|
@ -446,9 +446,9 @@ Zotero.DataObject.prototype.setRelations = function (newRelations) {
|
||||||
* calling this directly.
|
* calling this directly.
|
||||||
*
|
*
|
||||||
* @param {Integer} [libraryID]
|
* @param {Integer} [libraryID]
|
||||||
* @return {Promise<Zotero.DataObject>|false} Linked object, or false if not found
|
* @return {Zotero.DataObject|false} Linked object, or false if not found
|
||||||
*/
|
*/
|
||||||
Zotero.DataObject.prototype._getLinkedObject = Zotero.Promise.coroutine(function* (libraryID, bidirectional) {
|
Zotero.DataObject.prototype._getLinkedObject = function (libraryID, bidirectional) {
|
||||||
if (!libraryID) {
|
if (!libraryID) {
|
||||||
throw new Error("libraryID not provided");
|
throw new Error("libraryID not provided");
|
||||||
}
|
}
|
||||||
|
@ -466,7 +466,7 @@ Zotero.DataObject.prototype._getLinkedObject = Zotero.Promise.coroutine(function
|
||||||
for (let i = 0; i < uris.length; i++) {
|
for (let i = 0; i < uris.length; i++) {
|
||||||
let uri = uris[i];
|
let uri = uris[i];
|
||||||
if (uri.startsWith(libraryObjectPrefix)) {
|
if (uri.startsWith(libraryObjectPrefix)) {
|
||||||
let obj = yield Zotero.URI['getURI' + this._ObjectType](uri);
|
let obj = Zotero.URI['getURI' + this._ObjectType](uri);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
Zotero.debug("Referenced linked " + this._objectType + " '" + uri + "' not found "
|
Zotero.debug("Referenced linked " + this._objectType + " '" + uri + "' not found "
|
||||||
+ "in Zotero." + this._ObjectType + "::getLinked" + this._ObjectType + "()", 2);
|
+ "in Zotero." + this._ObjectType + "::getLinked" + this._ObjectType + "()", 2);
|
||||||
|
@ -479,7 +479,7 @@ Zotero.DataObject.prototype._getLinkedObject = Zotero.Promise.coroutine(function
|
||||||
// Then try relations with this as an object
|
// Then try relations with this as an object
|
||||||
if (bidirectional) {
|
if (bidirectional) {
|
||||||
var thisURI = Zotero.URI['get' + this._ObjectType + 'URI'](this);
|
var thisURI = Zotero.URI['get' + this._ObjectType + 'URI'](this);
|
||||||
var objects = yield Zotero.Relations.getByPredicateAndObject(
|
var objects = Zotero.Relations.getByPredicateAndObject(
|
||||||
this._objectType, predicate, thisURI
|
this._objectType, predicate, thisURI
|
||||||
);
|
);
|
||||||
for (let i = 0; i < objects.length; i++) {
|
for (let i = 0; i < objects.length; i++) {
|
||||||
|
@ -496,7 +496,7 @@ Zotero.DataObject.prototype._getLinkedObject = Zotero.Promise.coroutine(function
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -830,14 +830,14 @@ Zotero.DataObject.prototype.save = Zotero.Promise.coroutine(function* (options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create transaction
|
// Create transaction
|
||||||
|
let result
|
||||||
if (env.options.tx) {
|
if (env.options.tx) {
|
||||||
let result = yield Zotero.DB.executeTransaction(function* () {
|
result = yield Zotero.DB.executeTransaction(function* () {
|
||||||
Zotero.DataObject.prototype._saveData.call(this, env);
|
Zotero.DataObject.prototype._saveData.call(this, env);
|
||||||
yield this._saveData(env);
|
yield this._saveData(env);
|
||||||
yield Zotero.DataObject.prototype._finalizeSave.call(this, env);
|
yield Zotero.DataObject.prototype._finalizeSave.call(this, env);
|
||||||
return this._finalizeSave(env);
|
return this._finalizeSave(env);
|
||||||
}.bind(this), env.transactionOptions);
|
}.bind(this), env.transactionOptions);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
// Use existing transaction
|
// Use existing transaction
|
||||||
else {
|
else {
|
||||||
|
@ -845,8 +845,10 @@ Zotero.DataObject.prototype.save = Zotero.Promise.coroutine(function* (options)
|
||||||
Zotero.DataObject.prototype._saveData.call(this, env);
|
Zotero.DataObject.prototype._saveData.call(this, env);
|
||||||
yield this._saveData(env);
|
yield this._saveData(env);
|
||||||
yield Zotero.DataObject.prototype._finalizeSave.call(this, env);
|
yield Zotero.DataObject.prototype._finalizeSave.call(this, env);
|
||||||
return this._finalizeSave(env);
|
result = this._finalizeSave(env);
|
||||||
}
|
}
|
||||||
|
this._postSave(env);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
return this._recoverFromSaveError(env, e)
|
return this._recoverFromSaveError(env, e)
|
||||||
|
@ -906,6 +908,9 @@ Zotero.DataObject.prototype._initSave = Zotero.Promise.coroutine(function* (env)
|
||||||
Zotero.DB.addCurrentCallback("rollback", func);
|
Zotero.DB.addCurrentCallback("rollback", func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
env.relationsToRegister = [];
|
||||||
|
env.relationsToUnregister = [];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -967,6 +972,7 @@ Zotero.DataObject.prototype._finalizeSave = Zotero.Promise.coroutine(function* (
|
||||||
// Convert predicates to ids
|
// Convert predicates to ids
|
||||||
for (let i = 0; i < toAdd.length; i++) {
|
for (let i = 0; i < toAdd.length; i++) {
|
||||||
toAdd[i][0] = yield Zotero.RelationPredicates.add(toAdd[i][0]);
|
toAdd[i][0] = yield Zotero.RelationPredicates.add(toAdd[i][0]);
|
||||||
|
env.relationsToRegister.push([toAdd[i][0], toAdd[i][1]]);
|
||||||
}
|
}
|
||||||
yield Zotero.DB.queryAsync(
|
yield Zotero.DB.queryAsync(
|
||||||
sql + toAdd.map(x => "(?, ?, ?)").join(", "),
|
sql + toAdd.map(x => "(?, ?, ?)").join(", "),
|
||||||
|
@ -987,13 +993,15 @@ Zotero.DataObject.prototype._finalizeSave = Zotero.Promise.coroutine(function* (
|
||||||
toRemove[i][1]
|
toRemove[i][1]
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
env.relationsToUnregister.push([toRemove[i][0], toRemove[i][1]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env.isNew) {
|
if (env.isNew) {
|
||||||
if (!env.skipCache) {
|
if (!env.skipCache) {
|
||||||
// Register this object's identifiers in Zotero.DataObjects
|
// Register this object's identifiers in Zotero.DataObjects. This has to happen here so
|
||||||
|
// that the object exists for the reload() in objects' finalizeSave methods.
|
||||||
this.ObjectsClass.registerObject(this);
|
this.ObjectsClass.registerObject(this);
|
||||||
}
|
}
|
||||||
// If object isn't being reloaded, disable it, since its data may be out of date
|
// If object isn't being reloaded, disable it, since its data may be out of date
|
||||||
|
@ -1006,6 +1014,23 @@ Zotero.DataObject.prototype._finalizeSave = Zotero.Promise.coroutine(function* (
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actions to perform after DB transaction
|
||||||
|
*/
|
||||||
|
Zotero.DataObject.prototype._postSave = function (env) {
|
||||||
|
for (let i = 0; i < env.relationsToRegister.length; i++) {
|
||||||
|
let rel = env.relationsToRegister[i];
|
||||||
|
Zotero.debug(rel);
|
||||||
|
Zotero.Relations.register(this._objectType, this.id, rel[0], rel[1]);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < env.relationsToUnregister.length; i++) {
|
||||||
|
let rel = env.relationsToUnregister[i];
|
||||||
|
Zotero.Relations.unregister(this._objectType, this.id, rel[0], rel[1]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Zotero.DataObject.prototype._recoverFromSaveError = Zotero.Promise.coroutine(function* (env) {
|
Zotero.DataObject.prototype._recoverFromSaveError = Zotero.Promise.coroutine(function* (env) {
|
||||||
yield this.reload(null, true);
|
yield this.reload(null, true);
|
||||||
this._clearChanged();
|
this._clearChanged();
|
||||||
|
|
|
@ -500,7 +500,7 @@ Zotero.DataObjects.prototype._loadRelations = Zotero.Promise.coroutine(function*
|
||||||
let objectURI = getURI(this);
|
let objectURI = getURI(this);
|
||||||
|
|
||||||
// Related items are bidirectional, so include any pointing to this object
|
// Related items are bidirectional, so include any pointing to this object
|
||||||
let objects = yield Zotero.Relations.getByPredicateAndObject(
|
let objects = Zotero.Relations.getByPredicateAndObject(
|
||||||
Zotero.Relations.relatedItemPredicate, objectURI
|
Zotero.Relations.relatedItemPredicate, objectURI
|
||||||
);
|
);
|
||||||
for (let i = 0; i < objects.length; i++) {
|
for (let i = 0; i < objects.length; i++) {
|
||||||
|
@ -508,7 +508,7 @@ Zotero.DataObjects.prototype._loadRelations = Zotero.Promise.coroutine(function*
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also include any owl:sameAs relations pointing to this object
|
// Also include any owl:sameAs relations pointing to this object
|
||||||
objects = yield Zotero.Relations.getByPredicateAndObject(
|
objects = Zotero.Relations.getByPredicateAndObject(
|
||||||
Zotero.Relations.linkedObjectPredicate, objectURI
|
Zotero.Relations.linkedObjectPredicate, objectURI
|
||||||
);
|
);
|
||||||
for (let i = 0; i < objects.length; i++) {
|
for (let i = 0; i < objects.length; i++) {
|
||||||
|
|
|
@ -1492,7 +1492,7 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
||||||
// If undeleting, remove any merge-tracking relations
|
// If undeleting, remove any merge-tracking relations
|
||||||
let predicate = Zotero.Relations.replacedItemPredicate;
|
let predicate = Zotero.Relations.replacedItemPredicate;
|
||||||
let thisURI = Zotero.URI.getItemURI(this);
|
let thisURI = Zotero.URI.getItemURI(this);
|
||||||
let mergeItems = yield Zotero.Relations.getByPredicateAndObject(
|
let mergeItems = Zotero.Relations.getByPredicateAndObject(
|
||||||
'item', predicate, thisURI
|
'item', predicate, thisURI
|
||||||
);
|
);
|
||||||
for (let mergeItem of mergeItems) {
|
for (let mergeItem of mergeItems) {
|
||||||
|
|
|
@ -36,6 +36,82 @@ Zotero.Relations = new function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
var _types = ['collection', 'item'];
|
var _types = ['collection', 'item'];
|
||||||
|
var _subjectsByPredicateIDAndObject = {};
|
||||||
|
var _subjectPredicatesByObject = {};
|
||||||
|
|
||||||
|
|
||||||
|
this.init = Zotero.Promise.coroutine(function* () {
|
||||||
|
// Load relations for different types
|
||||||
|
for (let type of _types) {
|
||||||
|
let t = new Date();
|
||||||
|
Zotero.debug(`Loading ${type} relations`);
|
||||||
|
|
||||||
|
let sql = "SELECT * FROM " + type + "Relations "
|
||||||
|
+ "JOIN relationPredicates USING (predicateID)";
|
||||||
|
yield Zotero.DB.queryAsync(
|
||||||
|
sql,
|
||||||
|
false,
|
||||||
|
{
|
||||||
|
onRow: function (row) {
|
||||||
|
this.register(
|
||||||
|
type,
|
||||||
|
row.getResultByIndex(0),
|
||||||
|
row.getResultByIndex(1),
|
||||||
|
row.getResultByIndex(2)
|
||||||
|
);
|
||||||
|
}.bind(this)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Zotero.debug(`Loaded ${type} relations in ${new Date() - t} ms`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
this.register = function (objectType, subjectID, predicate, object) {
|
||||||
|
var predicateID = Zotero.RelationPredicates.getID(predicate);
|
||||||
|
|
||||||
|
if (!_subjectsByPredicateIDAndObject[objectType]) {
|
||||||
|
_subjectsByPredicateIDAndObject[objectType] = {};
|
||||||
|
}
|
||||||
|
if (!_subjectPredicatesByObject[objectType]) {
|
||||||
|
_subjectPredicatesByObject[objectType] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// _subjectsByPredicateIDAndObject
|
||||||
|
var o = _subjectsByPredicateIDAndObject[objectType];
|
||||||
|
if (!o[predicateID]) {
|
||||||
|
o[predicateID] = {};
|
||||||
|
}
|
||||||
|
if (!o[predicateID][object]) {
|
||||||
|
o[predicateID][object] = new Set();
|
||||||
|
}
|
||||||
|
o[predicateID][object].add(subjectID);
|
||||||
|
|
||||||
|
// _subjectPredicatesByObject
|
||||||
|
o = _subjectPredicatesByObject[objectType];
|
||||||
|
if (!o[object]) {
|
||||||
|
o[object] = {};
|
||||||
|
}
|
||||||
|
if (!o[object][predicateID]) {
|
||||||
|
o[object][predicateID] = new Set();
|
||||||
|
}
|
||||||
|
o[object][predicateID].add(subjectID);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.unregister = function (objectType, subjectID, predicate, object) {
|
||||||
|
var predicateID = Zotero.RelationPredicates.getID(predicate);
|
||||||
|
|
||||||
|
if (!_subjectsByPredicateIDAndObject[objectType]
|
||||||
|
|| !_subjectsByPredicateIDAndObject[objectType][predicateID]
|
||||||
|
|| !_subjectsByPredicateIDAndObject[objectType][predicateID][object]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_subjectsByPredicateIDAndObject[objectType][predicateID][object].delete(subjectID)
|
||||||
|
_subjectPredicatesByObject[objectType][object][predicateID].delete(subjectID)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,18 +120,22 @@ Zotero.Relations = new function () {
|
||||||
* @param {String} objectType - Type of relation to search for (e.g., 'item')
|
* @param {String} objectType - Type of relation to search for (e.g., 'item')
|
||||||
* @param {String} predicate
|
* @param {String} predicate
|
||||||
* @param {String} object
|
* @param {String} object
|
||||||
* @return {Promise<Zotero.DataObject[]>}
|
* @return {Zotero.DataObject[]}
|
||||||
*/
|
*/
|
||||||
this.getByPredicateAndObject = Zotero.Promise.coroutine(function* (objectType, predicate, object) {
|
this.getByPredicateAndObject = function (objectType, predicate, object) {
|
||||||
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(objectType);
|
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(objectType);
|
||||||
if (predicate) {
|
if (predicate) {
|
||||||
predicate = this._getPrefixAndValue(predicate).join(':');
|
predicate = this._getPrefixAndValue(predicate).join(':');
|
||||||
}
|
}
|
||||||
var sql = "SELECT " + objectsClass.idColumn + " FROM " + objectType + "Relations "
|
|
||||||
+ "JOIN relationPredicates USING (predicateID) WHERE predicate=? AND object=?";
|
var predicateID = Zotero.RelationPredicates.getID(predicate);
|
||||||
var ids = yield Zotero.DB.columnQueryAsync(sql, [predicate, object]);
|
|
||||||
return yield objectsClass.getAsync(ids, { noCache: true });
|
var o = _subjectsByPredicateIDAndObject[objectType];
|
||||||
});
|
if (!o || !o[predicateID] || !o[predicateID][object]) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return objectsClass.get(Array.from(o[predicateID][object].values()));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,24 +143,25 @@ Zotero.Relations = new function () {
|
||||||
*
|
*
|
||||||
* @param {String} objectType - Type of relation to search for (e.g., 'item')
|
* @param {String} objectType - Type of relation to search for (e.g., 'item')
|
||||||
* @param {String} object
|
* @param {String} object
|
||||||
* @return {Promise<Object[]>} - Promise for an object with a Zotero.DataObject as 'subject'
|
* @return {Object[]} - An array of objects with a Zotero.DataObject as 'subject'
|
||||||
* and a predicate string as 'predicate'
|
* and a predicate string as 'predicate'
|
||||||
*/
|
*/
|
||||||
this.getByObject = Zotero.Promise.coroutine(function* (objectType, object) {
|
this.getByObject = function (objectType, object) {
|
||||||
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(objectType);
|
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(objectType);
|
||||||
var sql = "SELECT " + objectsClass.idColumn + " AS id, predicate "
|
var predicateIDs = [];
|
||||||
+ "FROM " + objectType + "Relations JOIN relationPredicates USING (predicateID) "
|
var o = _subjectPredicatesByObject[objectType][object];
|
||||||
+ "WHERE object=?";
|
if (!o) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
var toReturn = [];
|
var toReturn = [];
|
||||||
var rows = yield Zotero.DB.queryAsync(sql, object);
|
for (let predicateID in o) {
|
||||||
for (let i = 0; i < rows.length; i++) {
|
o[predicateID].forEach(subjectID => toReturn.push({
|
||||||
toReturn.push({
|
subject: objectsClass.get(subjectID),
|
||||||
subject: yield objectsClass.getAsync(rows[i].id, { noCache: true }),
|
predicate: Zotero.RelationPredicates.getName(predicateID)
|
||||||
predicate: rows[i].predicate
|
}));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return toReturn;
|
return toReturn;
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
this.updateUser = Zotero.Promise.coroutine(function* (toUserID) {
|
this.updateUser = Zotero.Promise.coroutine(function* (toUserID) {
|
||||||
|
@ -93,14 +174,32 @@ Zotero.Relations = new function () {
|
||||||
}
|
}
|
||||||
Zotero.DB.requireTransaction();
|
Zotero.DB.requireTransaction();
|
||||||
for (let type of _types) {
|
for (let type of _types) {
|
||||||
var sql = "UPDATE " + type + "Relations SET "
|
let sql = `SELECT DISTINCT object FROM ${type}Relations WHERE object LIKE ?`;
|
||||||
+ "object=REPLACE(object, 'zotero.org/users/" + fromUserID + "', "
|
let objects = yield Zotero.DB.columnQueryAsync(
|
||||||
+ "'zotero.org/users/" + toUserID + "')";
|
sql, 'http://zotero.org/users/' + fromUserID + '/%'
|
||||||
|
);
|
||||||
|
Zotero.DB.addCurrentCallback("commit", function () {
|
||||||
|
for (let object of objects) {
|
||||||
|
let subPrefs = this.getByObject(type, object);
|
||||||
|
let newObject = object.replace(
|
||||||
|
new RegExp("^http://zotero.org/users/" + fromUserID + "/(.*)"),
|
||||||
|
"http://zotero.org/users/" + toUserID + "/$1"
|
||||||
|
);
|
||||||
|
for (let subPref of subPrefs) {
|
||||||
|
this.unregister(type, subPref.subject.id, subPref.predicate, object);
|
||||||
|
this.register(type, subPref.subject.id, subPref.predicate, newObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
sql = "UPDATE " + type + "Relations SET "
|
||||||
|
+ "object=REPLACE(object, 'zotero.org/users/" + fromUserID + "/', "
|
||||||
|
+ "'zotero.org/users/" + toUserID + "/')";
|
||||||
yield Zotero.DB.queryAsync(sql);
|
yield Zotero.DB.queryAsync(sql);
|
||||||
|
|
||||||
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(type);
|
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(type);
|
||||||
var objects = objectsClass.getLoaded();
|
let loadedObjects = objectsClass.getLoaded();
|
||||||
for (let object of objects) {
|
for (let object of loadedObjects) {
|
||||||
yield object.reload(['relations'], true);
|
yield object.reload(['relations'], true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3139,8 +3139,6 @@ Zotero.Integration.URIMap.prototype.getZoteroItemForURIs = function(uris) {
|
||||||
|
|
||||||
// Next try getting URI directly
|
// Next try getting URI directly
|
||||||
try {
|
try {
|
||||||
// TEMP
|
|
||||||
throw new Error("getURIItem() is now async");
|
|
||||||
zoteroItem = Zotero.URI.getURIItem(uri);
|
zoteroItem = Zotero.URI.getURIItem(uri);
|
||||||
if(zoteroItem) {
|
if(zoteroItem) {
|
||||||
// Ignore items in the trash
|
// Ignore items in the trash
|
||||||
|
@ -3152,42 +3150,14 @@ Zotero.Integration.URIMap.prototype.getZoteroItemForURIs = function(uris) {
|
||||||
}
|
}
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
|
|
||||||
// Try merged item mappings
|
// Try merged item mapping
|
||||||
var seen = [];
|
var replacer = Zotero.Relations.getByPredicateAndObject(
|
||||||
|
'item', Zotero.Relations.replacedItemPredicate, uri
|
||||||
// Follow merged item relations until we find an item or hit a dead end
|
);
|
||||||
while (!zoteroItem) {
|
if (replacer.length && !replacer[0].deleted) {
|
||||||
var relations = Zotero.Relations.getByURIs(uri, Zotero.Relations.replacedItemPredicate);
|
zoteroItem = replacer;
|
||||||
// No merged items found
|
|
||||||
if(!relations.length) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uri = relations[0].object;
|
|
||||||
|
|
||||||
// Keep track of mapped URIs in case there's a circular relation
|
|
||||||
if(seen.indexOf(uri) != -1) {
|
|
||||||
var msg = "Circular relation for '" + uri + "' in merged item mapping resolution";
|
|
||||||
Zotero.debug(msg, 2);
|
|
||||||
Components.utils.reportError(msg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
seen.push(uri);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// TEMP
|
|
||||||
throw new Error("getURIItem() is now async");
|
|
||||||
zoteroItem = Zotero.URI.getURIItem(uri);
|
|
||||||
if(zoteroItem) {
|
|
||||||
// Ignore items in the trash
|
|
||||||
if(zoteroItem.deleted) {
|
|
||||||
zoteroItem = false;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(e) {}
|
|
||||||
}
|
|
||||||
if(zoteroItem) break;
|
if(zoteroItem) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ Zotero.Report.HTML = new function () {
|
||||||
}
|
}
|
||||||
for (let i=0; i<rels.length; i++) {
|
for (let i=0; i<rels.length; i++) {
|
||||||
let rel = rels[i];
|
let rel = rels[i];
|
||||||
let relItem = yield Zotero.URI.getURIItem(rel);
|
let relItem = Zotero.URI.getURIItem(rel);
|
||||||
if (relItem) {
|
if (relItem) {
|
||||||
content += '\t\t\t\t\t<li id="item_' + relItem.key + '">';
|
content += '\t\t\t\t\t<li id="item_' + relItem.key + '">';
|
||||||
content += escapeXML(relItem.getDisplayTitle());
|
content += escapeXML(relItem.getDisplayTitle());
|
||||||
|
|
|
@ -191,13 +191,13 @@ Zotero.URI = new function () {
|
||||||
* Convert an item URI into an item
|
* Convert an item URI into an item
|
||||||
*
|
*
|
||||||
* @param {String} itemURI
|
* @param {String} itemURI
|
||||||
* @return {Promise<Zotero.Item|FALSE>}
|
* @return {Zotero.Item|false}
|
||||||
*/
|
*/
|
||||||
this.getURIItem = Zotero.Promise.method(function (itemURI) {
|
this.getURIItem = function (itemURI) {
|
||||||
var obj = this._getURIObject(itemURI, 'item');
|
var obj = this._getURIObject(itemURI, 'item');
|
||||||
if (!obj) return false;
|
if (!obj) return false;
|
||||||
return Zotero.Items.getByLibraryAndKeyAsync(obj.libraryID, obj.key);
|
return Zotero.Items.getByLibraryAndKey(obj.libraryID, obj.key);
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -225,13 +225,13 @@ Zotero.URI = new function () {
|
||||||
*
|
*
|
||||||
* @param {String} collectionURI
|
* @param {String} collectionURI
|
||||||
* @param {Zotero.Collection|FALSE}
|
* @param {Zotero.Collection|FALSE}
|
||||||
* @return {Promise<Zotero.Collection|FALSE>}
|
* @return {Zotero.Collection|false}
|
||||||
*/
|
*/
|
||||||
this.getURICollection = Zotero.Promise.method(function (collectionURI) {
|
this.getURICollection = function (collectionURI) {
|
||||||
var obj = this._getURIObject(collectionURI, 'collection');
|
var obj = this._getURIObject(collectionURI, 'collection');
|
||||||
if (!obj) return false;
|
if (!obj) return false;
|
||||||
return Zotero.Collections.getByLibraryAndKeyAsync(obj.libraryID, obj.key);
|
return Zotero.Collections.getByLibraryAndKey(obj.libraryID, obj.key);
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -626,6 +626,7 @@ Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||||
yield Zotero.Searches.init();
|
yield Zotero.Searches.init();
|
||||||
yield Zotero.Creators.init();
|
yield Zotero.Creators.init();
|
||||||
yield Zotero.Groups.init();
|
yield Zotero.Groups.init();
|
||||||
|
yield Zotero.Relations.init()
|
||||||
|
|
||||||
let libraryIDs = Zotero.Libraries.getAll().map(x => x.libraryID);
|
let libraryIDs = Zotero.Libraries.getAll().map(x => x.libraryID);
|
||||||
for (let libraryID of libraryIDs) {
|
for (let libraryID of libraryIDs) {
|
||||||
|
|
|
@ -424,7 +424,7 @@ describe("Zotero.CollectionTreeView", function() {
|
||||||
assert.equal(treeRow.ref.libraryID, group.libraryID);
|
assert.equal(treeRow.ref.libraryID, group.libraryID);
|
||||||
assert.equal(treeRow.ref.id, ids[0]);
|
assert.equal(treeRow.ref.id, ids[0]);
|
||||||
// New item should link back to original
|
// New item should link back to original
|
||||||
var linked = yield item.getLinkedItem(group.libraryID);
|
var linked = item.getLinkedItem(group.libraryID);
|
||||||
assert.equal(linked.id, treeRow.ref.id);
|
assert.equal(linked.id, treeRow.ref.id);
|
||||||
|
|
||||||
// Check attachment
|
// Check attachment
|
||||||
|
@ -434,7 +434,7 @@ describe("Zotero.CollectionTreeView", function() {
|
||||||
treeRow = itemsView.getRow(1);
|
treeRow = itemsView.getRow(1);
|
||||||
assert.equal(treeRow.ref.id, ids[1]);
|
assert.equal(treeRow.ref.id, ids[1]);
|
||||||
// New attachment should link back to original
|
// New attachment should link back to original
|
||||||
linked = yield attachment.getLinkedItem(group.libraryID);
|
linked = attachment.getLinkedItem(group.libraryID);
|
||||||
assert.equal(linked.id, treeRow.ref.id);
|
assert.equal(linked.id, treeRow.ref.id);
|
||||||
|
|
||||||
return group.eraseTx();
|
return group.eraseTx();
|
||||||
|
@ -466,7 +466,7 @@ describe("Zotero.CollectionTreeView", function() {
|
||||||
var item = yield createDataObject('item', false, { skipSelect: true });
|
var item = yield createDataObject('item', false, { skipSelect: true });
|
||||||
yield drop('item', 'L' + group.libraryID, [item.id]);
|
yield drop('item', 'L' + group.libraryID, [item.id]);
|
||||||
|
|
||||||
var droppedItem = yield item.getLinkedItem(group.libraryID);
|
var droppedItem = item.getLinkedItem(group.libraryID);
|
||||||
droppedItem.setCollections([collection.id]);
|
droppedItem.setCollections([collection.id]);
|
||||||
droppedItem.deleted = true;
|
droppedItem.deleted = true;
|
||||||
yield droppedItem.saveTx();
|
yield droppedItem.saveTx();
|
||||||
|
|
|
@ -411,7 +411,7 @@ describe("Zotero.DataObject", function() {
|
||||||
var item2URI = Zotero.URI.getItemURI(item2);
|
var item2URI = Zotero.URI.getItemURI(item2);
|
||||||
|
|
||||||
yield item2.addLinkedItem(item1);
|
yield item2.addLinkedItem(item1);
|
||||||
var linkedItem = yield item1.getLinkedItem(item2.libraryID);
|
var linkedItem = item1.getLinkedItem(item2.libraryID);
|
||||||
assert.equal(linkedItem.id, item2.id);
|
assert.equal(linkedItem.id, item2.id);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -422,7 +422,7 @@ describe("Zotero.DataObject", function() {
|
||||||
var item2 = yield createDataObject('item', { libraryID: group.libraryID });
|
var item2 = yield createDataObject('item', { libraryID: group.libraryID });
|
||||||
|
|
||||||
yield item2.addLinkedItem(item1);
|
yield item2.addLinkedItem(item1);
|
||||||
var linkedItem = yield item2.getLinkedItem(item1.libraryID);
|
var linkedItem = item2.getLinkedItem(item1.libraryID);
|
||||||
assert.isFalse(linkedItem);
|
assert.isFalse(linkedItem);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -433,7 +433,7 @@ describe("Zotero.DataObject", function() {
|
||||||
var item2 = yield createDataObject('item', { libraryID: group.libraryID });
|
var item2 = yield createDataObject('item', { libraryID: group.libraryID });
|
||||||
|
|
||||||
yield item2.addLinkedItem(item1);
|
yield item2.addLinkedItem(item1);
|
||||||
var linkedItem = yield item2.getLinkedItem(item1.libraryID, true);
|
var linkedItem = item2.getLinkedItem(item1.libraryID, true);
|
||||||
assert.equal(linkedItem.id, item1.id);
|
assert.equal(linkedItem.id, item1.id);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,7 +14,7 @@ describe("Zotero.Relations", function () {
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
yield item.saveTx();
|
yield item.saveTx();
|
||||||
var objects = yield Zotero.Relations.getByPredicateAndObject(
|
var objects = Zotero.Relations.getByPredicateAndObject(
|
||||||
'item', 'owl:sameAs', 'http://zotero.org/groups/1/items/SRRMGSRM'
|
'item', 'owl:sameAs', 'http://zotero.org/groups/1/items/SRRMGSRM'
|
||||||
);
|
);
|
||||||
assert.lengthOf(objects, 1);
|
assert.lengthOf(objects, 1);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user