diff --git a/chrome/content/zotero/xpcom/integration.js b/chrome/content/zotero/xpcom/integration.js index b1f7c7ed7d..dcdd7a3785 100644 --- a/chrome/content/zotero/xpcom/integration.js +++ b/chrome/content/zotero/xpcom/integration.js @@ -65,6 +65,8 @@ const NOTE_CITATION_PLACEHOLDER_LINK = 'https://www.zotero.org/?'; const TEMPLATE_VERSION = 1; +const MENDELEY_URI_RE = /^http:\/\/www\.mendeley\.com\/documents\/\?uuid=(.*)/; + Zotero.Integration = new function() { Components.utils.import("resource://gre/modules/Services.jsm"); @@ -2617,7 +2619,7 @@ Zotero.Integration.URIMap.prototype.getURIsForItemID = function(id) { /** * Gets Zotero item for a given set of URIs */ -Zotero.Integration.URIMap.prototype.getZoteroItemForURIs = Zotero.Promise.coroutine(function* (uris) { +Zotero.Integration.URIMap.prototype.getZoteroItemForURIs = async function (uris) { var zoteroItem = false; var needUpdate = false; var embeddedItem = false;; @@ -2632,43 +2634,52 @@ Zotero.Integration.URIMap.prototype.getZoteroItemForURIs = Zotero.Promise.corout // Next try getting URI directly try { - zoteroItem = yield Zotero.URI.getURIItem(uri); - if(zoteroItem) { - // Ignore items in the trash - if(zoteroItem.deleted) { - zoteroItem = false; - } else { - break; - } + var replacer = await Zotero.URI.getURIItem(uri); + if (replacer && !replacer.deleted) { + zoteroItem = replacer; + break; } } catch(e) {} // Try merged item mapping - var replacer = yield Zotero.Relations.getByPredicateAndObject( + var replacer = await Zotero.Relations.getByPredicateAndObject( 'item', Zotero.Relations.replacedItemPredicate, uri ); if (replacer.length && !replacer[0].deleted) { zoteroItem = replacer[0]; + break; + } + + // Check if it's a mendeley URI and if we have imported the item + let m = MENDELEY_URI_RE.exec(uri); + if (m) { + replacer = await Zotero.Relations.getByPredicateAndObject( + 'item', 'mendeleyDB:documentUUID', m[1] + ); + if (replacer.length && !replacer[0].deleted) { + zoteroItem = replacer[0]; + break; + } } - if(zoteroItem) break; } - if(zoteroItem) { + if (zoteroItem) { // make sure URI is up to date (in case user just began syncing) var newURI = Zotero.URI.getItemURI(zoteroItem); - if(newURI != uris[i]) { - uris[i] = newURI; + if (!uris.includes(newURI)) { + uris.push(newURI); needUpdate = true; } // cache uris - this.itemIDURIs[zoteroItem.id] = uris; - } else if(embeddedItem) { + this.add(zoteroItem.id, uris) + } + else if (embeddedItem) { return [embeddedItem, false]; } return [zoteroItem, needUpdate]; -}); +}; Zotero.Integration.Field = class { constructor(field, rawCode) { @@ -2847,8 +2858,13 @@ Zotero.Integration.CitationField = class extends Zotero.Integration.Field { } // for update from Zotero 2.1 or earlier - if(citationItem.uri) { - citationItem.uris = citationItem.uri; + if (citationItem.uri) { + if (Array.isArray(citationItem.uris)) { + citationItem.uris.push(citationItem.uri); + } + else { + citationItem.uris = [citationItem.uri]; + } delete citationItem.uri; } } diff --git a/test/tests/integrationTest.js b/test/tests/integrationTest.js index 3f42f1c81b..a831bfe401 100644 --- a/test/tests/integrationTest.js +++ b/test/tests/integrationTest.js @@ -720,11 +720,35 @@ describe("Zotero.Integration", function () { assert.isNotOk(citation.properties.dontUpdate); }); }); + + it('should detect items cited with Mendeley if they are imported into Zotero', async function() { + var docID = this.test.fullTitle(); + if (!(docID in applications)) await initDoc(docID); + var doc = applications[docID].doc; + + let testItem = await createDataObject('item', {libraryID: Zotero.Libraries.userLibraryID}); + testItem.setField('title', `Mendeley imported`); + testItem.setCreator(0, {creatorType: 'author', name: `Mendeleev, Dmitri `}); + testItem.addRelation('mendeleyDB:documentUUID', 'e213167f-af42-4ff1-95e8-a9aa6b0b3e1b'); + await testItem.saveTx(); + + setAddEditItems(testItem); + await execCommand('addEditCitation', docID); + + let uri = doc.fields[0].code.match(/"uris":\[([^\]]*)]/)[1]; + doc.fields[0].code = doc.fields[0].code.replace(/"uris":\[[^\]]*]/, `"uris":["http://www.mendeley.com/documents/?uuid=e213167f-af42-4ff1-95e8-a9aa6b0b3e1b"]`); + + sinon.stub(doc, 'canInsertField').resolves(false); + sinon.stub(doc, 'cursorInField').resolves(doc.fields[0]); + await execCommand('addEditCitation', docID); + assert.include(doc.fields[0].code, 'http://www.mendeley.com/documents/?uuid=e213167f-af42-4ff1-95e8-a9aa6b0b3e1b'); + assert.include(doc.fields[0].code, Zotero.URI.getItemURI(testItem)); + }); describe('when there are copy-pasted citations', function() { it('should resolve duplicate citationIDs and mark both as new citations', async function() { var docID = this.test.fullTitle(); - if (!(docID in applications)) initDoc(docID); + if (!(docID in applications)) await initDoc(docID); var doc = applications[docID].doc; setAddEditItems(testItems[0]); @@ -754,7 +778,7 @@ describe("Zotero.Integration", function () { it('should successfully process citations copied in from another doc', async function() { var docID = this.test.fullTitle(); - if (!(docID in applications)) initDoc(docID); + if (!(docID in applications)) await initDoc(docID); var doc = applications[docID].doc; setAddEditItems(testItems[0]); @@ -790,7 +814,7 @@ describe("Zotero.Integration", function () { it('should successfully insert a citation after canceled citation insert', async function () { var docID = this.test.fullTitle(); - if (!(docID in applications)) initDoc(docID); + if (!(docID in applications)) await initDoc(docID); var doc = applications[docID].doc; setAddEditItems(testItems[0]);