- 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:
Simon Kornblith 2007-11-26 22:06:06 +00:00
parent ad181f973c
commit 669f115376
4 changed files with 200 additions and 131 deletions

View File

@ -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();
}
}
/*

View File

@ -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

View File

@ -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;
}
/*

View File

@ -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;