implements Zotero.Styles and Zotero.Style using flat files

This commit is contained in:
Simon Kornblith 2008-09-11 21:29:05 +00:00
parent f6b1d6e56e
commit f06ce2705c
8 changed files with 228 additions and 191 deletions

View file

@ -51,7 +51,7 @@ var Zotero_File_Interface_Bibliography = new function() {
}
var listbox = document.getElementById("style-listbox");
var styles = Zotero.Cite.getStyles();
var styles = Zotero.Styles.getVisible();
// if no style is set, get the last style used
if(!_io.style) {
@ -61,13 +61,14 @@ var Zotero_File_Interface_Bibliography = new function() {
// add styles to list
var index = 0;
for (var i in styles) {
var nStyles = styles.length;
for(var i=0; i<nStyles; i++) {
var itemNode = document.createElement("listitem");
itemNode.setAttribute("value", i);
itemNode.setAttribute("label", styles[i]);
itemNode.setAttribute("value", styles[i].styleID);
itemNode.setAttribute("label", styles[i].title);
listbox.appendChild(itemNode);
if(i == _io.style) {
if(styles[i].styleID == _io.style) {
var selectIndex = index;
}
index++;
@ -142,7 +143,7 @@ var Zotero_File_Interface_Bibliography = new function() {
// update status of displayAs box based
var styleClass = Zotero.Cite.getStyleClass(selectedStyle);
var styleClass = Zotero.Styles.get(selectedStyle).class;
document.getElementById("displayAs").disabled = styleClass != "note";
}

View file

@ -629,7 +629,7 @@ Zotero_Browser.Tab.prototype._attemptLocalFileImport = function(doc) {
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);
Zotero.Styles.install(csl, doc.documentURI);
}
} else {
// see if we can import this file

View file

@ -320,7 +320,7 @@ var Zotero_File_Interface = new function() {
createInstance(Components.interfaces.nsITransferable);
var clipboardService = Components.classes["@mozilla.org/widget/clipboard;1"].
getService(Components.interfaces.nsIClipboard);
var csl = Zotero.Cite.getStyle(style);
var csl = Zotero.Styles.get(style).csl;
var itemSet = csl.createItemSet(items);
// add HTML
@ -357,7 +357,7 @@ var Zotero_File_Interface = new function() {
var clipboardService = Components.classes["@mozilla.org/widget/clipboard;1"].
getService(Components.interfaces.nsIClipboard);
var csl = Zotero.Cite.getStyle(style);
var csl = Zotero.Styles.get(style).csl;
var itemSet = csl.createItemSet(items);
var itemIDs = [];
for (var i=0; i<items.length; i++) {
@ -420,7 +420,7 @@ var Zotero_File_Interface = new function() {
return;
}
else {
var csl = Zotero.Cite.getStyle(io.style);
var csl = Zotero.Styles.get(io.style).csl;
var itemSet = csl.createItemSet(items);
var bibliography = csl.formatBibliography(itemSet, format);
}

View file

@ -371,13 +371,13 @@ function buildQuickCopyFormatDropDown(menulist, contentType, currentFormat) {
popup.appendChild(itemNode);
// add styles to list
var styles = Zotero.Cite.getStyles();
for (var i in styles) {
var styles = Zotero.Styles.getVisible();
for each(var style in styles) {
var baseVal = 'bibliography=' + i;
var val = 'bibliography' + (contentType == 'html' ? '/html' : '') + '=' + i;
var val = 'bibliography' + (contentType == 'html' ? '/html' : '') + '=' + style.styleID;
var itemNode = document.createElement("menuitem");
itemNode.setAttribute("value", val);
itemNode.setAttribute("label", styles[i]);
itemNode.setAttribute("label", style.title);
itemNode.setAttribute("oncommand", 'updateQuickCopyHTMLCheckbox()');
popup.appendChild(itemNode);
@ -1188,7 +1188,7 @@ function addStyle() {
var name = file.leafName.replace(/\.ens$/i, "");
var date = new Date(file.lastModifiedTime);
var cslID = Zotero.Cite.installStyle(read, false, date, name);
var cslID = Zotero.Styles.install(read, false, date, name);
} else {
// This _should_ get the right charset for us automatically
var fileURI = Components.classes["@mozilla.org/network/protocol;1?name=file"]
@ -1205,7 +1205,7 @@ function addStyle() {
throw e;
}
var cslID = Zotero.Cite.installStyle(req.responseText);
var cslID = Zotero.Styles.install(req.responseText);
}
}
@ -1221,8 +1221,14 @@ function deleteStyle() {
var treeitem = tree.lastChild.childNodes[tree.currentIndex];
var cslID = treeitem.getAttribute('id').substr(11);
Zotero.Cite.deleteStyle(cslID);
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var text = Zotero.getString('styles.deleteStyle', [title]);
if(ps.confirm(null, '', text)) {
Zotero.Styles.get(cslID).delete();
this.refreshStylesList();
}
document.getElementById('styleManager-delete').disabled = true;
}

View file

@ -20,175 +20,185 @@
***** END LICENSE BLOCK *****
*/
/*
* Zotero.Cite: a class for creating bibliographies from within Scholar
* this class handles pulling the CSL file and item data out of the database,
* while CSL, below, handles the actual generation of the bibliography
/**
* @property {Boolean} cacheTranslatorData Whether translator data should be cached or reloaded
* every time a translator is accessed
* @property {Zotero.CSL} lastCSL
*/
Zotero.Styles = new function() {
var _initialized = false;
var _styles, _visibleStyles;
Zotero.Cite = new function() {
default xml namespace = "http://purl.org/net/xbiblio/csl";
this.ios = Components.classes["@mozilla.org/network/io-service;1"].
getService(Components.interfaces.nsIIOService);
var _lastCSL = null;
var _lastStyle = null;
this.getStyles = getStyles;
this.getStyleClass = getStyleClass;
this.getStyle = getStyle;
this.installStyle = installStyle;
this.deleteStyle = deleteStyle;
/*
* returns an associative array of cslID => styleName pairs
/**
* Initializes styles cache, loading metadata for styles into memory
*/
function getStyles() {
// get styles
var sql = "SELECT cslID, title FROM csl ORDER BY title";
var styles = Zotero.DB.query(sql);
this.init = function() {
_initialized = true;
// convert to associative array
var stylesObject = new Object();
for each(var style in styles) {
stylesObject[style.cslID] = style.title;
}
var start = (new Date()).getTime()
return stylesObject;
}
_styles = {};
_visibleStyles = [];
this.cacheTranslatorData = Zotero.Prefs.get("cacheTranslatorData");
this.lastCSL = null;
/*
* gets the class of a given style
*/
function getStyleClass(cslID) {
var csl = _getCSL(cslID);
var xml = new XML(Zotero.CSL.Global.cleanXML(csl));
return xml["@class"].toString();
}
// main dir
var dir = Zotero.getStylesDirectory();
var i = _readStylesFromDirectory(dir, true);
/*
* gets CSL from the database, or, if it's the most recently used style,
* from the cache
*/
function getStyle(cslID) {
if(_lastStyle != cslID || Zotero.Prefs.get("cacheTranslatorData") == false) {
// create a CSL instance
var csl = _getCSL(cslID);
// hidden dir
dir.append("hidden");
if(dir.exists()) i += _readStylesFromDirectory(dir);
// load CSL in EN mode if necessary
if(csl.substr(0, 6) == "\x00\x08\xFF\x00\x00\x00") {
// EN style
var enConverter = new Zotero.ENConverter(csl);
csl = enConverter.parse();
}
_lastCSL = new Zotero.CSL(csl);
_lastStyle = cslID;
}
return _lastCSL;
}
/*
* get CSL for a given style from the database
*/
function _getCSL(cslID) {
var style = Zotero.DB.valueQuery("SELECT csl FROM csl WHERE cslID = ?", [cslID]);
if(!style) throw "Zotero.Cite: invalid CSL ID";
return style;
Zotero.debug("Cached "+i+" styles in "+((new Date()).getTime() - start)+" ms");
}
/**
* installs a style
**/
function installStyle(cslString, loadURI, date, name) {
var error = false;
try {
if(cslString.substr(0, 6) == "\x00\x08\xFF\x00\x00\x00") {
// EN style
var enConverter = new Zotero.ENConverter(cslString, date, name);
var xml = enConverter.parse();
* Reads all styles from a given directory and caches their metadata
*/
function _readStylesFromDirectory(dir, visible) {
var i = 0;
var contents = dir.directoryEntries;
while(contents.hasMoreElements()) {
var file = contents.getNext().QueryInterface(Components.interfaces.nsIFile);
if(!file.leafName || file.leafName[0] == "." || file.isDirectory()) continue;
var style = new Zotero.Style(file);
if(style.styleID) {
if(_styles[style.styleID]) {
// same style is already cached
Zotero.log('Style with ID '+style.styleID+' already loaded from "'+
_styles[style.styleID].file.leafName+'"', "error",
Zotero.Styles.ios.newFileURI(style.file).spec);
} else {
// CSL
var xml = new XML(Zotero.CSL.Global.cleanXML(cslString));
// add to cache
_styles[style.styleID] = style;
if(visible) _visibleStyles.push(style);
}
}
catch (e) {
error = true;
Components.utils.reportError(e);
}
if (!xml || error) {
alert(Zotero.getString('styles.installError', (loadURI ? loadURI : "This")));
return false;
}
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) {
if(loadURI) {
var text = Zotero.getString('styles.updateStyleURI', [existingTitle, title, loadURI]);
} else {
var text = Zotero.getString('styles.updateStyle', [existingTitle, title]);
}
}
else {
if(loadURI) {
var text = Zotero.getString('styles.installStyleURI', [title, loadURI]);
} else {
var text = Zotero.getString('styles.installStyle', [title]);
}
}
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));
return uri;
i++;
}
return i;
}
/**
* deletes a style
**/
function deleteStyle(uri) {
var sql = "SELECT title FROM csl WHERE cslID=?";
var title = Zotero.DB.valueQuery(sql, uri);
if(!title) throw "Cite: style to delete does not exist!"
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var text = Zotero.getString('styles.deleteStyle', [title]);
if(ps.confirm(null, '', text)) {
var sql = "DELETE FROM csl WHERE cslID=?";
Zotero.DB.query(sql, uri);
* Gets a style with a given ID
* @param {String} id
*/
this.get = function(id) {
if(!_initialized) this.init();
return _styles[id];
}
/**
* Gets all visible styles
*/
this.getVisible = function() {
if(!_initialized || !this.cacheTranslatorData) this.init();
return _visibleStyles;
}
/**
* Gets all styles
*/
this.getAll = function() {
if(!_initialized || !this.cacheTranslatorData) this.init();
return _styles;
}
}
/**
* @class Represents a style file and its metadata
* @property {String} styleID
* @property {String} title
* @property {String} updated
* @property {String} class
* @property {Zotero.CSL} csl
*/
Zotero.Style = function(file) {
this.file = file;
var extension = file.leafName.substr(-4).toLowerCase();
if(extension == ".ens") {
this.type = "ens";
this.styleID = Zotero.Styles.ios.newFileURI(this.file).spec;
this.title = file.leafName.substr(0, file.leafName.length-4);
this.updated = Zotero.Date.dateToSQL(new Date(file.lastModifiedTime));
} else if(extension == ".csl") {
// "with ({});" needed to fix default namespace scope issue
// See https://bugzilla.mozilla.org/show_bug.cgi?id=330572
default xml namespace = "http://purl.org/net/xbiblio/csl"; with ({});
this.type = "csl";
var xml = Zotero.CSL.Global.cleanXML(Zotero.File.getContents(file));
xml = new XML(xml);
this.styleID = xml.info.id.toString();
this.title = xml.info.title.toString();
this.updated = xml.info.updated.toString().replace(/(.+)T([^\+]+)\+?.*/, "$1 $2");
this._class = xml.@class.toString();
}
}
Zotero.Style.prototype.__defineGetter__("csl",
/**
* Retrieves the Zotero.CSL object for this style
* @type Zotero.CSL
*/
function() {
// cache last style
if(Zotero.Styles.cacheTranslatorData && Zotero.Styles.lastCSL.styleID == this.styleID) {
return Zotero.Styles.lastCSL;
}
Zotero.Cite.MIMEHandler = new function () {
if(this.type == "ens") {
// EN style
var iStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
.createInstance(Components.interfaces.nsIFileInputStream);
iStream.init(this.file, 0x01, 0664, 0);
var bStream = Components.classes["@mozilla.org/binaryinputstream;1"]
.createInstance(Components.interfaces.nsIBinaryInputStream);
bStream.setInputStream(iStream);
var string = bStream.readBytes(this.file.fileSize);
iStream.close();
var enConverter = new Zotero.ENConverter(string, null, this.title);
var xml = enConverter.parse();
} else {
var cslString = Zotero.File.getContents(this.file);
var xml = new XML(Zotero.CSL.Global.cleanXML(cslString));
}
return (Zotero.Styles.lastCSL = new Zotero.CSL(xml));
});
Zotero.Style.prototype.__defineGetter__("class",
/**
* Retrieves the style class, either from the metadata that's already loaded or by loading the file
* @type String
*/
function() {
if(this._class) return this._class;
return (this._class = this.csl.class);
});
/**
* Deletes a style
*/
Zotero.Style.prototype.delete = function() {
this.file.remove();
Zotero.Styles.init();
}
Zotero.Styles.MIMEHandler = new function () {
this.init = init;
/*
@ -198,16 +208,16 @@ Zotero.Cite.MIMEHandler = new function () {
Zotero.debug("Registering URIContentListener for text/x-csl");
var uriLoader = Components.classes["@mozilla.org/uriloader;1"]
.getService(Components.interfaces.nsIURILoader);
uriLoader.registerContentListener(Zotero.Cite.MIMEHandler.URIContentListener);
uriLoader.registerContentListener(Zotero.Styles.MIMEHandler.URIContentListener);
}
}
/*
* Zotero.Cite.MIMEHandler.URIContentListener: implements
* Zotero.Styles.MIMEHandler.URIContentListener: implements
* nsIURIContentListener interface to grab MIME types
*/
Zotero.Cite.MIMEHandler.URIContentListener = new function() {
Zotero.Styles.MIMEHandler.URIContentListener = new function() {
// list of content types to capture
// NOTE: must be from shortest to longest length
this.desiredContentTypes = ["text/x-csl"];
@ -236,7 +246,7 @@ Zotero.Cite.MIMEHandler.URIContentListener = new function() {
function doContent(contentType, isContentPreferred, request, contentHandler) {
Zotero.debug("Running doContent() for " + request.name);
contentHandler.value = new Zotero.Cite.MIMEHandler.StreamListener(request, contentType);
contentHandler.value = new Zotero.Styles.MIMEHandler.StreamListener(request, contentType);
return false;
}
@ -253,10 +263,10 @@ Zotero.Cite.MIMEHandler.URIContentListener = new function() {
}
/*
* Zotero.Cite.MIMEHandler.StreamListener: implements nsIStreamListener and
* Zotero.Styles.MIMEHandler.StreamListener: implements nsIStreamListener and
* nsIRequestObserver interfaces to download MIME types we've grabbed
*/
Zotero.Cite.MIMEHandler.StreamListener = function(request, contentType) {
Zotero.Styles.MIMEHandler.StreamListener = function(request, contentType) {
this._request = request;
this._contentType = contentType
this._readString = "";
@ -266,7 +276,7 @@ Zotero.Cite.MIMEHandler.StreamListener = function(request, contentType) {
Zotero.debug("Prepared to grab content type " + contentType);
}
Zotero.Cite.MIMEHandler.StreamListener.prototype.QueryInterface = function(iid) {
Zotero.Styles.MIMEHandler.StreamListener.prototype.QueryInterface = function(iid) {
if (iid.equals(Components.interfaces.nsISupports)
|| iid.equals(Components.interfaces.nsIRequestObserver)
|| iid.equals(Components.interfaces.nsIStreamListener)) {
@ -275,12 +285,12 @@ Zotero.Cite.MIMEHandler.StreamListener.prototype.QueryInterface = function(iid)
throw Components.results.NS_ERROR_NO_INTERFACE;
}
Zotero.Cite.MIMEHandler.StreamListener.prototype.onStartRequest = function(channel, context) {}
Zotero.Styles.MIMEHandler.StreamListener.prototype.onStartRequest = function(channel, context) {}
/*
* Called when there's data available; basically, we just want to collect this data
*/
Zotero.Cite.MIMEHandler.StreamListener.prototype.onDataAvailable = function(request, context, inputStream, offset, count) {
Zotero.Styles.MIMEHandler.StreamListener.prototype.onDataAvailable = function(request, context, inputStream, offset, count) {
Zotero.debug(count + " bytes available");
if (inputStream != this._scriptableStreamInput) {
@ -295,7 +305,7 @@ Zotero.Cite.MIMEHandler.StreamListener.prototype.onDataAvailable = function(requ
/*
* Called when the request is done
*/
Zotero.Cite.MIMEHandler.StreamListener.prototype.onStopRequest = function(channel, context, status) {
Zotero.Styles.MIMEHandler.StreamListener.prototype.onStopRequest = function(channel, context, status) {
Zotero.debug("Request finished");
var externalHelperAppService = Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"]
.getService(Components.interfaces.nsIExternalHelperAppService);
@ -307,7 +317,7 @@ Zotero.Cite.MIMEHandler.StreamListener.prototype.onStopRequest = function(channe
var loadURI = '';
}
Zotero.Cite.installStyle(this._readString, loadURI);
Zotero.Styles.install(this._readString, loadURI);
}
@ -333,12 +343,12 @@ Zotero.CSL = function(csl) {
// load localizations
this._terms = Zotero.CSL.Global.parseLocales(this._csl.terms);
// load class
// load class and styleID
this.styleID = this._csl.info.id.toString();
this.class = this._csl["@class"].toString();
Zotero.debug("CSL: style class is "+this.class);
this.hasBibliography = (this._csl.bibliography.length() ? 1 : 0);
Zotero.debug("hasBibliography "+this.hasBibliography);
}
/*

View file

@ -704,7 +704,7 @@ Zotero.Integration.SOAP_Compat = new function() {
}
try {
Zotero.Cite.getStyle(vars[2]);
Zotero.Styles.get(vars[2]);
} catch(e) {
return "ERROR:prefsNeedReset";
}
@ -809,7 +809,7 @@ Zotero.Integration.Session.prototype.setStyle = function(styleID, prefs) {
if(styleID) {
this.styleID = styleID;
try {
this.style = Zotero.Cite.getStyle(styleID);
this.style = Zotero.Styles.get(styleID).csl;
this.dateModified = new Object();
this.itemSet = this.style.createItemSet();
@ -1482,22 +1482,36 @@ Zotero.Integration.Session.prototype.getBibliographyData = function() {
}
}
/*
* Interface for bibliography editor
/**
* @class Interface for bibliography editor to alter document bibliography
* @constructor
* Creates a new bibliography editor interface
* @param {Zotero.Integration.Session} session
*/
Zotero.Integration.Session.BibliographyEditInterface = function(session) {
this.session = session;
}
/**
* Gets the @link {Zotero.CSL.ItemSet} for the bibliography being edited
* The item set should not be modified, but may be used to determine what items are in the
* bibliography.
*/
Zotero.Integration.Session.BibliographyEditInterface.prototype.getItemSet = function() {
return this.session.itemSet;
}
/**
* Checks whether an item is cited in the bibliography being edited
*/
Zotero.Integration.Session.BibliographyEditInterface.prototype.isCited = function(item) {
if(this.session.citationsByItemID[item.id]) return true;
return false;
}
/**
* Checks whether an item is cited in the bibliography being edited
*/
Zotero.Integration.Session.BibliographyEditInterface.prototype.add = function(item) {
// create new item
this.session.itemSet.add([item]);
@ -1505,6 +1519,9 @@ Zotero.Integration.Session.BibliographyEditInterface.prototype.add = function(it
this.session.sortItemSet();
}
/**
* Removes an item from the bibliography being edited
*/
Zotero.Integration.Session.BibliographyEditInterface.prototype.remove = function(item) {
// create new item
this.session.itemSet.remove([item]);
@ -1524,6 +1541,9 @@ Zotero.Integration.Session.BibliographyEditInterface.prototype.remove = function
if(this.session.uncitedItems[item.key]) this.session.uncitedItems[item.key] = undefined;
}
/**
* Generates a preview of the bibliography entry for a given item
*/
Zotero.Integration.Session.BibliographyEditInterface.prototype.preview = function(item) {
var itemSet = this.session.style.createItemSet([item]);
return this.session.style.formatBibliography(itemSet, "Integration");

View file

@ -190,7 +190,7 @@ Zotero.QuickCopy = new function() {
return content;
}
var csl = Zotero.Cite.getStyle(format);
var csl = Zotero.Styles.get(format).csl;
var itemSet = csl.createItemSet(items);
// Copy citations if shift key pressed
@ -223,9 +223,9 @@ Zotero.QuickCopy = new function() {
var translators = translation.getTranslators();
// add styles to list
var styles = Zotero.Cite.getStyles();
for (var i in styles) {
_formattedNames['bibliography=' + i] = styles[i];
var styles = Zotero.Styles.getVisible();
for each(var style in styles) {
_formattedNames['bibliography=' + style.styleID] = style.title;
}
for (var i=0; i<translators.length; i++) {

View file

@ -277,7 +277,7 @@ var Zotero = new function(){
Zotero.Proxies.init();
Zotero.Ingester.MIMEHandler.init();
Zotero.Cite.MIMEHandler.init();
Zotero.Styles.MIMEHandler.init();
this.initialized = true;
Zotero.debug("Initialized in "+((new Date()).getTime() - start)+" ms");