diff --git a/chrome/content/zotero/xpcom/citeproc.js b/chrome/content/zotero/xpcom/citeproc.js index b8383cfc9..8e020e517 100644 --- a/chrome/content/zotero/xpcom/citeproc.js +++ b/chrome/content/zotero/xpcom/citeproc.js @@ -67,6 +67,14 @@ var CSL = { "art.": "article", "para.": "paragraph" }, + STATUTE_SUBDIV_STRINGS_REVERSE: { + "part": "pt.", + "chapter": "ch.", + "subchapter": "subch.", + "section": "sec.", + "article": "art.", + "paragraph": "para." + }, NestedBraces: [ ["(", "["], [")", "]"] @@ -2153,7 +2161,7 @@ CSL.DateParser = function () { }; CSL.Engine = function (sys, style, lang, forceLang) { var attrs, langspec, localexml, locale; - this.processor_version = "1.0.316"; + this.processor_version = "1.0.319"; this.csl_version = "1.0"; this.sys = sys; this.sys.xml = new CSL.System.Xml.Parsing(); @@ -2522,20 +2530,6 @@ CSL.Engine.prototype.retrieveItem = function (id) { } } } - if (this.opt.development_extensions.atomic_statutes) { - if (Item.type && ["legislation","bill"].indexOf(Item.type) > -1 - && Item.title - && Item.jurisdiction) { - var legislation_id = []; - for (var i = 0, ilen = 3; i < ilen; i += 1) { - var varname = ["type", "genre", "jurisdiction"][i]; - if (Item[varname]) { - legislation_id.push(Item[varname]); - } - } - Item.legislation_id = legislation_id.join("::"); - } - } for (var i = 1, ilen = CSL.DATE_VARIABLES.length; i < ilen; i += 1) { var dateobj = Item[CSL.DATE_VARIABLES[i]]; if (dateobj) { @@ -2547,6 +2541,31 @@ CSL.Engine.prototype.retrieveItem = function (id) { Item[CSL.DATE_VARIABLES[i]] = this.dateParseArray(dateobj); } } + if (this.opt.development_extensions.static_statute_locator) { + if (Item.type && ["legislation","bill"].indexOf(Item.type) > -1 + && Item.title + && Item.jurisdiction) { + var elements = ["type", "title", "jurisdiction", "genre", "volume", "container-title", "original-date", "issued"]; + var legislation_id = []; + for (var i = 0, ilen = elements.length; i < ilen; i += 1) { + var varname = elements[i]; + var value; + if (Item[varname]) { + if (CSL.DATE_VARIABLES.indexOf(varname) > -1) { + if (Item[varname].year) { + value = Item[varname].year; + } else { + continue; + } + } else { + value = Item[varname]; + } + legislation_id.push(value); + } + } + Item.legislation_id = legislation_id.join("::"); + } + } return Item; }; CSL.Engine.prototype.setOpt = function (token, name, value) { @@ -2570,6 +2589,76 @@ CSL.Engine.prototype.fixOpt = function (token, name, localname) { } } }; +CSL.Engine.prototype.remapSectionVariable = function (inputList) { + for (var i = 0, ilen = inputList.length; i < ilen; i += 1) { + var Item = inputList[i][0]; + var item = inputList[i][1]; + if (Item.section + && item + && (Item.type === "bill" || Item.type === "legislation") + && this.opt.development_extensions.static_statute_locator) { + var value = "" + Item.section; + var locator = ""; + var labelstr = ""; + if (item.locator) { + locator = item.locator; + if (item.label && CSL.STATUTE_SUBDIV_STRINGS_REVERSE[item.label]) { + labelstr = " " + CSL.STATUTE_SUBDIV_STRINGS_REVERSE[item.label] + " "; + } + locator = labelstr + locator; + if (locator.slice(0,1) === "&") { + locator = " " + locator; + } + value = value + locator; + } + var m = value.match(CSL.STATUTE_SUBDIV_GROUPED_REGEX); + if (m) { + var splt = value.split(CSL.STATUTE_SUBDIV_PLAIN_REGEX); + if (CSL.STATUTE_SUBDIV_STRINGS[splt[0]]) { + item.label = CSL.STATUTE_SUBDIV_STRINGS[slt[0]]; + splt.reverse(); + splt.pop(); + splt.reverse(); + } else { + item.label = "section"; + } + if (splt.length > 1) { + var lst = []; + lst.push(splt[1].replace(/\s*$/, "").replace(/^\s*/, "")); + var has_repeat_label = false; + var has_sublabel = false; + for (var j=2, jlen=splt.length; j < jlen; j += 1) { + var subdiv = m[j - 1].replace(/^\s*/, ""); + subdiv = CSL.STATUTE_SUBDIV_STRINGS[subdiv]; + if (subdiv === item.label) { + has_repeat_label = true; + } else { + has_sublabel = true; + } + var subplural = false; + if (splt[j].match(/(?:&|, | and )/)) { + subplural = true; + } + lst.push(this.getTerm(subdiv, "symbol", subplural)); + lst.push(splt[j].replace(/\s*$/, "").replace(/^\s*/, "")); + } + for (var j=lst.length - 2; j > 0; j += -2) { + if (!has_sublabel) { + lst = lst.slice(0,j).concat(lst.slice(j + 1)); + } + } + value = lst.join(" "); + if (!has_sublabel && has_repeat_label) { + item.force_pluralism = true; + } else { + item.force_pluralism = false; + } + } + } + item.locator = value; + } + } +} CSL.substituteOne = function (template) { return function (state, list) { if (!list) { @@ -2775,9 +2864,8 @@ CSL.Engine.Opt = function () { this.development_extensions.raw_date_parsing = true; this.development_extensions.clean_up_csl_flaws = true; this.development_extensions.flip_parentheses_to_braces = true; - this.development_extensions.parse_section_variable = true; this.development_extensions.jurisdiction_subfield = true; - this.development_extensions.atomic_statutes = false; + this.development_extensions.static_statute_locator = false; this.development_extensions.csl_reverse_lookup_support = false; this.nodenames = []; this.gender = {}; @@ -3397,6 +3485,8 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre, var sortedItems = []; for (i = 0, ilen = citation.citationItems.length; i < ilen; i += 1) { item = citation.citationItems[i]; + Item = this.retrieveItem("" + item.id); + this.remapSectionVariable([[Item,item]]); if (this.opt.development_extensions.locator_date_and_revision) { if (item.locator) { item.locator = "" + item.locator; @@ -3423,7 +3513,6 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre, } } } - Item = this.retrieveItem("" + item.id); var newitem = [Item, item]; sortedItems.push(newitem); citation.citationItems[i].item = Item; @@ -3529,8 +3618,6 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre, var mylabel = item[1].label; if (item[0].legislation_id) { myid = item[0].legislation_id; - mylocator = item[0].section; - mylabel = ""; } var incitationid; if (k > 0) { @@ -3604,34 +3691,20 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre, } var prev, prev_locator, prev_label, curr_locator, curr_label; if (ibidme) { - var myprev_locator; - var myprev_label; if (k > 0) { - if (onecitation.sortedItems[(k - 1)][0].legislation_id) { - myprev_locator = onecitation.sortedItems[(k - 1)][0].section; - myprev_label = ""; - } else { - myprev_locator = onecitation.sortedItems[(k - 1)][1].locator; - myprev_label = onecitation.sortedItems[(k - 1)][1].label; - } + prev = onecitation.sortedItems[(k - 1)][1]; } else { - if (citations[(j - 1)].sortedItems[0][0].legislation_id) { - myprev_locator = citations[(j - 1)].sortedItems[0][0].section; - myprev_label = ""; - } else { - myprev_locator = citations[(j - 1)].sortedItems[0][1].locator; - myprev_label = citations[(j - 1)].sortedItems[0][1].label; - } + prev = citations[(j - 1)].sortedItems[0][1]; } - if (myprev_locator) { - if (myprev_label) { - prev_label = myprev_label; + if (prev.locator) { + if (prev.label) { + prev_label = prev.label; } else { prev_label = ""; } - prev_locator = "" + myprev_locator + prev_label; + prev_locator = "" + prev.locator + prev_label; } else { - prev_locator = myprev_locator; + prev_locator = prev.locator; } if (mylocator) { if (mylabel) { @@ -3785,6 +3858,7 @@ CSL.Engine.prototype.makeCitationCluster = function (rawList) { newitem = [Item, item]; inputList.push(newitem); } + this.remapSectionVariable(inputList); if (inputList && inputList.length > 1 && this.citation_sort.tokens.length > 0) { len = inputList.length; for (pos = 0; pos < len; pos += 1) { @@ -4274,6 +4348,13 @@ CSL.Engine.prototype.localeConfigure = function (langspec) { this.localeSet(this.cslXml, langspec.base, langspec.best); } this.localeSet(this.cslXml, langspec.best, langspec.best); + if ("undefined" === typeof this.locale[langspec.best].terms["page-range-delimiter"]) { + if (["fr", "pt"].indexOf(langspec.best.slice(0, 2).toLowerCase()) > -1) { + this.locale[langspec.best].terms["page-range-delimiter"] = "-"; + } else { + this.locale[langspec.best].terms["page-range-delimiter"] = "\u2013"; + } + } }; CSL.Engine.prototype.localeSet = function (myxml, lang_in, lang_out) { var blob, locale, nodes, attributes, pos, ppos, term, form, termname, styleopts, attr, date, attrname, len, genderform, target, i, ilen; @@ -4356,11 +4437,6 @@ CSL.Engine.prototype.localeSet = function (myxml, lang_in, lang_out) { } } } - if (lang_out && ["fr", "pt"].indexOf(lang_out.slice(0, 2).toLowerCase()) > -1) { - this.locale[lang_out].terms["page-range-delimiter"] = "-"; - } else { - this.locale[lang_out].terms["page-range-delimiter"] = "\u2013"; - } nodes = this.sys.xml.getNodesByName(locale, 'style-options'); for (pos = 0, len = this.sys.xml.numberofnodes(nodes); pos < len; pos += 1) { if (true) { @@ -7743,35 +7819,6 @@ CSL.Node.text = { var value; value = state.getVariable(Item, this.variables[0], form); if (value) { - if ((Item.type === "bill" || Item.type === "legislation") - && state.opt.development_extensions.parse_section_variable) { - value = "" + value; - var m = value.match(CSL.STATUTE_SUBDIV_GROUPED_REGEX); - if (m) { - var splt = value.split(CSL.STATUTE_SUBDIV_PLAIN_REGEX); - var lst = []; - if (!lst[0]) { - var parsed = false; - for (var i=1, ilen=splt.length; i < ilen; i += 1) { - var subdiv = m[i - 1].replace(/^\s*/, ""); - subdiv = CSL.STATUTE_SUBDIV_STRINGS[subdiv]; - var plural = false; - if (splt[i].match(/(?:&|, | and )/)) { - plural = true; - } - subdiv = state.getTerm(subdiv, "symbol", plural); - if (subdiv) { - parsed = true; - } - lst.push(subdiv); - lst.push(splt[i].replace(/\s*,*\s*$/, "").replace(/^\s*,*\s*/, "")); - } - if (parsed) { - value = lst.join(" "); - } - } - } - } state.output.append(value, this); } }; @@ -10353,7 +10400,7 @@ CSL.Engine.prototype.processNumber = function (node, ItemObject, variable) { this.tmp.shadow_numbers[variable].values.push(["Blob", elements[i], undefined]); } } - } + }; if (num.indexOf(" ") === -1 && num.match(/[0-9]/)) { this.tmp.shadow_numbers[variable].numeric = true; } else { @@ -10362,6 +10409,11 @@ CSL.Engine.prototype.processNumber = function (node, ItemObject, variable) { if (count > 1) { this.tmp.shadow_numbers[variable].plural = 1; } + if (ItemObject.force_pluralism === true) { + this.tmp.shadow_numbers[variable].plural = 1; + } else if (ItemObject.force_pluralism) { + this.tmp.shadow_numbers[variable].plural = 0; + } } }; CSL.Util.PageRangeMangler = {}; diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index 67528a513..fd26904cf 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -2848,15 +2848,21 @@ Zotero.Item.prototype.renameAttachmentFile = function(newName, overwrite) { // Ignore if no change // // Note: Just comparing file.leafName to newName isn't reliable - if (file.leafName == dest.leafName) { + if (file.leafName === dest.leafName) { return true; } - if (overwrite) { - dest.remove(false); - } - else if (dest.exists()) { - return -1; + // If old and new names differ only in case, let's bank on this + // just being a case change and not bother checking for existing + // files, since dest.exists() will just show true on a case-insensitive + // filesystem anyway. + if (file.leafName.toLowerCase() != dest.leafName.toLowerCase()) { + if (overwrite) { + dest.remove(false); + } + else if (dest.exists()) { + return -1; + } } file.moveTo(null, newName); diff --git a/chrome/content/zotero/xpcom/integration.js b/chrome/content/zotero/xpcom/integration.js index 5aeebecf9..34efe5a45 100644 --- a/chrome/content/zotero/xpcom/integration.js +++ b/chrome/content/zotero/xpcom/integration.js @@ -2265,11 +2265,24 @@ Zotero.Integration.Session.prototype.lookupItems = function(citation, index) { // get Zotero item var zoteroItem = false; - if(citationItem.cslItemID) { - - } else if(citationItem.uris) { + if(citationItem.uris) { [zoteroItem, needUpdate] = this.uriMap.getZoteroItemForURIs(citationItem.uris); if(needUpdate && index) this.updateIndices[index] = true; + + // Unfortunately, people do weird things with their documents. One weird thing people + // apparently like to do (http://forums.zotero.org/discussion/22262/) is to copy and + // paste citations from other documents created with earlier versions of Zotero into + // their documents and then not refresh the document. Usually, this isn't a problem. If + // document is edited by the same user, it will work without incident. If the first + // citation of a given item doesn't contain itemData, the user will get a + // MissingItemException. However, it may also happen that the first citation contains + // itemData, but later citations don't, because the user inserted the item properly and + // then copied and pasted the same citation from another document. We check for that + // possibility here. + if(zoteroItem.cslItemData && !citationItem.itemData) { + citationItem.itemData = zoteroItem.cslItemData; + this.updateIndices[index] = true; + } } else { if(citationItem.key) { zoteroItem = Zotero.Items.getByKey(citationItem.key); diff --git a/chrome/content/zotero/xpcom/translation/translate.js b/chrome/content/zotero/xpcom/translation/translate.js index b44713c66..11ca3ac5c 100644 --- a/chrome/content/zotero/xpcom/translation/translate.js +++ b/chrome/content/zotero/xpcom/translation/translate.js @@ -272,7 +272,7 @@ Zotero.Translate.Sandbox = { }; var translatorsHandlerSet = false; - safeTranslator.getTranslators = function(callback) { + safeTranslator.getTranslators = function() { if(!translation._handlers["translators"] || !translation._handlers["translators"].length) { if(Zotero.isConnector) { throw new Error('Translator must register a "translators" handler to '+ diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index 49d77abca..dcac0fba9 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -140,19 +140,24 @@ Zotero.Utilities = { * @return {Object} firstName, lastName, and creatorType */ "cleanAuthor":function(author, type, useComma) { - const allCapsRe = /^[A-Z\u0400-\u042f]+$/; - + var allCaps = 'A-Z' + + '\u0400-\u042f'; //cyrilic + + var allCapsRe = new RegExp('^[' + allCaps + ']+$'); + var initialRe = new RegExp('^-?[' + allCaps + ']$'); + if(typeof(author) != "string") { throw "cleanAuthor: author must be a string"; } - - author = author.replace(/^[\s\.\,\/\[\]\:]+/, ''); - author = author.replace(/[\s\,\/\[\]\:\.]+$/, ''); - author = author.replace(/ +/, ' '); + + author = author.replace(/^[\s\u00A0\.\,\/\[\]\:]+/, '') + .replace(/[\s\u00A0\.\,\/\[\]\:]+$/, '') + .replace(/[\s\u00A0]+/, ' '); + if(useComma) { // Add spaces between periods author = author.replace(/\.([^ ])/, ". $1"); - + var splitNames = author.split(/, ?/); if(splitNames.length > 1) { var lastName = splitNames[0]; @@ -165,7 +170,7 @@ Zotero.Utilities = { var lastName = author.substring(spaceIndex+1); var firstName = author.substring(0, spaceIndex); } - + if(firstName && allCapsRe.test(firstName) && firstName.length < 4 && (firstName.length == 1 || lastName.toUpperCase() != lastName)) { @@ -182,15 +187,15 @@ Zotero.Utilities = { var names = firstName.replace(/^[\s\.]+/,'') .replace(/[\s\,]+$/,'') //remove spaces surronding any dashes - .replace(/\s*([\u002D\u00AD\u2010-\u2015\u2212\u2E3A\u2E3B])\s*/,'$1') - .split(/[\s\.]+/); + .replace(/\s*([\u002D\u00AD\u2010-\u2015\u2212\u2E3A\u2E3B])\s*/,'-') + .split(/(?:[\s\.]+|(?=-))/); var newFirstName = ''; for(var i=0, n=names.length; i