diff --git a/chrome/content/zotero/xpcom/integration.js b/chrome/content/zotero/xpcom/integration.js index 93cdade4d..9e7b4905a 100644 --- a/chrome/content/zotero/xpcom/integration.js +++ b/chrome/content/zotero/xpcom/integration.js @@ -567,7 +567,8 @@ Zotero.Integration.Interface.prototype.addEditBibliography = Zotero.Promise.coro } } - if(!bibliographyField) { + var newBibliography = !bibliographyField; + if (!bibliographyField) { bibliographyField = new Zotero.Integration.BibliographyField(yield this._session.fields.addField()); bibliographyField.clearCode(); bibliographyField.writeToDoc(); @@ -579,7 +580,7 @@ Zotero.Integration.Interface.prototype.addEditBibliography = Zotero.Promise.coro this._session.reload = true; } yield this._session.fields.updateSession(FORCE_CITATIONS_FALSE); - yield this._session.editBibliography(bibliography); + if (!newBibliography) yield this._session.editBibliography(bibliography); yield this._session.fields.updateDocument(FORCE_CITATIONS_FALSE, true, false); }); @@ -1134,13 +1135,13 @@ Zotero.Integration.Fields.prototype.addEditCitation = Zotero.Promise.coroutine(f let fieldIndex = yield fieldIndexPromise; this._session.updateIndices[fieldIndex] = true; + // Make sure session updated + yield citationsByItemIDPromise; if (newField) { - // On next updateSession call this field will be properly recognised as citation + // For further processing this field will be properly recognised as citation // instead of skipped as a temp field. field.writeToDoc(); } - // Make sure session updated - yield citationsByItemIDPromise; return [fieldIndex, field, io.citation]; }); @@ -1887,7 +1888,7 @@ Zotero.Integration.Field = class { writeToDoc() { if (!this.dirty) return; - // Boo. Inconsistent. + // Boo. Inconsistent order. if (this.type == INTEGRATION_TYPE_ITEM) { this._field.setCode(`ITEM CSL_CITATION ${this.code}`); } else if (this.type == INTEGRATION_TYPE_BIBLIOGRAPHY) { @@ -1897,16 +1898,18 @@ Zotero.Integration.Field = class { } // NB: Setting code in LO removes rtf formatting, so the order here is important - let text = this.text; - let isRich = false; - // If RTF wrap with RTF tags - if (text.includes("\\")) { - if (text.substr(0,5) != "{\\rtf") { - text = "{\\rtf "+text+"}"; + let text = this._text; + if (text) { + let isRich = false; + // If RTF wrap with RTF tags + if (text.includes("\\")) { + if (text.substr(0,5) != "{\\rtf") { + text = "{\\rtf "+text+"}"; + } + isRich = true; } - isRich = true; + this._field.setText(text, isRich); } - this._field.setText(text, isRich); this.dirty = false; // Retrigger retrieval from doc. @@ -2048,7 +2051,6 @@ Zotero.Integration.CitationField = class extends Zotero.Integration.Field { citation.properties.custom = citation.custom; delete citation.custom; } - if(!citation.citationID) citation.citationID = Zotero.randomString(); citation.properties.field = code; return citation; @@ -2355,7 +2357,7 @@ Zotero.Integration.Citation = class { serializeCitationItem.id = citationItem.id; serializeCitationItem.uris = citationItem.uris; - // XXX For compatibility with older versions of Zotero; to be removed at a later date + // XXX For compatibility with Zotero 2.0; to be removed at a later date serializeCitationItem.uri = serializeCitationItem.uris; // always store itemData, since we have no way to get it back otherwise @@ -2364,7 +2366,7 @@ Zotero.Integration.Citation = class { serializeCitationItem.id = citationItem.id; serializeCitationItem.uris = Zotero.Integration.currentSession.uriMap.getURIsForItemID(citationItem.id); - // XXX For compatibility with older versions of Zotero; to be removed at a later date + // XXX For compatibility with Zotero 2.0; to be removed at a later date serializeCitationItem.uri = serializeCitationItem.uris; serializeCitationItem.itemData = Zotero.Integration.currentSession.style.sys.retrieveItem(citationItem.id); diff --git a/test/tests/integrationTest.js b/test/tests/integrationTest.js index c20086a72..4ef509f47 100644 --- a/test/tests/integrationTest.js +++ b/test/tests/integrationTest.js @@ -2,6 +2,9 @@ describe("Zotero.Integration", function () { Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + const INTEGRATION_TYPE_ITEM = 1; + const INTEGRATION_TYPE_BIBLIOGRAPHY = 2; + const INTEGRATION_TYPE_TEMP = 3; /** * To be used as a reference for Zotero-Word Integration plugins */ @@ -235,6 +238,7 @@ describe("Zotero.Integration", function () { if (typeof docID === "undefined") { throw new Error(`docID cannot be undefined`) } + Zotero.debug(`execCommand '${command}': ${docID}`, 2); return Zotero.Integration.execCommand("dummy", command, docID); } @@ -273,23 +277,13 @@ describe("Zotero.Integration", function () { function setAddEditItems(items) { if (items.length == undefined) items = [items]; - dialogResults.quickFormat = function(dialogName) { - var citationItems = items.map((i) => {return {id: i.id} }); - var field = new Zotero.Integration.CitationField(Zotero.Integration.currentDoc.insertField("Field", 0)); - field.clearCode(); - field.writeToDoc(); - var citation = new Zotero.Integration.Citation(field); - var integrationDoc = addEditCitationSpy.lastCall.thisValue; - var fieldGetter = new Zotero.Integration.Fields(integrationDoc._session, integrationDoc._doc, () => 0); - var io = new Zotero.Integration.CitationEditInterface( - citation, - field, - fieldGetter, - integrationDoc._session - ); - io._acceptDeferred.resolve(); - return io; - } + dialogResults.quickFormat = function(dialogName, io) { + io.citation.citationItems = items.map(function(item) { + item = Zotero.Cite.getItem(item.id); + return {id: item.id, uris: item.cslURIs, itemData: item.cslItemData}; + }); + io._acceptDeferred.resolve(() => {}); + }; } before(function* () { @@ -319,9 +313,10 @@ describe("Zotero.Integration", function () { Zotero.debug(`Display dialog: ${dialogName}`, 2); var ioResult = dialogResults[dialogName.substring(dialogName.lastIndexOf('/')+1, dialogName.length-4)]; if (typeof ioResult == 'function') { - ioResult = ioResult(dialogName); + ioResult(dialogName, io); + } else { + Object.assign(io, ioResult); } - Object.assign(io, ioResult); return Zotero.Promise.resolve(); }); @@ -334,8 +329,8 @@ describe("Zotero.Integration", function () { addEditCitationSpy.restore(); }); - describe('Document', function() { - describe('#addEditCitation', function() { + describe('Interface', function() { + describe('#execCommand', function() { var setDocumentDataSpy; var docID = this.fullTitle(); @@ -437,6 +432,68 @@ describe("Zotero.Integration", function () { }); }); + describe('#addEditCitation', function() { + var insertMultipleCitations = Zotero.Promise.coroutine(function *() { + var docID = this.test.fullTitle(); + if (!(docID in applications)) initDoc(docID); + var doc = applications[docID].doc; + + setAddEditItems(testItems[0]); + yield execCommand('addEditCitation', docID); + assert.equal(doc.fields.length, 1); + var citation = (new Zotero.Integration.CitationField(doc.fields[0])).unserialize(); + assert.equal(citation.citationItems.length, 1); + assert.equal(citation.citationItems[0].id, testItems[0].id); + + setAddEditItems(testItems.slice(1, 3)); + yield execCommand('addEditCitation', docID); + assert.equal(doc.fields.length, 2); + citation = (new Zotero.Integration.CitationField(doc.fields[1])).unserialize(); + assert.equal(citation.citationItems.length, 2); + for (let i = 1; i < 3; i++) { + assert.equal(citation.citationItems[i-1].id, testItems[i].id); + } + }); + it('should insert citation if not in field', insertMultipleCitations); + + it('should edit citation if in citation field', function* () { + yield insertMultipleCitations.call(this); + var docID = this.test.fullTitle(); + var doc = applications[docID].doc; + + sinon.stub(doc, 'cursorInField').returns(doc.fields[0]); + sinon.stub(doc, 'canInsertField').returns(false); + + setAddEditItems(testItems.slice(3, 5)); + yield execCommand('addEditCitation', docID); + assert.equal(doc.fields.length, 2); + var citation = (new Zotero.Integration.CitationField(doc.fields[0])).unserialize(); + assert.equal(citation.citationItems.length, 2); + assert.equal(citation.citationItems[0].id, testItems[3].id); + }); + + it('should update bibliography if present', function* () { + yield insertMultipleCitations.call(this); + var docID = this.test.fullTitle(); + var doc = applications[docID].doc; + + let getCiteprocBibliographySpy = + sinon.spy(Zotero.Integration.Bibliography.prototype, 'getCiteprocBibliography'); + + yield execCommand('addEditBibliography', docID); + assert.isTrue(getCiteprocBibliographySpy.calledOnce); + + assert.equal(getCiteprocBibliographySpy.lastCall.returnValue[0].entry_ids.length, 3); + getCiteprocBibliographySpy.reset(); + + setAddEditItems(testItems[3]); + yield execCommand('addEditCitation', docID); + assert.equal(getCiteprocBibliographySpy.lastCall.returnValue[0].entry_ids.length, 4); + + getCiteprocBibliographySpy.restore(); + }); + }); + describe('#addEditBibliography', function() { var docID = this.fullTitle(); beforeEach(function* () { @@ -445,12 +502,13 @@ describe("Zotero.Integration", function () { }); it('should insert bibliography if no bibliography field present', function* () { + displayDialogStub.reset(); yield execCommand('addEditBibliography', docID); + assert.isFalse(displayDialogStub.called); var biblPresent = false; for (let i = applications[docID].doc.fields.length-1; i >= 0; i--) { - let field = applications[docID].doc.fields[i]; - Zotero.debug(field.getCode(), 1); - if (field.getCode().includes("CSL_BIBLIOGRAPHY")) { + let field = Zotero.Integration.Field.loadExisting(applications[docID].doc.fields[i]); + if (field.type == INTEGRATION_TYPE_BIBLIOGRAPHY) { biblPresent = true; break; }