- update citeproc-js to 1.0.76

- fix issues with RTF export of brackets

From 1.0.71:
Variables (including names) should be (and have been) suppressed when
rendered via the cs:substitute node of cs:names.  Prior to this patch,
however, citeproc-js was unconditionally suppressing name variables
after their first use within a given cite, and this behavior differed
from the Zotero CSL 0.8.1 processor.  This patch restores the original
behavior, allowing names rendered outside of cs:substitute to be used
repeatedly within a cite.  (The only exception to this behavior is a
name rendered with et-al-min=1 and et-al-use-first=1, which will be
clipped from subsequent output within the same cite.)

The processor was using the localized close-inner-quote character for
apostrophes.  This caused problems in styles that use alternative
quotation marks.  The processor now uses a hard-coded apostrophe
character for apostrophes.

A bug in the normalization of names, for disambiguation purposes, that
contain punctuation or extraneous spaces has been fixed.

From 1.0.72:
Allow simple range, comma, and ampersand joins in the input to
cs:number, to permit "1st-2nd",  "xi-xv", etc.  When multiple numbers
are given, the following operations are performed: (1) ranges are
expanded and the numbers are converted to a list; (2) the resulting
list is sorted; (3) duplicates are eliminated; (4) ranges are
truncated; (5) numeric formatting is performed; and (6) appropriate
punctuation is applied to the result. (As of this writing, the use of
multiple numbers with cs:number is not covered by the CSL 1.0
specification, so this is an anticipatory change.  It is consistent
with the CSL 1.0 schema, however, and does not have any effect on
single input numbers. Production use of multiple number, issue,
volume, and edition variables should await the formal approval of a
CSL 1.0 schema change to allow the use of these variables with
cs:label, for contextual pluralization of any associated label.)

Eliminate space following a trailing apostrophe on a dropping-
particle, when immediately followed by the family name part in
rendered output.

Recognize multiple parameters to a position attribute on cs:if and
cs:else-if, per the CSL 1.0 schema.  For the fix, we eliminate cutted-
and-pasteded code from node_if.js and node_elseif.js, and consolidate
all position node-level position logic in attributes.js.

From 1.0.73:
Limit the recognition of multiple numbers to cases in which they are
separated by at least one space, to prevent the accidental
reformatting of things like "Document no. 1-3752,42".

From 1.0.74:
Recognize new Khmer locale for CSL provided by Hem Sras.

When parsing number ranges in the input to cs:number, abort parsing
when spread of range is over an arbitrary limit of 1000.

Support names-use-last attribute on cs:key. (Anticipatory change to
support upcoming change to CSL schema and specification.)

Use unicode ellipsis character rather than (nonexistent) locale term
when splicing author listings trucated with et-al-use-last.

From 1.0.75:
Do not apply decorative formatting to name suffixes.

Fix breakage in ordinal suffix formatting for days in a date.

For an all-lowercase name suffix (such as an explicit "et al."),
exclude the suffix from the name for disambiguation purposes, and
include it in the strict short form of the name in the short form of a
citation.

Add and recognize delimiter-precedes-et-al attribute, in line with
draft CSL proposal.

Implement grammatical gender sensitivity for ordinal suffixes, in line
with draft CSL proposal.

From 1.0.76:
Fix bug in locale processing, arising from the previous release, that
could trigger a processor crash.
This commit is contained in:
Simon Kornblith 2010-11-20 22:37:38 +00:00
parent 3a9adcc25e
commit 87363fbe2e

View file

