www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit f0f22009c49790c38d5ea72a3cffc2af11eca0bd
parent e44dcb1bb4f8fb689b9bd1f9b93e40c1c83db33d
Author: Simon Kornblith <simon@simonster.com>
Date:   Sat,  5 Jun 2010 17:49:04 +0000

- 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.



Diffstat:
Mchrome/content/zotero/xpcom/citeproc.js | 26+++++++++++++++-----------
Mchrome/content/zotero/xpcom/integration.js | 76+++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mchrome/content/zotero/xpcom/zotero.js | 140++++---------------------------------------------------------------------------
3 files changed, 62 insertions(+), 180 deletions(-)

diff --git a/chrome/content/zotero/xpcom/citeproc.js b/chrome/content/zotero/xpcom/citeproc.js @@ -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 = []; -}; -\ No newline at end of file +}; diff --git a/chrome/content/zotero/xpcom/integration.js b/chrome/content/zotero/xpcom/integration.js @@ -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 diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js @@ -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; - - // 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; - } + var nativeJSON = Components.classes["@mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON); - 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); + this.serialize = function(arg) { + return nativeJSON.encode(arg); } - 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); } } \ No newline at end of file