- 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
|
||||
*/
|
||||
Zotero_Browser.Tab.prototype._attemptLocalFileImport = function(doc) {
|
||||
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();
|
||||
if(doc.documentURI.substr(doc.documentURI.length-4).toLowerCase() == ".csl") {
|
||||
// read CSL string
|
||||
var csl = Zotero.File.getContentsFromURL(doc.documentURI);
|
||||
if(csl.indexOf("http://purl.org/net/xbiblio/csl") != -1) {
|
||||
// looks like a CSL; try to import
|
||||
Zotero.Cite.installStyle(csl, doc.documentURI);
|
||||
}
|
||||
} else {
|
||||
// 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.getStyleClass = getStyleClass;
|
||||
this.getStyle = getStyle;
|
||||
this.installStyle = installStyle;
|
||||
|
||||
/*
|
||||
* returns an associative array of cslID => styleName pairs
|
||||
|
@ -90,6 +91,59 @@ Zotero.Cite = new function() {
|
|||
if(!style) throw "Zotero.Cite: invalid CSL ID";
|
||||
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 = '';
|
||||
}
|
||||
|
||||
try {
|
||||
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));
|
||||
}
|
||||
Zotero.Cite.installStyle(this._readString, loadURI);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* CSL: a class for creating bibliographies from CSL files
|
||||
* 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);
|
||||
}
|
||||
|
||||
if(this.dateArray[variable] || this.dateArray[variable] === 0) {
|
||||
if(this.dateArray[variable] !== undefined && this.dateArray[variable] !== false) {
|
||||
return this.dateArray[variable];
|
||||
} else if(variable == "month") {
|
||||
if(this.dateArray.part) {
|
||||
|
@ -2474,9 +2481,33 @@ Zotero.CSL.FormattedString.prototype.append = function(string, element, dontDeli
|
|||
if(newPrefix != "" && newPrefix != prefix) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -2502,19 +2533,35 @@ Zotero.CSL.FormattedString.prototype.append = function(string, element, dontDeli
|
|||
this.closePunctuation = false;
|
||||
}
|
||||
|
||||
// handle text transformation
|
||||
if(element) {
|
||||
if(element["@text-transform"].length()) {
|
||||
if(element["@text-transform"] == "lowercase") {
|
||||
// all lowercase
|
||||
string = string.toLowerCase();
|
||||
} else if(element["@text-transform"] == "uppercase") {
|
||||
// all uppercase
|
||||
string = string.toUpperCase();
|
||||
} else if(element["@text-transform"] == "capitalize") {
|
||||
// capitalize first
|
||||
string = string[0].toUpperCase()+string.substr(1);
|
||||
// handling of "text-transform" attribute (now obsolete)
|
||||
if(element && element["@text-transform"].length() && !element["@text-case"].length()) {
|
||||
var mapping = {"lowercase":"lowercase", "uppercase":"uppercase", "capitalize":"capitalize-first"};
|
||||
element["@text-case"] = mapping[element["@text-transform"].toString()];
|
||||
}
|
||||
// handle text case
|
||||
if(element && element["@text-case"].length()) {
|
||||
if(element["@text-case"] == "lowercase") {
|
||||
// all lowercase
|
||||
string = string.toLowerCase();
|
||||
} else if(element["@text-case"] == "uppercase") {
|
||||
// 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(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) {
|
||||
if(style) {
|
||||
string = '<span style="'+style+'">'+string+'</span>';
|
||||
}
|
||||
} else {
|
||||
|
@ -2589,17 +2626,6 @@ Zotero.CSL.FormattedString.prototype.append = function(string, element, dontDeli
|
|||
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
|
||||
|
@ -2616,13 +2642,16 @@ Zotero.CSL.FormattedString.prototype.append = function(string, element, dontDeli
|
|||
|
||||
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;
|
||||
if(element && element.@suffix.length()) {
|
||||
this.append(element.@suffix.toString(), null, true);
|
||||
}
|
||||
|
||||
// close div for display=block in HTML
|
||||
if(closeDiv) {
|
||||
this.string += "</div>";
|
||||
}
|
||||
|
||||
// save for second-field-align
|
||||
if(!dontDelimit && this.insertTabAfterField) {
|
||||
// replace any space following this entry
|
||||
|
|
|
@ -332,41 +332,14 @@ Zotero.Utilities.prototype.getLocalizedCreatorType = function(type) {
|
|||
*
|
||||
* Follows capitalizeTitles pref, unless |force| is true
|
||||
*/
|
||||
Zotero.Utilities.capitalizeSkipWords = ["but", "or", "yet", "so", "for", "and",
|
||||
"nor", "a", "an", "the", "at", "by", "from", "in", "into", "of", "on", "to",
|
||||
"with", "up", "down"];
|
||||
Zotero.Utilities.prototype.capitalizeTitle = function(title, force) {
|
||||
if (!Zotero.Prefs.get('capitalizeTitles') && !force) {
|
||||
return title;
|
||||
Zotero.Utilities.prototype.capitalizeTitle = function(string, force) {
|
||||
string = this.cleanString(string);
|
||||
if(Zotero.Prefs.get('capitalizeTitles') || force) {
|
||||
// fix colons
|
||||
string = string.replace(" : ", ": ", "g");
|
||||
string = Zotero.Text.titleCase(string.replace(/ : /g, ": "));
|
||||
}
|
||||
title = this.cleanString(title);
|
||||
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(" ");
|
||||
return string;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1115,7 +1115,64 @@ Zotero.Hash.prototype.has = function(in_key){
|
|||
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(){
|
||||
this.sqlToDate = sqlToDate;
|
||||
|
|
Loading…
Reference in New Issue
Block a user