From 1f08592d0ea1644c56790402adf049470216aa97 Mon Sep 17 00:00:00 2001 From: Aurimas Vinckevicius Date: Fri, 25 Jan 2013 21:25:04 -0600 Subject: [PATCH 1/6] [Utilities] add cleanISSN --- chrome/content/zotero/xpcom/utilities.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index 9443751ae..e2229c679 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -308,6 +308,28 @@ Zotero.Utilities = { return false; }, + /** + * Clean and validate ISSN. + * Return issn if valid, otherwise return false + */ + "cleanISSN":function(/**String*/ issn) { + issn = issn.replace(/[^0-9a-z]+/ig, '').toUpperCase() //we only want to ignore punctuation, spaces + .match(/[0-9]{7}[0-9X]/); //13 digit or 10 digit + if(!issn) return false; + issn = issn[0]; + + // Verify ISBN-10 checksum + var sum = 0; + for (var i = 0; i < 7; i++) { + if(issn[i] == 'X') return false; //X can only be a check digit + sum += issn[i] * (8-i); + } + //check digit might be 'X' + sum += (issn[9] == 'X')? 10 : issn[9]*1; + + return (sum % 11 == 0) ? issn.substring(0,4) + '-' + issn.substring(4) : false; + }, + /** * Convert plain text to HTML by replacing special characters and replacing newlines with BRs or * P tags From f9978e8f026fa16315a76cfe3359bfef27de4f46 Mon Sep 17 00:00:00 2001 From: Simon Kornblith Date: Sat, 26 Jan 2013 01:49:06 -0500 Subject: [PATCH 2/6] Update citeproc-js to 1.0.422 --- chrome/content/zotero/xpcom/citeproc.js | 357 ++++++++++++------------ 1 file changed, 184 insertions(+), 173 deletions(-) diff --git a/chrome/content/zotero/xpcom/citeproc.js b/chrome/content/zotero/xpcom/citeproc.js index d906a7733..f14fdafa6 100644 --- a/chrome/content/zotero/xpcom/citeproc.js +++ b/chrome/content/zotero/xpcom/citeproc.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011 and 2012 Frank G. Bennett, Jr. All Rights + * Copyright (c) 2009-2013 Frank G. Bennett, Jr. All Rights * Reserved. * * The contents of this file are subject to the Common Public @@ -31,7 +31,7 @@ * * The Initial Developer of the Original Code is Frank G. Bennett, * Jr. All portions of the code written by Frank G. Bennett, Jr. are - * Copyright (c) 2009, 2010, 2011, and 2012 Frank G. Bennett, Jr. All Rights Reserved. + * Copyright (c) 2009-2013 Frank G. Bennett, Jr. All Rights Reserved. * * Alternatively, the contents of this file may be used under the * terms of the GNU Affero General Public License (the [AGPLv3] @@ -57,7 +57,7 @@ if (!Array.indexOf) { }; } var CSL = { - PROCESSOR_VERSION: "1.0.409", + PROCESSOR_VERSION: "1.0.422", PLAIN_HYPHEN_REGEX: /(?:[^\\]-|\u2013)/, STATUTE_SUBDIV_GROUPED_REGEX: /((?:^| )(?:art|ch|Ch|subch|p|pp|para|subpara|pt|r|sec|subsec|Sec|sch|tit)\.)/g, STATUTE_SUBDIV_PLAIN_REGEX: /(?:(?:^| )(?:art|ch|Ch|subch|p|pp|para|subpara|pt|r|sec|subsec|Sec|sch|tit)\.)/, @@ -157,7 +157,7 @@ var CSL = { MARK_TRAILING_NAMES: true, POSITION_TEST_VARS: ["position", "first-reference-note-number", "near-note"], AREAS: ["citation", "citation_sort", "bibliography", "bibliography_sort"], - MULTI_FIELDS: ["event", "publisher", "publisher-place", "event-place", "title", "container-title", "collection-title", "authority","edition","genre","title-short","medium","jurisdiction"], + MULTI_FIELDS: ["event", "publisher", "publisher-place", "event-place", "title", "container-title", "collection-title", "authority","edition","genre","title-short","medium","jurisdiction","archive","archive-place"], CITE_FIELDS: ["first-reference-note-number", "locator", "locator-revision"], MINIMAL_NAME_FIELDS: ["literal", "family"], SWAPPING_PUNCTUATION: [".", "!", "?", ":",","], @@ -217,8 +217,8 @@ var CSL = { ALL_ROMANESQUE_REGEXP: /^[a-zA-Z\u0590-\u05ff\u0080-\u017f\u0400-\u052f\u0386-\u03fb\u1f00-\u1ffe\u0600-\u06ff\u200c\u200d\u200e\u202a-\u202e]+$/, VIETNAMESE_SPECIALS: /[\u00c0-\u00c3\u00c8-\u00ca\u00cc\u00cd\u00d2-\u00d5\u00d9\u00da\u00dd\u00e0-\u00e3\u00e8-\u00ea\u00ec\u00ed\u00f2-\u00f5\u00f9\u00fa\u00fd\u0101\u0103\u0110\u0111\u0128\u0129\u0168\u0169\u01a0\u01a1\u01af\u01b0\u1ea0-\u1ef9]/, VIETNAMESE_NAMES: /^(?:(?:[.AaBbCcDdEeGgHhIiKkLlMmNnOoPpQqRrSsTtUuVvXxYy \u00c0-\u00c3\u00c8-\u00ca\u00cc\u00cd\u00d2-\u00d5\u00d9\u00da\u00dd\u00e0-\u00e3\u00e8-\u00ea\u00ec\u00ed\u00f2-\u00f5\u00f9\u00fa\u00fd\u0101\u0103\u0110\u0111\u0128\u0129\u0168\u0169\u01a0\u01a1\u01af\u01b0\u1ea0-\u1ef9]{2,6})(\s+|$))+$/, - NOTE_FIELDS_REGEXP: /\{:[\-_a-z]+:[^\}]+\}/g, - NOTE_FIELD_REGEXP: /\{:([\-_a-z]+):\s*([^\}]+)\}/, + NOTE_FIELDS_REGEXP: /\{:(?:[\-_a-z]+|[A-Z]+):[^\}]+\}/g, + NOTE_FIELD_REGEXP: /\{:([\-_a-z]+|[A-Z]+):\s*([^\}]+)\}/, DISPLAY_CLASSES: ["block", "left-margin", "right-inline", "indent"], NAME_VARIABLES: [ "author", @@ -246,7 +246,18 @@ var CSL = { "volume", "citation-number" ], - DATE_VARIABLES: ["locator-date", "issued", "event-date", "accessed", "container", "original-date"], + DATE_VARIABLES: [ + "locator-date", + "issued", + "event-date", + "accessed", + "container", + "original-date", + "publication-date", + "original-date", + "available-date", + "submitted" + ], TAG_ESCAPE: function (str) { var mx, lst, len, pos, m, buf1, buf2, idx, ret, myret; mx = str.match(/(\"|\'|.*?<\/span>|<\/?(?:i|sc|b)>|<\/span>)/g); @@ -2596,11 +2607,60 @@ CSL.Engine.prototype.retrieveItems = function (ids) { CSL.ITERATION = 0; CSL.Engine.prototype.retrieveItem = function (id) { var Item, m, pos, len, mm; + 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; iilen; i+=1) { + var ctype = CSL.CREATORS[i]; + if (Item[ctype] && Item[ctype].multi) { + for (var j=0, jlen=Item[ctype].length; j -1; + if (isLegalType) { + if (!Item["title-short"]) { + Item["title-short"] = Item.title; + } + } else if (Item.title && this.sys.getAbbreviation) { var jurisdiction = this.transform.loadAbbreviation(Item.jurisdiction, "title", Item.title); if (this.transform.abbrevs[jurisdiction].title) { if (this.transform.abbrevs[jurisdiction].title[Item.title]) { @@ -2719,6 +2797,9 @@ CSL.Engine.prototype.remapSectionVariable = function (inputList) { var value = false; if (["bill","gazette","legislation","treaty"].indexOf(Item.type) > -1) { item.force_pluralism = 0; + if (!item.label) { + item.label = "page" + } var loci = ["section","","",""]; var split; if (Item.section) { @@ -3036,19 +3117,6 @@ CSL.Engine.prototype.setAbbreviations = function (arg) { this.sys.setAbbreviations(arg); } }; -CSL.Engine.prototype.setEnglishLocaleEscapes = function (arg) { - if ("string" === typeof arg) { - arg = arg.split(/\s+,\s+/); - } - if (!arg || !arg.length) { - arg = []; - } - for (var i = 0, ilen = arg.length; i < ilen; i += 1) { - if (this.opt.english_locale_escapes.indexOf(arg[i]) === -1) { - this.opt.english_locale_escapes.push(arg[i]); - } - } -}; CSL.Engine.Opt = function () { this.has_disambiguate = false; this.mode = "html"; @@ -3142,7 +3210,6 @@ CSL.Engine.Opt = function () { this.citation_number_slug = false; this.max_number_of_names = 0; this.trigraph = "Aaaa00:AaAa00:AaAA00:AAAA00"; - this.english_locale_escapes = []; this.development_extensions = {}; this.development_extensions.field_hack = true; this.development_extensions.locator_date_and_revision = true; @@ -3161,6 +3228,7 @@ CSL.Engine.Opt = function () { this.development_extensions.thin_non_breaking_space_html_hack = false; this.development_extensions.apply_citation_wrapper = false; this.development_extensions.main_title_from_short_title = false; + this.development_extensions.normalize_lang_keys_to_lowercase = false; this.nodenames = []; this.gender = {}; this['cite-lang-prefs'] = { @@ -3473,7 +3541,7 @@ CSL.Engine.prototype.getCitationLabel = function (Item) { CSL.Engine.prototype.getTrigraphParams = function () { var params = []; var ilst = this.opt.trigraph.split(":"); - if (!this.opt.trigraph || this.opt.trigraph[0] !== "A") { + if (!this.opt.trigraph || this.opt.trigraph.slice(0,1) !== "A") { throw "Bad trigraph definition: "+this.opt.trigraph; } for (var i = 0, ilen = ilst.length; i < ilen; i += 1) { @@ -3551,36 +3619,6 @@ CSL.getBibliographyEntries = function (bibsection) { if (bibsection && bibsection.page_start && bibsection.page_length) { input = this.registry.getSortedIds(); } else { - originalIDs = this.registry.getSortedIds(); - newIDs = []; - this.registry.generate.items = {}; - for (var id in this.registry.generate.origIDs) { - var rule = this.registry.generate.origIDs[id]; - item = this.retrieveItem(id); - var clonedItem = {}; - for (var key in item) { - clonedItem[key] = item[key]; - } - clonedItem.type = rule.to; - for (i = 0, ilen = rule.triggers.length; i < ilen; i += 1) { - if (clonedItem[rule.triggers[i]]) { - delete clonedItem[rule.triggers[i]]; - if (rule.triggers[i] === "title-short") { - delete clonedItem.shortTitle; - } - if (rule.triggers[i] === "container-title-short") { - delete clonedItem.journalAbbreviation; - } - } - } - var newID = clonedItem.id + ":gen"; - clonedItem.id = newID; - this.registry.generate.items[clonedItem.id] = clonedItem; - newIDs.push(newID); - } - if (newIDs.length) { - this.updateItems(originalIDs.concat(newIDs)); - } input = this.retrieveItems(this.registry.getSortedIds()); } this.tmp.disambig_override = true; @@ -3765,10 +3803,6 @@ CSL.getBibliographyEntries = function (bibsection) { if (!last_expected_id || !last_seen_id || last_expected_id == last_seen_id) { done = true; } - } else { - if (newIDs.length) { - this.updateItems(originalIDs); - } } this.tmp.disambig_override = false; return [processed_item_ids, ret, done]; @@ -3832,8 +3866,8 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre, item[key] = citation.citationItems[i][key]; } Item = this.retrieveItem("" + item.id); - if (Item.system_id) { - this.transform.loadAbbreviation("default", "hereinafter", Item.system_id); + if (Item.id) { + this.transform.loadAbbreviation("default", "hereinafter", Item.id); } this.remapSectionVariable([[Item,item]]); if (this.opt.development_extensions.locator_date_and_revision) { @@ -4608,20 +4642,20 @@ CSL.citeEnd = function (Item, item) { this.tmp.cut_var = false; this.tmp.disambig_request = false; this.tmp.cite_locales.push(this.tmp.last_cite_locale); - if (this.tmp.original_date && this.tmp.renders_collection_number) { + if (this.tmp.issued_date && this.tmp.renders_collection_number) { var buf = []; - for (var i = this.tmp.original_date.list.length - 1; i > this.tmp.original_date.pos; i += -1) { - buf.push(this.tmp.original_date.list.pop()); + for (var i = this.tmp.issued_date.list.length - 1; i > this.tmp.issued_date.pos; i += -1) { + buf.push(this.tmp.issued_date.list.pop()); } - this.tmp.original_date.list.pop(); + this.tmp.issued_date.list.pop(); for (i = buf.length - 1; i > -1; i += -1) { - this.tmp.original_date.list.push(buf.pop()); + this.tmp.issued_date.list.push(buf.pop()); } if (this.parallel.use_parallels) { - this.parallel.cite["original-date"] = false; + this.parallel.cite["issued"] = false; } } - this.tmp.original_date = false; + this.tmp.issued_date = false; this.tmp.renders_collection_number = false; if (this.opt.development_extensions.flip_parentheses_to_braces && item && item.suffix) { var openBrace = CSL.checkNestedBraceOpen.exec(item.suffix); @@ -5025,7 +5059,7 @@ CSL.Node.date = { this.execs.push(func); func = function (state, Item) { state.output.startTag("date", this); - if (this.variables[0] === "original-date" + if (this.variables[0] === "issued" && Item.type === "legal_case" && !state.tmp.extension && "" + Item["collection-number"] === "" + state.tmp.date_object.year @@ -5034,10 +5068,10 @@ CSL.Node.date = { for (var key in state.tmp.date_object) { if (state.tmp.date_object.hasOwnProperty(key)) { if (key.slice(0, 4) === "year") { - state.tmp.original_date = {}; + state.tmp.issued_date = {}; var lst = state.output.current.mystack.slice(-2)[0].blobs; - state.tmp.original_date.list = lst; - state.tmp.original_date.pos = lst.length - 1; + state.tmp.issued_date.list = lst; + state.tmp.issued_date.pos = lst.length - 1; } } } @@ -8245,7 +8279,9 @@ CSL.Node.number = { if (i < values.length - 1) { blob.strings.suffix = blob.strings.suffix.replace(/\s*$/, ""); } - blob.gender = state.locale[state.opt.lang]["noun-genders"][varname]; + if ("undefined" === typeof blob.gender) { + blob.gender = state.locale[state.opt.lang]["noun-genders"][varname]; + } state.output.append(blob, "literal", false, false, true); } state.output.closeLevel("empty"); @@ -8451,8 +8487,7 @@ CSL.Node.text = { func = function (state, Item, item) { var parallel_variable = this.variables[0]; if (parallel_variable === "title" - && form === "short" - && !state.opt.development_extensions.main_title_from_short_title) { + && form === "short") { parallel_variable = "shortTitle"; } state.parallel.StartVariable(parallel_variable); @@ -8551,9 +8586,10 @@ CSL.Node.text = { }; } else if (this.variables_real[0] === "hereinafter") { func = function (state, Item) { - var value = state.transform.abbrevs["default"]["hereinafter"][Item.system_id]; + var value = state.transform.abbrevs["default"]["hereinafter"][Item.id]; if (value) { state.output.append(value, this); + state.tmp.group_context.value()[2] = true; } } } else { @@ -8592,6 +8628,9 @@ CSL.Node.text = { } }; CSL.Attributes = {}; +CSL.Attributes["@gender"] = function (state, arg) { + this.gender = arg; +} CSL.Attributes["@cslid"] = function (state, arg) { this.cslid = parseInt(arg, 10); }; @@ -8718,16 +8757,6 @@ CSL.Attributes["@context"] = function (state, arg) { }; this.tests.push(func); }; -CSL.Attributes["@trigger-fields"] = function (state, arg) { - var mylst = arg.split(/\s+/); - this.generate_trigger_fields = mylst; -}; -CSL.Attributes["@type-map"] = function (state, arg) { - var mymap = arg.split(/\s+/); - this.generate_type_map = {}; - this.generate_type_map.from = mymap[0]; - this.generate_type_map.to = mymap[1]; -}; CSL.Attributes["@leading-noise-words"] = function (state, arg) { this["leading-noise-words"] = arg; }; @@ -8863,9 +8892,9 @@ CSL.Attributes["@variable"] = function (state, arg) { } break; } else if ("hereinafter" === variable) { - if (state.transform.abbrevs["default"].hereinafter[Item.system_id] + if (state.transform.abbrevs["default"].hereinafter[Item.id] && state.sys.getAbbreviation - && Item.system_id) { + && Item.id) { output = true; } break; @@ -8909,8 +8938,8 @@ CSL.Attributes["@variable"] = function (state, arg) { if (item && ["locator", "locator-revision", "first-reference-note-number", "locator-date"].indexOf(variable) > -1) { myitem = item; } - if (variable === "hereinafter" && state.sys.getAbbreviation && myitem.system_id) { - if (state.transform.abbrevs["default"].hereinafter[myitem.system_id]) { + if (variable === "hereinafter" && state.sys.getAbbreviation && myitem.id) { + if (state.transform.abbrevs["default"].hereinafter[myitem.id]) { x = true; } } else if (myitem[variable]) { @@ -9446,21 +9475,6 @@ CSL.Attributes["@text-case"] = function (state, arg) { var default_locale = state.opt["default-locale"][0].slice(0, 2); if (Item.jurisdiction) { this.strings["text-case"] = "passthrough"; - } else if (Item.language) { - m = Item.language.match(/^\s*([A-Za-z]{2})(?:$|-| )/); - if (!m) { - this.strings["text-case"] = "passthrough"; - } else if (m[1].toLowerCase() !== "en") { - this.strings["text-case"] = "passthrough"; - for (var i = 0, ilen = state.opt.english_locale_escapes.length; i < ilen; i += 1) { - var escaper = state.opt.english_locale_escapes[i]; - if (m[1].slice(0, escaper.length).toLowerCase() === escaper) { - this.strings["text-case"] = arg; - } - } - } - } else if (default_locale !== "en") { - this.strings["text-case"] = "passthrough"; } } } @@ -9475,6 +9489,11 @@ CSL.Attributes["@year-range-format"] = function (state, arg) { }; CSL.Attributes["@default-locale"] = function (state, arg) { var lst, len, pos, m, ret; + if (state.opt.development_extensions.normalize_lang_keys_to_lowercase) { + if (arg) { + arg = arg.toLowerCase(); + } + } m = arg.match(/-x-(sort|translit|translat)-/g); if (m) { for (pos = 0, len = m.length; pos < len; pos += 1) { @@ -9682,15 +9701,18 @@ CSL.Transform = function (state) { if (CSL.NUMERIC_VARIABLES.indexOf(myabbrev_family) > -1) { myabbrev_family = "number"; } - if (["publisher-place", "event-place", "jurisdiction"].indexOf(myabbrev_family) > -1) { + if (["publisher-place", "event-place", "jurisdiction", "archive-place"].indexOf(myabbrev_family) > -1) { myabbrev_family = "place"; } if (["publisher", "authority"].indexOf(myabbrev_family) > -1) { myabbrev_family = "institution-part"; } - if (["genre", "event", "medium"].indexOf(myabbrev_family) > -1) { + if (["genre", "event", "medium", "title-short"].indexOf(myabbrev_family) > -1) { myabbrev_family = "title"; } + if (["archive"].indexOf(myabbrev_family) > -1) { + myabbrev_family = "collection-title"; + } value = ""; if (state.sys.getAbbreviation) { var jurisdiction = state.transform.loadAbbreviation(Item.jurisdiction, myabbrev_family, basevalue); @@ -9715,37 +9737,57 @@ CSL.Transform = function (state) { } return value; } + function getFieldLocale(Item,field) { + var ret = state.opt["default-locale"][0].slice(0, 2) + if (Item.language) { + m = ("" + Item.language).match(/^([a-zA-Z]{2})(?:$|-.*| .*)/); + if (m) { + ret = m[1]; + } else { + ret = "tlh"; + } + } + if (Item.multi && Item.multi && Item.multi.main && Item.multi.main[field]) { + ret = Item.multi.main[field]; + } + if (state.opt.development_extensions.normalize_lang_keys_to_lowercase) { + ret = ret.toLowerCase(); + } + return ret; + }; function getTextSubField(Item, field, locale_type, use_default, stopOrig) { var m, lst, opt, o, oo, pos, key, ret, len, myret, opts; var usedOrig = stopOrig; if (!Item[field]) { return {name:"", usedOrig:stopOrig}; } - ret = {name:"", usedOrig:stopOrig}; + ret = {name:"", usedOrig:stopOrig,locale:getFieldLocale(Item,field)}; opts = state.opt[locale_type]; if (locale_type === 'locale-orig') { if (stopOrig) { ret = {name:"", usedOrig:stopOrig}; } else { - ret = {name:Item[field], usedOrig:false}; + ret = {name:Item[field], usedOrig:false, locale:getFieldLocale(Item,field)}; } return ret; } else if (use_default && ("undefined" === typeof opts || opts.length === 0)) { - return {name:Item[field], usedOrig:true}; + return {name:Item[field], usedOrig:true, locale:getFieldLocale(Item,field)}; } for (var i = 0, ilen = opts.length; i < ilen; i += 1) { opt = opts[i]; o = opt.split(/[\-_]/)[0]; if (opt && Item.multi && Item.multi._keys[field] && Item.multi._keys[field][opt]) { ret.name = Item.multi._keys[field][opt]; + ret.locale = o; break; } else if (o && Item.multi && Item.multi._keys[field] && Item.multi._keys[field][o]) { ret.name = Item.multi._keys[field][o]; + ret.locale = o; break; } } if (!ret.name && use_default) { - ret = {name:Item[field], usedOrig:true}; + ret = {name:Item[field], usedOrig:true, locale:getFieldLocale(Item,field)}; } return ret; } @@ -9816,13 +9858,10 @@ CSL.Transform = function (state) { localesets = state.opt['cite-lang-prefs'][langPrefs]; } return function (state, Item, item, usedOrig) { - var primary, secondary, tertiary, primary_tok, group_tok, key; + var primary, primary_locale, secondary, secondary_locale, tertiary, tertiary_locale, primary_tok, group_tok, key; if (!variables[0] || (!Item[variables[0]] && !Item[alternative_varname])) { return null; } - if (variables[0] === "title" && state.opt.development_extensions.main_title_from_short_title) { - alternative_varname = false; - } var slot = {primary:false, secondary:false, tertiary:false}; if (state.tmp.area.slice(-5) === "_sort") { slot.primary = 'locale-sort'; @@ -9858,6 +9897,7 @@ CSL.Transform = function (state) { } var res = getTextSubField(Item, variables[0], slot.primary, true); primary = res.name; + primary_locale = res.locale; var primaryUsedOrig = res.usedOrig; if (publisherCheck(this, Item, primary, myabbrev_family)) { return null; @@ -9867,10 +9907,12 @@ CSL.Transform = function (state) { if (slot.secondary) { res = getTextSubField(Item, variables[0], slot.secondary, false, res.usedOrig); secondary = res.name; + secondary_locale = res.locale; } if (slot.tertiary) { res = getTextSubField(Item, variables[0], slot.tertiary, false, res.usedOrig); tertiary = res.name; + tertiary_locale = res.locale; } if (myabbrev_family) { primary = abbreviate(state, Item, alternative_varname, primary, myabbrev_family, true); @@ -9885,6 +9927,7 @@ CSL.Transform = function (state) { secondary = CSL.demoteNoiseWords(state, secondary); tertiary = CSL.demoteNoiseWords(state, tertiary); } + var template_tok = CSL.Util.cloneToken(this); var primary_tok = CSL.Util.cloneToken(this); var primaryPrefix; if (slot.primary === "locale-translit") { @@ -9902,12 +9945,15 @@ CSL.Transform = function (state) { primary_tok.decorations.push(["@font-style", "italic"]) } } + if (primary_locale !== "en" && primary_tok.strings["text-case"] === "title") { + primary_tok.strings["text-case"] = "passthrough"; + } if (secondary || tertiary) { state.output.openLevel("empty"); primary_tok.strings.suffix = ""; state.output.append(primary, primary_tok); if (secondary) { - secondary_tok = CSL.Util.cloneToken(primary_tok); + secondary_tok = CSL.Util.cloneToken(template_tok); secondary_tok.strings.prefix = state.opt.citeAffixes[langPrefs][slot.secondary].prefix; secondary_tok.strings.suffix = state.opt.citeAffixes[langPrefs][slot.secondary].suffix; if (!secondary_tok.strings.prefix) { @@ -9918,6 +9964,9 @@ CSL.Transform = function (state) { secondary_tok.decorations = secondary_tok.decorations.slice(0, i).concat(secondary_tok.decorations.slice(i + 1)) } } + if (secondary_locale !== "en" && secondary_tok.strings["text-case"] === "title") { + secondary_tok.strings["text-case"] = "passthrough"; + } state.output.append(secondary, secondary_tok); var blob_obj = state.output.current.value(); var blobs_pos = state.output.current.value().blobs.length - 1; @@ -9927,7 +9976,7 @@ CSL.Transform = function (state) { } } if (tertiary) { - tertiary_tok = CSL.Util.cloneToken(primary_tok); + tertiary_tok = CSL.Util.cloneToken(template_tok); tertiary_tok.strings.prefix = state.opt.citeAffixes[langPrefs][slot.tertiary].prefix; tertiary_tok.strings.suffix = state.opt.citeAffixes[langPrefs][slot.tertiary].suffix; if (!tertiary_tok.strings.prefix) { @@ -9938,6 +9987,9 @@ CSL.Transform = function (state) { tertiary_tok.decorations = tertiary_tok.decorations.slice(0, i).concat(tertiary_tok.decorations.slice(i + 1)) } } + if (tertiary_locale !== "en" && tertiary_tok.strings["text-case"] === "title") { + tertiary_tok.strings["text-case"] = "passthrough"; + } state.output.append(tertiary, tertiary_tok); var blob_obj = state.output.current.value(); var blobs_pos = state.output.current.value().blobs.length - 1; @@ -10174,14 +10226,14 @@ CSL.Parallel.prototype.CloseVariable = function () { this.cite[this.variable] = this.data; if (this.sets.value().length > 0) { var prev = this.sets.value()[(this.sets.value().length - 1)]; - if (this.target === "front" && this.variable === "original-date") { + if (this.target === "front" && this.variable === "issued") { if (this.data.value && this.master_was_neutral_cite) { this.target = "mid"; } } if (this.target === "front") { if ((prev[this.variable] || this.data.value) && (!prev[this.variable] || this.data.value !== prev[this.variable].value)) { - if ("original-date" !== this.variable) { + if ("issued" !== this.variable) { this.in_series = false; } } @@ -10251,22 +10303,22 @@ CSL.Parallel.prototype.CloseCite = function () { has_date = false; for (pos = 0, len = this.cite.back.length; pos < len; pos += 1) { x = this.cite.back[pos]; - if (x === "original-date" && this.cite["original-date"] && this.cite["original-date"].value) { + if (x === "issued" && this.cite["issued"] && this.cite["issued"].value) { has_date = true; break; } } if (!has_date) { - this.cite.back_forceme.push("original-date"); + this.cite.back_forceme.push("issued"); } } else { - var idx = this.cite.front.indexOf("original-date"); + var idx = this.cite.front.indexOf("issued"); if (idx === -1 || this.master_was_neutral_cite) { this.cite.back_forceme = this.sets.value().slice(-1)[0].back_forceme; } if (idx > -1) { var prev = this.sets.value()[this.sets.value().length - 1]; - if (!prev["original-date"]) { + if (!prev["issued"]) { this.cite.front = this.cite.front.slice(0, idx).concat(this.cite.front.slice(idx + 1)); } } @@ -10801,22 +10853,10 @@ CSL.Util.Names.doInitialize = function (state, namelist, terminator, mode) { namelist[i] = " " + n; } } - var ret = CSL.Util.Names.stripRight(namelist.join("")); - ret = ret.replace(/\s*\-\s*/g, "-").replace(/\s+/g, " "); + var ret = namelist.join(""); + ret = ret.replace(/\s+$/,"").replace(/\s*\-\s*/g, "-").replace(/\s+/g, " "); return ret; }; -CSL.Util.Names.stripRight = function (str) { - var end, pos, len; - end = 0; - len = str.length - 1; - for (pos = len; pos > -1; pos += -1) { - if (str[pos] !== " ") { - end = pos + 1; - break; - } - } - return str.slice(0, end); -}; CSL.Util.Names.getRawName = function (name) { var ret = []; if (name.given) { @@ -11401,8 +11441,11 @@ CSL.Engine.prototype.processNumber = function (node, ItemObject, variable, type) } if (elements[i].match(/^[1-9][0-9]*$/)) { elements[i] = parseInt(elements[i], 10); - if (node) { + if (node && "undefined" === typeof node.gender) { node.gender = this.locale[this.opt.lang]["noun-genders"][variable]; + if (!node.gender) { + node.gender = ""; + } } this.tmp.shadow_numbers[variable].values.push(["NumericBlob", elements[i], node]); } else { @@ -12333,10 +12376,6 @@ CSL.Registry = function (state) { this.namereg = new CSL.Registry.NameReg(state); this.citationreg = new CSL.Registry.CitationReg(state); this.authorstrings = {}; - this.generate = {}; - this.generate.origIDs = {}; - this.generate.genIDs = {}; - this.generate.rules = []; this.mylist = []; this.myhash = {}; this.deletes = []; @@ -12453,10 +12492,6 @@ CSL.Registry.prototype.dodeletes = function (myhash) { } } delete this.registry[key]; - if (this.generate.origIDs[key]) { - delete this.generate.origIDs[key]; - delete this.generate.genIDs[key + ":gen"]; - } this.return_data.bibchange = true; } } @@ -12470,21 +12505,6 @@ CSL.Registry.prototype.doinserts = function (mylist) { item = mylist[i]; if (!this.registry[item]) { Item = this.state.retrieveItem(item); - for (j = 0, jlen = this.generate.rules.length; j < jlen; j += 1) { - if (Item.type === this.generate.rules[j].from) { - var needsRule = true; - for (k = 0, klen = this.generate.rules[j].triggers.length; k < klen; k += 1) { - if (!Item[this.generate.rules[j].triggers[k]]) { - needsRule = false; - break; - } - } - if (needsRule) { - this.generate.origIDs[item] = this.generate.rules[j]; - this.generate.genIDs[item + ":gen"] = this.generate.rules[j]; - } - } - } akey = CSL.getAmbiguousCite.call(this.state, Item); this.ambigsTouched[akey] = true; if (!Item.legislation_id) { @@ -13235,12 +13255,3 @@ CSL.Registry.CitationReg = function (state) { this.citationById = {}; this.citationByIndex = []; }; -CSL.Node.generate = { - build: function (state, target) { - if (state.build.area === "bibliography") { - var obj = this.generate_type_map; - obj.triggers = this.generate_trigger_fields; - state.registry.generate.rules.push(obj); - } - } -}; From baf772741be5574493a4d7a48a1c56a9b639b2ef Mon Sep 17 00:00:00 2001 From: aurimasv Date: Sun, 27 Jan 2013 02:34:08 -0600 Subject: [PATCH 3/6] [Zotero_TranslatorTester] Move _generateDiff and _compare out of prototype --- .../tools/testTranslators/translatorTester.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/chrome/content/zotero/tools/testTranslators/translatorTester.js b/chrome/content/zotero/tools/testTranslators/translatorTester.js index 01a07a349..c0deb002c 100644 --- a/chrome/content/zotero/tools/testTranslators/translatorTester.js +++ b/chrome/content/zotero/tools/testTranslators/translatorTester.js @@ -189,7 +189,7 @@ Zotero_TranslatorTester = function(translator, type, debugCallback) { * Removes document objects, which contain cyclic references, and other fields to be ignored from items * @param {Object} Item, in the format returned by Zotero.Item.serialize() */ -Zotero_TranslatorTester._sanitizeItem = function(item, testItem) { +Zotero_TranslatorTester._sanitizeItem = function(item, testItem, keepValidFields) { // remove cyclic references if(item.attachments && item.attachments.length) { // don't actually test URI equality @@ -244,7 +244,7 @@ Zotero_TranslatorTester._sanitizeItem = function(item, testItem) { } // remove fields to be ignored - if("accessDate" in item) delete item.accessDate; + if(!keepValidFields && "accessDate" in item) delete item.accessDate; //sort tags, if they're still there if(item.tags && typeof item.tags === "object" && "sort" in item.tags) item.tags.sort(); @@ -510,10 +510,10 @@ Zotero_TranslatorTester.prototype._checkResult = function(test, translate, retur var testItem = Zotero_TranslatorTester._sanitizeItem(test.items[i], true); var translatedItem = Zotero_TranslatorTester._sanitizeItem(translate.newItems[i]); - if(!this._compare(testItem, translatedItem)) { + if(!Zotero_TranslatorTester._compare(testItem, translatedItem)) { // Show diff this._debug(this, "TranslatorTester: Data mismatch detected:"); - this._debug(this, this._generateDiff(testItem, translatedItem)); + this._debug(this, Zotero_TranslatorTester._generateDiff(testItem, translatedItem)); // Save items. This makes it easier to correct tests automatically. var m = translate.newItems.length; @@ -598,7 +598,7 @@ Zotero_TranslatorTester.prototype._createTest = function(translate, multipleMode /** * Compare items or sets thereof */ -Zotero_TranslatorTester.prototype._compare = function(a, b) { +Zotero_TranslatorTester._compare = function(a, b) { // If a is false, comparisons always succeed. This allows us to explicitly set that // certain properties are allowed. if(a === false) return true; @@ -612,7 +612,7 @@ Zotero_TranslatorTester.prototype._compare = function(a, b) { for(var key in a) { if(!a.hasOwnProperty(key)) continue; if(a[key] !== false && !b.hasOwnProperty(key)) return false; - if(!this._compare(a[key], b[key])) return false; + if(!Zotero_TranslatorTester._compare(a[key], b[key])) return false; } for(var key in b) { if(!b.hasOwnProperty(key)) continue; @@ -629,7 +629,7 @@ Zotero_TranslatorTester.prototype._compare = function(a, b) { /** * Generate a diff of items */ -Zotero_TranslatorTester.prototype._generateDiff = new function() { +Zotero_TranslatorTester._generateDiff = new function() { function show(a, action, prefix, indent) { if((typeof a === "object" && a !== null) || typeof a === "function") { var isArray = Object.prototype.toString.apply(a) === "[object Array]", From 56bb5b17ad386d67a1ef52987a4ead38a862f47f Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Mon, 28 Jan 2013 22:44:02 -0500 Subject: [PATCH 4/6] Better MIME type detection of Office files For at least one Windows user, a .docx file was being interpreted as text/plain. Instead of relying entirely on the system, hard-code some extensions we know. (More can be added.) Also: - Determine MIME type when opening files instead of using stored type, since we might have gotten smarter --- chrome/content/zotero/xpcom/mime.js | 76 +++++++++++++++++++++++------ chrome/content/zotero/zoteroPane.js | 12 ++--- 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/chrome/content/zotero/xpcom/mime.js b/chrome/content/zotero/xpcom/mime.js index 7a64e5f24..9627e6e26 100644 --- a/chrome/content/zotero/xpcom/mime.js +++ b/chrome/content/zotero/xpcom/mime.js @@ -29,11 +29,8 @@ Zotero.MIME = new function(){ this.getPrimaryExtension = getPrimaryExtension; this.sniffForMIMEType = sniffForMIMEType; this.sniffForBinary = sniffForBinary; - this.getMIMETypeFromData = getMIMETypeFromData; - this.getMIMETypeFromFile = getMIMETypeFromFile; this.hasNativeHandler = hasNativeHandler; this.hasInternalHandler = hasInternalHandler; - this.fileHasInternalHandler = fileHasInternalHandler; // Magic numbers var _snifferEntries = [ @@ -55,6 +52,41 @@ Zotero.MIME = new function(){ ]; + var _extensions = { + // MS Office + 'doc': 'application/msword', + 'dot': 'application/msword', + 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dotx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'docm': 'application/vnd.ms-word.document.macroEnabled.12', + 'dotm': 'application/vnd.ms-word.template.macroEnabled.12', + 'xls': 'application/vnd.ms-excel', + 'xlt': 'application/vnd.ms-excel', + 'xla': 'application/vnd.ms-excel', + 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xltx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xlsm': 'application/vnd.ms-excel.sheet.macroEnabled.12', + 'xltm': 'application/vnd.ms-excel.template.macroEnabled.12', + 'xlam': 'application/vnd.ms-excel.addin.macroEnabled.12', + 'xlsb': 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'ppt': 'application/vnd.ms-powerpoint', + 'pot': 'application/vnd.ms-powerpoint', + 'pps': 'application/vnd.ms-powerpoint', + 'ppa': 'application/vnd.ms-powerpoint', + 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'potx': 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppsx': 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppam': 'application/vnd.ms-powerpoint.addin.macroEnabled.12', + 'pptm': 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', + 'potm': 'application/vnd.ms-powerpoint.template.macroEnabled.12', + 'ppsm': 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', + + // OpenOffice/LibreOffice + 'odt': 'application/vnd.oasis.opendocument.text', + + 'pdf': 'application/pdf' + }; + var _textTypes = { 'application/xhtml+xml': true, 'application/xml': true, @@ -245,22 +277,19 @@ Zotero.MIME = new function(){ * * ext is an optional file extension hint if data sniffing is unsuccessful */ - function getMIMETypeFromData(str, ext){ + this.getMIMETypeFromData = function (str, ext){ var mimeType = sniffForMIMEType(str); if (mimeType){ Zotero.debug('Detected MIME type ' + mimeType); return mimeType; } - try { - if (ext) { - var mimeType = Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"] - .getService(Components.interfaces.nsIMIMEService).getTypeFromExtension(ext); - Zotero.debug('Got MIME type ' + mimeType + ' from extension'); + if (ext) { + mimeType = this.getMIMETypeFromExtension(ext); + if (mimeType) { return mimeType; } } - catch (e) {} var mimeType = sniffForBinary(str); Zotero.debug('Cannot determine MIME type from magic number or extension -- settling for ' + mimeType); @@ -268,15 +297,34 @@ Zotero.MIME = new function(){ } + this.getMIMETypeFromExtension = function (ext) { + var type = false; + + if (_extensions[ext]) { + var type = _extensions[ext]; + } + else { + try { + var type = Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"] + .getService(Components.interfaces.nsIMIMEService).getTypeFromExtension(ext); + } + catch (e) {} + } + + Zotero.debug("Got MIME type " + type + " from extension '" + ext + "'"); + return type; + } + + /* * Try to determine the MIME type of the file, using a few different * techniques */ - function getMIMETypeFromFile(file){ + this.getMIMETypeFromFile = function (file) { var str = Zotero.File.getSample(file); var ext = Zotero.File.getExtension(file); - return getMIMETypeFromData(str, ext); + return this.getMIMETypeFromData(str, ext); } @@ -378,8 +426,8 @@ Zotero.MIME = new function(){ } - function fileHasInternalHandler(file){ - var mimeType = getMIMETypeFromFile(file); + this.fileHasInternalHandler = function (file){ + var mimeType = this.getMIMETypeFromFile(file); var ext = Zotero.File.getExtension(file); return hasInternalHandler(mimeType, ext); } diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js index 4e2177a57..50e5dfa40 100644 --- a/chrome/content/zotero/zoteroPane.js +++ b/chrome/content/zotero/zoteroPane.js @@ -3443,14 +3443,10 @@ var ZoteroPane = new function() if(forceExternalViewer !== undefined) { var externalViewer = forceExternalViewer; } else { - var mimeType = attachment.attachmentMIMEType; - // If no MIME type specified, try to detect again (I guess in case - // we've gotten smarter since the file was imported?) - if (!mimeType) { - mimeType = Zotero.MIME.getMIMETypeFromFile(file); - - // TODO: update DB with new info - } + var mimeType = Zotero.MIME.getMIMETypeFromFile(file); + + //var mimeType = attachment.attachmentMIMEType; + // TODO: update DB with new info if changed? var ext = Zotero.File.getExtension(file); var externalViewer = Zotero.isStandalone || (!Zotero.MIME.hasNativeHandler(mimeType, ext) && From 7cd3479094e6f05a52e8ccc3c0d8ccb7a7d17563 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Tue, 29 Jan 2013 04:03:56 -0500 Subject: [PATCH 5/6] Use eraseByURI() instead of eraseByURIPrefix(), and fix params --- .../content/zotero/xpcom/data/collection.js | 2 +- chrome/content/zotero/xpcom/data/item.js | 2 +- chrome/content/zotero/xpcom/data/relations.js | 19 ++++++++++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/chrome/content/zotero/xpcom/data/collection.js b/chrome/content/zotero/xpcom/data/collection.js index 95fefa2f7..e257bc97b 100644 --- a/chrome/content/zotero/xpcom/data/collection.js +++ b/chrome/content/zotero/xpcom/data/collection.js @@ -966,7 +966,7 @@ Zotero.Collection.prototype.erase = function(deleteItems) { // Remove relations var uri = Zotero.URI.getCollectionURI(this); - Zotero.Relations.eraseByURIPrefix(uri); + Zotero.Relations.eraseByURI(uri); var placeholders = collections.map(function () '?').join(); diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index 39673ad2a..b4ca880bd 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -4170,7 +4170,7 @@ Zotero.Item.prototype.erase = function() { // Remove relations (except for merge tracker) var uri = Zotero.URI.getItemURI(this); - Zotero.Relations.eraseByURIPrefix(uri, [Zotero.Relations.deletedItemPredicate]); + Zotero.Relations.eraseByURI(uri, [Zotero.Relations.deletedItemPredicate]); Zotero.DB.query('DELETE FROM annotations WHERE itemID=?', this.id); Zotero.DB.query('DELETE FROM highlights WHERE itemID=?', this.id); diff --git a/chrome/content/zotero/xpcom/data/relations.js b/chrome/content/zotero/xpcom/data/relations.js index 532489073..be26ba280 100644 --- a/chrome/content/zotero/xpcom/data/relations.js +++ b/chrome/content/zotero/xpcom/data/relations.js @@ -185,8 +185,10 @@ Zotero.Relations = new function () { var sql = "SELECT ROWID FROM relations WHERE (subject LIKE ? OR object LIKE ?)"; var params = [prefix, prefix]; if (ignorePredicates) { - sql += " AND predicate != ?"; - params = params.concat(ignorePredicates); + for each(var ignorePredicate in ignorePredicates) { + sql += " AND predicate != ?"; + params.push(ignorePredicate); + } } var ids = Zotero.DB.columnQuery(sql, params); @@ -199,11 +201,18 @@ Zotero.Relations = new function () { } - this.eraseByURI = function (uri) { + this.eraseByURI = function (uri, ignorePredicates) { Zotero.DB.beginTransaction(); - var sql = "SELECT ROWID FROM relations WHERE subject=? OR object=?"; - var ids = Zotero.DB.columnQuery(sql, [uri, uri]); + var sql = "SELECT ROWID FROM relations WHERE (subject=? OR object=?)"; + var params = [uri, uri]; + if (ignorePredicates) { + for each(var ignorePredicate in ignorePredicates) { + sql += " AND predicate != ?"; + params.push(ignorePredicate); + } + } + var ids = Zotero.DB.columnQuery(sql, params); for each(var id in ids) { var relation = this.get(id); From 6dd420458fbac30f4d2def9200e2f3e265360156 Mon Sep 17 00:00:00 2001 From: Simon Kornblith Date: Tue, 29 Jan 2013 17:43:30 -0500 Subject: [PATCH 6/6] Detect CAPTCHA --- chrome/content/zotero/recognizePDF.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chrome/content/zotero/recognizePDF.js b/chrome/content/zotero/recognizePDF.js index dae4c2951..ae2fcdb63 100644 --- a/chrome/content/zotero/recognizePDF.js +++ b/chrome/content/zotero/recognizePDF.js @@ -488,7 +488,8 @@ Zotero_RecognizePDF.Recognizer.prototype._queryGoogle = function() { Zotero_RecognizePDF.Recognizer.prototype._scrape = function(/**Zotero.Translate*/ translate) { if(this._hiddenBrowser.contentDocument.location.href == "about:blank") return; - if(this._hiddenBrowser.contentDocument.title == "403 Forbidden") { + if(Zotero.Utilities.xpath(this._hiddenBrowser.contentDocument, "//form[@action='Captcha']").length || + this._hiddenBrowser.contentDocument.location.toString().indexOf("/sorry") !== -1) { // hit the captcha /* var forms = this._hiddenBrowser.contentDocument.getElementsByTagName("form");