www

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

commit 21d3ca298bd7d4e3d7f6f467c96b0c235cfcc824
parent 3741a75b1d75e089bdf01db4001e3adb24ada467
Author: Dan Stillman <dstillman@zotero.org>
Date:   Sun, 18 Sep 2016 18:39:18 -0400

Merge branch '4.0'

Diffstat:
M.travis.yml | 5++---
Mchrome/content/zotero/xpcom/citeproc.js | 143++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mchrome/content/zotero/xpcom/utilities.js | 2++
Mresource/schema/repotime.txt | 2+-
Mtest/tests/utilitiesTest.js | 12++++++++----
5 files changed, 129 insertions(+), 35 deletions(-)

diff --git a/.travis.yml b/.travis.yml @@ -16,9 +16,8 @@ notifications: install: # Use unbranded builds for 'release' and 'beta' - if [ $FX_CHANNEL != "esr" ]; then - TS="`curl -s https://archive.mozilla.org/pub/firefox/tinderbox-builds/mozilla-${FX_CHANNEL}-linux64-add-on-devel/ | grep mozilla-$FX_CHANNEL | tail -n 1 | sed -r 's/.+add-on-devel\/([0-9]+).+/\1/'`"; - FN="`curl -s https://archive.mozilla.org/pub/firefox/tinderbox-builds/mozilla-${FX_CHANNEL}-linux64-add-on-devel/$TS/ | grep add-on-devel.tar.bz2 | head -n 1 | sed -r 's/.+>(firefox-[^<]+).+/\1/g'`"; - wget -O tarball "https://archive.mozilla.org/pub/firefox/tinderbox-builds/mozilla-${FX_CHANNEL}-linux64-add-on-devel/$TS/$FN"; + URL="`curl -s https://wiki.mozilla.org/Addons/Extension_Signing | sed -n -r \"s/.+https?(:\/\/archive.mozilla.org[^ ]+\/mozilla-${FX_CHANNEL}-linux64-add-on-devel\/[0-9]+\/.+.bz2).+/https\1/p\"`"; + wget -O tarball "$URL"; fi # Use official build for 'esr' - if [ $FX_CHANNEL == "esr" ]; then diff --git a/chrome/content/zotero/xpcom/citeproc.js b/chrome/content/zotero/xpcom/citeproc.js @@ -23,7 +23,7 @@ * <http://www.gnu.org/licenses/> respectively. */ var CSL = { - PROCESSOR_VERSION: "1.1.119", + PROCESSOR_VERSION: "1.1.130", CONDITION_LEVEL_TOP: 1, CONDITION_LEVEL_BOTTOM: 2, PLAIN_HYPHEN_REGEX: /(?:[^\\]-|\u2013)/, @@ -776,7 +776,6 @@ var CSL = { }; if (typeof require !== "undefined" && typeof module !== 'undefined' && "exports" in module) { var CSL_IS_NODEJS = true; - var CSL_NODEJS = require("./csl_nodejs_jsdom").CSL_NODEJS_JSDOM; exports.CSL = CSL; } CSL.TERMINAL_PUNCTUATION_REGEXP = new RegExp("^([" + CSL.TERMINAL_PUNCTUATION.slice(0, -1).join("") + "])(.*)"); @@ -2729,6 +2728,11 @@ CSL.Engine.prototype.retrieveItems = function (ids) { CSL.ITERATION = 0; CSL.Engine.prototype.retrieveItem = function (id) { var Item, m, pos, len, mm; + if (!this.tmp.loadedItemIDs[id]) { + this.tmp.loadedItemIDs[id] = true; + } else { + return this.registry.refhash[id]; + } if (this.opt.development_extensions.normalize_lang_keys_to_lowercase && "boolean" === typeof this.opt.development_extensions.normalize_lang_keys_to_lowercase) { for (var i=0,ilen=this.opt["default-locale"].length; i<ilen; i+=1) { @@ -2743,7 +2747,7 @@ CSL.Engine.prototype.retrieveItem = function (id) { this.opt.development_extensions.normalize_lang_keys_to_lowercase = 100; } CSL.ITERATION += 1; - Item = this.sys.retrieveItem("" + id); + Item = JSON.parse(JSON.stringify(this.sys.retrieveItem("" + id))); if (this.opt.development_extensions.normalize_lang_keys_to_lowercase) { if (Item.multi) { if (Item.multi._keys) { @@ -2906,6 +2910,7 @@ CSL.Engine.prototype.retrieveItem = function (id) { } } } + this.registry.refhash[id] = Item; return Item; }; CSL.Engine.prototype.setOpt = function (token, name, value) { @@ -3649,10 +3654,15 @@ CSL.Output.Queue.prototype.string = function (state, myblobs, blob) { } else if (blobjr.blobs.length) { var addtoret = state.output.string(state, blobjr.blobs, blobjr); if (blob) { - if (addtoret.length > 1 - && "string" === typeof addtoret.slice(-1)[0] - && "string" !== typeof addtoret.slice(-2)[0]) { - addtoret[addtoret.length-1] = (blobjr.strings.delimiter + addtoret.slice(-1)[0]); + if ("string" !== addtoret && addtoret.length > 1 && blobjr.strings.delimiter) { + var numberSeen = false; + for (var j=0,jlen=addtoret.length;j<jlen;j++) { + if ("string" !== typeof addtoret[j]) { + numberSeen = true; + } else if (numberSeen) { + addtoret[j] = (blobjr.strings.delimiter + addtoret[j]); + } + } } } ret = ret.concat(addtoret); @@ -4538,6 +4548,7 @@ CSL.Engine.Tmp = function () { this.strip_periods = 0; this.shadow_numbers = {}; this.authority_stop_last = 0; + this.loadedItemIDs = {}; }; CSL.Engine.Fun = function (state) { this.match = new CSL.Util.Match; @@ -4645,6 +4656,8 @@ CSL.Engine.prototype.appendCitationCluster = function (citation) { CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre, citationsPost, flag) { var c, i, ilen, j, jlen, k, klen, n, nlen, key, Item, item, noteCitations, textCitations, m, citationsInNote; this.debug = false; + this.tmp.loadedItemIDs = {}; + citation = JSON.parse(JSON.stringify(citation)); this.tmp.citation_errors = []; var return_data = {"bibchange": false}; this.setCitationId(citation); @@ -4752,7 +4765,7 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre, } } if (flag !== CSL.ASSUME_ALL_ITEMS_REGISTERED) { - this.updateItems(update_items); + this.updateItems(update_items, null, null, true); } if (!this.opt.citation_number_sort && sortedItems && sortedItems.length > 1 && this.citation_sort.tokens.length > 0) { for (i = 0, ilen = sortedItems.length; i < ilen; i += 1) { @@ -5040,7 +5053,7 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre, for (i = 0, ilen = oldItemList.length; i < ilen; i += 1) { oldItemIds.push("" + oldItemList[i].id); } - this.updateItems(oldItemIds); + this.updateItems(oldItemIds, null, null, true); for (key in oldAmbigs) { if (oldAmbigs.hasOwnProperty(key)) { this.registry.registry[key].disambig = oldAmbigs[key]; @@ -5499,6 +5512,7 @@ CSL.getCite = function (Item, item, prevItemID, blockShadowNumberReset) { this.parallel.StartCite(Item, item, prevItemID); CSL.citeStart.call(this, Item, item, blockShadowNumberReset); next = 0; + this.tmp.name_node = {}; this.nameOutput = new CSL.NameOutput(this, Item, item); while (next < this[this.tmp.area].tokens.length) { next = CSL.tokenExec.call(this, this[this.tmp.area].tokens[next], Item, item); @@ -5987,14 +6001,17 @@ CSL.Engine.prototype.restoreProcessorState = function (citations) { } return ret; }; -CSL.Engine.prototype.updateItems = function (idList, nosort, rerun_ambigs) { +CSL.Engine.prototype.updateItems = function (idList, nosort, rerun_ambigs, implicitUpdate) { var debug = false; var oldArea = this.tmp.area; var oldRoot = this.tmp.root; var oldExtension = this.tmp.extension; this.tmp.area = "citation"; - this.tmp.root = "citation" - this.tmp.extension = "" + this.tmp.root = "citation"; + this.tmp.extension = ""; + if (!implicitUpdate) { + this.tmp.loadedItemIDs = {}; + } this.registry.init(idList); if (rerun_ambigs) { for (var ambig in this.registry.ambigcites) { @@ -6024,6 +6041,7 @@ CSL.Engine.prototype.updateUncitedItems = function (idList, nosort) { this.tmp.area = "citation"; this.tmp.root = "citation" this.tmp.extension = "" + this.tmp.loadedItemIDs = {}; if (!idList) { idList = []; } @@ -6069,7 +6087,6 @@ CSL.localeResolve = function (langstr, defaultLocale) { langlst = langstr.split(/[\-_]/); ret.base = CSL.LANG_BASES[langlst[0]]; if ("undefined" === typeof ret.base) { - CSL.debug("Warning: unknown locale "+langstr+", setting fallback to "+defaultLocale); return {base:defaultLocale, best:langstr, bare:langlst[0]}; } if (langlst.length === 1) { @@ -6341,6 +6358,42 @@ CSL.Engine.prototype.localeSet = function (myxml, lang_in, lang_out) { } } }; +CSL.getLocaleNames = function (myxml, preferredLocale) { + var stylexml = CSL.setupXml(myxml); + function extendLocaleList(localeList, locale) { + var forms = ["base", "best"]; + if (locale) { + normalizedLocale = CSL.localeResolve(locale); + for (var i=0,ilen=forms.length;i<ilen;i++) { + if (normalizedLocale[forms[i]] && localeList.indexOf(normalizedLocale[forms[i]]) === -1) { + localeList.push(normalizedLocale[forms[i]]); + } + } + } + } + function sniffLocaleOnOneNodeName(nodeName) { + var nodes = stylexml.getNodesByName(stylexml.dataObj, nodeName); + for (var i=0,ilen=nodes.length;i<ilen;i++) { + var nodeLocales = stylexml.getAttributeValue(nodes[i], "locale"); + if (nodeLocales) { + nodeLocales = nodeLocales.split(/ +/); + for (var j=0,jlen=nodeLocales.length;j<jlen;j++) { + this.extendLocaleList(localeIDs, nodeLocales[j]); + } + } + } + } + var localeIDs = ["en-US"]; + extendLocaleList(localeIDs, preferredLocale); + var styleNode = stylexml.getNodesByName(stylexml.dataObj, "style")[0]; + var defaultLocale = stylexml.getAttributeValue(styleNode, "default-locale"); + extendLocaleList(localeIDs, defaultLocale); + var nodeNames = ["layout", "if", "else-if", "condition"]; + for (var i=0,ilen=nodeNames.length;i<ilen;i++) { + sniffLocaleOnOneNodeName(stylexml, localeIDs, nodeNames[i]); + } + return localeIDs; +}; CSL.Node = {}; CSL.Node.bibliography = { build: function (state, target) { @@ -7464,7 +7517,6 @@ CSL.Node.layout = { state.tmp.done_vars.push("first-reference-note-number"); } state.tmp.rendered_name = false; - state.tmp.name_node = {}; }; this.execs.push(func); func = function (state, Item) { @@ -10631,6 +10683,7 @@ CSL.Attributes["@variable"] = function (state, arg) { if (state.tmp.can_substitute.value() && state.tmp.area === "bibliography" && "string" === typeof Item[variable]) { + state.tmp.name_node.top = state.output.current.value(); state.tmp.rendered_name.push(Item[variable]); } } @@ -11953,6 +12006,11 @@ CSL.Transform = function (state) { if (CSL.NUMERIC_VARIABLES.indexOf(myabbrev_family) > -1) { myabbrev_family = "number"; } + if (myabbrev_family === "jurisdiction") { + if (state.opt.suppressedJurisdictions[Item.jurisdiction]) { + return ""; + } + } if (["publisher-place", "event-place", "jurisdiction", "archive-place", "language-name", "language-name-original"].indexOf(myabbrev_family) > -1) { myabbrev_family = "place"; } @@ -12554,6 +12612,15 @@ CSL.Util.fixDateNode = function (parent, pos, node) { this.cslXml.deleteNodeByNameAttribute(datexml, 'day'); } else if ("year-month" === this.cslXml.getAttributeValue(node, "date-parts")) { this.cslXml.deleteNodeByNameAttribute(datexml, 'day'); + } else if ("month-day" === this.cslXml.getAttributeValue(node, "date-parts")) { + var childNodes = this.cslXml.children(datexml); + for (var i=1,ilen=childNodes.length;i<ilen;i++) { + if (this.cslXml.getAttributeValue(childNodes[i], 'name') === "year") { + this.cslXml.setAttribute(childNodes[i-1], "suffix", ""); + break; + } + } + this.cslXml.deleteNodeByNameAttribute(datexml, 'year'); } return this.cslXml.insertChildNodeAfter(parent, node, pos, datexml); }; @@ -13193,15 +13260,19 @@ CSL.Util.substituteEnd = function (state, target) { choose_end = new CSL.Token("choose", CSL.END); CSL.Node.choose.build.call(choose_end, state, target); } - toplevel = "names" === this.name && state.build.substitute_level.value() === 0; - hasval = "string" === typeof state[state.build.area].opt["subsequent-author-substitute"]; - var subrule = state[state.build.area].opt["subsequent-author-substitute-rule"]; - if (toplevel && hasval) { + if ("names" === this.name || ("text" === this.name && this.variables_real !== "title")) { author_substitute = new CSL.Token("text", CSL.SINGLETON); func = function (state, Item) { + if (state.tmp.area !== "bibliography") return; + if ("string" !== typeof state.bibliography.opt["subsequent-author-substitute"]) return; + if (this.variables_real && !Item[this.variables_real]) return; + if (state.tmp.substituted_variable !== this.variables_real) { + return; + } + var subrule = state.bibliography.opt["subsequent-author-substitute-rule"]; var i, ilen; var printing = !state.tmp.suppress_decorations; - if (printing && state.tmp.area === "bibliography" && state.tmp.subsequent_author_substitute_ok) { + if (printing && state.tmp.subsequent_author_substitute_ok) { if (state.tmp.rendered_name) { if ("partial-each" === subrule || "partial-first" === subrule) { var dosub = true; @@ -13236,22 +13307,25 @@ CSL.Util.substituteEnd = function (state, target) { } else { var rendered_name = state.tmp.rendered_name.join(","); if (rendered_name) { - if (!rendered_name.localeCompare(state.tmp.last_rendered_name)) { + if (state.tmp.last_rendered_name && !rendered_name.localeCompare(state.tmp.last_rendered_name)) { str = new CSL.Blob(state[state.tmp.area].opt["subsequent-author-substitute"]); if (state.tmp.label_blob) { state.tmp.name_node.top.blobs = [str,state.tmp.label_blob]; + } else if (state.tmp.name_node.top.blobs.length) { + state.tmp.name_node.top.blobs[0].blobs = [str]; } else { state.tmp.name_node.top.blobs = [str]; } + state.tmp.substituted_variable = this.variables_real; } state.tmp.last_rendered_name = rendered_name; } } + state.tmp.subsequent_author_substitute_ok = false; } } }; - author_substitute.execs.push(func); - target.push(author_substitute); + this.execs.push(func); } if (("text" === this.name && !this.postponed_macro) || ["number", "date", "names"].indexOf(this.name) > -1) { func = function (state, Item) { @@ -13481,7 +13555,14 @@ CSL.Engine.prototype.processNumber = function (node, ItemObject, variable, type) var m = elems[i].match(/((?:^| )(?:[a-z]|[a-z][a-z]|[a-z][a-z][a-z]|[a-z][a-z][a-z][a-z])\. *)/g); if (m) { var lst = elems[i].split(/(?:(?:^| )(?:[a-z]|[a-z][a-z]|[a-z][a-z][a-z]|[a-z][a-z][a-z][a-z])\. *)/); - if (i === 0) { + for (var j=lst.length-1;j>0;j--) { + if (lst[j-1] && (!lst[j].match(/^[0-9]+([-,:a-zA-Z]*)$/) || !lst[j-1].match(/^[0-9]+([-,:a-zA-Z]*)$/))) { + lst[j-1] = lst[j-1] + m[j-1] + lst[j]; + lst = lst.slice(0,j).concat(lst.slice(j+1)) + m = m.slice(0,j-1).concat(m.slice(j)) + } + } + if (m.length > 0 && i === 0) { var slug = m[0].trim(); if (!CSL.STATUTE_SUBDIV_STRINGS[slug] || !me.getTerm(CSL.STATUTE_SUBDIV_STRINGS[slug]) @@ -13752,12 +13833,16 @@ CSL.Engine.prototype.processNumber = function (node, ItemObject, variable, type) manglePageNumbers(values, values.length-1, currentInfo); } } - function setVariableParams(obj, values) { + function setVariableParams(shadow_numbers, variable, values) { + var obj = shadow_numbers[variable]; if (values.length) { obj.numeric = values[0].numeric; obj.collapsible = values[0].collapsible; obj.plural = values[0].plural; obj.label = CSL.STATUTE_SUBDIV_STRINGS[values[0].label]; + if (variable === "number" && obj.label === "issue" && me.getTerm("number")) { + obj.label = "number"; + } } } if (node && this.tmp.shadow_numbers[variable] && this.tmp.shadow_numbers[variable].values.length) { @@ -13807,7 +13892,7 @@ CSL.Engine.prototype.processNumber = function (node, ItemObject, variable, type) fixRanges(values); this.tmp.shadow_numbers[variable].masterStyling = setStyling(values) } - setVariableParams(this.tmp.shadow_numbers[variable], values); + setVariableParams(this.tmp.shadow_numbers, variable, values); } }; CSL.Util.outputNumericField = function(state, varname, itemID) { @@ -14818,6 +14903,7 @@ CSL.Registry = function (state) { this.state = state; this.registry = {}; this.reflist = []; + this.refhash = {}; this.namereg = new CSL.Registry.NameReg(state); this.citationreg = new CSL.Registry.CitationReg(state); this.authorstrings = {}; @@ -14952,6 +15038,7 @@ CSL.Registry.prototype.dodeletes = function (myhash) { } } delete this.registry[key]; + delete this.refhash[key]; this.return_data.bibchange = true; } } @@ -15792,14 +15879,16 @@ CSL.Engine.prototype.retrieveAllStyleModules = function (jurisdictionList) { var ret = {}; var preferences = this.locale[this.opt.lang].opts["jurisdiction-preference"]; preferences = preferences ? preferences : []; - preferences = [null].concat(preferences); + preferences = [""].concat(preferences); for (var i=preferences.length-1;i>-1;i--) { var preference = preferences[i]; for (var j=0,jlen=jurisdictionList.length;j<jlen;j++) { var jurisdiction = jurisdictionList[j]; if (this.opt.jurisdictions_seen[jurisdiction]) continue; var res = this.sys.retrieveStyleModule(jurisdiction, preference); - this.opt.jurisdictions_seen[jurisdiction] = true; + if ((!res && !preference) || res) { + this.opt.jurisdictions_seen[jurisdiction] = true; + } if (!res) continue; ret[jurisdiction] = res; } diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js @@ -1767,6 +1767,8 @@ Zotero.Utilities = { if(m) cslItem.PMID = m[1]; m = /(?:^|\n)PMCID:\s*((?:PMC)?[0-9]+)/.exec(extra); if(m) cslItem.PMCID = m[1]; + m = /(?:^|\n)DOI:\s*(10\.[0-9]{4,}\/[^\s]*[^\s\.,])/.exec(extra); + if(m) cslItem.DOI = m[1]; } //this._cache[zoteroItem.id] = cslItem; diff --git a/resource/schema/repotime.txt b/resource/schema/repotime.txt @@ -1 +1 @@ -2016-09-06 03:45:00 +2016-09-10 12:00:00 diff --git a/test/tests/utilitiesTest.js b/test/tests/utilitiesTest.js @@ -237,13 +237,14 @@ describe("Zotero.Utilities", function() { })); it("should map additional fields from Extra field", Zotero.Promise.coroutine(function* () { let item = new Zotero.Item('journalArticle'); - item.setField('extra', 'PMID: 12345\nPMCID:123456'); + item.setField('extra', 'PMID: 12345\nPMCID:123456\nDOI:10.5064/F6PN93H4'); yield item.saveTx(); let cslJSON = Zotero.Utilities.itemToCSLJSON(item); assert.equal(cslJSON.PMID, '12345', 'PMID from Extra is mapped to PMID'); assert.equal(cslJSON.PMCID, '123456', 'PMCID from Extra is mapped to PMCID'); + assert.equal(cslJSON.DOI, '10.5064/F6PN93H4', 'DOI from Extra field is mapped to DOI'); item.setField('extra', 'PMID: 12345'); yield item.saveTx(); @@ -251,20 +252,23 @@ describe("Zotero.Utilities", function() { assert.equal(cslJSON.PMID, '12345', 'single-line entry is extracted correctly'); - item.setField('extra', 'some junk: note\nPMID: 12345\nstuff in-between\nPMCID: 123456\nlast bit of junk!'); + item.setField('extra', 'some junk: note\nPMID: 12345\nstuff in-between\nPMCID: 123456\nDOI: 10.5064/F6PN93H4\nlast bit of junk!'); yield item.saveTx(); cslJSON = Zotero.Utilities.itemToCSLJSON(item); assert.equal(cslJSON.PMID, '12345', 'PMID from mixed Extra field is mapped to PMID'); assert.equal(cslJSON.PMCID, '123456', 'PMCID from mixed Extra field is mapped to PMCID'); + assert.equal(cslJSON.DOI, '10.5064/F6PN93H4', 'DOI from mixed Extra field is mapped to DOI'); - item.setField('extra', 'a\n PMID: 12345\nfoo PMCID: 123456'); + item.setField('extra', 'a\n PMID: 12345\nfoo PMCID: 123456\n10.5064/F6PN93H4'); yield item.saveTx(); cslJSON = Zotero.Utilities.itemToCSLJSON(item); assert.isUndefined(cslJSON.PMCID, 'field label must not be preceded by other text'); assert.isUndefined(cslJSON.PMID, 'field label must not be preceded by a space'); - assert.equal(cslJSON.note, 'a\n PMID: 12345\nfoo PMCID: 123456', 'note is left untouched if nothing is extracted'); + assert.isUndefined(cslJSON.DOI, 'DOI must be preceded by label'); + assert.equal(cslJSON.note, 'a\n PMID: 12345\nfoo PMCID: 123456\n10.5064/F6PN93H4', 'note is left untouched if nothing is extracted'); + item.setField('extra', 'something\npmid: 12345\n'); yield item.saveTx();