Option to delay updating citation in document.
The checkbox in doc prefs is hidden until an update takes 5s or longer after which the user is prompted to enable delaying.
This commit is contained in:
parent
6d05c3472b
commit
2827f70daa
|
@ -167,11 +167,24 @@ var Zotero_File_Interface_Bibliography = new function() {
|
||||||
document.getElementById("automaticJournalAbbreviations-checkbox").checked = true;
|
document.getElementById("automaticJournalAbbreviations-checkbox").checked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (document.getElementById("delayCitationUpdates-checkbox")) {
|
||||||
|
if (_io.delayCitationUpdates) {
|
||||||
|
document.getElementById("delayCitationUpdates-checkbox").checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// set style to false, in case this is cancelled
|
// set style to false, in case this is cancelled
|
||||||
_io.style = false;
|
_io.style = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.openHelpLink = function() {
|
||||||
|
var url = "https://www.zotero.org/support/word_processor_plugin_usage";
|
||||||
|
var win = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||||
|
.getService(Components.interfaces.nsIWindowMediator)
|
||||||
|
.getMostRecentWindow("navigator:browser");
|
||||||
|
Zotero.launchURL(url);
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when locale is changed
|
* Called when locale is changed
|
||||||
*/
|
*/
|
||||||
|
@ -211,6 +224,13 @@ var Zotero_File_Interface_Bibliography = new function() {
|
||||||
document.getElementById("automaticJournalAbbreviations-vbox").hidden =
|
document.getElementById("automaticJournalAbbreviations-vbox").hidden =
|
||||||
!selectedStyleObj.usesAbbreviation;
|
!selectedStyleObj.usesAbbreviation;
|
||||||
}
|
}
|
||||||
|
// Hide the delayCitationUpdates checkbox before the prompt is shown
|
||||||
|
document.getElementById("delayCitationUpdates-vbox").hidden = _io.dontAskDelayCitationUpdates == undefined;
|
||||||
|
// Highlight delay citations checkbox after displaying the alert
|
||||||
|
// NOTE: Currently unused
|
||||||
|
if (_io.highlightDelayCitations) {
|
||||||
|
document.getElementById("delayCitationUpdates-vbox").style.border = "1px dashed #e52e2e"
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// For bibliography.xul
|
// For bibliography.xul
|
||||||
|
@ -266,6 +286,7 @@ var Zotero_File_Interface_Bibliography = new function() {
|
||||||
}
|
}
|
||||||
_io.useEndnotes = document.getElementById("displayAs").selectedIndex;
|
_io.useEndnotes = document.getElementById("displayAs").selectedIndex;
|
||||||
_io.fieldType = (document.getElementById("formatUsing").selectedIndex == 0 ? _io.primaryFieldType : _io.secondaryFieldType);
|
_io.fieldType = (document.getElementById("formatUsing").selectedIndex == 0 ? _io.primaryFieldType : _io.secondaryFieldType);
|
||||||
|
_io.delayCitationUpdates = document.getElementById("delayCitationUpdates-checkbox").checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember style and locale if user selected these explicitly
|
// remember style and locale if user selected these explicitly
|
||||||
|
|
|
@ -31,10 +31,11 @@
|
||||||
<dialog
|
<dialog
|
||||||
id="zotero-doc-prefs-dialog"
|
id="zotero-doc-prefs-dialog"
|
||||||
orient="vertical"
|
orient="vertical"
|
||||||
buttons="accept,cancel"
|
buttons="accept,cancel,help"
|
||||||
title="&zotero.integration.docPrefs.title;"
|
title="&zotero.integration.docPrefs.title;"
|
||||||
onload="Zotero_File_Interface_Bibliography.init();"
|
onload="Zotero_File_Interface_Bibliography.init();"
|
||||||
ondialogaccept="Zotero_File_Interface_Bibliography.acceptSelection();"
|
ondialogaccept="Zotero_File_Interface_Bibliography.acceptSelection();"
|
||||||
|
ondialoghelp="Zotero_File_Interface_Bibliography.openHelpLink();"
|
||||||
onclose="document.documentElement.cancelDialog(); event.preventDefault(); event.stopPropagation();"
|
onclose="document.documentElement.cancelDialog(); event.preventDefault(); event.stopPropagation();"
|
||||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
persist="screenX screenY"
|
persist="screenX screenY"
|
||||||
|
@ -84,5 +85,10 @@
|
||||||
<checkbox id="automaticJournalAbbreviations-checkbox" label="&zotero.integration.prefs.automaticJournalAbbeviations.label;"/>
|
<checkbox id="automaticJournalAbbreviations-checkbox" label="&zotero.integration.prefs.automaticJournalAbbeviations.label;"/>
|
||||||
<description class="radioDescription">&zotero.integration.prefs.automaticJournalAbbeviations.caption;</description>
|
<description class="radioDescription">&zotero.integration.prefs.automaticJournalAbbeviations.caption;</description>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
||||||
|
<vbox id="delayCitationUpdates-vbox">
|
||||||
|
<checkbox id="delayCitationUpdates-checkbox" label="&zotero.integration.prefs.delayCitationUpdates.label;" tooltiptext="&zotero.integration.prefs.delayCitationUpdates.tooltip;"/>
|
||||||
|
<description class="radioDescription">&zotero.integration.prefs.delayCitationUpdates.description;</description>
|
||||||
|
</vbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
</dialog>
|
</dialog>
|
|
@ -51,6 +51,8 @@ const INTEGRATION_TYPE_ITEM = 1;
|
||||||
const INTEGRATION_TYPE_BIBLIOGRAPHY = 2;
|
const INTEGRATION_TYPE_BIBLIOGRAPHY = 2;
|
||||||
const INTEGRATION_TYPE_TEMP = 3;
|
const INTEGRATION_TYPE_TEMP = 3;
|
||||||
|
|
||||||
|
const DELAY_CITATIONS_PROMPT_TIMEOUT = 5/*seconds*/;
|
||||||
|
|
||||||
|
|
||||||
Zotero.Integration = new function() {
|
Zotero.Integration = new function() {
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||||
|
@ -212,18 +214,25 @@ Zotero.Integration = new function() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
inProgress = true;
|
inProgress = true;
|
||||||
|
Zotero.debug(`Integration: ${agent}-${command}${docId ? `:'${docId}'` : ''} invoked`)
|
||||||
|
|
||||||
var application = Zotero.Integration.getApplication(agent, command, docId);
|
var startTime = (new Date()).getTime();
|
||||||
|
|
||||||
// Try to execute the command; otherwise display an error in alert service or word processor
|
// Try to execute the command; otherwise display an error in alert service or word processor
|
||||||
// (depending on what is possible)
|
// (depending on what is possible)
|
||||||
|
try {
|
||||||
|
// Word for windows throws RPC_E_CANTCALLOUT_ININPUTSYNCCALL if we invoke an OLE call in the
|
||||||
|
// current event loop (which.. who would have guessed would be the case?)
|
||||||
|
yield Zotero.Promise.delay();
|
||||||
|
var application = Zotero.Integration.getApplication(agent, command, docId);
|
||||||
|
|
||||||
Zotero.Integration.currentDoc = document = (application.getDocument && docId ? application.getDocument(docId) : application.getActiveDocument());
|
Zotero.Integration.currentDoc = document = (application.getDocument && docId ? application.getDocument(docId) : application.getActiveDocument());
|
||||||
Zotero.Integration.currentSession = session = yield Zotero.Integration.getSession(application, document);
|
Zotero.Integration.currentSession = session = yield Zotero.Integration.getSession(application, document);
|
||||||
// TODO: this is pretty awful
|
// TODO: this is pretty awful
|
||||||
session.fields = new Zotero.Integration.Fields(session, document);
|
session.fields = new Zotero.Integration.Fields(session, document);
|
||||||
session._doc = document;
|
session._doc = document;
|
||||||
try {
|
|
||||||
yield (new Zotero.Integration.Interface(application, document, session))[command]();
|
yield (new Zotero.Integration.Interface(application, document, session))[command]();
|
||||||
|
document.setDocumentData(session.data.serialize());
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if(!(e instanceof Zotero.Exception.UserCancelled)) {
|
if(!(e instanceof Zotero.Exception.UserCancelled)) {
|
||||||
|
@ -262,12 +271,16 @@ Zotero.Integration = new function() {
|
||||||
} finally {
|
} finally {
|
||||||
Zotero.logError(e);
|
Zotero.logError(e);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// If user cancels we should still write the currently assigned session ID
|
||||||
|
document.setDocumentData(session.data.serialize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
var diff = ((new Date()).getTime() - startTime)/1000;
|
||||||
|
Zotero.debug(`Integration: ${agent}-${command}${docId ? `:'${docId}'` : ''} complete in ${diff}s`)
|
||||||
if (document) {
|
if (document) {
|
||||||
try {
|
try {
|
||||||
document.setDocumentData(session.data.serialize());
|
|
||||||
document.cleanup();
|
document.cleanup();
|
||||||
document.activate();
|
document.activate();
|
||||||
|
|
||||||
|
@ -378,18 +391,19 @@ Zotero.Integration = new function() {
|
||||||
[], "integration.error.title");
|
[], "integration.error.title");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Zotero.Integration.sessions[data.sessionID]) {
|
session = Zotero.Integration.sessions[data.sessionID];
|
||||||
// If communication occured with this document since restart
|
|
||||||
return Zotero.Integration.sessions[data.sessionID];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!session) {
|
||||||
session = new Zotero.Integration.Session(doc, app);
|
session = new Zotero.Integration.Session(doc, app);
|
||||||
|
session.reload = true;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
yield session.setData(data);
|
yield session.setData(data);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// make sure style is defined
|
// make sure style is defined
|
||||||
if (e instanceof Zotero.Exception.Alert && e.name === "integration.error.invalidStyle") {
|
if (e instanceof Zotero.Exception.Alert && e.name === "integration.error.invalidStyle") {
|
||||||
if (data.style.styleID) {
|
if (data.style.styleID) {
|
||||||
|
session.reload = true;
|
||||||
let trustedSource = /^https?:\/\/(www\.)?(zotero\.org|citationstyles\.org)/.test(data.style.styleID);
|
let trustedSource = /^https?:\/\/(www\.)?(zotero\.org|citationstyles\.org)/.test(data.style.styleID);
|
||||||
let errorString = Zotero.getString("integration.error.styleMissing", data.style.styleID);
|
let errorString = Zotero.getString("integration.error.styleMissing", data.style.styleID);
|
||||||
if (trustedSource ||
|
if (trustedSource ||
|
||||||
|
@ -422,7 +436,6 @@ Zotero.Integration = new function() {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session.reload = true;
|
|
||||||
return session;
|
return session;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -461,7 +474,12 @@ Zotero.Integration.Interface.prototype.addCitation = Zotero.Promise.coroutine(fu
|
||||||
|
|
||||||
let [idx, field, citation] = yield this._session.fields.addEditCitation(null);
|
let [idx, field, citation] = yield this._session.fields.addEditCitation(null);
|
||||||
yield this._session.addCitation(idx, field.noteIndex, citation);
|
yield this._session.addCitation(idx, field.noteIndex, citation);
|
||||||
|
|
||||||
|
if (this._session.data.prefs.delayCitationUpdates) {
|
||||||
|
return this._session.writeDelayedCitation(idx, field, citation);
|
||||||
|
} else {
|
||||||
return this._session.fields.updateDocument(FORCE_CITATIONS_FALSE, false, false);
|
return this._session.fields.updateDocument(FORCE_CITATIONS_FALSE, false, false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -487,7 +505,11 @@ Zotero.Integration.Interface.prototype.addEditCitation = Zotero.Promise.coroutin
|
||||||
|
|
||||||
let [idx, field, citation] = yield this._session.fields.addEditCitation(docField);
|
let [idx, field, citation] = yield this._session.fields.addEditCitation(docField);
|
||||||
yield this._session.addCitation(idx, field.noteIndex, citation);
|
yield this._session.addCitation(idx, field.noteIndex, citation);
|
||||||
|
if (this._session.data.prefs.delayCitationUpdates) {
|
||||||
|
return this._session.writeDelayedCitation(idx, field, citation);
|
||||||
|
} else {
|
||||||
return this._session.fields.updateDocument(FORCE_CITATIONS_FALSE, false, false);
|
return this._session.fields.updateDocument(FORCE_CITATIONS_FALSE, false, false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -588,14 +610,12 @@ Zotero.Integration.Interface.prototype.addEditBibliography = Zotero.Promise.coro
|
||||||
* Updates the citation data for all citations and bibliography entries.
|
* Updates the citation data for all citations and bibliography entries.
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
Zotero.Integration.Interface.prototype.refresh = function() {
|
Zotero.Integration.Interface.prototype.refresh = async function() {
|
||||||
var me = this;
|
await this._session.init(true, false)
|
||||||
return this._session.init(true, false).then(function() {
|
|
||||||
// Send request, forcing update of citations and bibliography
|
this._session.reload = this._session.data.prefs.delayCitationUpdates;
|
||||||
return me._session.fields.updateSession(FORCE_CITATIONS_REGENERATE).then(function() {
|
await this._session.fields.updateSession(FORCE_CITATIONS_REGENERATE)
|
||||||
return me._session.fields.updateDocument(FORCE_CITATIONS_REGENERATE, true, false);
|
await this._session.fields.updateDocument(FORCE_CITATIONS_REGENERATE, true, false);
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -898,11 +918,26 @@ Zotero.Integration.Fields.prototype._processFields = Zotero.Promise.coroutine(fu
|
||||||
*/
|
*/
|
||||||
Zotero.Integration.Fields.prototype.updateDocument = Zotero.Promise.coroutine(function* (forceCitations, forceBibliography,
|
Zotero.Integration.Fields.prototype.updateDocument = Zotero.Promise.coroutine(function* (forceCitations, forceBibliography,
|
||||||
ignoreCitationChanges) {
|
ignoreCitationChanges) {
|
||||||
// Iterate through citations, yielding for UI updates
|
var startTime = (new Date()).getTime();
|
||||||
yield Zotero.Promise.each(this._session._updateCitations(), () => {});
|
|
||||||
|
|
||||||
yield Zotero.Promise.each(
|
yield this._session._updateCitations()
|
||||||
this._updateDocument(forceCitations, forceBibliography, ignoreCitationChanges), () => {});
|
yield this._updateDocument(forceCitations, forceBibliography, ignoreCitationChanges)
|
||||||
|
|
||||||
|
var diff = ((new Date()).getTime() - startTime)/1000;
|
||||||
|
Zotero.debug(`Integration: updateDocument complete in ${diff}s`)
|
||||||
|
// If the update takes longer than 5s suggest delaying citation updates
|
||||||
|
if (diff > DELAY_CITATIONS_PROMPT_TIMEOUT && !this._session.data.prefs.dontAskDelayCitationUpdates && !this._session.data.prefs.delayCitationUpdates) {
|
||||||
|
this._doc.activate();
|
||||||
|
var result = this._doc.displayAlert(Zotero.getString('integration.delayCitationUpdates.alert'),
|
||||||
|
DIALOG_ICON_WARNING, DIALOG_BUTTONS_YES_NO_CANCEL);
|
||||||
|
if (result == 2) {
|
||||||
|
this._session.data.prefs.delayCitationUpdates = true;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
this._session.data.prefs.dontAskDelayCitationUpdates = true;
|
||||||
|
// yield this._session.setDocPrefs(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -912,7 +947,7 @@ Zotero.Integration.Fields.prototype.updateDocument = Zotero.Promise.coroutine(fu
|
||||||
* @param {Boolean} [ignoreCitationChanges] Whether to ignore changes to citations that have been
|
* @param {Boolean} [ignoreCitationChanges] Whether to ignore changes to citations that have been
|
||||||
* modified since they were created, instead of showing a warning
|
* modified since they were created, instead of showing a warning
|
||||||
*/
|
*/
|
||||||
Zotero.Integration.Fields.prototype._updateDocument = function* (forceCitations, forceBibliography,
|
Zotero.Integration.Fields.prototype._updateDocument = async function(forceCitations, forceBibliography,
|
||||||
ignoreCitationChanges) {
|
ignoreCitationChanges) {
|
||||||
if(this.progressCallback) {
|
if(this.progressCallback) {
|
||||||
var nFieldUpdates = Object.keys(this._session.updateIndices).length;
|
var nFieldUpdates = Object.keys(this._session.updateIndices).length;
|
||||||
|
@ -929,21 +964,25 @@ Zotero.Integration.Fields.prototype._updateDocument = function* (forceCitations,
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
Zotero.logError(e);
|
Zotero.logError(e);
|
||||||
}
|
}
|
||||||
yield;
|
|
||||||
}
|
}
|
||||||
|
// Jump to next event loop step for UI updates
|
||||||
|
await Zotero.Promise.delay();
|
||||||
|
|
||||||
var citation = this._session.citationsByIndex[i];
|
var citation = this._session.citationsByIndex[i];
|
||||||
let citationField = citation._field;
|
let citationField = citation._field;
|
||||||
|
|
||||||
if (!citation.properties.dontUpdate) {
|
if (!citation.properties.dontUpdate) {
|
||||||
var formattedCitation = citation.properties.custom
|
var formattedCitation = citation.properties.formattedCitation && citation.properties.custom
|
||||||
? citation.properties.custom : citation.text;
|
? citation.properties.custom : citation.text;
|
||||||
|
var plainCitation = citation.properties.plainCitation && citationField.text;
|
||||||
|
|
||||||
|
// If we're not specifically *not* trying to regen text
|
||||||
|
if (forceCitations != FORCE_CITATIONS_FALSE
|
||||||
|
// Or metadata has changed thus changing the formatted citation
|
||||||
|
|| (citation.properties.formattedCitation !== formattedCitation)
|
||||||
|
// Or we shouldn't ignore citation changes and the citation text has changed
|
||||||
|
|| (!ignoreCitationChanges && plainCitation !== citation.properties.plainCitation)) {
|
||||||
|
|
||||||
if(forceCitations === FORCE_CITATIONS_RESET_TEXT
|
|
||||||
|| citation.properties.formattedCitation !== formattedCitation) {
|
|
||||||
// Check if citation has been manually modified
|
|
||||||
if(!ignoreCitationChanges && citation.properties.plainCitation) {
|
|
||||||
var plainCitation = citationField.text;
|
|
||||||
if (plainCitation !== citation.properties.plainCitation) {
|
if (plainCitation !== citation.properties.plainCitation) {
|
||||||
// Citation manually modified; ask user if they want to save changes
|
// Citation manually modified; ask user if they want to save changes
|
||||||
Zotero.debug("[_updateDocument] Attempting to update manually modified citation.\n"
|
Zotero.debug("[_updateDocument] Attempting to update manually modified citation.\n"
|
||||||
|
@ -958,7 +997,6 @@ Zotero.Integration.Fields.prototype._updateDocument = function* (forceCitations,
|
||||||
citation.properties.dontUpdate = true;
|
citation.properties.dontUpdate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(!citation.properties.dontUpdate) {
|
if(!citation.properties.dontUpdate) {
|
||||||
// setText and getText here bypass the setter/getter abstraction
|
// setText and getText here bypass the setter/getter abstraction
|
||||||
|
@ -972,11 +1010,13 @@ Zotero.Integration.Fields.prototype._updateDocument = function* (forceCitations,
|
||||||
citation.properties.formattedCitation = formattedCitation;
|
citation.properties.formattedCitation = formattedCitation;
|
||||||
citation.properties.plainCitation = citationField.getText();
|
citation.properties.plainCitation = citationField.getText();
|
||||||
|
|
||||||
|
if (isRich) {
|
||||||
// But we still need writeToDoc to trigger RTF write for LO (see comment in writeToDoc())
|
// But we still need writeToDoc to trigger RTF write for LO (see comment in writeToDoc())
|
||||||
citationField.text = formattedCitation;
|
citationField.text = formattedCitation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var serializedCitation = citation.serialize();
|
var serializedCitation = citation.serialize();
|
||||||
if (serializedCitation != citation.properties.field) {
|
if (serializedCitation != citation.properties.field) {
|
||||||
|
@ -1027,8 +1067,9 @@ Zotero.Integration.Fields.prototype._updateDocument = function* (forceCitations,
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
Zotero.logError(e);
|
Zotero.logError(e);
|
||||||
}
|
}
|
||||||
yield;
|
|
||||||
}
|
}
|
||||||
|
// Jump to next event loop step for UI updates
|
||||||
|
await Zotero.Promise.delay();
|
||||||
|
|
||||||
if (bibliographyText) {
|
if (bibliographyText) {
|
||||||
field.text = bibliographyText;
|
field.text = bibliographyText;
|
||||||
|
@ -1081,14 +1122,17 @@ Zotero.Integration.Fields.prototype.addEditCitation = Zotero.Promise.coroutine(f
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var citationsByItemIDPromise = fieldIndexPromise.then(function() {
|
var citationsByItemIDPromise;
|
||||||
|
if (this._session.data.prefs.delayCitationUpdates) {
|
||||||
|
citationsByItemIDPromise = Zotero.Promise.resolve(this._session.citationsByItemID);
|
||||||
|
} else {
|
||||||
|
citationsByItemIDPromise = fieldIndexPromise.then(function() {
|
||||||
return this.updateSession(FORCE_CITATIONS_FALSE);
|
return this.updateSession(FORCE_CITATIONS_FALSE);
|
||||||
}.bind(this)).then(function() {
|
}.bind(this)).then(function() {
|
||||||
return this._session.citationsByItemID;
|
return this._session.citationsByItemID;
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
// Required for preview fn
|
|
||||||
citation.properties.noteIndex = field.noteIndex;
|
|
||||||
var previewFn = Zotero.Promise.coroutine(function* (citation) {
|
var previewFn = Zotero.Promise.coroutine(function* (citation) {
|
||||||
let idx = yield fieldIndexPromise;
|
let idx = yield fieldIndexPromise;
|
||||||
yield citationsByItemIDPromise;
|
yield citationsByItemIDPromise;
|
||||||
|
@ -1352,7 +1396,7 @@ Zotero.Integration.Session.prototype.setData = Zotero.Promise.coroutine(function
|
||||||
* if there wasn't, or rejected with Zotero.Exception.UserCancelled if the dialog was
|
* if there wasn't, or rejected with Zotero.Exception.UserCancelled if the dialog was
|
||||||
* cancelled.
|
* cancelled.
|
||||||
*/
|
*/
|
||||||
Zotero.Integration.Session.prototype.setDocPrefs = Zotero.Promise.coroutine(function* () {
|
Zotero.Integration.Session.prototype.setDocPrefs = Zotero.Promise.coroutine(function* (highlightDelayCitations=false) {
|
||||||
var io = new function() { this.wrappedJSObject = this; };
|
var io = new function() { this.wrappedJSObject = this; };
|
||||||
io.primaryFieldType = this.primaryFieldType;
|
io.primaryFieldType = this.primaryFieldType;
|
||||||
io.secondaryFieldType = this.secondaryFieldType;
|
io.secondaryFieldType = this.secondaryFieldType;
|
||||||
|
@ -1362,6 +1406,9 @@ Zotero.Integration.Session.prototype.setDocPrefs = Zotero.Promise.coroutine(func
|
||||||
io.locale = this.data.style.locale;
|
io.locale = this.data.style.locale;
|
||||||
io.useEndnotes = this.data.prefs.noteType == 0 ? 0 : this.data.prefs.noteType-1;
|
io.useEndnotes = this.data.prefs.noteType == 0 ? 0 : this.data.prefs.noteType-1;
|
||||||
io.fieldType = this.data.prefs.fieldType;
|
io.fieldType = this.data.prefs.fieldType;
|
||||||
|
io.delayCitationUpdates = this.data.prefs.delayCitationUpdates;
|
||||||
|
io.dontAskDelayCitationUpdates = this.data.prefs.dontAskDelayCitationUpdates;
|
||||||
|
io.highlightDelayCitations = highlightDelayCitations;
|
||||||
io.automaticJournalAbbreviations = this.data.prefs.automaticJournalAbbreviations;
|
io.automaticJournalAbbreviations = this.data.prefs.automaticJournalAbbreviations;
|
||||||
io.requireStoreReferences = !Zotero.Utilities.isEmpty(this.embeddedItems);
|
io.requireStoreReferences = !Zotero.Utilities.isEmpty(this.embeddedItems);
|
||||||
}
|
}
|
||||||
|
@ -1380,8 +1427,10 @@ Zotero.Integration.Session.prototype.setDocPrefs = Zotero.Promise.coroutine(func
|
||||||
data.sessionID = oldData.sessionID;
|
data.sessionID = oldData.sessionID;
|
||||||
data.style.styleID = io.style;
|
data.style.styleID = io.style;
|
||||||
data.style.locale = io.locale;
|
data.style.locale = io.locale;
|
||||||
|
data.prefs = oldData ? Object.assign({}, oldData.prefs) : {};
|
||||||
data.prefs.fieldType = io.fieldType;
|
data.prefs.fieldType = io.fieldType;
|
||||||
data.prefs.automaticJournalAbbreviations = io.automaticJournalAbbreviations;
|
data.prefs.automaticJournalAbbreviations = io.automaticJournalAbbreviations;
|
||||||
|
data.prefs.delayCitationUpdates = io.delayCitationUpdates
|
||||||
|
|
||||||
var forceStyleReset = oldData
|
var forceStyleReset = oldData
|
||||||
&& (
|
&& (
|
||||||
|
@ -1396,9 +1445,11 @@ Zotero.Integration.Session.prototype.setDocPrefs = Zotero.Promise.coroutine(func
|
||||||
if (!oldData || oldData.style.styleID != data.style.styleID
|
if (!oldData || oldData.style.styleID != data.style.styleID
|
||||||
|| oldData.prefs.noteType != data.prefs.noteType
|
|| oldData.prefs.noteType != data.prefs.noteType
|
||||||
|| oldData.prefs.fieldType != data.prefs.fieldType
|
|| oldData.prefs.fieldType != data.prefs.fieldType
|
||||||
|
|| (!data.prefs.delayCitationUpdates && oldData.prefs.delayCitationUpdates != data.prefs.delayCitationUpdates)
|
||||||
|| oldData.prefs.automaticJournalAbbreviations != data.prefs.automaticJournalAbbreviations) {
|
|| oldData.prefs.automaticJournalAbbreviations != data.prefs.automaticJournalAbbreviations) {
|
||||||
// This will cause us to regenerate all citations
|
// This will cause us to regenerate all citations
|
||||||
this.regenAll = true;
|
this.regenAll = true;
|
||||||
|
this.reload = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return oldData || null;
|
return oldData || null;
|
||||||
|
@ -1450,7 +1501,6 @@ Zotero.Integration.Session.prototype.addCitation = Zotero.Promise.coroutine(func
|
||||||
Zotero.debug("Integration: "+citation.citationID+" ("+index+") needs new citationID");
|
Zotero.debug("Integration: "+citation.citationID+" ("+index+") needs new citationID");
|
||||||
citation.citationID = Zotero.randomString();
|
citation.citationID = Zotero.randomString();
|
||||||
}
|
}
|
||||||
this.newIndices[index] = true;
|
|
||||||
this.updateIndices[index] = true;
|
this.updateIndices[index] = true;
|
||||||
}
|
}
|
||||||
Zotero.debug("Integration: Adding citationID "+citation.citationID);
|
Zotero.debug("Integration: Adding citationID "+citation.citationID);
|
||||||
|
@ -1468,7 +1518,7 @@ Zotero.Integration.Session.prototype.getCiteprocLists = function() {
|
||||||
/**
|
/**
|
||||||
* Updates the list of citations to be serialized to the document
|
* Updates the list of citations to be serialized to the document
|
||||||
*/
|
*/
|
||||||
Zotero.Integration.Session.prototype._updateCitations = function* () {
|
Zotero.Integration.Session.prototype._updateCitations = async function () {
|
||||||
Zotero.debug("Integration: Indices of new citations");
|
Zotero.debug("Integration: Indices of new citations");
|
||||||
Zotero.debug(Object.keys(this.newIndices));
|
Zotero.debug(Object.keys(this.newIndices));
|
||||||
Zotero.debug("Integration: Indices of updated citations");
|
Zotero.debug("Integration: Indices of updated citations");
|
||||||
|
@ -1478,6 +1528,8 @@ Zotero.Integration.Session.prototype._updateCitations = function* () {
|
||||||
|
|
||||||
for (let indexList of [this.newIndices, this.updateIndices]) {
|
for (let indexList of [this.newIndices, this.updateIndices]) {
|
||||||
for (let index in indexList) {
|
for (let index in indexList) {
|
||||||
|
// Jump to next event loop step for UI updates
|
||||||
|
await Zotero.Promise.delay();
|
||||||
index = parseInt(index);
|
index = parseInt(index);
|
||||||
|
|
||||||
var citation = this.citationsByIndex[index];
|
var citation = this.citationsByIndex[index];
|
||||||
|
@ -1503,9 +1555,7 @@ Zotero.Integration.Session.prototype._updateCitations = function* () {
|
||||||
this.citationsByIndex[idx].text = text;
|
this.citationsByIndex[idx].text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yield for UI updates
|
|
||||||
delete this.newIndices[index];
|
delete this.newIndices[index];
|
||||||
yield;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1531,6 +1581,32 @@ Zotero.Integration.Session.prototype.restoreProcessorState = function() {
|
||||||
this.style.rebuildProcessorState(citations, 'rtf', uncited);
|
this.style.rebuildProcessorState(citations, 'rtf', uncited);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Zotero.Integration.Session.prototype.writeDelayedCitation = Zotero.Promise.coroutine(function* (idx, field, citation) {
|
||||||
|
try {
|
||||||
|
var text = citation.properties.custom || this.style.previewCitationCluster(citation, [], [], "rtf");
|
||||||
|
} catch(e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
text = `\\uldash{${text}}`;
|
||||||
|
|
||||||
|
// Make sure we'll prompt for manually edited citations
|
||||||
|
if(!citation.properties.dontUpdate) {
|
||||||
|
// setText and getText here bypass the setter/getter abstraction
|
||||||
|
text = '{\\rtf' + text + '}';
|
||||||
|
field.setText(text, true);
|
||||||
|
field.text = text;
|
||||||
|
|
||||||
|
citation.properties.formattedCitation = text;
|
||||||
|
citation.properties.plainCitation = field.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
field.code = citation.serialize();
|
||||||
|
field.text = text;
|
||||||
|
field.writeToDoc();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits integration bibliography
|
* Edits integration bibliography
|
||||||
* @param {Zotero.Integration.Bibliography} bibliography
|
* @param {Zotero.Integration.Bibliography} bibliography
|
||||||
|
@ -1682,6 +1758,7 @@ Zotero.Integration.DocumentData.prototype.serialize = function() {
|
||||||
// Otherwise default to XML for now
|
// Otherwise default to XML for now
|
||||||
var prefs = "";
|
var prefs = "";
|
||||||
for (var pref in this.prefs) {
|
for (var pref in this.prefs) {
|
||||||
|
if (!this.prefs[pref]) continue;
|
||||||
prefs += `<pref name="${Zotero.Utilities.htmlSpecialChars(pref)}" `+
|
prefs += `<pref name="${Zotero.Utilities.htmlSpecialChars(pref)}" `+
|
||||||
`value="${Zotero.Utilities.htmlSpecialChars(this.prefs[pref].toString())}"/>`;
|
`value="${Zotero.Utilities.htmlSpecialChars(this.prefs[pref].toString())}"/>`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,6 +231,10 @@
|
||||||
<!ENTITY zotero.integration.prefs.bookmarks.label "Bookmarks">
|
<!ENTITY zotero.integration.prefs.bookmarks.label "Bookmarks">
|
||||||
<!ENTITY zotero.integration.prefs.bookmarks.caption "Bookmarks can be shared between Word and LibreOffice, but may cause errors if accidentally modified and cannot be inserted into footnotes.">
|
<!ENTITY zotero.integration.prefs.bookmarks.caption "Bookmarks can be shared between Word and LibreOffice, but may cause errors if accidentally modified and cannot be inserted into footnotes.">
|
||||||
|
|
||||||
|
<!ENTITY zotero.integration.prefs.delayCitationUpdates.label "Delay citation updates until manual refresh">
|
||||||
|
<!ENTITY zotero.integration.prefs.delayCitationUpdates.tooltip "Citations with pending updates are visually highlighted">
|
||||||
|
<!ENTITY zotero.integration.prefs.delayCitationUpdates.description "Delaying updates can speed up citation insertion in large documents.">
|
||||||
|
|
||||||
|
|
||||||
<!ENTITY zotero.integration.prefs.automaticJournalAbbeviations.label "Use MEDLINE journal abbreviations">
|
<!ENTITY zotero.integration.prefs.automaticJournalAbbeviations.label "Use MEDLINE journal abbreviations">
|
||||||
<!ENTITY zotero.integration.prefs.automaticJournalAbbeviations.caption "The “Journal Abbr” field will be ignored.">
|
<!ENTITY zotero.integration.prefs.automaticJournalAbbeviations.caption "The “Journal Abbr” field will be ignored.">
|
||||||
|
|
|
@ -870,6 +870,7 @@ integration.corruptBibliography.description = All items cited in the text will a
|
||||||
integration.citationChanged = You have modified this citation since Zotero generated it. Do you want to keep your modifications and prevent future updates?
|
integration.citationChanged = You have modified this citation since Zotero generated it. Do you want to keep your modifications and prevent future updates?
|
||||||
integration.citationChanged.description = Clicking "Yes" will prevent Zotero from updating this citation if you add additional citations, switch styles, or modify the item to which it refers. Clicking "No" will erase your changes.
|
integration.citationChanged.description = Clicking "Yes" will prevent Zotero from updating this citation if you add additional citations, switch styles, or modify the item to which it refers. Clicking "No" will erase your changes.
|
||||||
integration.citationChanged.edit = You have modified this citation since Zotero generated it. Editing will clear your modifications. Do you want to continue?
|
integration.citationChanged.edit = You have modified this citation since Zotero generated it. Editing will clear your modifications. Do you want to continue?
|
||||||
|
integration.delayCitationUpdates.alert = Updating citations in this document is taking a long time. Would you like to delay citation updates until manual refresh?\n\nYou can change this setting later in the document preferences.
|
||||||
|
|
||||||
styles.install.title = Install Style
|
styles.install.title = Install Style
|
||||||
styles.install.unexpectedError = An unexpected error occurred while installing "%1$S"
|
styles.install.unexpectedError = An unexpected error occurred while installing "%1$S"
|
||||||
|
|
|
@ -292,7 +292,10 @@ describe("Zotero.Integration", function () {
|
||||||
|
|
||||||
testItems = [];
|
testItems = [];
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
testItems.push(yield createDataObject('item', {libraryID: Zotero.Libraries.userLibraryID}));
|
let testItem = yield createDataObject('item', {libraryID: Zotero.Libraries.userLibraryID});
|
||||||
|
testItem.setField('title', `title${1}`);
|
||||||
|
testItem.setCreator(0, {creatorType: 'author', name: `Author No${i}`});
|
||||||
|
testItems.push(testItem);
|
||||||
}
|
}
|
||||||
setAddEditItems(testItems[0]);
|
setAddEditItems(testItems[0]);
|
||||||
|
|
||||||
|
@ -492,6 +495,132 @@ describe("Zotero.Integration", function () {
|
||||||
|
|
||||||
getCiteprocBibliographySpy.restore();
|
getCiteprocBibliographySpy.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when original citation text has been modified', function() {
|
||||||
|
var displayAlertStub;
|
||||||
|
before(function* () {
|
||||||
|
displayAlertStub = sinon.stub(DocumentPluginDummy.Document.prototype, 'displayAlert').returns(0);
|
||||||
|
});
|
||||||
|
beforeEach(function() {
|
||||||
|
displayAlertStub.reset();
|
||||||
|
});
|
||||||
|
after(function() {
|
||||||
|
displayAlertStub.restore();
|
||||||
|
});
|
||||||
|
it('should keep modification if "Cancel" selected in editCitation triggered alert', async function () {
|
||||||
|
await insertMultipleCitations.call(this);
|
||||||
|
var docID = this.test.fullTitle();
|
||||||
|
var doc = applications[docID].doc;
|
||||||
|
|
||||||
|
doc.fields[0].text = "modified";
|
||||||
|
sinon.stub(doc, 'cursorInField').returns(doc.fields[0]);
|
||||||
|
sinon.stub(doc, 'canInsertField').returns(false);
|
||||||
|
|
||||||
|
await execCommand('addEditCitation', docID);
|
||||||
|
assert.equal(doc.fields.length, 2);
|
||||||
|
assert.equal(doc.fields[0].text, "modified");
|
||||||
|
});
|
||||||
|
it('should display citation dialog if "OK" selected in editCitation triggered alert', async function () {
|
||||||
|
await insertMultipleCitations.call(this);
|
||||||
|
var docID = this.test.fullTitle();
|
||||||
|
var doc = applications[docID].doc;
|
||||||
|
|
||||||
|
let origText = doc.fields[0].text;
|
||||||
|
doc.fields[0].text = "modified";
|
||||||
|
// Return OK
|
||||||
|
displayAlertStub.returns(1);
|
||||||
|
sinon.stub(doc, 'cursorInField').returns(doc.fields[0]);
|
||||||
|
sinon.stub(doc, 'canInsertField').returns(false);
|
||||||
|
setAddEditItems(testItems[0]);
|
||||||
|
|
||||||
|
await execCommand('addEditCitation', docID);
|
||||||
|
assert.isTrue(displayAlertStub.called);
|
||||||
|
assert.equal(doc.fields.length, 2);
|
||||||
|
assert.equal(doc.fields[0].text, origText);
|
||||||
|
});
|
||||||
|
it('should set dontUpdate: true if "yes" selected in refresh prompt', async function() {
|
||||||
|
await insertMultipleCitations.call(this);
|
||||||
|
var docID = this.test.fullTitle();
|
||||||
|
var doc = applications[docID].doc;
|
||||||
|
|
||||||
|
var citation = (new Zotero.Integration.CitationField(doc.fields[0])).unserialize();
|
||||||
|
assert.isNotOk(citation.properties.dontUpdate);
|
||||||
|
doc.fields[0].text = "modified";
|
||||||
|
// Return Yes
|
||||||
|
displayAlertStub.returns(1);
|
||||||
|
|
||||||
|
await execCommand('refresh', docID);
|
||||||
|
assert.isTrue(displayAlertStub.called);
|
||||||
|
assert.equal(doc.fields.length, 2);
|
||||||
|
assert.equal(doc.fields[0].text, "modified");
|
||||||
|
var citation = (new Zotero.Integration.CitationField(doc.fields[0])).unserialize();
|
||||||
|
assert.isOk(citation.properties.dontUpdate);
|
||||||
|
});
|
||||||
|
it('should reset citation text if "no" selected in refresh prompt', async function() {
|
||||||
|
await insertMultipleCitations.call(this);
|
||||||
|
var docID = this.test.fullTitle();
|
||||||
|
var doc = applications[docID].doc;
|
||||||
|
|
||||||
|
var citation = (new Zotero.Integration.CitationField(doc.fields[0])).unserialize();
|
||||||
|
assert.isNotOk(citation.properties.dontUpdate);
|
||||||
|
let origText = doc.fields[0].text;
|
||||||
|
doc.fields[0].text = "modified";
|
||||||
|
// Return No
|
||||||
|
displayAlertStub.returns(0);
|
||||||
|
|
||||||
|
await execCommand('refresh', docID);
|
||||||
|
assert.isTrue(displayAlertStub.called);
|
||||||
|
assert.equal(doc.fields.length, 2);
|
||||||
|
assert.equal(doc.fields[0].text, origText);
|
||||||
|
var citation = (new Zotero.Integration.CitationField(doc.fields[0])).unserialize();
|
||||||
|
assert.isNotOk(citation.properties.dontUpdate);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when delayCitationUpdates is set', function() {
|
||||||
|
it('should insert a citation with wave underlining', function* (){
|
||||||
|
yield insertMultipleCitations.call(this);
|
||||||
|
var docID = this.test.fullTitle();
|
||||||
|
var doc = applications[docID].doc;
|
||||||
|
var data = new Zotero.Integration.DocumentData(doc.data);
|
||||||
|
data.prefs.delayCitationUpdates = true;
|
||||||
|
doc.data = data.serialize();
|
||||||
|
|
||||||
|
var setTextSpy = sinon.spy(DocumentPluginDummy.Field.prototype, 'setText');
|
||||||
|
setAddEditItems(testItems[3]);
|
||||||
|
yield execCommand('addEditCitation', docID);
|
||||||
|
assert.isTrue(setTextSpy.lastCall.args[0].includes('\\uldash'));
|
||||||
|
|
||||||
|
setTextSpy.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not write to any other fields besides the one being updated', function* () {
|
||||||
|
yield insertMultipleCitations.call(this);
|
||||||
|
var docID = this.test.fullTitle();
|
||||||
|
var doc = applications[docID].doc;
|
||||||
|
var data = new Zotero.Integration.DocumentData(doc.data);
|
||||||
|
data.prefs.delayCitationUpdates = true;
|
||||||
|
doc.data = data.serialize();
|
||||||
|
|
||||||
|
var setTextSpy = sinon.spy(DocumentPluginDummy.Field.prototype, 'setText');
|
||||||
|
var setCodeSpy = sinon.spy(DocumentPluginDummy.Field.prototype, 'setCode');
|
||||||
|
|
||||||
|
setAddEditItems(testItems[3]);
|
||||||
|
yield execCommand('addEditCitation', docID);
|
||||||
|
var field = setTextSpy.firstCall.thisValue;
|
||||||
|
|
||||||
|
for (let i = 0; i < setTextSpy.callCount; i++) {
|
||||||
|
assert.isTrue(field.equals(setTextSpy.getCall(i).thisValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < setCodeSpy.callCount; i++) {
|
||||||
|
assert.isTrue(field.equals(setCodeSpy.getCall(i).thisValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
setTextSpy.restore();
|
||||||
|
setCodeSpy.restore();
|
||||||
|
})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#addEditBibliography', function() {
|
describe('#addEditBibliography', function() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user