From 19951b0af2188b8fc01c0b9a8b70fc3df7471264 Mon Sep 17 00:00:00 2001 From: Frank Bennett Date: Sun, 21 Apr 2019 12:02:05 +0900 Subject: [PATCH] More generous subtitle capitalization --- src/build.js | 2 +- src/load.js | 134 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 126 insertions(+), 10 deletions(-) diff --git a/src/build.js b/src/build.js index c4428e7b2..21d13abdb 100644 --- a/src/build.js +++ b/src/build.js @@ -692,7 +692,7 @@ CSL.Engine.prototype.retrieveItem = function (id) { } // Add support for main_title_from_short_title if (this.opt.development_extensions.main_title_from_short_title) { - CSL.extractTitleAndSubtitle(Item); + CSL.extractTitleAndSubtitle.call(this, Item); } var isLegalType = ["bill","legal_case","legislation","gazette","regulation"].indexOf(Item.type) > -1; if (this.opt.development_extensions.force_jurisdiction && isLegalType) { diff --git a/src/load.js b/src/load.js index d716f99d6..9e6e5cf15 100644 --- a/src/load.js +++ b/src/load.js @@ -631,7 +631,7 @@ var CSL = { "container-title" ], TITLE_FIELD_SPLITS: function(seg) { - var keys = ["title", "short", "main", "sub"]; + var keys = ["title", "short", "main", "sub", "subjoin"]; var ret = {}; for (var i=0,ilen=keys.length;i -1) { + vals[title.subjoin] = ": "; + } + if (vals[title.subjoin].indexOf("-") > -1 || vals[title.subjoin].indexOf("—") > -1) { + vals[title.subjoin] = "—"; } } if (lang) { @@ -716,6 +769,12 @@ var CSL = { }, titlecaseSentenceOrNormal: function(state, Item, seg, lang, sentenceCase) { + // Hold on here. + // What is seg here? + // It's ... either "" or "container-". Which is ugly, but works. + // But this ALWAYS returns the full title, never short. + // So sentence-casing cannot be applied to short. + // Goes unnoticed because forced sentence-casing almost never appears in styles. var title = CSL.TITLE_FIELD_SPLITS(seg); var vals = {}; if (lang && Item.multi) { @@ -728,13 +787,18 @@ var CSL = { if (Item.multi._keys[title.sub]) { vals[title.sub] = Item.multi._keys[title.sub][lang]; } + if (Item.multi._keys[title.subjoin]) { + vals[title.subjoin] = Item.multi._keys[title.subjoin][lang]; + } } else { vals[title.title] = Item[title.title]; vals[title.main] = Item[title.main]; vals[title.sub] = Item[title.sub]; + vals[title.subjoin] = Item[title.subjoin]; } if (vals[title.main] && vals[title.sub]) { var mainTitle = vals[title.main]; + var subJoin = vals[title.subjoin]; var subTitle = vals[title.sub]; if (sentenceCase) { mainTitle = CSL.Output.Formatters.sentence(state, mainTitle); @@ -742,10 +806,26 @@ var CSL = { } else if (state.opt.development_extensions.uppercase_subtitles) { subTitle = CSL.Output.Formatters["capitalize-first"](state, subTitle); } - return [mainTitle, subTitle].join(vals[title.title].slice(mainTitle.length, -1 * subTitle.length)); + return [mainTitle, subJoin, subTitle].join(""); } else { if (sentenceCase) { return CSL.Output.Formatters.sentence(state, vals[title.title]); + } else if (state.opt.development_extensions.uppercase_subtitles) { + // Split and apply everywhere. + var splits = CSL.TITLE_SPLIT(vals[title.title]); + for (var i=0,ilen=splits.length; i -1) { + splits[i] = ": "; + } + if (splits[i].indexOf("-") > -1 || splits[i].indexOf("—") > -1) { + splits[i] = "—"; + } + } + vals[title.title] = splits.join(""); + return vals[title.title]; } else { return vals[title.title]; } @@ -1063,5 +1143,41 @@ var CSL = { "csl_reverse_lookup_support", "main_title_from_short_title", "uppercase_subtitles" - ] + ], + + TITLE_SPLIT_REGEXP: (function() { + var splits = [ + "\\.\\s+", + "\\!\\s+", + "\\?\\s+", + "\\s*::*\\s+", + "\\s*—\\s*", + "\\s+\\-\\s+", + "\\s*\\-\\-\\-*\\s*" + ] + return { + match: new RegExp("(" + splits.join("|") + ")", "g"), + matchfirst: new RegExp("^(" + splits.join("|") + ")"), + split: new RegExp("(?:" + splits.join("|") + ")") + } + })(), + + TITLE_SPLIT: function(str) { + if (!str) { + return str; + } + var m = str.match(CSL.TITLE_SPLIT_REGEXP.match); + var lst = str.split(CSL.TITLE_SPLIT_REGEXP.split); + for (var i=lst.length-2; i>-1; i--) { + if (lst[i] && lst[i].slice(-1).toLowerCase() !== lst[i].slice(-1)) { + // recombine + lst[i] = lst[i] + m[i] + lst[i+1]; + lst = lst.slice(0, i+1).concat(lst.slice(i+2)) + } else { + // merge + lst = lst.slice(0, i+1).concat([m[i]]).concat(lst.slice(i+1)) + } + } + return lst; + } };