- fix (most) unnecessary citation update issues
- switch Zotero.JSON to native Firefox JSON support - update to citeproc-js 1.0.21 From Frank's announcement: In this release: - Tighten up internal "NUMERIC" update_mode to mean styles that render citation-number in citations (renderings in the bibliography are now ignored for purposes of setting this flag). - The numeric styles fix introduced at version 1.0.17 broke with styles that sort the bibliography on anything other than citation- number (i.e. document first-reference order). With this release, arbitrary sorts of the bibliography work with numeric styles. - Position evaluation code is now invoked only in styles that make use of position testing (to save a few cycles). - Numeric styles now perform targetted citation updates correctly.
This commit is contained in:
parent
e44dcb1bb4
commit
f0f22009c4
|
@ -1432,7 +1432,7 @@ CSL.dateParser = function (txt) {
|
|||
};
|
||||
CSL.Engine = function (sys, style, lang, xmlmode) {
|
||||
var attrs, langspec, localexml, locale;
|
||||
this.processor_version = "1.0.20";
|
||||
this.processor_version = "1.0.21";
|
||||
this.csl_version = "1.0";
|
||||
this.sys = sys;
|
||||
this.sys.xml = new CSL.System.Xml.Parsing();
|
||||
|
@ -2224,7 +2224,7 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre,
|
|||
sortedItems.push(newitem);
|
||||
citation.citationItems[pos].item = Item;
|
||||
}
|
||||
if (!this[this.tmp.area].opt["citation-number-sort"] && sortedItems && sortedItems.length > 1 && this.citation_sort.tokens.length > 0) {
|
||||
if (!this.citation.opt["citation-number-sort"] && sortedItems && sortedItems.length > 1 && this.citation_sort.tokens.length > 0) {
|
||||
len = sortedItems.length;
|
||||
for (pos = 0; pos < len; pos += 1) {
|
||||
sortedItems[pos][1].sortkeys = CSL.getSortKeys.call(this, sortedItems[pos][0], "citation_sort");
|
||||
|
@ -2248,7 +2248,7 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre,
|
|||
}
|
||||
this.registry.citationreg.citationByIndex = citationByIndex;
|
||||
this.registry.citationreg.citationsByItemId = {};
|
||||
if (this.opt.update_mode === CSL.POSITION || true) {
|
||||
if (this.opt.update_mode === CSL.POSITION) {
|
||||
textCitations = [];
|
||||
noteCitations = [];
|
||||
}
|
||||
|
@ -2267,7 +2267,7 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre,
|
|||
this.registry.citationreg.citationsByItemId[item[1].id].push(citationByIndex[pos]);
|
||||
}
|
||||
}
|
||||
if (this.opt.update_mode === CSL.POSITION || true) {
|
||||
if (this.opt.update_mode === CSL.POSITION) {
|
||||
if (citationByIndex[pos].properties.noteIndex) {
|
||||
noteCitations.push(citationByIndex[pos]);
|
||||
} else {
|
||||
|
@ -2278,7 +2278,7 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre,
|
|||
if (!has_bibliography) {
|
||||
this.updateItems(update_items);
|
||||
}
|
||||
if (this.opt.update_mode === CSL.POSITION || true) {
|
||||
if (this.opt.update_mode === CSL.POSITION) {
|
||||
for (pos = 0; pos < 2; pos += 1) {
|
||||
citations = [textCitations, noteCitations][pos];
|
||||
first_ref = {};
|
||||
|
@ -2385,7 +2385,7 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (this[this.tmp.area].opt["citation-number-sort"] && sortedItems && sortedItems.length > 1 && this.citation_sort.tokens.length > 0) {
|
||||
if (this.citation.opt["citation-number-sort"] && sortedItems && sortedItems.length > 1 && this.citation_sort.tokens.length > 0) {
|
||||
len = sortedItems.length;
|
||||
for (pos = 0; pos < len; pos += 1) {
|
||||
sortedItems[pos][1].sortkeys = CSL.getSortKeys.call(this, sortedItems[pos][0], "citation_sort");
|
||||
|
@ -4188,7 +4188,9 @@ CSL.Node.text = {
|
|||
}
|
||||
if ("citation-number" === variable || "year-suffix" === variable || "citation-label" === variable) {
|
||||
if (variable === "citation-number") {
|
||||
state.opt.update_mode = CSL.NUMERIC;
|
||||
if (state.build.area === "citation") {
|
||||
state.opt.update_mode = CSL.NUMERIC;
|
||||
}
|
||||
if ("citation-number" === state[state.tmp.area].opt.collapse) {
|
||||
this.range_prefix = "-";
|
||||
}
|
||||
|
@ -7032,6 +7034,7 @@ CSL.Registry = function (state) {
|
|||
this.uncited = [];
|
||||
this.refreshes = {};
|
||||
this.akeys = {};
|
||||
this.oldseq = {};
|
||||
this.ambigcites = {};
|
||||
this.sorter = new CSL.Registry.Comparifier(state, "bibliography_sort");
|
||||
this.modes = CSL.getModes.call(this.state);
|
||||
|
@ -7047,6 +7050,7 @@ CSL.Registry = function (state) {
|
|||
};
|
||||
CSL.Registry.prototype.init = function (myitems, uncited_flag) {
|
||||
var len, pos;
|
||||
this.oldseq = {};
|
||||
if (uncited_flag && this.mylist && this.mylist.length) {
|
||||
this.uncited = myitems;
|
||||
for (pos = 0, len = myitems.length; pos < len; pos += 1) {
|
||||
|
@ -7139,6 +7143,7 @@ CSL.Registry.prototype.rebuildlist = function () {
|
|||
for (pos = 0; pos < len; pos += 1) {
|
||||
item = this.mylist[pos];
|
||||
this.reflist.push(this.registry[item]);
|
||||
this.oldseq[item] = this.registry[item].seq;
|
||||
this.registry[item].seq = (pos + 1);
|
||||
}
|
||||
};
|
||||
|
@ -7200,10 +7205,10 @@ CSL.Registry.prototype.renumber = function () {
|
|||
len = this.reflist.length;
|
||||
for (pos = 0; pos < len; pos += 1) {
|
||||
item = this.reflist[pos];
|
||||
if (this.state.opt.update_mode === CSL.NUMERIC && this.state.tmp.taintedItemIDs && item.seq !== (pos + 1)) {
|
||||
item.seq = (pos + 1);
|
||||
if (this.state.opt.update_mode === CSL.NUMERIC && this.state.tmp.taintedItemIDs && item.seq !== this.oldseq[item.id]) {
|
||||
this.state.tmp.taintedItemIDs[item.id] = true;
|
||||
}
|
||||
item.seq = (pos + 1);
|
||||
}
|
||||
};
|
||||
CSL.Registry.prototype.yearsuffix = function () {
|
||||
|
@ -7893,4 +7898,4 @@ CSL.getModes = function () {
|
|||
CSL.Registry.CitationReg = function (state) {
|
||||
this.citationById = {};
|
||||
this.citationByIndex = [];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -557,12 +557,6 @@ Zotero.Integration.Document.prototype._updateSession = function(newField, editFi
|
|||
}
|
||||
var endTime = (new Date()).getTime();
|
||||
Zotero.debug("Collected "+this._fields.length+" fields in "+(endTime-collectFieldsTime)/1000+"; "+1000/((endTime-collectFieldsTime)/this._fields.length)+" fields/second");
|
||||
|
||||
// if we are reloading this session, assume no item IDs to be updated except for edited items
|
||||
if(this._reloadSession) {
|
||||
this._session.updateItemIDs = {};
|
||||
this._session.bibliographyHasChanged = false;
|
||||
}
|
||||
|
||||
// load uncited items from bibliography
|
||||
if(bibliographyData && !this._session.bibliographyData) {
|
||||
|
@ -588,7 +582,13 @@ Zotero.Integration.Document.prototype._updateSession = function(newField, editFi
|
|||
}
|
||||
}
|
||||
|
||||
this._session.updateCitations(true);
|
||||
// if we are reloading this session, assume no item IDs to be updated except for edited items
|
||||
if(this._reloadSession) {
|
||||
this._session.updateCitations();
|
||||
this._session.updateIndices = {};
|
||||
this._session.updateItemIDs = {};
|
||||
this._session.bibliographyHasChanged = false;
|
||||
}
|
||||
|
||||
// create new citation or edit existing citation
|
||||
if(editFieldIndex) {
|
||||
|
@ -886,7 +886,6 @@ Zotero.Integration.Session.prototype.setData = function(data) {
|
|||
this.data = data;
|
||||
if(data.style.styleID && oldStyleID != data.style.styleID) {
|
||||
this.styleID = data.style.styleID;
|
||||
Zotero.debug("style is "+data.style.styleID);
|
||||
try {
|
||||
var getStyle = Zotero.Styles.get(data.style.styleID);
|
||||
data.style.hasBibliography = getStyle.hasBibliography;
|
||||
|
@ -990,12 +989,15 @@ Zotero.Integration.Session.prototype.getCitationField = function(citation) {
|
|||
var type;
|
||||
var field = [];
|
||||
|
||||
field.push('"citationID":'+Zotero.JSON.serialize(citation.citationID));
|
||||
field.push('"citationID":'+uneval(citation.citationID));
|
||||
var properties = [];
|
||||
for(var j=0; j<Zotero.Integration.Session._saveProperties.length; j++) {
|
||||
var property = Zotero.Integration.Session._saveProperties[j];
|
||||
if(citation.properties[property] || citation.properties[property] === false) {
|
||||
properties.push('"'+property+'":'+Zotero.JSON.serialize(citation.properties[property]));
|
||||
let propval = typeof citation.properties[property] == "object" ?
|
||||
Zotero.JSON.serialize(citation.properties[property]) :
|
||||
uneval(citation.properties[property]);
|
||||
properties.push('"'+property+'":'+propval);
|
||||
}
|
||||
}
|
||||
if(properties.length) field.push('"properties":{'+properties.join(",")+"}");
|
||||
|
@ -1009,7 +1011,10 @@ Zotero.Integration.Session.prototype.getCitationField = function(citation) {
|
|||
type = typeof(citation.citationItems[j][k]);
|
||||
if(citation.citationItems[j][k] && Zotero.Integration.Session._saveItems.indexOf(k) !== -1
|
||||
&& Zotero.Integration.Session._acceptableTypes.indexOf(type) !== -1) {
|
||||
citationItem.push('"'+k+'":'+Zotero.JSON.serialize(citation.citationItems[j][k]));
|
||||
let propval = typeof citation.citationItems[j][k] == "object" ?
|
||||
Zotero.JSON.serialize(citation.citationItems[j][k]) :
|
||||
uneval(citation.citationItems[j][k]);
|
||||
citationItem.push('"'+k+'":'+propval);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1125,13 +1130,16 @@ Zotero.Integration.Session.prototype.addCitation = function(index, noteIndex, ar
|
|||
}
|
||||
}
|
||||
|
||||
if(!citation.citationID) {
|
||||
this.newIndices[index] = true;
|
||||
this.updateIndices[index] = true;
|
||||
} else if(!this.oldCitationIDs[citation.citationID]) {
|
||||
var needNewID = !citation.citationID || this.citationIDs[citation.citationID];
|
||||
if(needNewID || !this.oldCitationIDs[citation.citationID]) {
|
||||
if(needNewID) {
|
||||
Zotero.debug("Zotero.Integration: "+citation.citationID+" ("+index+") needs new citationID");
|
||||
citation.citationID = Zotero.randomString();
|
||||
}
|
||||
this.newIndices[index] = true;
|
||||
this.updateIndices[index] = true;
|
||||
}
|
||||
Zotero.debug("Zotero.Integration: adding citationID "+citation.citationID);
|
||||
this.citationIDs[citation.citationID] = true;
|
||||
}
|
||||
/**
|
||||
|
@ -1251,9 +1259,9 @@ Zotero.Integration.Session.prototype.deleteCitation = function(index) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(oldCitation.citationID) delete this.citationIDs[oldCitation.citationID];
|
||||
}
|
||||
Zotero.debug("Zotero.Integration: deleting old citationID "+oldCitation.citationID);
|
||||
if(oldCitation.citationID) delete this.citationIDs[oldCitation.citationID];
|
||||
|
||||
this.updateIndices[index] = true;
|
||||
}
|
||||
|
@ -1319,7 +1327,9 @@ Zotero.Integration.Session.prototype.formatCitation = function(index, citation)
|
|||
//Zotero.debug("style.processCitationCluster("+citation.toSource()+", "+citationsPre.toSource()+", "+citationsPost.toSource());
|
||||
var newCitations = this.style.processCitationCluster(citation, citationsPre, citationsPost);
|
||||
for each(var newCitation in newCitations) {
|
||||
Zotero.debug("Zotero.Integration: Citation "+citationIndices[newCitation[0]]+" needs to be updated");
|
||||
this.citationText[citationIndices[newCitation[0]]] = newCitation[1];
|
||||
this.updateIndices[citationIndices[newCitation[0]]] = true;
|
||||
}
|
||||
// this is a heuristic: if other citations get updated, then we should update the
|
||||
// bibliography. it would be nice if citeproc-js gave us a better hint about this
|
||||
|
@ -1330,8 +1340,8 @@ Zotero.Integration.Session.prototype.formatCitation = function(index, citation)
|
|||
/**
|
||||
* Updates the list of citations to be serialized to the document
|
||||
*/
|
||||
Zotero.Integration.Session.prototype.updateCitations = function(force) {
|
||||
var allUpdatesForced = false;
|
||||
Zotero.Integration.Session.prototype.updateCitations = function() {
|
||||
/*var allUpdatesForced = false;
|
||||
var forcedUpdates = {};
|
||||
if(force) {
|
||||
allUpdatesForced = true;
|
||||
|
@ -1353,23 +1363,21 @@ Zotero.Integration.Session.prototype.updateCitations = function(force) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
Zotero.debug("Zotero.Integration: indices of new citations");
|
||||
Zotero.debug([key for(key in this.newIndices)]);
|
||||
Zotero.debug("Zotero.Integration: indices of updated citations");
|
||||
Zotero.debug([key for(key in this.updateIndices)]);
|
||||
Zotero.debug("Zotero.Integration: indices of forcedUpdates");
|
||||
Zotero.debug([key for(key in forcedUpdates)]);
|
||||
|
||||
var deleteCitations = [];
|
||||
for each(var indexList in [this.newIndices, this.updateIndices, forcedUpdates]) {
|
||||
for each(var indexList in [this.newIndices, this.updateIndices]) {
|
||||
for(var index in indexList) {
|
||||
index = parseInt(index);
|
||||
|
||||
var citation = this.citationsByIndex[index];
|
||||
if(citation.properties.delete) {
|
||||
deleteCitations.push(index);
|
||||
if(deleteCitations.indexOf(index) == -1) deleteCitations.push(index);
|
||||
continue;
|
||||
}
|
||||
if(this.formatCitation(index, citation)) {
|
||||
|
@ -1382,10 +1390,10 @@ Zotero.Integration.Session.prototype.updateCitations = function(force) {
|
|||
}
|
||||
}
|
||||
|
||||
if(allUpdatesForced) {
|
||||
/*if(allUpdatesForced) {
|
||||
this.newIndices = {};
|
||||
this.updateIndices = {};
|
||||
}
|
||||
}*/
|
||||
|
||||
return deleteCitations;
|
||||
}
|
||||
|
@ -1489,18 +1497,20 @@ Zotero.Integration.Session.prototype.getBibliographyData = function() {
|
|||
* and position)
|
||||
*/
|
||||
Zotero.Integration.Session.prototype.previewCitation = function(citation) {
|
||||
// remove cached citation text
|
||||
this.citationText = {};
|
||||
this.addCitation(citation.properties.index, citation.properties.noteIndex, citation);
|
||||
|
||||
// add citation items
|
||||
try {
|
||||
this.addCitation(citation.properties.index, citation.properties.noteIndex, citation);
|
||||
this.formatCitation(citation.properties.index, citation);
|
||||
this.deleteCitation(citation.properties.index);
|
||||
} catch(e) {
|
||||
Zotero.debug(e);
|
||||
this.deleteCitation(citation.properties.index);
|
||||
throw e;
|
||||
}
|
||||
this.deleteCitation(citation.properties.index);
|
||||
|
||||
// we don't delete the citationText only because the add citation dialog always calls
|
||||
// previewCitation before returning
|
||||
return this.citationText[citation.properties.index];
|
||||
}
|
||||
|
||||
|
@ -1542,10 +1552,6 @@ Zotero.Integration.Session.prototype.editCitation = function(index, noteIndex, c
|
|||
.openWindow(null, 'chrome://zotero/content/integration/addCitationDialog.xul', '',
|
||||
'chrome,centerscreen,resizable', io);
|
||||
while(!window.closed) Zotero.mainThread.processNextEvent(true);
|
||||
|
||||
if(citation && !io.citation.citationItems.length) {
|
||||
io.citation = citation;
|
||||
}
|
||||
|
||||
if(io.citation.citationItems.length) { // we have an item
|
||||
this.addCitation(index, noteIndex, io.citation);
|
||||
|
@ -1625,7 +1631,7 @@ Zotero.Integration.Session.BibliographyEditInterface.prototype.remove = function
|
|||
citation.properties["delete"] = true;
|
||||
}
|
||||
delete this.session.citationsByItemID[itemID];
|
||||
this.session.updateCitations(true);
|
||||
this.session.updateCitations();
|
||||
}
|
||||
|
||||
// delete uncited if neceessary
|
||||
|
|
|
@ -2552,144 +2552,16 @@ Zotero.WebProgressFinishListener = function(onFinish) {
|
|||
}
|
||||
|
||||
/*
|
||||
* Saves or loads JSON objects. Based on public domain code from
|
||||
* http://www.json.org/json.js
|
||||
* Saves or loads JSON objects.
|
||||
*/
|
||||
Zotero.JSON = new function() {
|
||||
this.serialize = serialize;
|
||||
this.unserialize = unserialize;
|
||||
var nativeJSON = Components.classes["@mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON);
|
||||
|
||||
// m is a table of character substitutions.
|
||||
var m = {
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
};
|
||||
|
||||
// Format integers to have at least two digits.
|
||||
function f(n) {
|
||||
return n < 10 ? '0' + n : n;
|
||||
this.serialize = function(arg) {
|
||||
return nativeJSON.encode(arg);
|
||||
}
|
||||
|
||||
function replaceFunction(a) {
|
||||
var c = m[a];
|
||||
if (c) {
|
||||
return c;
|
||||
}
|
||||
c = a.charCodeAt();
|
||||
return '\\u00' +
|
||||
Math.floor(c / 16).toString(16) +
|
||||
(c % 16).toString(16);
|
||||
}
|
||||
|
||||
function serialize(arg) {
|
||||
if(arg === null) {
|
||||
return "null";
|
||||
} else if(arg instanceof Array) {
|
||||
var a = [], // The array holding the partial texts.
|
||||
i, // Loop counter.
|
||||
l = arg.length,
|
||||
v; // The value to be stringified.
|
||||
|
||||
|
||||
// For each value in arg array...
|
||||
|
||||
for (i = 0; i < l; i += 1) {
|
||||
var out = serialize(arg[i]);
|
||||
if(out !== undefined) {
|
||||
a.push(out);
|
||||
}
|
||||
}
|
||||
|
||||
// Join all of the member texts together and wrap them in brackets.
|
||||
|
||||
return '[' + a.join(',') + ']';
|
||||
} else if(typeof(arg) == "boolean") {
|
||||
return String(arg);
|
||||
} else if(arg instanceof Date) {
|
||||
// Eventually, this method will be based on the date.toISOString method.
|
||||
|
||||
return '"' + arg.getUTCFullYear() + '-' +
|
||||
f(arg.getUTCMonth() + 1) + '-' +
|
||||
f(arg.getUTCDate()) + 'T' +
|
||||
f(arg.getUTCHours()) + ':' +
|
||||
f(arg.getUTCMinutes()) + ':' +
|
||||
f(arg.getUTCSeconds()) + 'Z"';
|
||||
} else if(typeof(arg) == "number") {
|
||||
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||
|
||||
return isFinite(arg) ? String(arg) : 'null';
|
||||
} else if(typeof(arg) == "string") {
|
||||
if (/["\\\x00-\x1f]/.test(arg)) {
|
||||
return '"' + arg.replace(/[\x00-\x1f\\"]/g, replaceFunction) + '"';
|
||||
}
|
||||
return '"' + arg + '"';
|
||||
} else if(arg instanceof Object) {
|
||||
var a = [], // The array holding the partial texts.
|
||||
k, // The current key.
|
||||
v; // The current value.
|
||||
|
||||
// Iterate through all of the keys in the object, ignoring the proto chain
|
||||
// and keys that are not strings.
|
||||
|
||||
for (k in arg) {
|
||||
if (typeof k === 'string' &&
|
||||
Object.prototype.hasOwnProperty.apply(arg, [k])) {
|
||||
var out = serialize(arg[k]);
|
||||
if(out !== undefined) {
|
||||
a.push(serialize(k) + ':' + out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Join all of the member texts together and wrap them in braces.
|
||||
|
||||
return '{' + a.join(',') + '}';
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
function unserialize(arg) {
|
||||
var j;
|
||||
|
||||
// Parsing happens in three stages. In the first stage, we run the text against
|
||||
// a regular expression which looks for non-JSON characters. We are especially
|
||||
// concerned with '()' and 'new' because they can cause invocation, and '='
|
||||
// because it can cause mutation. But just to be safe, we will reject all
|
||||
// unexpected characters.
|
||||
|
||||
// We split the first stage into 3 regexp operations in order to work around
|
||||
// crippling deficiencies in Safari's regexp engine. First we replace all
|
||||
// backslash pairs with '@' (a non-JSON character). Second we delete all of
|
||||
// the string literals. Third, we look to see if only JSON characters
|
||||
// remain. If so, then the text is safe for eval.
|
||||
|
||||
if (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/.test(arg.
|
||||
replace(/\\./g, '@').
|
||||
replace(/"[^"\\\n\r]*"/g, ''))) {
|
||||
|
||||
// In the second stage we use the eval function to compile the text into a
|
||||
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||
// in parens to eliminate the ambiguity.
|
||||
|
||||
// Friendly AMO reviewer: This is the official json.org library and is safe.
|
||||
j = eval('(' + arg + ')');
|
||||
|
||||
// In the optional third stage, we recursively walk the new structure, passing
|
||||
// each name/value pair to a filter function for possible transformation.
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||
|
||||
throw new SyntaxError('parseJSON');
|
||||
this.unserialize = function(arg) {
|
||||
return nativeJSON.decode(arg);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user