- implements CSL text-case attribute (text-transform is now deprecated)
- allows CSLs to be imported from the file system - implements preliminary text-case="title" transform
This commit is contained in:
parent
ad181f973c
commit
669f115376
|
@ -624,15 +624,25 @@ Zotero_Browser.Tab.prototype._searchFrames = function(rootDoc, searchDoc) {
|
||||||
* Attempts import of a file; to be run on local files only
|
* Attempts import of a file; to be run on local files only
|
||||||
*/
|
*/
|
||||||
Zotero_Browser.Tab.prototype._attemptLocalFileImport = function(doc) {
|
Zotero_Browser.Tab.prototype._attemptLocalFileImport = function(doc) {
|
||||||
var file = Components.classes["@mozilla.org/network/protocol;1?name=file"]
|
if(doc.documentURI.substr(doc.documentURI.length-4).toLowerCase() == ".csl") {
|
||||||
.getService(Components.interfaces.nsIFileProtocolHandler)
|
// read CSL string
|
||||||
.getFileFromURLSpec(doc.documentURI);
|
var csl = Zotero.File.getContentsFromURL(doc.documentURI);
|
||||||
|
if(csl.indexOf("http://purl.org/net/xbiblio/csl") != -1) {
|
||||||
var me = this;
|
// looks like a CSL; try to import
|
||||||
var translate = new Zotero.Translate("import");
|
Zotero.Cite.installStyle(csl, doc.documentURI);
|
||||||
translate.setLocation(file);
|
}
|
||||||
translate.setHandler("translators", function(obj, item) { me._translatorsAvailable(obj, item) });
|
} else {
|
||||||
translate.getTranslators();
|
// see if we can import this file
|
||||||
|
var file = Components.classes["@mozilla.org/network/protocol;1?name=file"]
|
||||||
|
.getService(Components.interfaces.nsIFileProtocolHandler)
|
||||||
|
.getFileFromURLSpec(doc.documentURI);
|
||||||
|
|
||||||
|
var me = this;
|
||||||
|
var translate = new Zotero.Translate("import");
|
||||||
|
translate.setLocation(file);
|
||||||
|
translate.setHandler("translators", function(obj, item) { me._translatorsAvailable(obj, item) });
|
||||||
|
translate.getTranslators();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -34,6 +34,7 @@ Zotero.Cite = new function() {
|
||||||
this.getStyles = getStyles;
|
this.getStyles = getStyles;
|
||||||
this.getStyleClass = getStyleClass;
|
this.getStyleClass = getStyleClass;
|
||||||
this.getStyle = getStyle;
|
this.getStyle = getStyle;
|
||||||
|
this.installStyle = installStyle;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns an associative array of cslID => styleName pairs
|
* returns an associative array of cslID => styleName pairs
|
||||||
|
@ -90,6 +91,59 @@ Zotero.Cite = new function() {
|
||||||
if(!style) throw "Zotero.Cite: invalid CSL ID";
|
if(!style) throw "Zotero.Cite: invalid CSL ID";
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* installs a style
|
||||||
|
**/
|
||||||
|
function installStyle(cslString, loadURI) {
|
||||||
|
try {
|
||||||
|
var xml = new XML(Zotero.CSL.Global.cleanXML(cslString));
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
var error = true;
|
||||||
|
Components.utils.reportError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xml || error) {
|
||||||
|
alert(Zotero.getString('styles.installError', loadURI));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var uri = xml.info.id.toString();
|
||||||
|
var title = xml.info.title.toString();
|
||||||
|
var updated = xml.info.updated.toString().replace(/(.+)T([^\+]+)\+?.*/, "$1 $2");
|
||||||
|
|
||||||
|
var sql = "SELECT title FROM csl WHERE cslID=?";
|
||||||
|
var existingTitle = Zotero.DB.valueQuery(sql, uri);
|
||||||
|
|
||||||
|
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIPromptService);
|
||||||
|
|
||||||
|
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
||||||
|
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
|
||||||
|
|
||||||
|
if (existingTitle) {
|
||||||
|
var text = Zotero.getString('styles.updateStyle', [existingTitle, title, loadURI]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var text = Zotero.getString('styles.installStyle', [title, loadURI]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var acceptButton = Zotero.getString('general.install');
|
||||||
|
|
||||||
|
var index = ps.confirmEx(null,
|
||||||
|
'',
|
||||||
|
text,
|
||||||
|
buttonFlags,
|
||||||
|
acceptButton, null, null, null, {}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
var sql = "REPLACE INTO csl VALUES (?,?,?,?)";
|
||||||
|
Zotero.DB.query(sql, [uri, updated, title, cslString]);
|
||||||
|
alert(Zotero.getString('styles.installed', title));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -213,57 +267,10 @@ Zotero.Cite.MIMEHandler.StreamListener.prototype.onStopRequest = function(channe
|
||||||
var loadURI = '';
|
var loadURI = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
Zotero.Cite.installStyle(this._readString, loadURI);
|
||||||
var xml = new XML(Zotero.CSL.Global.cleanXML(this._readString));
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
var error = true;
|
|
||||||
Components.utils.reportError(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!xml || error) {
|
|
||||||
alert(Zotero.getString('styles.installError', loadURI));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var uri = xml.info.id.toString();
|
|
||||||
var title = xml.info.title.toString();
|
|
||||||
var updated = xml.info.updated.toString().replace(/(.+)T([^\+]+)\+?.*/, "$1 $2");
|
|
||||||
|
|
||||||
var sql = "SELECT title FROM csl WHERE cslID=?";
|
|
||||||
var existingTitle = Zotero.DB.valueQuery(sql, uri);
|
|
||||||
|
|
||||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
|
||||||
.getService(Components.interfaces.nsIPromptService);
|
|
||||||
|
|
||||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
|
||||||
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
|
|
||||||
|
|
||||||
if (existingTitle) {
|
|
||||||
var text = Zotero.getString('styles.updateStyle', [existingTitle, title, loadURI]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var text = Zotero.getString('styles.installStyle', [title, loadURI]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var acceptButton = Zotero.getString('general.install');
|
|
||||||
|
|
||||||
var index = ps.confirmEx(null,
|
|
||||||
'',
|
|
||||||
text,
|
|
||||||
buttonFlags,
|
|
||||||
acceptButton, null, null, null, {}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (index == 0) {
|
|
||||||
var sql = "REPLACE INTO csl VALUES (?,?,?,?)";
|
|
||||||
Zotero.DB.query(sql, [uri, updated, title, this._readString]);
|
|
||||||
alert(Zotero.getString('styles.installed', title));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CSL: a class for creating bibliographies from CSL files
|
* CSL: a class for creating bibliographies from CSL files
|
||||||
* this is abstracted as a separate class for the benefit of anyone who doesn't
|
* this is abstracted as a separate class for the benefit of anyone who doesn't
|
||||||
|
@ -1974,7 +1981,7 @@ Zotero.CSL.Item.Date.prototype.getDateVariable = function(variable) {
|
||||||
this.dateArray = Zotero.Date.strToDate(this.date);
|
this.dateArray = Zotero.Date.strToDate(this.date);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.dateArray[variable] || this.dateArray[variable] === 0) {
|
if(this.dateArray[variable] !== undefined && this.dateArray[variable] !== false) {
|
||||||
return this.dateArray[variable];
|
return this.dateArray[variable];
|
||||||
} else if(variable == "month") {
|
} else if(variable == "month") {
|
||||||
if(this.dateArray.part) {
|
if(this.dateArray.part) {
|
||||||
|
@ -2474,9 +2481,33 @@ Zotero.CSL.FormattedString.prototype.append = function(string, element, dontDeli
|
||||||
if(newPrefix != "" && newPrefix != prefix) {
|
if(newPrefix != "" && newPrefix != prefix) {
|
||||||
this.suppressLeadingWhitespace = false;
|
this.suppressLeadingWhitespace = false;
|
||||||
}
|
}
|
||||||
prefix = newPrefix
|
prefix = newPrefix;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// append line before if display="block"
|
||||||
|
var closeDiv = false;
|
||||||
|
if(element && (element["@display"] == "block" || this.appendLine)) {
|
||||||
|
if(this.format == "HTML") {
|
||||||
|
if(this.option.(@name == "hanging-indent").@value == "true") {
|
||||||
|
this.string += '<div style="text-indent:0.5in;">'
|
||||||
|
} else {
|
||||||
|
this.string += '<div>';
|
||||||
|
}
|
||||||
|
var closeDiv;
|
||||||
|
} else {
|
||||||
|
if(this.format == "RTF") {
|
||||||
|
this.string += "\r\n\\line ";
|
||||||
|
} else if(this.format == "Integration") {
|
||||||
|
this.string += "\x0B";
|
||||||
|
} else {
|
||||||
|
this.string += (Zotero.isWin ? "\r\n" : "\n");
|
||||||
|
}
|
||||||
|
this.appendLine = element["@display"] == "block";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(prefix) {
|
||||||
this.append(prefix, null, true);
|
this.append(prefix, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2502,19 +2533,35 @@ Zotero.CSL.FormattedString.prototype.append = function(string, element, dontDeli
|
||||||
this.closePunctuation = false;
|
this.closePunctuation = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle text transformation
|
// handling of "text-transform" attribute (now obsolete)
|
||||||
if(element) {
|
if(element && element["@text-transform"].length() && !element["@text-case"].length()) {
|
||||||
if(element["@text-transform"].length()) {
|
var mapping = {"lowercase":"lowercase", "uppercase":"uppercase", "capitalize":"capitalize-first"};
|
||||||
if(element["@text-transform"] == "lowercase") {
|
element["@text-case"] = mapping[element["@text-transform"].toString()];
|
||||||
// all lowercase
|
}
|
||||||
string = string.toLowerCase();
|
// handle text case
|
||||||
} else if(element["@text-transform"] == "uppercase") {
|
if(element && element["@text-case"].length()) {
|
||||||
// all uppercase
|
if(element["@text-case"] == "lowercase") {
|
||||||
string = string.toUpperCase();
|
// all lowercase
|
||||||
} else if(element["@text-transform"] == "capitalize") {
|
string = string.toLowerCase();
|
||||||
// capitalize first
|
} else if(element["@text-case"] == "uppercase") {
|
||||||
string = string[0].toUpperCase()+string.substr(1);
|
// all uppercase
|
||||||
|
string = string.toUpperCase();
|
||||||
|
} else if(element["@text-case"] == "capitalize-first") {
|
||||||
|
// capitalize first
|
||||||
|
string = string[0].toUpperCase()+string.substr(1).toLowerCase();
|
||||||
|
} else if(element["@text-case"] == "capitalize-all") {
|
||||||
|
// capitalize first
|
||||||
|
var strings = string.split(" ");
|
||||||
|
for(var i=0; i<strings.length; i++) {
|
||||||
|
if(strings[i].length > 1) {
|
||||||
|
strings[i] = strings[i][0].toUpperCase()+strings[i].substr(1).toLowerCase();
|
||||||
|
} else if(strings[i].length == 1) {
|
||||||
|
strings[i] = strings[i].toUpperCase();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
string = strings.join(" ");
|
||||||
|
} else if(element["@text-case"] == "title") {
|
||||||
|
string = Zotero.Text.titleCase(string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2552,17 +2599,7 @@ Zotero.CSL.FormattedString.prototype.append = function(string, element, dontDeli
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(element["@display"] == "block") {
|
if(style) {
|
||||||
if(this.option.(@name == "hanging-indent").@value == "true") {
|
|
||||||
style += "text-indent:0.5in;"
|
|
||||||
}
|
|
||||||
|
|
||||||
if(style) {
|
|
||||||
string = '<div style="'+style+'">'+string+'</div>';
|
|
||||||
} else {
|
|
||||||
string = '<div>'+string+'</div>';
|
|
||||||
}
|
|
||||||
} else if(style) {
|
|
||||||
string = '<span style="'+style+'">'+string+'</span>';
|
string = '<span style="'+style+'">'+string+'</span>';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2589,17 +2626,6 @@ Zotero.CSL.FormattedString.prototype.append = function(string, element, dontDeli
|
||||||
string = "\\sub "+string+"\\sub0 ";
|
string = "\\sub "+string+"\\sub0 ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(element["@display"] == "block" || this.appendLine) {
|
|
||||||
if(this.format == "RTF") {
|
|
||||||
string = "\r\n\\line "+string;
|
|
||||||
} else if(this.format == "Integration") {
|
|
||||||
string = "\x0B"+string;
|
|
||||||
} else {
|
|
||||||
string = (Zotero.isWin ? "\r\n" : "\n")+string;
|
|
||||||
}
|
|
||||||
this.appendLine = element["@display"] == "block";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add quotes if necessary
|
// add quotes if necessary
|
||||||
|
@ -2616,13 +2642,16 @@ Zotero.CSL.FormattedString.prototype.append = function(string, element, dontDeli
|
||||||
|
|
||||||
this.string += string;
|
this.string += string;
|
||||||
|
|
||||||
// special rule: if a variable ends in a punctuation mark, and the suffix
|
|
||||||
// begins with a period, chop the period off the suffix
|
|
||||||
var suffix;
|
var suffix;
|
||||||
if(element && element.@suffix.length()) {
|
if(element && element.@suffix.length()) {
|
||||||
this.append(element.@suffix.toString(), null, true);
|
this.append(element.@suffix.toString(), null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// close div for display=block in HTML
|
||||||
|
if(closeDiv) {
|
||||||
|
this.string += "</div>";
|
||||||
|
}
|
||||||
|
|
||||||
// save for second-field-align
|
// save for second-field-align
|
||||||
if(!dontDelimit && this.insertTabAfterField) {
|
if(!dontDelimit && this.insertTabAfterField) {
|
||||||
// replace any space following this entry
|
// replace any space following this entry
|
||||||
|
|
|
@ -332,41 +332,14 @@ Zotero.Utilities.prototype.getLocalizedCreatorType = function(type) {
|
||||||
*
|
*
|
||||||
* Follows capitalizeTitles pref, unless |force| is true
|
* Follows capitalizeTitles pref, unless |force| is true
|
||||||
*/
|
*/
|
||||||
Zotero.Utilities.capitalizeSkipWords = ["but", "or", "yet", "so", "for", "and",
|
Zotero.Utilities.prototype.capitalizeTitle = function(string, force) {
|
||||||
"nor", "a", "an", "the", "at", "by", "from", "in", "into", "of", "on", "to",
|
string = this.cleanString(string);
|
||||||
"with", "up", "down"];
|
if(Zotero.Prefs.get('capitalizeTitles') || force) {
|
||||||
Zotero.Utilities.prototype.capitalizeTitle = function(title, force) {
|
// fix colons
|
||||||
if (!Zotero.Prefs.get('capitalizeTitles') && !force) {
|
string = string.replace(" : ", ": ", "g");
|
||||||
return title;
|
string = Zotero.Text.titleCase(string.replace(/ : /g, ": "));
|
||||||
}
|
}
|
||||||
title = this.cleanString(title);
|
return string;
|
||||||
if (!title) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
title = title.replace(/ : /g, ": ");
|
|
||||||
var words = title.split(" ");
|
|
||||||
|
|
||||||
// always capitalize first
|
|
||||||
words[0] = words[0][0].toUpperCase() + words[0].substr(1);
|
|
||||||
if(words.length > 1) {
|
|
||||||
var lastWordIndex = words.length-1;
|
|
||||||
// always capitalize last
|
|
||||||
words[lastWordIndex] = words[lastWordIndex][0].toUpperCase() + words[lastWordIndex].substr(1);
|
|
||||||
|
|
||||||
if(words.length > 2) {
|
|
||||||
for(var i=1; i<lastWordIndex; i++) {
|
|
||||||
// if not a skip word
|
|
||||||
if(Zotero.Utilities.capitalizeSkipWords.indexOf(words[i].toLowerCase()) == -1 ||
|
|
||||||
(words[i-1].length && words[i-1][words[i-1].length-1] == ":")) {
|
|
||||||
words[i] = words[i][0].toUpperCase() + words[i].substr(1);
|
|
||||||
} else {
|
|
||||||
words[i] = words[i].toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return words.join(" ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1115,7 +1115,64 @@ Zotero.Hash.prototype.has = function(in_key){
|
||||||
return typeof(this.items[in_key]) != 'undefined';
|
return typeof(this.items[in_key]) != 'undefined';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Singleton for common text formatting routines
|
||||||
|
**/
|
||||||
|
Zotero.Text = new function() {
|
||||||
|
this.titleCase = titleCase;
|
||||||
|
|
||||||
|
var skipWords = ["but", "or", "yet", "so", "for", "and", "nor", "a", "an",
|
||||||
|
"the", "at", "by", "from", "in", "into", "of", "on", "to", "with", "up",
|
||||||
|
"down", "as"];
|
||||||
|
// this may only match a single character
|
||||||
|
var delimiterRegexp = /([ \/\-–—])/;
|
||||||
|
|
||||||
|
function titleCase(string) {
|
||||||
|
if (!string) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// split words
|
||||||
|
var words = string.split(delimiterRegexp);
|
||||||
|
var isUpperCase = string.toUpperCase() == string;
|
||||||
|
|
||||||
|
var newString = "";
|
||||||
|
var delimiterOffset = words[0].length;
|
||||||
|
var lastWordIndex = words.length-1;
|
||||||
|
var previousWordIndex = -1;
|
||||||
|
for(var i=0; i<=lastWordIndex; i++) {
|
||||||
|
// only do manipulation if not a delimiter character
|
||||||
|
if(words[i].length != 0 && (words[i].length != 1 || !delimiterRegexp.test(words[i]))) {
|
||||||
|
var upperCaseVariant = words[i].toUpperCase();
|
||||||
|
var lowerCaseVariant = words[i].toLowerCase();
|
||||||
|
|
||||||
|
// only use if word does not already possess some capitalization
|
||||||
|
if(isUpperCase || words[i] == lowerCaseVariant) {
|
||||||
|
if(
|
||||||
|
// a skip word
|
||||||
|
skipWords.indexOf(lowerCaseVariant.replace(/[^a-zA-Z]+/, "")) != -1
|
||||||
|
// not first or last word
|
||||||
|
&& i != 0 && i != lastWordIndex
|
||||||
|
// does not follow a colon
|
||||||
|
&& (previousWordIndex == -1 || words[previousWordIndex][words[previousWordIndex].length-1] != ":")
|
||||||
|
) {
|
||||||
|
words[i] = lowerCaseVariant;
|
||||||
|
} else {
|
||||||
|
// this is not a skip word or comes after a colon;
|
||||||
|
// we must capitalize
|
||||||
|
words[i] = upperCaseVariant[0] + lowerCaseVariant.substr(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previousWordIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
newString += words[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return newString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Zotero.Date = new function(){
|
Zotero.Date = new function(){
|
||||||
this.sqlToDate = sqlToDate;
|
this.sqlToDate = sqlToDate;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user