Fix citeproc errors due to improper citeproc state updates

The error is triggered upon initial interaction with a doc after Zotero
restart or if new external citations (copied into the document) are
peresnt and `session.updateSession()` is called without a subsequent
`session.updateDocument()` call. `session.updateSession()` is called
without a subsequent `session.updateDocument()` call every time the
user cancels a citation insert.

More specifically, `session.updateSession()` is called every time a
citation dialog is invoked. It retrieves all citations and writes them
into a local `session.citationsByIndex` object. Moreover, it marks
each citation that hasn't seen before in a `session.newIndices` object.
`session.newIndices` is there to ensure that we load every new citation
into citeproc upon document update. This object is built by marking any
citation that does not appear in the previous invocation's list of
citations as new. However, if the document is never updated (because the
user cancels the insertion) then the new indices are not loaded
into citeproc. This commit fixes that, by excluding citeproc unloaded
items from the previous invocation's citation list.
This commit is contained in:
Adomas Venčkauskas 2019-04-08 16:43:29 +03:00
parent ff6a4400b4
commit 78c3d5808b
2 changed files with 44 additions and 10 deletions

View file

@ -1381,6 +1381,19 @@ Zotero.Integration.Session.prototype.resetRequest = function(doc) {
this.bibliographyHasChanged = false;
this.bibliographyDataHasChanged = false;
// When processing citations this list will be checked for citations that are new to the document
// (i.e. copied from somewhere else) and marked as newIndices to be processed with citeproc if
// not present
this.oldCitations = new Set();
for (let i in this.citationsByIndex) {
// But ignore indices from this.newIndices. If any are present it means that the last
// call to this.updateSession() was never followed up with this.updateDocument()
// i.e. the operation was user cancelled
if (i in this.newIndices) continue;
this.oldCitations.add(this.citationsByIndex[i].citationID);
}
// After adding fields to the session
// citations that are new to the document will be marked
// as new, so that they are correctly loaded into and processed with citeproc
@ -1390,15 +1403,8 @@ Zotero.Integration.Session.prototype.resetRequest = function(doc) {
this.updateIndices = {};
// Citations that require updating in the document will be marked in
// processIndices
this.processIndices = {};
// When processing citations this list will be checked for citations that are new to the document
// (i.e. copied from somewhere else) and marked as newIndices to be processed with citeproc if
// not present
this.oldCitations = new Set();
for (let i in this.citationsByIndex) {
this.oldCitations.add(this.citationsByIndex[i].citationID);
}
this.citationsByItemID = {};
this.citationsByIndex = {};
this.documentCitationIDs = {};

View file

@ -138,7 +138,7 @@ describe("Zotero.Integration", function () {
/**
* Deletes this field and its contents.
*/
delete: function() {this.doc.fields.filter((field) => field !== this)},
delete: function() {this.doc.fields = this.doc.fields.filter((field) => field !== this)},
/**
* Removes this field, but maintains the field's contents.
*/
@ -268,7 +268,10 @@ describe("Zotero.Integration", function () {
item = Zotero.Cite.getItem(item.id);
return {id: item.id, uris: item.cslURIs, itemData: item.cslItemData};
});
await io.previewFn(io.citation);
try {
await io.previewFn(io.citation);
}
catch (e) {}
io._acceptDeferred.resolve(() => {});
};
}
@ -715,6 +718,31 @@ describe("Zotero.Integration", function () {
stubUpdateDocument.restore();
}
});
it('should successfully insert a citation after canceled citation insert', async function () {
var docID = this.test.fullTitle();
if (!(docID in applications)) initDoc(docID);
var doc = applications[docID].doc;
setAddEditItems(testItems[0]);
await execCommand('addEditCitation', docID);
assert.equal(doc.fields.length, 1);
doc.fields.push(new DocumentPluginDummy.Field(doc));
// Add a "citation copied from somewhere else"
// the content doesn't really matter, just make sure that the citationID is different
var newCitationID = Zotero.Utilities.randomString();
doc.fields[1].code = doc.fields[0].code;
doc.fields[1].code = doc.fields[1].code.replace(/"citationID":"[A-Za-z0-9^"]*"/,
`"citationID":"${newCitationID}"`);
doc.fields[1].text = doc.fields[0].text;
setAddEditItems([]);
await execCommand('addEditCitation', docID);
setAddEditItems(testItems[1]);
await execCommand('addEditCitation', docID);
assert.notEqual(doc.fields[2].code, "TEMP");
});
});
describe('when delayCitationUpdates is set', function() {