diff --git a/chrome/content/zotero/about.xul b/chrome/content/zotero/about.xul index 6414110a93..52949ca227 100644 --- a/chrome/content/zotero/about.xul +++ b/chrome/content/zotero/about.xul @@ -148,7 +148,7 @@ ], "sk-SK": [ - "athelas" + "Milan Regec" ], "sl-SI": [ diff --git a/chrome/content/zotero/charsetMenu.js b/chrome/content/zotero/charsetMenu.js new file mode 100644 index 0000000000..47f2f0cbe9 --- /dev/null +++ b/chrome/content/zotero/charsetMenu.js @@ -0,0 +1,102 @@ +/* + ***** BEGIN LICENSE BLOCK ***** + + Copyright (c) 2006 Center for History and New Media + George Mason University, Fairfax, Virginia, USA + http://chnm.gmu.edu + + Licensed under the Educational Community License, Version 1.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.opensource.org/licenses/ecl1.php + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ***** END LICENSE BLOCK ***** +*/ + +Zotero_Charset_Menu = new function() { + this.populate = populate; + + /** + * Populate a character set menu, placing more commonly used character sets + * closer to the top + * + * @param {DOMElement} charsetMenu The menu to populate + * @param {Boolean} showEndian Whether to show endian (e.g., UTF-32) options + **/ + function populate(charsetMenu, showEndian) { + var charsetMap = {}; + + // get charset popup and charset RDF + var charsetPopup = document.createElement("menupopup"); + charsetMenu.appendChild(charsetPopup); + var charsetSeparator = document.createElement("menuseparator"); + charsetPopup.appendChild(charsetSeparator); + + var rdfService = Components.classes["@mozilla.org/rdf/rdf-service;1"]. + getService(Components.interfaces.nsIRDFService); + var RDFCU = Components.classes["@mozilla.org/rdf/container-utils;1"]. + getService(Components.interfaces.nsIRDFContainerUtils); + var rdfDataSource = rdfService.GetDataSource("rdf:charset-menu"); + var rdfName = rdfService.GetResource("http://home.netscape.com/NC-rdf#Name"); + var rdfContainer = Components.classes["@mozilla.org/rdf/container;1"]. + createInstance(Components.interfaces.nsIRDFContainer); + rdfContainer.Init(rdfDataSource, rdfService.GetResource("NC:EncodersRoot")); + var charsets = rdfContainer.GetElements(); + + // add charsets to popup in order + while(charsets.hasMoreElements()) { + var charset = charsets.getNext().QueryInterface(Components.interfaces.nsIRDFResource); + var label = rdfDataSource.GetTarget(charset, rdfName, true). + QueryInterface(Components.interfaces.nsIRDFLiteral); + charset = charset.Value; + label = label.Value; + + var isUTF16 = charset.length >= 6 && charset.substr(0, 6) == "UTF-16"; + + // Show UTF-16 element appropriately depending on showEndian + if(isUTF16 && showEndian == (charset == "UTF-16") || + (!showEndian && charset == "UTF-32LE")) { + continue; + } else if(charset == "x-mac-roman") { + // use the IANA name + value = "macintosh"; + } else if(!showEndian && charset == "UTF-32BE") { + label = "Unicode (UTF-32)"; + value = "UTF-32"; + } + + // add element + var itemNode = document.createElement("menuitem"); + itemNode.setAttribute("label", label); + itemNode.setAttribute("value", charset); + + charsetMap[charset] = itemNode; + if(isUTF16 || (label.length > 7 && + label.substr(0, 7) == "Western")) { + charsetPopup.insertBefore(itemNode, charsetSeparator); + } else if(charset == "UTF-8") { + var oldFirst = (charsetPopup.firstChild ? charsetPopup.firstChild : null); + charsetPopup.insertBefore(itemNode, oldFirst); + // also add (without BOM) if requested + if(showEndian) { + var itemNode = document.createElement("menuitem"); + itemNode.setAttribute("label", Zotero.getString("charset.UTF8withoutBOM")); + itemNode.setAttribute("value", charset+"xBOM"); + charsetMap[charset+"xBOM"] = itemNode; + charsetPopup.insertBefore(itemNode, oldFirst); + } + } else { + charsetPopup.appendChild(itemNode); + } + } + + return charsetMap; + } +} \ No newline at end of file diff --git a/chrome/content/zotero/exportOptions.js b/chrome/content/zotero/exportOptions.js index 3ba676735b..a88cc4d896 100644 --- a/chrome/content/zotero/exportOptions.js +++ b/chrome/content/zotero/exportOptions.js @@ -26,6 +26,8 @@ // ////////////////////////////////////////////////////////////////////////////// +const OPTION_PREFIX = "export-option-"; + // Class to provide options for export var Zotero_File_Interface_Export = new function() { @@ -34,6 +36,8 @@ var Zotero_File_Interface_Export = new function() { this.accept = accept; this.cancel = cancel; + var _charsets; + /* * add options to export */ @@ -46,17 +50,19 @@ var Zotero_File_Interface_Export = new function() { var translators = window.arguments[0].translators; - var listbox = document.getElementById("format-popup"); + // get format popup + var formatPopup = document.getElementById("format-popup"); var formatMenu = document.getElementById("format-menu"); var optionsBox = document.getElementById("translator-options"); + var charsetBox = document.getElementById("charset-box"); var selectedTranslator = Zotero.Prefs.get("export.lastTranslator"); - // add styles to list + // add styles to format popup for(var i in translators) { var itemNode = document.createElement("menuitem"); itemNode.setAttribute("label", translators[i].label); - listbox.appendChild(itemNode); + formatPopup.appendChild(itemNode); // add options for(var option in translators[i].displayOptions) { @@ -73,9 +79,9 @@ var Zotero_File_Interface_Export = new function() { // it interprets as checkboxes if(typeof(translators[i].displayOptions[option]) == "boolean") { var checkbox = document.createElement("checkbox"); - checkbox.setAttribute("id", "export-option-"+option); + checkbox.setAttribute("id", OPTION_PREFIX+option); checkbox.setAttribute("label", optionLabel); - optionsBox.appendChild(checkbox); + optionsBox.insertBefore(checkbox, charsetBox); } addedOptions[option] = true; @@ -93,6 +99,9 @@ var Zotero_File_Interface_Export = new function() { formatMenu.selectedIndex = 0; } + // from charsetMenu.js + _charsets = Zotero_Charset_Menu.populate(document.getElementById(OPTION_PREFIX+"exportCharset"), true); + updateOptions(Zotero.Prefs.get("export.translatorSettings")); } @@ -105,7 +114,9 @@ var Zotero_File_Interface_Export = new function() { var translatorOptions = window.arguments[0].translators[index].displayOptions; if(optionString) { - var options = optionString.split(","); + try { + var options = Zotero.JSON.unserialize(optionString); + } catch(e) {} } var optionsBox = document.getElementById("translator-options"); @@ -114,8 +125,13 @@ var Zotero_File_Interface_Export = new function() { for(var i=0; i - + +%zoteroDTD; + +%charsetDTD; +]> + @@ -19,7 +33,13 @@ - + + + \ No newline at end of file diff --git a/chrome/content/zotero/fileInterface.js b/chrome/content/zotero/fileInterface.js index 3313f7e149..255aac07b6 100644 --- a/chrome/content/zotero/fileInterface.js +++ b/chrome/content/zotero/fileInterface.js @@ -44,7 +44,7 @@ Zotero_File_Exporter.prototype.save = function() { // present options dialog var io = {translators:translators} window.openDialog("chrome://zotero/content/exportOptions.xul", - "_blank", "chrome,modal,centerscreen", io); + "_blank", "chrome,modal,centerscreen,resizable=no", io); if(!io.selectedTranslator) { return false; } @@ -209,30 +209,34 @@ var Zotero_File_Interface = new function() { if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) { translation.setLocation(fp.file); // get translators again, bc now we can check against the file + translation.setHandler("translators", function(obj, item) { _importTranslatorsAvailable(obj, item) }); translators = translation.getTranslators(); - if(translators.length) { - // create a new collection to take in imported items - var date = new Date(); - _importCollection = Zotero.Collections.add(Zotero.getString("fileInterface.imported")+" "+date.toLocaleString()); - - // import items - translation.setTranslator(translators[0]); - translation.setHandler("collectionDone", _importCollectionDone); - translation.setHandler("done", _importDone); - Zotero.UnresponsiveScriptIndicator.disable(); - - // show progress indicator - Zotero_File_Interface.Progress.show( - Zotero.getString("fileInterface.itemsImported"), - function() { - Zotero.DB.beginTransaction(); - - // translate - translation.translate(); - }); - } else { - window.alert(Zotero.getString("fileInterface.fileFormatUnsupported")); - } + } + } + + function _importTranslatorsAvailable(translation, translators) { + if(translators.length) { + // create a new collection to take in imported items + var date = new Date(); + _importCollection = Zotero.Collections.add(Zotero.getString("fileInterface.imported")+" "+date.toLocaleString()); + + // import items + translation.setTranslator(translators[0]); + translation.setHandler("collectionDone", _importCollectionDone); + translation.setHandler("done", _importDone); + Zotero.UnresponsiveScriptIndicator.disable(); + + // show progress indicator + Zotero_File_Interface.Progress.show( + Zotero.getString("fileInterface.itemsImported"), + function() { + Zotero.DB.beginTransaction(); + + // translate + translation.translate(); + }); + } else { + window.alert(Zotero.getString("fileInterface.fileFormatUnsupported")); } } diff --git a/chrome/content/zotero/overlay.js b/chrome/content/zotero/overlay.js index e170d26d16..67717fa67a 100644 --- a/chrome/content/zotero/overlay.js +++ b/chrome/content/zotero/overlay.js @@ -410,9 +410,9 @@ var ZoteroPane = new function() return; } - // Ignore modifiers other than accel-alt (or accel-shift if useShift is on) + // Ignore modifiers other than Ctrl-Alt or Cmd-Shift if (!((Zotero.isMac ? event.metaKey : event.ctrlKey) && - useShift ? event.shiftKey : event.altKey)) { + (useShift ? event.shiftKey : event.altKey))) { return; } @@ -1400,6 +1400,10 @@ var ZoteroPane = new function() if (this.itemsView.rowCount>0) { var enable = [m.exportCollection, m.createBibCollection, m.loadReport]; } + else if (!this.collectionsView.isContainerEmpty(this.collectionsView.selection.currentIndex)) { + var enable = [m.exportCollection]; + var disable = [m.createBibCollection, m.loadReport]; + } else { var disable = [m.exportCollection, m.createBibCollection, m.loadReport]; @@ -2038,13 +2042,15 @@ var ZoteroPane = new function() var isNative = Zotero.MIME.hasNativeHandler(mimeType, ext); var internal = Zotero.MIME.hasInternalHandler(mimeType, ext); - var fileURL = attachment.getLocalFileURL(); - if (isNative || (internal && !Zotero.Prefs.get('launchNonNativeFiles'))) { - this.loadURI(fileURL, event, { attachmentID: itemID}); + + var url = 'zotero://attachment/' + itemID + '/'; + this.loadURI(url, event, { attachmentID: itemID}); } else { + var fileURL = attachment.getLocalFileURL(); + // Some platforms don't have nsILocalFile.launch, so we just load it and // let the Firefox external helper app window handle it try { diff --git a/chrome/content/zotero/xpcom/cite.js b/chrome/content/zotero/xpcom/cite.js index 6c4f44ffbd..0c851cd024 100644 --- a/chrome/content/zotero/xpcom/cite.js +++ b/chrome/content/zotero/xpcom/cite.js @@ -701,7 +701,7 @@ Zotero.CSL.prototype.formatBibliography = function(itemSet, format) { if(format == "HTML") { var coins = Zotero.OpenURL.createContextObject(item.zoteroItem, "1.0"); - var span = (coins ? ' ' : ''); + var span = (coins ? '  ' : ''); if(this.class == "note" && isCitation) { output += "
  • "+string+span+"
  • \r\n"; diff --git a/chrome/content/zotero/xpcom/translate.js b/chrome/content/zotero/xpcom/translate.js index 924933a91a..d43f6fa201 100644 --- a/chrome/content/zotero/xpcom/translate.js +++ b/chrome/content/zotero/xpcom/translate.js @@ -24,6 +24,18 @@ // Zotero Translate Engine // + +/** + * Set of byte order marks + **/ +const BOMs = { + "UTF-8":"\xEF\xBB\xBF", + "UTF-16BE":"\xFE\xFF", + "UTF-16LE":"\xFF\xFE", + "UTF-32BE":"\x00\x00\xFE\xFF", + "UTF-32LE":"\xFF\xFE\x00\x00" +} + /* * Zotero.Translate: a class for translation of Zotero metadata from and to * other formats @@ -80,6 +92,7 @@ * * PRIVATE PROPERTIES: * + * _charset - character set * _numericTypes - possible numeric types as a comma-delimited string * _handlers - handlers for various events (see setHandler) * _sandbox - sandbox in which translators will be executed @@ -92,7 +105,6 @@ * _storage - the stored string to be treated as input * _storageLength - the length of the stored string * _exportFileDirectory - the directory to which files will be exported - * _hasBOM - whether the given file ready to be imported has a BOM or not * * WEB-ONLY PROPERTIES: * @@ -105,7 +117,6 @@ * * output - export output (if no location has been specified) */ - Zotero.Translate = function(type, saveItem) { this.type = type; @@ -471,9 +482,6 @@ Zotero.Translate.prototype.getTranslators = function() { // do not allow simultaneous instances of getTranslators if(this._translatorSearch) this._translatorSearch.running = false; - // clear BOM - this._hasBOM = null; - if(Zotero.Translate.cache) { var translators = Zotero.Translate.cache[this.type]; } else { @@ -543,7 +551,6 @@ Zotero.Translate.prototype.translate = function() { this._IDMap = new Array(); this._complete = false; this._itemsDone = false; - this._hasBOM = null; if(!this.translator || !this.translator.length) { throw("cannot translate: no translator specified"); @@ -593,8 +600,8 @@ Zotero.Translate.prototype.translate = function() { * parses translator detect code */ Zotero.Translate.prototype._parseDetectCode = function(translator) { - this.configOptions = new Array(); - this.displayOptions = new Array(); + this.configOptions = {}; + this.displayOptions = {}; if(translator.detectCode) { var detectCode = translator.detectCode; @@ -672,7 +679,7 @@ Zotero.Translate.prototype._generateSandbox = function() { if(this.type == "import") { // add routines to add new collections - this._sandbox.Zotero.Collection = Zotero.Translate.GenerateZoteroItemClass(); + this._sandbox.Zotero.Collection = Zotero.Translate.GenerateZoteroCollectionClass(); // attach the function to be run when a collection is done this._sandbox.Zotero.Collection.prototype.complete = function() {me._collectionDone(this)}; } @@ -1528,9 +1535,9 @@ Zotero.Translate.prototype._web = function() { return true; } -/* - * does the actual search translation - */ +/** + * Does the actual search translation + **/ Zotero.Translate.prototype._search = function() { try { this._sandbox.doSearch(this.search); @@ -1542,11 +1549,47 @@ Zotero.Translate.prototype._search = function() { return true; } -/* - * does the actual import translation - */ +/** + * Does the actual import translation + **/ Zotero.Translate.prototype._import = function() { - this._importConfigureIO(); + this.waitForCompletion = true; + var me = this; + this._importGetCharacterSet(function(charset) { me._importDoComplete(charset) }); + return true; +} + +/** + * Sniff file if a real file exists + * + * @param {Function} callback A callback function to be executed after sniffing + **/ +Zotero.Translate.prototype._importGetCharacterSet = function(callback) { + if(!this._storage) { + // need to check charset + + if(this._charset) { + // have charset already; just go on + callback(this._charset); + } else { + // look for charset + var me = this; + Zotero.File.getCharsetFromFile(this.location, "text/plain", + function(charset) { + me._charset = charset; + callback(charset); + }); + } + } else { + callback(); + } +} + +/** + * Complete import (used as callback after sniffing) + **/ +Zotero.Translate.prototype._importDoComplete = function(charset) { + this._importConfigureIO(charset); try { this._sandbox.doImport(); @@ -1558,14 +1601,13 @@ Zotero.Translate.prototype._import = function() { return false; } } - - return true; + this._translationComplete(true); } /* - * sets up import for IO + * set up import for IO */ -Zotero.Translate.prototype._importConfigureIO = function() { +Zotero.Translate.prototype._importConfigureIO = function(charset) { if(this._storage) { if(this.configOptions.dataMode && this.configOptions.dataMode == "rdf") { this._rdf = new Object(); @@ -1622,32 +1664,43 @@ Zotero.Translate.prototype._importConfigureIO = function() { } var filePosition = 0; - var intlStream = this._importDefuseBOM(); - if(intlStream) { - // found a UTF BOM at the beginning of the file; don't allow - // translator to set the character set - this._sandbox.Zotero.setCharacterSet = function() {} - this._streams.push(intlStream); - } else { - // allow translator to set charset - this._sandbox.Zotero.setCharacterSet = function(charset) { - // seek - if(filePosition != 0) { - me._inputStream.QueryInterface(Components.interfaces.nsISeekableStream) - .seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, filePosition); - me._inputStream.QueryInterface(Components.interfaces.nsIFileInputStream); - } - - intlStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"] - .createInstance(Components.interfaces.nsIConverterInputStream); - try { - intlStream.init(me._inputStream, charset, 65535, - Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); - } catch(e) { - throw "Text encoding not supported"; - } - me._streams.push(intlStream); + + if(charset) { // if have detected charset + Zotero.debug("Using detected character set "+charset); + // seek past BOM + if(charset.length > 3 && charset.substr(0, 3) == "UTF") { + var BOMLength = this._importGetBOMLength(); + this._inputStream.QueryInterface(Components.interfaces.nsISeekableStream) + .seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, BOMLength); } + + // convert from detected charset + var intlStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"] + .createInstance(Components.interfaces.nsIConverterInputStream); + intlStream.init(this._inputStream, charset, 65535, + Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + me._streams.push(intlStream); + } + + // allow translator to set charset + this._sandbox.Zotero.setCharacterSet = function(charset) { + // seek + if(filePosition != 0) { + me._inputStream.QueryInterface(Components.interfaces.nsISeekableStream) + .seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, filePosition); + me._inputStream.QueryInterface(Components.interfaces.nsIFileInputStream); + } + + intlStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"] + .createInstance(Components.interfaces.nsIConverterInputStream); + try { + intlStream.init(me._inputStream, charset, 65535, + Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + } catch(e) { + throw "Text encoding not supported"; + } + + me._streams.push(intlStream); } var str = new Object(); @@ -1703,87 +1756,49 @@ Zotero.Translate.prototype._importConfigureIO = function() { } } -/* - * searches for a UTF BOM at the beginning of the input stream. if one is found, - * returns an appropriate converter-input-stream for the UTF type, and sets - * _hasBOM to the UTF type. if one is not found, returns false, and sets - * _hasBOM to false to prevent further checking. +/** + * Searches for a UTF BOM at the beginning of the input stream. + * + * @return The length of the UTF BOM. */ -Zotero.Translate.prototype._importDefuseBOM = function() { - // if already found not to have a BOM, skip - if(this._hasBOM === false) { - return; - } +Zotero.Translate.prototype._importGetBOMLength = function() { + // if not checked for a BOM, open a binary input stream and read + var binStream = Components.classes["@mozilla.org/binaryinputstream;1"]. + createInstance(Components.interfaces.nsIBinaryInputStream); + binStream.setInputStream(this._inputStream); - if(!this._hasBOM) { - // if not checked for a BOM, open a binary input stream and read - var binStream = Components.classes["@mozilla.org/binaryinputstream;1"]. - createInstance(Components.interfaces.nsIBinaryInputStream); - binStream.setInputStream(this._inputStream); + var possibleBOMs = BOMs; + var couldHaveBOM = true; + var newBOMs, readByte; + + while(couldHaveBOM) { + newBOMs = {}; + couldHaveBOM = false; - // read the first byte - var byte1 = binStream.read8(); + readByte = binStream.read8(); + readChar = String.fromCharCode(readByte) - // at the moment, we don't support UTF-32 or UTF-7. while mozilla - // supports these encodings, they add slight additional complexity to - // the function and anyone using them for storing bibliographic metadata - // is insane. - if(byte1 == 0xEF) { // UTF-8: EF BB BF - var byte2 = binStream.read8(); - if(byte2 == 0xBB) { - var byte3 = binStream.read8(); - if(byte3 == 0xBF) { - this._hasBOM = "UTF-8"; + for(var charset in possibleBOMs) { + if(possibleBOMs[charset][0] == readChar) { + if(possibleBOMs[charset].length == 1) { + // have checked entire BOM + return BOMs[charset].length; + } else { + // keep checking + newBOMs[charset] = possibleBOMs[charset].substr(1); + couldHaveBOM = true; } } - } else if(byte1 == 0xFE) { // UTF-16BE: FE FF - var byte2 = binStream.read8(); - if(byte2 == 0xFF) { - this._hasBOM = "UTF-16BE"; - } - } else if(byte1 == 0xFF) { // UTF-16LE: FF FE - var byte2 = binStream.read8(); - if(byte2 == 0xFE) { - this._hasBOM = "UTF16-LE"; - } } - if(!this._hasBOM) { - // seek back to begining of file - this._inputStream.QueryInterface(Components.interfaces.nsISeekableStream) - .seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, 0); - this._inputStream.QueryInterface(Components.interfaces.nsIFileInputStream); - - // say there's no BOM - this._hasBOM = false; - - return false; - } - } else { - // if it had a BOM the last time, it has one this time, too. seek to the - // correct position. - - if(this._hasBOM == "UTF-8") { - var seekPosition = 3; - } else { - var seekPosition = 2; - } - - this._inputStream.QueryInterface(Components.interfaces.nsISeekableStream) - .seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, seekPosition); - this._inputStream.QueryInterface(Components.interfaces.nsIFileInputStream); + possibleBOMs = newBOMs; } - // if we know what kind of BOM it has, generate an input stream - var intlStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"] - .createInstance(Components.interfaces.nsIConverterInputStream); - intlStream.init(this._inputStream, this._hasBOM, 65535, - Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); - return intlStream; + return 0; } -/* - * does the actual export, after code has been loaded and parsed +/** + * Does the actual export, after code has been loaded and parsed */ Zotero.Translate.prototype._export = function() { @@ -1793,13 +1808,25 @@ Zotero.Translate.prototype._export = function() { } else if(this.collection) { // get items in this collection this._itemsLeft = this.collection.getChildItems(); + if(!this._itemsLeft) { + this._itemsLeft = []; + } if(this.configOptions.getCollections) { // get child collections this._collectionsLeft = Zotero.getCollections(this.collection.id, true); + + if(this._collectionsLeft.length) { + // only include parent collection if there are actually children + this._collectionsLeft.unshift(this.collection); + } + // get items in child collections for each(var collection in this._collectionsLeft) { - this._itemsLeft = this._itemsLeft.concat(collection.getChildItems()); + var childItems = collection.getChildItems(); + if(childItems) { + this._itemsLeft = this._itemsLeft.concat(childItems); + } } } } else { @@ -1859,8 +1886,9 @@ Zotero.Translate.prototype._export = function() { return true; } -/* - * configures IO for export +/** + * Configures the output stream for export and adds writing functions to the + * sandbox */ Zotero.Translate.prototype._exportConfigureIO = function() { if(this.location) { @@ -1888,20 +1916,51 @@ Zotero.Translate.prototype._exportConfigureIO = function() { } else { // regular io; write just writes to file var intlStream = null; + var writtenToStream = false; + var streamCharset = null; // allow setting of character sets this._sandbox.Zotero.setCharacterSet = function(charset) { + streamCharset = charset.toUpperCase(); intlStream = Components.classes["@mozilla.org/intl/converter-output-stream;1"] .createInstance(Components.interfaces.nsIConverterOutputStream); + if(charset == "UTF-8xBOM") charset = "UTF-8"; intlStream.init(fStream, charset, 1024, "?".charCodeAt(0)); }; + // if exportCharset option was presented to user, use the result + if(this.displayOptions.exportCharset) { + this._sandbox.Zotero.setCharacterSet(this.displayOptions.exportCharset); + } + this._sandbox.Zotero.write = function(data) { - if(intlStream) { - intlStream.writeString(data); + if(streamCharset) { + if(!writtenToStream && BOMs[streamCharset]) { + // If stream has not yet been written to, and a UTF type + // has been selected, write the BOM + fStream.write(BOMs[streamCharset], BOMs[streamCharset].length); + } + + if(streamCharset == "MACINTOSH") { + // fix buggy Mozilla MacRoman + splitData = data.split(/([\r\n]+)/); + Zotero.debug(splitData); + for(var i=0; i + + + + diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index 3b9e350271..a527ad2ef5 100644 --- a/chrome/locale/en-US/zotero/zotero.properties +++ b/chrome/locale/en-US/zotero/zotero.properties @@ -452,7 +452,7 @@ fulltext.indexState.partial = Partial exportOptions.exportNotes = Export Notes exportOptions.exportFileData = Export Files -exportOptions.UTF8 = Export as UTF-8 +charset.UTF8withoutBOM = Unicode (UTF-8 without BOM) date.daySuffixes = st, nd, rd, th date.abbreviation.year = y diff --git a/components/zotero-protocol-handler.js b/components/zotero-protocol-handler.js index 20861dff1e..87b7e27327 100644 --- a/components/zotero-protocol-handler.js +++ b/components/zotero-protocol-handler.js @@ -619,10 +619,73 @@ function ChromeExtensionHandler() { }; + /* + zotero://attachment/[id]/ + */ + var AttachmentExtension = new function() { + this.newChannel = newChannel; + + function newChannel(uri) { + var ioService = Components.classes["@mozilla.org/network/io-service;1"] + .getService(Components.interfaces.nsIIOService); + + var Zotero = Components.classes["@zotero.org/Zotero;1"] + .getService(Components.interfaces.nsISupports) + .wrappedJSObject; + + try { + var errorMsg; + var [id, fileName] = uri.path.substr(1).split('/'); + + if (parseInt(id) != id) { + return _errorChannel("Attachment id not an integer"); + } + + var item = Zotero.Items.get(id); + if (!item) { + return _errorChannel("Item not found"); + } + + var file = item.getFile(); + if (!file) { + return _errorChannel("File not found"); + } + + if (fileName) { + file = file.parent; + file.append(fileName); + if (!file.exists()) { + return _errorChannel("File not found"); + } + } + + var ph = Components.classes["@mozilla.org/network/protocol;1?name=file"]. + createInstance(Components.interfaces.nsIFileProtocolHandler); + fileURI = ph.newFileURI(file); + var channel = ioService.newChannelFromURI(fileURI); + return channel; + } + catch (e) { + Zotero.debug(e); + throw (e); + } + } + + + function _errorChannel(msg) { + var ioService = Components.classes["@mozilla.org/network/io-service;1"] + .getService(Components.interfaces.nsIIOService); + var uriStr = 'data:text/plain,' + encodeURIComponent(msg); + var dataURI = ioService.newURI(uriStr, null, null); + var channel = ioService.newChannelFromURI(dataURI); + return channel; + } + }; + + /* zotero://select/type/id */ - var SelectExtension = new function(){ this.newChannel = newChannel; @@ -660,19 +723,17 @@ function ChromeExtensionHandler() { var ReportExtensionSpec = ZOTERO_SCHEME + "://report" - ReportExtensionSpec = ReportExtensionSpec.toLowerCase(); - this._extensions[ReportExtensionSpec] = ReportExtension; var TimelineExtensionSpec = ZOTERO_SCHEME + "://timeline" - TimelineExtensionSpec = TimelineExtensionSpec.toLowerCase(); - this._extensions[TimelineExtensionSpec] = TimelineExtension; + var AttachmentExtensionSpec = ZOTERO_SCHEME + "://attachment" + this._extensions[AttachmentExtensionSpec] = AttachmentExtension; + var SelectExtensionSpec = ZOTERO_SCHEME + "://select" - SelectExtensionSpec = SelectExtensionSpec.toLowerCase(); - this._extensions[SelectExtensionSpec] = SelectExtension; + } diff --git a/scrapers.sql b/scrapers.sql index 59715555f9..0b86c08030 100644 --- a/scrapers.sql +++ b/scrapers.sql @@ -22,7 +22,7 @@ -- Set the following timestamp to the most recent scraper update date -REPLACE INTO version VALUES ('repository', STRFTIME('%s', '2008-07-07 14:50:00')); +REPLACE INTO version VALUES ('repository', STRFTIME('%s', '2008-07-20 01:40:00')); REPLACE INTO translators VALUES ('96b9f483-c44d-5784-cdad-ce21b984fe01', '1.0.0b4.r1', '', '2008-06-16 21:30:00', '1', '100', '4', 'Amazon.com', 'Sean Takats and Michael Berkowitz', '^https?://(?:www\.)?amazon', 'function detectWeb(doc, url) { @@ -932,13 +932,14 @@ function doWeb(doc, url) { } }'); -REPLACE INTO translators VALUES ('88915634-1af6-c134-0171-56fd198235ed', '1.0.0b3.r1', '', '2008-05-05 07:45:00', '1', '100', '4', 'Library Catalog (Voyager)', 'Simon Kornblith', 'Pwebrecon\.cgi', +REPLACE INTO translators VALUES ('88915634-1af6-c134-0171-56fd198235ed', '1.0.0b3.r1', '', '2008-07-16 20:10:00', '1', '100', '4', 'Library Catalog (Voyager)', 'Simon Kornblith', 'Pwebrecon\.cgi', 'function detectWeb(doc, url) { var export_options = doc.forms.namedItem(''frm'').elements.namedItem(''RD'').options; for(var i in export_options) { if(export_options[i].text == ''Latin1 MARC'' || export_options[i].text == ''Raw MARC'' || export_options[i].text == ''MARC 8'' + || export_options[i].text == ''MARC-8'' || export_options[i].text == ''UTF-8'' || export_options[i].text == ''MARC (Unicode/UTF-8)'' || export_options[i].text == ''MARC UTF-8'' @@ -1037,6 +1038,7 @@ REPLACE INTO translators VALUES ('88915634-1af6-c134-0171-56fd198235ed', '1.0.0b for(var i=0; i 10) { + strdate += ''-'' + date.day; + } + else { + strdate += ''-0'' + date.day; + } + + newItem.date = strdate; + } + + // abstract + xpath = ''//div[@class="teaser"]//div[contains(@class,"teaser")]''; + temp = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null).iterateNext(); + if (temp) { + newItem.abstractNote = Zotero.Utilities.trimInternal(temp.textContent); + } + + // article snapshot + // grabs 5-digit article code from url and uses it to derive printable page url for use in article snapshot + var index = url.toString().indexOf(''.org/'') + 5; + index += url.toString().substr(index).indexOf(''/''); + if (index != -1) { + var printurl; + // ordinary article + var id = url.toString().substr(index + 1, 5); + if (Number(id)) { + printurl = "http://www.alternet.org/module/printversion/" + id; + newItem.attachments.push({url:printurl, title:"AlterNet Article Snapshot", mimeType:"text/html"}); + } + // columnist article + else { + index += url.toString().substr(index + 1).indexOf(''/''); + id = url.toString().substr(index + 2, 5); + Zotero.Utilities.cleanString(id); + if (Number(id)) { + printurl = "http://www.alternet.org/module/printversion/" + id; + if (newItem.itemType == "blogPost") { + printurl += "/?type=blog"; + } + newItem.attachments.push({url:printurl, title:"AlterNet Article Snapshot", mimeType:"text/html"}); + } + } + } + + newItem.complete(); +} + + + +function doWeb(doc, url) { + // ordinary and columnist articles + var xpath = ''//p[@class="storyheadline"]''; + var title; + if (title = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null).iterateNext()) { + scrape(doc, url, title.textContent); + } + + return null; +}'); + REPLACE INTO translators VALUES ('56ea09bc-57ee-4f50-976e-cf7cb1f6c6d8', '1.0.0b4.r5', '', '2008-04-23 09:45:00', '0', '100', '4', 'Royal Society Publishing', 'Michael Berkowitz', 'http://journals.royalsociety.org/', 'function detectWeb(doc, url) { if (doc.evaluate(''//div[@class="listItemName"]/a'', doc, null, XPathResult.ANY_TYPE, null).iterateNext()) { @@ -10048,7 +10836,7 @@ REPLACE INTO translators VALUES ('303c2744-ea37-4806-853d-e1ca67be6818', '1.0.0b Zotero.wait(); }'); -REPLACE INTO translators VALUES ('27ee5b2c-2a5a-4afc-a0aa-d386642d4eed', '1.0.0b4.r5', '', '2008-04-10 03:00:00', '1', '100', '4', 'PubMed Central', 'Michael Berkowitz', 'http://[^/]*.nih.gov/', +REPLACE INTO translators VALUES ('27ee5b2c-2a5a-4afc-a0aa-d386642d4eed', '1.0.0b4.r5', '', '2008-07-16 20:10:00', '1', '100', '4', 'PubMed Central', 'Michael Berkowitz', 'http://[^/]*.nih.gov/', 'function detectWeb(doc, url) { if (doc.evaluate(''//table[@id="ResultPanel"]//td[2]'', doc, null, XPathResult.ANY_TYPE, null).iterateNext()) { return "multiple"; @@ -10087,7 +10875,6 @@ REPLACE INTO translators VALUES ('27ee5b2c-2a5a-4afc-a0aa-d386642d4eed', '1.0.0b } else { URIs.push(url); } - for each (var link in URIs) { Zotero.Utilities.HTTP.doGet(link, function(text) { var tags = new Object(); @@ -10113,6 +10900,8 @@ REPLACE INTO translators VALUES ('27ee5b2c-2a5a-4afc-a0aa-d386642d4eed', '1.0.0b } newItem.url = tags["fulltext_html_url"]; newItem.extra = text.match(/PMC\d+/)[0]; + newItem.journalAbbreviation = text.match(/span class=\"citation-abbreviation\">([^<]+)([^<]+)=3 && doi != ""){ + if(splitURL.length>=3 && doi){ var doiSuffix = doi.slice(doi.indexOf(''/'')+1); var pdfURL = splitURL[0] + ''/'' + splitURL[1] + ''/'' + splitURL[2]; pdfURL += ''/content/pdf/'' + doiSuffix + ''.pdf''; @@ -12949,7 +13740,7 @@ function doWeb(doc,url) } '); -REPLACE INTO translators VALUES ('8a07dd43-2bce-47bf-b4bf-c0fc441b79a9', '1.0.0b4.r5', '', '2008-02-27 23:00:00', '0', '100', '4', 'Optics Express', 'Michael Berkowitz', 'http://(www.)?opticsexpress\.org', +REPLACE INTO translators VALUES ('8a07dd43-2bce-47bf-b4bf-c0fc441b79a9', '1.0.0b4.r5', '', '2008-07-15 19:40:00', '0', '100', '4', 'Optics Express', 'Michael Berkowitz', 'http://(www.)?opticsexpress\.org', 'function detectWeb(doc, url) { var namespace = doc.documentElement.namespaceURI; var nsResolver = namespace ? function(prefix) { @@ -12989,13 +13780,11 @@ REPLACE INTO translators VALUES ('8a07dd43-2bce-47bf-b4bf-c0fc441b79a9', '1.0.0b for (var a in articles) { var link = articles[a]; Zotero.Utilities.HTTP.doGet(link, function(text) { + if (text.match(/doi:.*\"/)) var doi = text.match(/doi:(.*)\"/)[1]; var id = text.match(/name=\"articles\"\s+value=\"([^"]+)\"/)[1]; var action = text.match(/select\s+name=\"([^"]+)\"/)[1]; - Zotero.debug(id); - Zotero.debug(action); var get = ''http://www.opticsinfobase.org/custom_tags/IB_Download_Citations.cfm''; var post = ''articles='' + id + ''&ArticleAction=save_endnote2&'' + action + ''=save_endnote2''; - Zotero.debug(get + "?" + post); Zotero.Utilities.HTTP.doPost(get, post, function(text) { var translator = Zotero.loadTranslator("import"); translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7"); @@ -13007,7 +13796,7 @@ REPLACE INTO translators VALUES ('8a07dd43-2bce-47bf-b4bf-c0fc441b79a9', '1.0.0b } else { pubName = item.publicationTitle; } - Zotero.debug(pubName); + if (doi) item.DOI = doi; item.attachments = [{url:articles[a], title:pubName + " Snapshot", mimeType:"text/html"}]; item.complete(); }); @@ -13017,7 +13806,7 @@ REPLACE INTO translators VALUES ('8a07dd43-2bce-47bf-b4bf-c0fc441b79a9', '1.0.0b } }'); -REPLACE INTO translators VALUES ('a1a97ad4-493a-45f2-bd46-016069de4162', '1.0.0b4.r1', '', '2008-02-27 23:00:00', '0', '100', '4', 'Optical Society of America', 'Michael Berkowitz', 'https?://[^.]+\.(opticsinfobase|osa)\.org', +REPLACE INTO translators VALUES ('a1a97ad4-493a-45f2-bd46-016069de4162', '1.0.0b4.r1', '', '2008-07-15 19:40:00', '0', '100', '4', 'Optical Society of America', 'Michael Berkowitz', 'https?://[^.]+\.(opticsinfobase|osa)\.org', 'function detectWeb(doc, url) { var namespace = doc.documentElement.namespaceURI; var nsResolver = namespace ? function(prefix) { @@ -13053,14 +13842,15 @@ REPLACE INTO translators VALUES ('a1a97ad4-493a-45f2-bd46-016069de4162', '1.0.0b } else { articles = [url]; } - Zotero.debug(articles); Zotero.Utilities.processDocuments(articles, function(newDoc) { - Zotero.debug(newDoc.location.href); var osalink = newDoc.evaluate(''//div[@id="abstract"]/p/a[contains(text(), "opticsinfobase")]'', newDoc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext().href; - Zotero.debug(osalink); Zotero.Utilities.HTTP.doGet(osalink, function(text) { var action = text.match(/select\s+name=\"([^"]+)\"/)[1]; var id = text.match(/input\s+type=\"hidden\"\s+name=\"articles\"\s+value=\"([^"]+)\"/)[1]; + if (newDoc.evaluate(''//p[*[contains(text(), "DOI")]]'', newDoc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext()) { + var doi = Zotero.Utilities.trimInternal(newDoc.evaluate(''//p[*[contains(text(), "DOI")]]'', newDoc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext().textContent); + doi = doi.match(/doi:(.*)$/)[1]; + } var get = ''http://'' + host + ''/custom_tags/IB_Download_Citations.cfm''; var post = ''articles='' + id + ''&ArticleAction=save_endnote2&'' + action + ''=save_endnote2''; Zotero.Utilities.HTTP.doPost(get, post, function(text) { @@ -13074,7 +13864,7 @@ REPLACE INTO translators VALUES ('a1a97ad4-493a-45f2-bd46-016069de4162', '1.0.0b } else { pubName = item.publicationTitle; } - Zotero.debug(pubName); + if (doi) item.DOI = doi; item.attachments = [{url:osalink, title:pubName + " Snapshot", mimeType:"text/html"}]; item.complete(); }); @@ -13082,10 +13872,9 @@ REPLACE INTO translators VALUES ('a1a97ad4-493a-45f2-bd46-016069de4162', '1.0.0b }); }); }, function() {Zotero.done;}); - }'); -REPLACE INTO translators VALUES ('b61c224b-34b6-4bfd-8a76-a476e7092d43', '1.0.0b4.r5', '', '2008-07-03 08:00:00', '1', '100', '4', 'SSRN', 'Michael Berkowitz', 'http://papers\.ssrn\.com/', +REPLACE INTO translators VALUES ('b61c224b-34b6-4bfd-8a76-a476e7092d43', '1.0.0b4.r5', '', '2008-07-07 17:00:00', '1', '100', '4', 'SSRN', 'Michael Berkowitz', 'http://papers\.ssrn\.com/', 'function detectWeb(doc, url) { var namespace=doc.documentElement.namespaceURI; var nsResolver=namespace?function(prefix) { @@ -15640,7 +16429,7 @@ REPLACE INTO translators VALUES ('c54d1932-73ce-dfd4-a943-109380e06574', '1.0.0b } }'); -REPLACE INTO translators VALUES ('fcf41bed-0cbc-3704-85c7-8062a0068a7a', '1.0.0b3.r1', '', '2008-06-12 19:00:00', '1', '100', '4', 'NCBI PubMed', 'Simon Kornblith and Michael Berkowitz', 'http://[^/]*www\.ncbi\.nlm\.nih\.gov[^/]*/(pubmed|sites/entrez|entrez/query\.fcgi\?.*db=PubMed)', +REPLACE INTO translators VALUES ('fcf41bed-0cbc-3704-85c7-8062a0068a7a', '1.0.0b3.r1', '', '2008-07-21 09:38:53', '1', '100', '4', 'NCBI PubMed', 'Simon Kornblith and Michael Berkowitz', 'http://[^/]*www\.ncbi\.nlm\.nih\.gov[^/]*/(pubmed|sites/entrez|entrez/query\.fcgi\?.*db=PubMed)', 'function detectWeb(doc, url) { var namespace = doc.documentElement.namespaceURI; var nsResolver = namespace ? function(prefix) { @@ -15679,7 +16468,6 @@ function detectSearch(item) { ', 'function lookupPMIDs(ids, doc) { Zotero.wait(); - var newUri = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=PubMed&retmode=xml&rettype=citation&id="+ids.join(","); Zotero.Utilities.HTTP.doGet(newUri, function(text) { // Remove xml parse instruction and doctype @@ -15693,6 +16481,7 @@ function detectSearch(item) { var citation = xml.PubmedArticle[i].MedlineCitation; var PMID = citation.PMID.text().toString(); + newItem.url = "http://www.ncbi.nlm.nih.gov/pubmed/" + PMID; newItem.extra = "PMID: "+PMID; // add attachments if(doc) { @@ -18420,7 +19209,7 @@ REPLACE INTO translators VALUES ('8917b41c-8527-4ee7-b2dd-bcbc3fa5eabd', '1.0.0b Zotero.wait(); }'); -REPLACE INTO translators VALUES ('ecddda2e-4fc6-4aea-9f17-ef3b56d7377a', '1.0.0b3.r1', '', '2008-07-03 09:00:00', '1', '100', '4', 'arXiv.org', 'Sean Takats and Michael Berkowitz', 'http://(?:(www|uk)\.)?(?:(arxiv\.org|xxx.lanl.gov)/(?:find/\w|list/\w|abs/)|eprintweb.org/S/(?:search|archive|article)(?!.*refs$)(?!.*cited$))', +REPLACE INTO translators VALUES ('ecddda2e-4fc6-4aea-9f17-ef3b56d7377a', '1.0.0b3.r1', '', '2008-07-07 17:00:00', '1', '100', '4', 'arXiv.org', 'Sean Takats and Michael Berkowitz', 'http://(?:(www|uk)\.)?(?:(arxiv\.org|xxx.lanl.gov)/(?:find/\w|list/\w|abs/)|eprintweb.org/S/(?:search|archive|article)(?!.*refs$)(?!.*cited$))', 'function detectWeb(doc, url) { var searchRe = /^http:\/\/(?:(www|uk)\.)?(?:(arxiv\.org|xxx\.lanl\.gov)\/(?:find|list)|eprintweb.org\/S\/(?:archive|search$))/; if(searchRe.test(url)) { @@ -19882,7 +20671,7 @@ REPLACE INTO translators VALUES ('7bdb79e-a47f-4e3d-b317-ccd5a0a74456', '1.0.0b3 Zotero.wait(); }'); -REPLACE INTO translators VALUES ('850f4c5f-71fb-4669-b7da-7fb7a95500ef', '1.0.0b3r1', '', '2008-05-05 07:45:00', '1', '100', '4', 'Cambridge Journals Online', 'Sean Takats and Michael Berkowitz', 'https?://[^/]*journals.cambridge.org[^/]*//?action/(quickSearch|search|displayAbstract|displayFulltext|displayIssue)', +REPLACE INTO translators VALUES ('850f4c5f-71fb-4669-b7da-7fb7a95500ef', '1.0.0b3r1', '', '2008-07-08 15:35:00', '1', '100', '4', 'Cambridge Journals Online', 'Sean Takats and Michael Berkowitz', 'https?://[^/]*journals.cambridge.org[^/]*//?action/(quickSearch|search|displayAbstract|displayFulltext|displayIssue)', 'function detectWeb(doc, url) { var namespace=doc.documentElement.namespaceURI; var nsResolver=namespace?function(prefix) { @@ -19895,26 +20684,7 @@ REPLACE INTO translators VALUES ('850f4c5f-71fb-4669-b7da-7fb7a95500ef', '1.0.0b return "multiple"; } }', -'function titleCase(str) { - var skipWords = ["but", "or", "yet", "so", "for", "and", "nor", "a", "an", "the", "at", "by", "from", "in", "into", "of", "on", "to", "with", "up", "down", "as"]; - var words = str.toLowerCase().split(/\s+/); - var newstr = ""; - for (var i in words) { - if (i == 0) { - newstr += words[i][0].toUpperCase() + words[i].substr(1); - } else if (skipWords.indexOf(words[i].replace(/[^a-zA-Z]+/, "")) != -1) { - newstr += " " + words[i]; - } else if (words[i].indexOf("-") != -1) { - newword = words[i].split("-"); - newstr += " " + newword[0][0].toUpperCase() + newword[0].substr(1) + "-" + newword[1][0].toUpperCase() + newword[1].substr(1); - } else { - newstr += " " + words[i][0].toUpperCase() + words[i].substr(1); - } - } - return Zotero.Utilities.trimInternal(newstr); -} - -function doWeb(doc, url){ +'function doWeb(doc, url){ var namespace=doc.documentElement.namespaceURI; var nsResolver=namespace?function(prefix) { return (prefix=="x")?namespace:null; @@ -19931,7 +20701,7 @@ function doWeb(doc, url){ while (tableRow = tableRows.iterateNext()){ var id = doc.evaluate(''./td/input[@type="checkbox"][@name="toView"]/@value'', tableRow, nsResolver, XPathResult.ANY_TYPE, null).iterateNext(); var title = doc.evaluate(''./td/h3'', tableRow, nsResolver, XPathResult.ANY_TYPE, null).iterateNext(); - items[''http://'' + host + ''/action/displayAbstract?aid='' + id.nodeValue]=titleCase(title.textContent); + items[''http://'' + host + ''/action/displayAbstract?aid='' + id.nodeValue] = Zotero.Utilities.capitalizeTitle(title.textContent); } items=Zotero.selectItems(items); for (var i in items) { @@ -19948,7 +20718,9 @@ function doWeb(doc, url){ var kws = doc.evaluate(''//p[@class="KeyWords"]'', doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext().textContent.substr(11).split(''; ''); } var pdfpath=''//div/ul/li/a[contains(text(), "PDF")]''; - var pdflink =doc.evaluate(pdfpath, doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext().href; + if (doc.evaluate(pdfpath, doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext()) { + var pdflink =doc.evaluate(pdfpath, doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext().href; + } idRe = /aid=([0-9]+)/ var m = idRe.exec(doc.location.href); var id = m[1]; @@ -19958,16 +20730,14 @@ function doWeb(doc, url){ translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7"); translator.setString(text); translator.setHandler("itemDone", function(obj, item) { - item.attachments = [ - {url:url, title:"Cambridge Journals Snapshot", mimeType:"text/html"}, - {url:pdflink, title:"Cambridge Journals PDF", mimeType:"application/pdf"} - ]; + item.attachments = [{url:url, title:"Cambridge Journals Snapshot", mimeType:"text/html"}] + if (pdflink) item.attachments.push({url:pdflink, title:"Cambridge Journals PDF", mimeType:"application/pdf"}); item.url = url; - item.title = titleCase(item.title); + item.title = Zotero.Utilities.capitalizeTitle(item.title); var authors = item.creators; item.creators = new Array(); for each (var aut in authors) { - item.creators.push({firstName:titleCase(aut.firstName), lastName:titleCase(aut.lastName), creatorType:"author"}); + item.creators.push({firstName:aut.firstName, lastName:aut.lastName, creatorType:"author"}); } if (kws) item.tags = kws; if (abs) item.abstractNote = Zotero.Utilities.trimInternal(abs); @@ -20280,6 +21050,52 @@ function doWeb(doc, url) { Zotero.wait(); }'); +REPLACE INTO translators VALUES ('6f5f1b24-7519-4314-880f-d7004fbcfe7e', '1.0.0b4.r5', '', '2008-07-10 06:15:00', '0', '100', '4', 'ReliefWeb', 'Michael Berkowitz', 'http://(www.)?reliefweb.int/', +'function detectWeb(doc, url) { + if (url.match(/(S|s)earch(R|r)esults/)) { + return "multiple"; + } else if (url.match(/(O|o)pen(D|d)ocument/)) { + return "journalArticle"; + } +}', +'function doWeb(doc, url) { + var arts = new Array(); + if (detectWeb(doc, url) == "multiple") { + var items = new Object(); + var links = doc.evaluate(''//div[@id="View"]/table/tbody/tr/td[4][@class="docView"]/a'', doc, null, XPathResult.ANY_TYPE, null); + var link; + while (link = links.iterateNext()) { + items[link.href] = Zotero.Utilities.trimInternal(link.textContent); + } + items = Zotero.selectItems(items); + for (var i in items) { + arts.push(i); + } + } else { + arts = [url]; + } + Zotero.debug(arts); + Zotero.Utilities.processDocuments(arts, function(doc) { + var item = new Zotero.Item("journalArticle"); + item.title = Zotero.Utilities.trimInternal(doc.evaluate(''//div[@id="docTitle"]/h1'', doc, null, XPathResult.ANY_TYPE, null).iterateNext().textContent); + item.date = Zotero.Utilities.trimInternal(doc.evaluate(''//div[@id="link"]/p[2]'', doc, null, XPathResult.ANY_TYPE, null).iterateNext().textContent.substr(6)); + item.url = doc.location.href; + if (doc.evaluate(''//div[@id="docBody"]/p/i'',doc, null, XPathResult.ANY_TYPE, null).iterateNext()) { + var auts = doc.evaluate(''//div[@id="docBody"]/p/i'', doc, null, XPathResult.ANY_TYPE, null).iterateNext().textContent; + item.abstractNote = Zotero.Utilities.trimInternal(doc.evaluate(''//div[@id="docBody"]/p[1]'', doc, null, XPathResult.ANY_TYPE, null).iterateNext().textContent.replace(auts, "")); + auts = auts.replace(''By '', "").split(/\//); + for each (var aut in auts) { + item.creators.push(Zotero.Utilities.cleanAuthor(aut, "author")); + } + } else { + item.abstractNote = Zotero.Utilities.trimInternal(doc.evaluate(''//div[@id="docBody"]/p[1]'', doc, null, XPathResult.ANY_TYPE, null).iterateNext().textContent); + } + + item.complete(); + }, function() {Zotero.done;}); + Zotero.wait(); +}'); + REPLACE INTO translators VALUES ('594ebe3c-90a0-4830-83bc-9502825a6810', '1.0.0b4.r5', '', '2008-07-07 14:50:00', '1', '100', '4', 'ISI Web of Knowledge', 'Michael Berkowitz', '(WOS_GeneralSearch|product=WOS)', 'function detectWeb(doc, url) { if (doc.title.indexOf("Web of Science Results") != -1) { @@ -22317,7 +23133,7 @@ function doImport() { } }'); -REPLACE INTO translators VALUES ('14763d24-8ba0-45df-8f52-b8d1108e7ac9', '1.0.0b4.r1', '', '2008-02-08 07:30:00', 1, 25, 2, 'Zotero RDF', 'Simon Kornblith', 'rdf', +REPLACE INTO translators VALUES ('14763d24-8ba0-45df-8f52-b8d1108e7ac9', '1.0.0b4.r1', '', '2008-07-20 01:40:00', 1, 25, 2, 'Zotero RDF', 'Simon Kornblith', 'rdf', 'Zotero.configure("getCollections", true); Zotero.configure("dataMode", "rdf"); Zotero.addOption("exportNotes", true); @@ -22364,7 +23180,9 @@ function generateCollection(collection) { Zotero.RDF.addStatement(collectionResource, rdf+"type", n.z+"Collection", false); Zotero.RDF.addStatement(collectionResource, n.dc+"title", collection.name, true); - for each(var child in collection.descendents) { + var children = collection.children ? collection.children : collection.descendents; + if(!children) return; + for each(var child in children) { // add child list items if(child.type == "collection") { Zotero.RDF.addStatement(collectionResource, n.dcterms+"hasPart", "#collection_"+child.id, false); @@ -23451,9 +24269,10 @@ function doImport() { } }'); -REPLACE INTO translators VALUES ('32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7', '1.0.2', '', '2008-03-10 19:45:00', '1', '100', '3', 'RIS', 'Simon Kornblith', 'ris', +REPLACE INTO translators VALUES ('32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7', '1.0.2', '', '2008-07-17 22:05:00', '1', '100', '3', 'RIS', 'Simon Kornblith', 'ris', 'Zotero.configure("dataMode", "line"); Zotero.addOption("exportNotes", true); +Zotero.addOption("exportCharset", "UTF-8xBOM"); function detectImport() { var line; @@ -23539,7 +24358,7 @@ var inputTypeMap = { function processTag(item, tag, value) { if (Zotero.Utilities.unescapeHTML) { - value = Zotero.Utilities.unescapeHTML(value); + value = Zotero.Utilities.unescapeHTML(value.replace("\n", "
    ", "g")); } if(fieldMap[tag]) { @@ -23655,7 +24474,10 @@ function processTag(item, tag, value) { item.abstractNote = value; } else if(tag == "KW") { // keywords/tags - item.tags.push(value); + + // technically, treating newlines as new tags breaks the RIS spec, but + // it''s required to work with EndNote + item.tags = item.tags.concat(value.split("\n")); } else if(tag == "SP") { // start page if(!item.pages) { @@ -23747,14 +24569,9 @@ function completeItem(item) { } function doImport(attachments) { - // this is apparently the proper character set for RIS, although i''m not - // sure how many people follow this - Zotero.setCharacterSet("IBM850"); - var line = true; var tag = data = false; do { // first valid line is type - Zotero.debug("ignoring "+line); line = Zotero.read(); line = line.replace(/^\s+/, ""); } while(line !== false && !line.substr(0, 6).match(/^TY {1,2}- /)); @@ -23779,11 +24596,11 @@ function doImport(attachments) { while((rawLine = Zotero.read()) !== false) { // until EOF // trim leading space if this line is not part of a note line = rawLine.replace(/^\s+/, ""); - Zotero.debug("line is "+rawLine); if(line.substr(2, 4) == " - " || line == "ER -" || line.substr(0, 5) == "TY - ") { // if this line is a tag, take a look at the previous line to map // its tag if(tag) { + Zotero.debug("tag: ''"+tag+"''; data: ''"+data+"''"); processTag(item, tag, data); } @@ -23798,8 +24615,6 @@ function doImport(attachments) { data = line.substr(6); } - Zotero.debug("tag: ''"+tag+"''; data: ''"+data+"''"); - if(tag == "ER") { // ER signals end of reference // unset info tag = data = false; @@ -23813,7 +24628,7 @@ function doImport(attachments) { } } else { // otherwise, assume this is data from the previous line continued - if(tag == "N1" || tag == "N2" || tag == "AB") { + if(tag == "N1" || tag == "N2" || tag == "AB" || tag == "KW") { // preserve line endings for N1/N2/AB fields, for EndNote // compatibility data += "\n"+rawLine; @@ -23842,10 +24657,6 @@ function addTag(tag, value) { } function doExport() { - // this is apparently the proper character set for RIS, although i''m not - // sure how many people follow this - Zotero.setCharacterSet("IBM850"); - var item; while(item = Zotero.nextItem()) { @@ -23968,8 +24779,9 @@ function doExport() { } }'); -REPLACE INTO translators VALUES ('881f60f2-0802-411a-9228-ce5f47b64c7d', '1.0.0b4.r5', '', '2008-02-03 21:00:00', '1', '100', '3', 'Refer/BibIX', 'Simon Kornblith', 'txt', +REPLACE INTO translators VALUES ('881f60f2-0802-411a-9228-ce5f47b64c7d', '1.0.0b4.r5', '', '2008-07-17 22:05:00', '1', '100', '3', 'Refer/BibIX', 'Simon Kornblith', 'txt', 'Zotero.configure("dataMode", "line"); +Zotero.addOption("exportCharset", "UTF-8xBOM"); function detectImport() { var lineRe = /%[A-Z0-9\*\$] .+/; @@ -24135,9 +24947,6 @@ function processTag(item, tag, value) { } function doImport() { - // no character set is defined for this format. we use UTF-8. - Zotero.setCharacterSet("UTF-8"); - var line = true; var tag = data = false; do { // first valid line is type @@ -24192,9 +25001,6 @@ function addTag(tag, value) { } function doExport() { - // use UTF-8 to export - Zotero.setCharacterSet("UTF-8"); - var item; while(item = Zotero.nextItem()) { // can''t store independent notes in RIS @@ -24246,9 +25052,9 @@ function doExport() { } }'); -REPLACE INTO translators VALUES ('9cb70025-a888-4a29-a210-93ec52da40d4', '1.0.0b4.r1', '', '2008-07-01 14:30:13', '1', '200', '3', 'BibTeX', 'Simon Kornblith', 'bib', +REPLACE INTO translators VALUES ('9cb70025-a888-4a29-a210-93ec52da40d4', '1.0.0b4.r1', '', '2008-07-17 22:05:00', '1', '200', '3', 'BibTeX', 'Simon Kornblith', 'bib', 'Zotero.configure("dataMode", "block"); -Zotero.addOption("UTF8", true); +Zotero.addOption("exportCharset", "UTF-8"); function detectImport() { var block = ""; @@ -24343,7 +25149,7 @@ var bibtex2zoteroTypeMap = { "manual":"book", "mastersthesis":"thesis", "misc":"book", - "proceedings":"conference" + "proceedings":"book" }; /* @@ -25921,7 +26727,7 @@ function getFieldValue(read) { function beginRecord(type, closeChar) { type = Zotero.Utilities.cleanString(type.toLowerCase()); if(type != "string") { - zoteroType = bibtex2zoteroTypeMap[type]; + var zoteroType = bibtex2zoteroTypeMap[type]; if (!zoteroType) { Zotero.debug("discarded item from BibTeX; type was "+type); } @@ -25991,8 +26797,6 @@ function doImport() { var read = "", text = "", recordCloseElement = false; var type = false; - Zotero.setCharacterSet("UTF-8"); - while(read = Zotero.read(1)) { if(read == "@") { type = ""; @@ -26115,13 +26919,6 @@ function buildCiteKey (item,citekeys) { } function doExport() { - if(Zotero.getOption("UTF8")) { - Zotero.setCharacterSet("UTF-8"); - } - else { - Zotero.setCharacterSet("us-ascii"); - } - //Zotero.write("% BibTeX export generated by Zotero "+Zotero.Utilities.getVersion()); var first = true; @@ -26618,8 +27415,6 @@ function doImport() { var text; var holdOver = ""; // part of the text held over from the last loop - Zotero.setCharacterSet("utf-8"); - while(text = Zotero.read(4096)) { // read in 4096 byte increments var records = text.split("\x1D"); @@ -26643,7 +27438,8 @@ function doImport() { } }'); -REPLACE INTO translators VALUES ('3f50aaac-7acc-4350-acd0-59cb77faf620', '1.0.0b4.r1', '', '2007-11-02 08:30:00', '1', '100', '2', 'Wikipedia Citation Templates', 'Simon Kornblith', '', '', +REPLACE INTO translators VALUES ('3f50aaac-7acc-4350-acd0-59cb77faf620', '1.0.0b4.r1', '', '2008-07-17 22:05:00', '1', '100', '2', 'Wikipedia Citation Templates', 'Simon Kornblith', '', +'Zotero.addOption("exportCharset", "UTF-8");', 'var fieldMap = { edition:"edition", publisher:"publisher",