@ -57,6 +57,7 @@ if (!Array.indexOf) {
};
}
var CSL = {
GENDERS: ["masculine", "feminine"],
ERROR_NO_RENDERED_FORM: 1,
PREVIEW: "Just for laughs.",
ASSUME_ALL_ITEMS_REGISTERED: 2,
@ -114,6 +115,7 @@ var CSL = {
NAME_ATTRIBUTES: [
"and",
"delimiter-precedes-last",
"delimiter-precedes-et-al",
"initialize-with",
"name-as-sort-order",
"sort-separator",
@ -259,6 +261,7 @@ var CSL = {
is: "is_IS",
it: "it_IT",
ja: "ja_JP",
kh: "kh_KH",
ko: "ko_KR",
mn: "mn_MN",
nb: "nb_NO",
@ -283,19 +286,12 @@ var CSL = {
};
CSL.TERMINAL_PUNCTUATION_REGEXP = new RegExp("^([" + CSL.TERMINAL_PUNCTUATION.slice(0, -1).join("") + "])(.*)");
CSL.CLOSURES = new RegExp(".*[\\]\\)]");
if ("undefined" === typeof console) {
CSL.debug = function () {};
CSL.error = function (str) {
throw "CSL error: " + str;
};
} else {
CSL.debug = function (str) {
CSL.debug = function (str) {
Zotero.debug("CSL: " + str);
};
CSL.error = function (str) {
Zotero.debug("CSL error: " + str);
};
}
};
CSL.error = function (str) {
throw "CSL error: " + str;
};
var CSL_E4X = function () {};
CSL_E4X.prototype.clean = function (xml) {
xml = xml.replace(/<\?[^?]+\?>/g, "");
@ -760,6 +756,16 @@ CSL.Output.Queue.prototype.renderBlobs = function (blobs, delim) {
blobs[pos].checkNext(blobs[(pos + 1)]);
}
}
var doit = true;
for (pos = blobs.length - 1; pos > 0; pos += -1) {
if (blobs[pos].checkLast) {
if (doit && blobs[pos].checkLast(blobs[pos - 1])) {
doit = false;
}
} else {
doit = true;
}
}
len = blobs.length;
for (pos = 0; pos < len; pos += 1) {
blob = blobs[pos];
@ -770,7 +776,7 @@ CSL.Output.Queue.prototype.renderBlobs = function (blobs, delim) {
ret += txt_esc(use_delim);
ret += blob;
} else if (blob.status !== CSL.SUPPRESS) {
str = blob.formatter.format(blob.num);
str = blob.formatter.format(blob.num, blob.gender);
if (blob.strings["text-case"]) {
str = CSL.Output.Formatters[blob.strings["text-case"]](this.state, str);
}
@ -789,7 +795,7 @@ CSL.Output.Queue.prototype.renderBlobs = function (blobs, delim) {
} else if (blob.status === CSL.START) {
ret += "";
} else if (blob.status === CSL.SEEN) {
ret += blob.successor_prefix;
ret += blob.splice_prefix;
}
ret += str;
}
@ -1065,7 +1071,7 @@ CSL.localeResolve = function (langstr) {
return ret;
};
CSL.localeSet = function (sys, myxml, lang_in, lang_out) {
var blob, locale, nodes, attributes, pos, ppos, term, form, termname, styleopts, attr, date, attrname, len;
var blob, locale, nodes, attributes, pos, ppos, term, form, termname, styleopts, attr, date, attrname, len, genderform, target;
lang_in = lang_in.replace("_", "-");
lang_out = lang_out.replace("_", "-");
if (!this.locale[lang_out]) {
@ -1091,22 +1097,46 @@ CSL.localeSet = function (sys, myxml, lang_in, lang_out) {
}
nodes = sys.xml.getNodesByName(locale, 'term');
for (pos = 0, len = sys.xml.numberofnodes(nodes); pos < len; pos += 1) {
if (true) {
term = nodes[pos];
termname = sys.xml.getAttributeValue(term, 'name');
if ("undefined" === typeof this.locale[lang_out].terms[termname]) {
this.locale[lang_out].terms[termname] = {};
}
form = "long";
genderform = false;
if (sys.xml.getAttributeValue(term, 'form')) {
form = sys.xml.getAttributeValue(term, 'form');
}
if (sys.xml.numberofnodes(sys.xml.getNodesByName(term, 'multiple'))) {
this.locale[lang_out].terms[termname][form] = [];
this.locale[lang_out].terms[sys.xml.getAttributeValue(term, 'name')][form][0] = sys.xml.getNodeValue(term, 'single');
this.locale[lang_out].terms[sys.xml.getAttributeValue(term, 'name')][form][1] = sys.xml.getNodeValue(term, 'multiple');
if (sys.xml.getAttributeValue(term, 'gender-form')) {
genderform = sys.xml.getAttributeValue(term, 'gender-form');
}
if (sys.xml.getAttributeValue(term, 'gender')) {
this.opt["noun-genders"][termname] = sys.xml.getAttributeValue(term, 'gender');
}
if (genderform) {
this.locale[lang_out].terms[termname][genderform] = {};
this.locale[lang_out].terms[termname][genderform][form] = [];
target = this.locale[lang_out].terms[termname][genderform];
} else {
this.locale[lang_out].terms[sys.xml.getAttributeValue(term, 'name')][form] = sys.xml.getNodeValue(term);
this.locale[lang_out].terms[termname][form] = [];
target = this.locale[lang_out].terms[termname];
}
if (sys.xml.numberofnodes(sys.xml.getNodesByName(term, 'multiple'))) {
target[form][0] = sys.xml.getNodeValue(term, 'single');
target[form][1] = sys.xml.getNodeValue(term, 'multiple');
} else {
target[form] = sys.xml.getNodeValue(term);
}
}
for (termname in this.locale[lang_out].terms) {
for (var i = 0, ilen = 2; i < ilen; i += 1) {
genderform = CSL.GENDERS[i];
if (this.locale[lang_out].terms[termname][genderform]) {
for (form in this.locale[lang_out].terms[termname]) {
if (!this.locale[lang_out].terms[termname][genderform][form]) {
this.locale[lang_out].terms[termname][genderform][form] = this.locale[lang_out].terms[termname][form];
}
}
}
}
}
@ -1623,7 +1653,7 @@ CSL.dateParser = function (txt) {
};
CSL.Engine = function (sys, style, lang, xmlmode) {
var attrs, langspec, localexml, locale;
this.processor_version = "1.0.70";
this.processor_version = "1.0.76";
this.csl_version = "1.0";
this.sys = sys;
this.sys.xml = new CSL.System.Xml.Parsing();
@ -1665,17 +1695,14 @@ CSL.Engine = function (sys, style, lang, xmlmode) {
lang = this.opt["default-locale"][0];
langspec = CSL.localeResolve(lang);
this.opt.lang = langspec.best;
if (!CSL.locale[langspec.best]) {
localexml = sys.xml.makeXml(sys.retrieveLocale(langspec.best));
CSL.localeSet.call(CSL, sys, localexml, langspec.best, langspec.best);
}
this.locale = {};
locale = sys.xml.makeXml();
if (!this.locale[langspec.best]) {
localexml = sys.xml.makeXml(sys.retrieveLocale(langspec.best));
CSL.localeSet.call(this, sys, localexml, langspec.best, langspec.best);
}
CSL.localeSet.call(this, sys, this.cslXml, "", langspec.best);
CSL.localeSet.call(this, sys, this.cslXml, langspec.bare, langspec.best);
CSL.localeSet.call(this, sys, this.cslXml, langspec.best, langspec.best);
}
this.buildTokenLists("citation");
this.buildTokenLists("bibliography");
this.configureTokenLists();
@ -1822,10 +1849,10 @@ CSL.Engine.prototype.setLangTagsForCslTranslation = function (tags) {
this.opt['locale-sec'].push(tags[i]);
}
}
CSL.Engine.prototype.getTerm = function (term, form, plural) {
var ret = CSL.Engine.getField(CSL.LOOSE, this.locale[this.opt.lang].terms, term, form, plural);
CSL.Engine.prototype.getTerm = function (term, form, plural, gender, loose) {
var ret = CSL.Engine.getField(CSL.LOOSE, this.locale[this.opt.lang].terms, term, form, plural, gender);
if (typeof ret === "undefined") {
ret = CSL.Engine.getField(CSL.STRICT, CSL.locale[this.opt.lang].terms, term, form, plural);
ret = CSL.Engine.getField(CSL.STRICT, this.locale[this.opt.lang].terms, term, form, plural, gender);
}
if (ret) {
this.tmp.cite_renders_content = true;
@ -1843,7 +1870,7 @@ CSL.Engine.prototype.getOpt = function (arg) {
if ("undefined" !== typeof this.locale[this.opt.lang].opts[arg]) {
return this.locale[this.opt.lang].opts[arg];
} else {
return CSL.locale[this.opt.lang].opts[arg];
return this.locale[this.opt.lang].opts[arg];
}
};
CSL.Engine.prototype.getVariable = function (Item, varname, form, plural) {
@ -1856,16 +1883,21 @@ CSL.Engine.prototype.getDateNum = function (ItemField, partname) {
return ItemField[partname];
}
};
CSL.Engine.getField = function (mode, hash, term, form, plural) {
var ret, forms, f, pos, len;
CSL.Engine.getField = function (mode, hash, term, form, plural, gender) {
var ret, forms, f, pos, len, hashterm;
ret = "";
if ("undefined" === typeof hash[term]) {
if (mode === CSL.STRICT) {
throw "Error in getField: term\"" + term + "\" does not exist.";
throw "Error in getField: term \"" + term + "\" does not exist.";
} else {
return undefined;
}
}
if (gender && hash[term][gender]) {
hashterm = hash[term][gender];
} else {
hashterm = hash[term];
}
forms = [];
if (form === "symbol") {
forms = ["symbol", "short"];
@ -1878,16 +1910,16 @@ CSL.Engine.getField = function (mode, hash, term, form, plural) {
len = forms.length;
for (pos = 0; pos < len; pos += 1) {
f = forms[pos];
if ("string" === typeof hash[term] || "number" === typeof hash[term]) {
ret = hash[term];
} else if ("undefined" !== typeof hash[term][f]) {
if ("string" === typeof hash[term][f] || "number" === typeof hash[term][f]) {
ret = hash[term][f];
if ("string" === typeof hashterm || "number" === typeof hashterm) {
ret = hashterm;
} else if ("undefined" !== typeof hashterm[f]) {
if ("string" === typeof hashterm[f] || "number" === typeof hashterm[f]) {
ret = hashterm[f];
} else {
if ("number" === typeof plural) {
ret = hash[term][f][plural];
ret = hashterm[f][plural];
} else {
ret = hash[term][f][0];
ret = hashterm[f][0];
}
}
break;
@ -2095,6 +2127,7 @@ CSL.Engine.Opt = function () {
this["locale-sec"] = [];
this["locale-name"] = [];
this["default-locale"] = ["en"];
this["noun-genders"] = {};
this.update_mode = CSL.NONE;
this.bib_mode = CSL.NONE;
this.sort_citations = false;
@ -2974,7 +3007,6 @@ CSL.getCitationCluster = function (inputList, citationID) {
objects.push(compie);
}
}
composite.reverse();
llen = composite.length;
for (ppos = 0; ppos < llen; ppos += 1) {
obj = composite[ppos];
@ -3063,6 +3095,7 @@ CSL.citeEnd = function (Item) {
this.tmp.last_suffix_used = this.tmp.suffix.value();
this.tmp.last_years_used = this.tmp.years_used.slice();
this.tmp.last_names_used = this.tmp.names_used.slice();
this.tmp.cut_var = false;
if (this.tmp.disambig_restore && this.registry.registry[Item.id]) {
this.registry.registry[Item.id].disambig = this.tmp.disambig_restore;
}
@ -3080,6 +3113,7 @@ CSL.Node.bibliography = {
state.fixOpt(this, "name-form", "form");
state.fixOpt(this, "and", "and");
state.fixOpt(this, "delimiter-precedes-last", "delimiter-precedes-last");
state.fixOpt(this, "delimiter-precedes-et-al", "delimiter-precedes-et-al");
state.fixOpt(this, "initialize-with", "initialize-with");
state.fixOpt(this, "name-as-sort-order", "name-as-sort-order");
state.fixOpt(this, "sort-separator", "sort-separator");
@ -3131,6 +3165,7 @@ CSL.Node.citation = {
state.fixOpt(this, "name-form", "form");
state.fixOpt(this, "and", "and");
state.fixOpt(this, "delimiter-precedes-last", "delimiter-precedes-last");
state.fixOpt(this, "delimiter-precedes-et-al", "delimiter-precedes-et-al");
state.fixOpt(this, "initialize-with", "initialize-with");
state.fixOpt(this, "name-as-sort-order", "name-as-sort-order");
state.fixOpt(this, "sort-separator", "sort-separator");
@ -3308,10 +3343,16 @@ CSL.Node["date-part"] = {
}
}
state.parallel.AppendToVariable(value);
var monthnameid = ""+state.tmp.date_object.month;
while (monthnameid.length < 2) {
monthnameid = "0"+monthnameid;
}
monthnameid = "month-"+monthnameid;
var gender = state.opt["noun-genders"][monthnameid];
if (this.strings.form) {
value = CSL.Util.Dates[this.strings.name][this.strings.form](state, value);
value = CSL.Util.Dates[this.strings.name][this.strings.form](state, value, gender);
if (value_end) {
value_end = CSL.Util.Dates[this.strings.name][this.strings.form](state, value_end);
value_end = CSL.Util.Dates[this.strings.name][this.strings.form](state, value_end, gender);
}
}
state.output.openLevel("empty");
@ -3409,34 +3450,6 @@ CSL.Node["else-if"] = {
build: function (state, target) {
var func, tryposition;
if (this.tokentype === CSL.START || this.tokentype === CSL.SINGLETON) {
if ("number" === typeof this.strings.position) {
tryposition = this.strings.position;
func = function (state, Item, item) {
if (item && "undefined" === typeof item.position) {
item.position = 0;
}
if (item && typeof item.position === "number") {
if (item.position === 0 && tryposition === 0) {
return true;
} else if (tryposition > 0 && item.position >= tryposition) {
return true;
}
} else if (tryposition === 0) {
return true;
}
return false;
};
this.tests.push(func);
}
if (this.strings["near-note-distance-check"]) {
func = function (state, Item, item) {
if (item && item["near-note"]) {
return true;
}
return false;
};
this.tests.push(func);
}
if (! this.evaluator) {
this.evaluator = state.fun.match.any;
}
@ -3544,36 +3557,7 @@ CSL.Node.group = {
};
CSL.Node["if"] = {
build: function (state, target) {
var tryposition, func;
if (this.tokentype === CSL.START || this.tokentype === CSL.SINGLETON) {
if ("number" === typeof this.strings.position) {
tryposition = this.strings.position;
func = function (state, Item, item) {
if (item && "undefined" === typeof item.position) {
item.position = 0;
}
if (item && typeof item.position === "number") {
if (item.position === 0 && tryposition === 0) {
return true;
} else if (tryposition > 0 && item.position >= tryposition) {
return true;
}
} else if (tryposition === 0) {
return true;
}
return false;
};
this.tests.push(func);
}
if (this.strings["near-note-distance-check"]) {
func = function (state, Item, item) {
if (item && item["near-note"]) {
return true;
}
return false;
};
this.tests.push(func);
}
if (!this.evaluator) {
this.evaluator = state.fun.match.any;
}
@ -3651,6 +3635,7 @@ CSL.Node.key = {
start_key = new CSL.Token("key", CSL.START);
start_key.strings["et-al-min"] = this.strings["et-al-min"];
start_key.strings["et-al-use-first"] = this.strings["et-al-use-first"];
start_key.strings["et-al-use-last"] = this.strings["et-al-use-last"];
func = function (state, Item) {
state.tmp.done_vars = [];
};
@ -3672,6 +3657,9 @@ CSL.Node.key = {
if (this.strings["et-al-use-first"]) {
state.tmp["et-al-use-first"] = this.strings["et-al-use-first"];
}
if (this.strings["et-al-use-last"]) {
state.tmp["et-al-use-last"] = this.strings["et-al-use-last"];
}
};
start_key.execs.push(func);
target.push(start_key);
@ -3818,6 +3806,7 @@ CSL.Node.key = {
func = function (state, Item) {
state.tmp["et-al-min"] = false;
state.tmp["et-al-use-first"] = false;
state.tmp["et-al-use-last"] = false;
state.tmp.sort_key_flag = false;
};
end_key.execs.push(func);
@ -4006,6 +3995,7 @@ CSL.Node.name = {
state.fixOpt(this, "name-form", "form");
state.fixOpt(this, "and", "and");
state.fixOpt(this, "delimiter-precedes-last", "delimiter-precedes-last");
state.fixOpt(this, "delimiter-precedes-et-al", "delimiter-precedes-et-al");
state.fixOpt(this, "initialize-with", "initialize-with");
state.fixOpt(this, "name-as-sort-order", "name-as-sort-order");
state.fixOpt(this, "sort-separator", "sort-separator");
@ -4049,7 +4039,7 @@ CSL.Node.name = {
state.tmp["et-al-use-first"] = this.strings["et-al-use-first"];
}
}
if ("undefined" !== this.strings["et-al-use-last"]) {
if ("undefined" !== typeof this.strings["et-al-use-last"]) {
state.tmp["et-al-use-last"] = this.strings["et-al-use-last"];
}
};
@ -4240,7 +4230,7 @@ CSL.Node.names = {
}
}
func = function (state, Item, item) {
var common_term, nameset, name, local_count, withtoken, namesetIndex, lastones, currentones, compset, display_names, suppress_min, suppress_condition, sane, discretionary_names_length, overlength, et_al, and_term, outer_and_term, use_first, append_last, delim, param, paramx, val, s, myform, myinitials, termname, form, namepart, namesets, llen, ppos, label, plural, last_variable, cutinfo, cut_var, obj, et_al_pers, et_al_org, and_pers, and_org, with_term, chk, apply_ellipsis;
var common_term, nameset, name, local_count, withtoken, namesetIndex, lastones, currentones, compset, display_names, suppress_min, suppress_condition, sane, discretionary_names_length, overlength, et_al, and_term, outer_and_term, use_first, append_last, delim, param, paramx, val, s, myform, myinitials, termname, form, namepart, namesets, llen, ppos, label, plural, last_variable, cutinfo, obj, et_al_pers, et_al_org, and_pers, and_org, with_term, chk, apply_ellipsis;
namesets = [];
common_term = CSL.Util.Names.getCommonTerm(state, state.tmp.value);
if (common_term) {
@ -4250,10 +4240,14 @@ CSL.Node.names = {
}
len = namesets.length;
if (namesets.length && (state.tmp.area === "bibliography" || state.tmp.area === "bibliography_sort" || (state.tmp.area && state.opt.xclass === "note"))) {
cut_var = namesets[0].variable;
if (state.tmp["et-al-min"] === 1 && state.tmp["et-al-use-first"] === 1) {
state.tmp.cut_var = namesets[0].variable;
}
cutinfo = state.tmp.names_cut;
if (namesets[0].species === "pers") {
namesets[0].names = namesets[0].names.slice(cutinfo.counts[cut_var]);
if (state.tmp.cut_var) {
namesets[0].names = namesets[0].names.slice(cutinfo.counts[state.tmp.cut_var]);
}
if (namesets[0].names.length === 0) {
if (namesets[0].free_agent_start) {
namesets[1].free_agent_start = true;
@ -4269,10 +4263,10 @@ CSL.Node.names = {
namesets[0].organization_last = true;
}
}
if (cutinfo.used === cut_var) {
llen = cutinfo.variable[cut_var].length - 1;
if (state.tmp.cut_var && cutinfo.used === state.tmp.cut_var) {
llen = cutinfo.variable[state.tmp.cut_var].length - 1;
for (ppos = llen; ppos > -1; ppos += -1) {
obj = cutinfo.variable[cut_var][ppos];
obj = cutinfo.variable[state.tmp.cut_var][ppos];
obj[0].blobs = obj[0].blobs.slice(0, obj[1]).concat(obj[0].blobs.slice(obj[1] + 1));
}
}
@ -4291,7 +4285,8 @@ CSL.Node.names = {
llen = nameset.names.length;
for (ppos = 0; ppos < llen; ppos += 1) {
name = nameset.names[ppos];
if (name["parse-names"] || state.opt["parse-names"]) {
if (state.opt["parse-names"]
&& name["parse-names"] !== 0) {
state.parseName(name);
}
if (name.family && name.family.length && name.family.slice(0, 1) === '"' && name.family.slice(-1)) {
@ -4309,8 +4304,17 @@ CSL.Node.names = {
if (!state.output.getToken("et-al-pers")) {
state.output.addToken("et-al-pers");
}
var nametok = state.output.getToken("name");
if (nametok.strings["delimiter-precedes-et-al"] === "always") {
state.output.getToken("et-al-pers").strings["prefix-single"] = nametok.strings.delimiter;
state.output.getToken("et-al-pers").strings["prefix-multiple"] = nametok.strings.delimiter;
} else if (nametok.strings["delimiter-precedes-et-al"] === "never") {
state.output.getToken("et-al-pers").strings["prefix-single"] = " ";
state.output.getToken("et-al-pers").strings["prefix-multiple"] = ", ";
state.output.getToken("et-al-pers").strings["prefix-multiple"] = " ";
} else {
state.output.getToken("et-al-pers").strings["prefix-single"] = " ";
state.output.getToken("et-al-pers").strings["prefix-multiple"] = nametok.strings.delimiter;
}
et_al_pers = state.getTerm("et-al", "long", 0);
if ("undefined" !== typeof state.output.getToken("et-al-pers").strings.term) {
et_al_pers = state.output.getToken("et-al-pers").strings.term;
@ -4356,6 +4360,7 @@ CSL.Node.names = {
state.output.addToken("dropping-particle", false, state.output.getToken("family"));
state.output.addToken("non-dropping-particle", false, state.output.getToken("family"));
state.output.addToken("suffix", false, state.output.getToken("family"));
state.output.getToken("suffix").decorations = [];
state.output.openLevel("term-join");
len = namesets.length;
for (namesetIndex = 0; namesetIndex < len; namesetIndex += 1) {
@ -4527,7 +4532,7 @@ CSL.Node.names = {
state.output.openLevel("term-join");
}
if (nameset.trailers3_start) {
state.output.openLevel("trailing-names", cut_var);
state.output.openLevel("trailing-names", state.tmp.cut_var);
}
if (nameset.after_people) {
state.output.append("with", "with");
@ -4536,13 +4541,13 @@ CSL.Node.names = {
state.output.openLevel("institution-outer");
}
if (nameset.trailers2_start) {
state.output.openLevel("trailing-names", cut_var);
state.output.openLevel("trailing-names", state.tmp.cut_var);
}
if (nameset.organization_first) {
state.output.openLevel("inner");
}
if (nameset.trailers1_start) {
state.output.openLevel("trailing-names", cut_var);
state.output.openLevel("trailing-names", state.tmp.cut_var);
}
if (nameset.species === "pers") {
state.output.openLevel("etal-join"); // join for etal
@ -4641,8 +4646,11 @@ CSL.Node.number = {
if ("undefined" === typeof this.successor_prefix) {
this.successor_prefix = state[state.tmp.area].opt.layout_delimiter;
}
if ("undefined" === typeof this.splice_prefix) {
this.splice_prefix = state[state.tmp.area].opt.layout_delimiter;
}
func = function (state, Item) {
var varname, num, number, m;
var varname, num, number, m, j, jlen;
varname = this.variables[0];
state.parallel.StartVariable(this.variables[0]);
state.parallel.AppendToVariable(Item[this.variables[0]]);
@ -4655,15 +4663,83 @@ CSL.Node.number = {
m = num.split(/\s*(?:&|,|-)\s*/);
num = m[0];
}
var prefixes = num.split(/[0-9]+/);
var all_with_spaces = true;
for (var i = 1, ilen = prefixes.length - 1; i < ilen; i += 1) {
if (prefixes[i].indexOf(" ") === -1) {
all_with_spaces = false;
break;
}
}
if (state.tmp.area !== "citation_sort"
&& state.tmp.area !== "bibliography_sort"
&& all_with_spaces
&& num.match(/[-,&]/)
&& !num.match(/[^- 0-9,&]/)) {
var nums = num.match(/[0-9]+/g);
var range_ok = true;
for (i = prefixes.length - 2; i > 0; i += -1) {
if (prefixes && prefixes[i].indexOf("-") > -1) {
var start = parseInt(nums[i - 1], 10);
var end = parseInt(nums[i], 10);
if (start >= end || start < (end - 1000)) {
range_ok = false;
break;
}
var replacement = [];
for (j = start, jlen = end + 1; j < jlen; j += 1) {
replacement.push(""+j);
}
nums = nums.slice(0, i - 1).concat(replacement).concat(nums.slice(i + 1));
}
}
if (range_ok) {
nums = nums.sort(function (a,b) {
a = parseInt(a, 10);
b = parseInt(b, 10);
if (a > b) {
return 1;
} else if (a < b) {
return -1;
} else {
return 0;
}
});
for (i = nums.length; i > -1; i += -1) {
if (nums[i] === nums[i + 1]) {
nums = nums.slice(0, i).concat(nums.slice(i + 1));
}
}
state.output.openLevel("empty");
for (var i = 0, ilen = nums.length; i < ilen; i += 1) {
num = parseInt(nums[i], 10);
number = new CSL.NumericBlob(num, this);
number.gender = state.opt["noun-genders"][varname];
if (i > 0) {
number.successor_prefix = " & ";
number.range_prefix = "-";
number.splice_prefix = ", ";
}
state.output.append(number, "literal");
}
state.output.closeLevel("empty");
} else {
state.output.append(num, this);
}
} else if (!all_with_spaces) {
state.output.append(num, this);
} else {
m = num.match(/\s*([0-9]+)/);
if (m) {
num = parseInt(m[1], 10);
number = new CSL.NumericBlob(num, this);
number.gender = state.opt["noun-genders"][varname];
state.output.append(number, "literal");
} else {
state.output.append(num, this);
}
}
}
state.parallel.CloseVariable("number");
};
this.execs.push(func);
@ -4731,6 +4807,7 @@ CSL.Node.text = {
this.range_prefix = "-";
}
this.successor_prefix = state[state.build.area].opt.layout_delimiter;
this.splice_prefix = state[state.build.area].opt.layout_delimiter;
func = function (state, Item, item) {
id = Item.id;
if (!state.tmp.just_looking) {
@ -4996,7 +5073,7 @@ CSL.Attributes["@macro"] = function (state, arg) {
};
CSL.Attributes["@term"] = function (state, arg) {
if (this.name === "et-al") {
if (CSL.locale[state.opt.lang].terms[arg]) {
if (state.locale[state.opt.lang].terms[arg]) {
this.strings.term = state.getTerm(arg, "long", 0);
} else {
this.strings.term = arg;
@ -5238,6 +5315,13 @@ CSL.Attributes["@names-min"] = function (state, arg) {
CSL.Attributes["@names-use-first"] = function (state, arg) {
this.strings["et-al-use-first"] = parseInt(arg, 10);
};
CSL.Attributes["@names-use-last"] = function (state, arg) {
if (arg === "true") {
this.strings["et-al-use-last"] = true;
} else {
this.strings["et-al-use-last"] = false;
}
};
CSL.Attributes["@sort"] = function (state, arg) {
if (arg === "descending") {
this.strings.sort_direction = CSL.DESCENDING;
@ -5273,17 +5357,54 @@ CSL.Attributes["@locator"] = function (state, arg) {
CSL.Attributes["@newdate"] = function (state, arg) {
};
CSL.Attributes["@position"] = function (state, arg) {
var tryposition;
state.opt.update_mode = CSL.POSITION;
if (arg === "first") {
this.strings.position = CSL.POSITION_FIRST;
} else if (arg === "subsequent") {
this.strings.position = CSL.POSITION_SUBSEQUENT;
} else if (arg === "ibid") {
this.strings.position = CSL.POSITION_IBID;
} else if (arg === "ibid-with-locator") {
this.strings.position = CSL.POSITION_IBID_WITH_LOCATOR;
} else if (arg === "near-note") {
this.strings["near-note-distance-check"] = true;
var lst = arg.split(/\s+/);
for (var i = 0, ilen = lst.length; i < ilen; i += 1) {
if (state.build.area.slice(0, 12) === "bibliography") {
func = function (state, Item, item) {
return false;
}
this.tests.push(func);
} else {
if (lst[i] === "first") {
tryposition = CSL.POSITION_FIRST;
} else if (lst[i] === "subsequent") {
tryposition = CSL.POSITION_SUBSEQUENT;
} else if (lst[i] === "ibid") {
tryposition = CSL.POSITION_IBID;
} else if (lst[i] === "ibid-with-locator") {
tryposition = CSL.POSITION_IBID_WITH_LOCATOR;
}
var factory = function (tryposition) {
return function (state, Item, item) {
if (item && "undefined" === typeof item.position) {
item.position = 0;
}
if (item && typeof item.position === "number") {
if (item.position === 0 && tryposition === 0) {
return true;
} else if (tryposition > 0 && item.position >= tryposition) {
return true;
}
} else if (tryposition === 0) {
return true;
}
return false;
};
};
func = factory(tryposition);
this.tests.push(func);
}
if (lst[i] === "near-note") {
func = function (state, Item, item) {
if (item && item["near-note"]) {
return true;
}
return false;
};
this.tests.push(func);
}
}
};
CSL.Attributes["@disambiguate"] = function (state, arg) {
@ -5356,6 +5477,9 @@ CSL.Attributes["@and"] = function (state, arg) {
CSL.Attributes["@delimiter-precedes-last"] = function (state, arg) {
state.setOpt(this, "delimiter-precedes-last", arg);
};
CSL.Attributes["@delimiter-precedes-et-al"] = function (state, arg) {
state.setOpt(this, "delimiter-precedes-et-al", arg);
};
CSL.Attributes["@initialize-with"] = function (state, arg) {
state.setOpt(this, "initialize-with", arg);
};
@ -6206,7 +6330,7 @@ CSL.NumericBlob = function (num, mother_token) {
this.strings["text-case"] = mother_token.strings["text-case"];
this.successor_prefix = mother_token.successor_prefix;
this.range_prefix = mother_token.range_prefix;
this.splice_prefix = "";
this.splice_prefix = mother_token.splice_prefix;
this.formatter = mother_token.formatter;
if (!this.formatter) {
this.formatter = new CSL.Output.DefaultFormatter();
@ -6251,10 +6375,15 @@ CSL.NumericBlob.prototype.checkNext = function (next) {
next.status = CSL.SUCCESSOR;
}
}
if (this.status === CSL.SEEN) {
}
};
CSL.NumericBlob.prototype.checkLast = function (last) {
if (this.status === CSL.SEEN
|| (last.num !== (this.num - 1) && this.status === CSL.SUCCESSOR)) {
this.status = CSL.SUCCESSOR;
return true;
}
}
return false;
};
CSL.Util.fixDateNode = function (parent, pos, node) {
var form, variable, datexml, subnode, partname, attr, val, prefix, suffix, children, key, cchildren, kkey, display;
@ -6341,7 +6470,7 @@ CSL.Util.Names.outputNames = function (state, display_names) {
segments = new this.StartMiddleEnd(state, display_names);
and = state.output.getToken("name").strings.delimiter;
if (state.tmp.use_ellipsis) {
and = state.output.getToken("inner").strings.delimiter + state.getTerm("ellipsis") + " ";
and = state.output.getToken("inner").strings.delimiter + "\u2026 ";
} else if (state.output.getToken("name").strings["delimiter-precedes-last"] === "always") {
and = state.output.getToken("inner").strings.delimiter + and;
} else if (state.output.getToken("name").strings["delimiter-precedes-last"] === "never") {
@ -6415,16 +6544,39 @@ CSL.Util.Names.StartMiddleEnd.prototype.outputSegmentNames = function (seg) {
this.nameoffset += this.segments[seg].length;
};
CSL.Util.Names.StartMiddleEnd.prototype.outputNameParts = function (subsequence) {
var state, len, pos, key, namepart, initialize_with;
var state, len, pos, key, namepart, initialize_with, preffie;
state = this.state;
for (var i = subsequence.length - 1; i > -1; i += -1) {
if (!this.name[subsequence[i]]) {
subsequence = subsequence.slice(0, i).concat(subsequence.slice(i + 1));
}
}
preffie = "";
len = subsequence.length;
for (pos = 0; pos < len; pos += 1) {
key = subsequence[pos];
namepart = this.name[key];
if (preffie) {
namepart = preffie + namepart;
preffie = "";
}
if (["given", "suffix", "dropping-particle"].indexOf(key) > -1 && 0 === state.tmp.disambig_settings.givens[state.tmp.nameset_counter][this.namenum + this.nameoffset]) {
if (!(key === "given" && !this.name.family)) {
if (key === "suffix") {
if (this.name.suffix !== this.name.suffix.toLowerCase()) {
continue;
}
} else {
continue;
}
}
}
if (key === "dropping-particle"
&& ["'","\u02bc","\u2019"].indexOf(namepart.slice(-1)) > -1
&& pos < subsequence.length - 1
&& subsequence[pos + 1] === "family") {
preffie = namepart;
continue;
}
if ("given" === key) {
if (1 === state.tmp.disambig_settings.givens[state.tmp.nameset_counter][(this.namenum + this.nameoffset)]) {
@ -6720,8 +6872,8 @@ CSL.Util.Dates.day["numeric-leading-zeros"] = function (state, num) {
}
return num.toString();
};
CSL.Util.Dates.day.ordinal = function (state, num) {
return state.fun.ordinalizer(num);
CSL.Util.Dates.day.ordinal = function (state, num, gender) {
return state.fun.ordinalizer.format(num, gender);
};
CSL.Util.Sort = {};
CSL.Util.Sort.strip_prepositions = function (str) {
@ -6872,40 +7024,55 @@ CSL.Util.substituteEnd = function (state, target) {
CSL.Util.LongOrdinalizer = function () {};
CSL.Util.LongOrdinalizer.prototype.init = function (state) {
this.state = state;
this.names = {};
for (var i = 1; i < 10; i += 1) {
this.names[("" + i)] = state.getTerm(("long-ordinal-0" + i));
}
this.names["10"] = state.getTerm("long-ordinal-10");
};
CSL.Util.LongOrdinalizer.prototype.format = function (num) {
var ret = this.names[("" + num)];
if (!ret) {
ret = this.state.fun.ordinalizer.format(num);
CSL.Util.LongOrdinalizer.prototype.format = function (num, gender) {
if (num < 10) {
num = "0" + num;
}
var ret = CSL.Engine.getField(
CSL.LOOSE,
this.state.locale[this.state.opt.lang].terms,
"long-ordinal-" + num,
"long",
0,
gender
);
if (!ret) {
ret = this.state.fun.ordinalizer.format(num, gender);
}
this.state.tmp.cite_renders_content = true;
return ret;
};
CSL.Util.Ordinalizer = function () {};
CSL.Util.Ordinalizer.prototype.init = function (state) {
this.suffixes = [];
for (var i = 1; i < 5; i += 1) {
this.suffixes.push(state.getTerm(("ordinal-0" + i)));
this.suffixes = {};
for (var i = 0, ilen = 3; i < ilen; i += 1) {
var gender = [undefined, "masculine", "feminine"][i];
this.suffixes[gender] = [];
for (var j = 1; j < 5; j += 1) {
var ordinal = state.getTerm("ordinal-0" + j, "long", false, gender);
if ("undefined" === typeof ordinal) {
delete this.suffixes[gender];
break;
}
this.suffixes[gender].push(ordinal);
}
}
};
CSL.Util.Ordinalizer.prototype.format = function (num) {
CSL.Util.Ordinalizer.prototype.format = function (num, gender) {
var str;
num = parseInt(num, 10);
str = num.toString();
if ((num / 10) % 10 === 1) {
str += this.suffixes[3];
str += this.suffixes[gender][3];
} else if (num % 10 === 1) {
str += this.suffixes[0];
str += this.suffixes[gender][0];
} else if (num % 10 === 2) {
str += this.suffixes[1];
str += this.suffixes[gender][1];
} else if (num % 10 === 3) {
str += this.suffixes[2];
str += this.suffixes[gender][2];
} else {
str += this.suffixes[3];
str += this.suffixes[gender][3];
}
return str;
};
@ -7292,7 +7459,7 @@ CSL.Util.FlipFlopper.prototype.getSplitStrings = function (str) {
}
len = strs.length;
for (pos = 0; pos < len; pos += 2) {
strs[pos] = strs[pos].replace("'", this.state.getTerm("close-inner-quote"), "g");
strs[pos] = strs[pos].replace("'", "\u02bc");
strs[pos] = CSL.Output.Formats[this.state.opt.mode].text_escape(strs[pos]);
}
return strs;
@ -7644,7 +7811,7 @@ CSL.Output.Formats.prototype.text = {
};
CSL.Output.Formats.prototype.rtf = {
"text_escape": function (text) {
return text.replace(/\\/, "\\\\", "g").replace(/[\x7F-\uFFFF]/g,
return text.replace(/([\\{}])/g, "\\$1", "g").replace(/[\x7F-\uFFFF]/g,
function(aChar) { return "\\uc0\\u"+aChar.charCodeAt(0).toString()+"{}" })
.replace("\t", "\\tab{}", "g");
},
@ -7978,11 +8145,15 @@ CSL.Registry.NameReg = function (state) {
if (!str) {
str = "";
}
return str.replace(".", " ").replace(/\s+/, " ");
return str.replace(".", " ", "g").replace(/\s+/g, " ").replace(/\s+$/,"");
};
set_keys = function (state, itemid, nameobj) {
pkey = strip_periods(nameobj.family);
skey = strip_periods(nameobj.given);
var m = skey.match(/,\!* [^,]$/);
if (m && m[1] === m[1].toLowerCase()) {
skey = skey.replace(/,\!* [^,]$/, "");
}
ikey = CSL.Util.Names.initializeWith(state, skey, "");
if (state.opt["givenname-disambiguation-rule"] === "by-cite") {
pkey = itemid + pkey;