www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit db313abc736f675eb5e1694f43f8d3315a47abad
parent 3726f81896abe13bdbc62fc411183cab56bd0461
Author: Simon Kornblith <simon@simonster.com>
Date:   Mon, 22 Apr 2013 03:08:07 -0400

Merge branch '4.0'

Conflicts:
	chrome/content/zotero/xpcom/zotero.js
	install.rdf
	update.rdf

Diffstat:
Mchrome.manifest | 2+-
Mchrome/content/zotero/bibliography.js | 7+++----
Mchrome/content/zotero/bindings/itembox.xml | 22++++++++++++++--------
Mchrome/content/zotero/bindings/tagsbox.xml | 10++++++++--
Mchrome/content/zotero/bindings/zoterosearch.xml | 22++++++++++------------
Mchrome/content/zotero/browser.js | 27+++++++++++++++++----------
Mchrome/content/zotero/preferences/preferences_advanced.js | 28+++++++++++++++++++---------
Achrome/content/zotero/preferences/preferences_advanced_standalone.xul | 36++++++++++++++++++++++++++++++++++++
Mchrome/content/zotero/preferences/preferences_sync.js | 2+-
Mchrome/content/zotero/rtfScan.js | 6++++--
Mchrome/content/zotero/tools/testTranslators/translatorTester.js | 4+++-
Mchrome/content/zotero/xpcom/attachments.js | 112++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mchrome/content/zotero/xpcom/citeproc.js | 1234+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mchrome/content/zotero/xpcom/connector/connector.js | 12++++++++++--
Mchrome/content/zotero/xpcom/data/item.js | 175+++++++++++++++++++++++++------------------------------------------------------
Mchrome/content/zotero/xpcom/data/notes.js | 2+-
Mchrome/content/zotero/xpcom/file.js | 7+++----
Mchrome/content/zotero/xpcom/fulltext.js | 10++++++++--
Mchrome/content/zotero/xpcom/mimeTypeHandler.js | 5++++-
Mchrome/content/zotero/xpcom/schema.js | 23+++++++++--------------
Mchrome/content/zotero/xpcom/server.js | 3++-
Mchrome/content/zotero/xpcom/server_connector.js | 25+++++++++++++++++++++----
Mchrome/content/zotero/xpcom/storage.js | 2+-
Mchrome/content/zotero/xpcom/storage/request.js | 2+-
Mchrome/content/zotero/xpcom/storage/webdav.js | 139++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mchrome/content/zotero/xpcom/storage/zfs.js | 4++++
Mchrome/content/zotero/xpcom/style.js | 34++++++++++++++++++++--------------
Mchrome/content/zotero/xpcom/sync.js | 4+++-
Mchrome/content/zotero/xpcom/translation/translate.js | 2+-
Mchrome/content/zotero/xpcom/translation/translate_item.js | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mchrome/content/zotero/xpcom/zotero.js | 2++
Mchrome/content/zotero/zoteroPane.js | 6++++--
Mchrome/locale/en-US/zotero/preferences.dtd | 5+++--
Mchrome/skin/default/zotero/integration.css | 2--
Mchrome/skin/default/zotero/zotero.css | 1-
Mcomponents/zotero-autocomplete.js | 89++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Aresource/schema/renamed-styles.json | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mresource/schema/repotime.txt | 2+-
38 files changed, 1422 insertions(+), 915 deletions(-)

diff --git a/chrome.manifest b/chrome.manifest @@ -47,7 +47,6 @@ locale zotero zh-TW chrome/locale/zh-TW/zotero/ skin zotero default chrome/skin/default/zotero/ -overlay chrome://browser/content/browser.xul chrome://zotero/content/statusBarOverlay.xul appversion<4.0 overlay chrome://browser/content/browser.xul chrome://zotero/content/overlay.xul overlay chrome://zotero/content/preferences/preferences.xul chrome://zotero/content/preferences/preferences_firefox.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} @@ -55,6 +54,7 @@ overlay chrome://zotero/content/preferences/preferences.xul#cite chrome://zotero overlay chrome://zotero/content/preferences/preferences_general.xul chrome://zotero/content/preferences/preferences_general_firefox.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} overlay chrome://zotero/content/preferences/preferences_export.xul chrome://zotero/content/preferences/preferences_export_firefox.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} overlay chrome://zotero/content/preferences/preferences_advanced.xul chrome://zotero/content/preferences/preferences_advanced_firefox.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} +overlay chrome://zotero/content/preferences/preferences_advanced.xul chrome://zotero/content/preferences/preferences_advanced_standalone.xul application=zotero@chnm.gmu.edu overlay chrome://mozapps/content/downloads/unknownContentType.xul chrome://zotero/content/downloadOverlay.xul diff --git a/chrome/content/zotero/bibliography.js b/chrome/content/zotero/bibliography.js @@ -88,10 +88,10 @@ var Zotero_File_Interface_Bibliography = new function() { } // Has to be async to work properly - setTimeout(function () { + window.setTimeout(function () { listbox.ensureIndexIsVisible(selectIndex); listbox.selectedIndex = selectIndex; - }); + }, 0); // ONLY FOR bibliography.xul: export options if(document.getElementById("save-as-rtf")) { @@ -119,8 +119,7 @@ var Zotero_File_Interface_Bibliography = new function() { // bookmarks text if(document.getElementById("displayAs")) { if(_io.useEndnotes && _io.useEndnotes == 1) document.getElementById("displayAs").selectedIndex = 1; - styleChanged(selectIndex); - } + } if(document.getElementById("formatUsing")) { if(_io.fieldType == "Bookmark") document.getElementById("formatUsing").selectedIndex = 1; var formatOption = (_io.primaryFieldType == "ReferenceMark" ? "referenceMarks" : "fields"); diff --git a/chrome/content/zotero/bindings/itembox.xml b/chrome/content/zotero/bindings/itembox.xml @@ -552,7 +552,7 @@ this._displayAllCreators = true; if (this._addCreatorRow) { - this.addCreatorRow(false, false, true); + this.addCreatorRow(false, this.item.getCreator(max-1).creatorTypeID, true); this._addCreatorRow = false; this.disableCreatorAddButtons(); } @@ -1416,11 +1416,17 @@ || fieldName == 'creator') { t.setAttribute('type', 'autocomplete'); t.setAttribute('autocompletesearch', 'zotero'); - var suffix = itemID ? itemID : ''; - if (field=='creator') { - suffix = elem.getAttribute('fieldMode') + '-' + suffix; - } - t.setAttribute('autocompletesearchparam', fieldName + '/' + suffix); + let params = { + fieldName: fieldName, + libraryID: this.item.libraryID + }; + if (field == 'creator') { + params.fieldMode = parseInt(elem.getAttribute('fieldMode')); + params.itemID = itemID ? itemID : ''; + }; + t.setAttribute( + 'autocompletesearchparam', JSON.stringify(params) + ); t.setAttribute('ontextentered', 'document.getBindingParent(this).handleCreatorAutoCompleteSelect(this)'); } @@ -1555,8 +1561,8 @@ this._focusNextField(this._dynamicFields, this._lastTabIndex, false); } else { - // TODO: should use current creator type - this.addCreatorRow(false, false, true); + var creatorFields = this.getCreatorFields(Zotero.getAncestorByTagName(target, 'row')); + this.addCreatorRow(false, creatorFields.creatorTypeID, true); } } // Value has changed diff --git a/chrome/content/zotero/bindings/tagsbox.xml b/chrome/content/zotero/bindings/tagsbox.xml @@ -437,8 +437,14 @@ else { t.setAttribute('type', 'autocomplete'); t.setAttribute('autocompletesearch', 'zotero'); - var suffix = itemID ? itemID : ''; - t.setAttribute('autocompletesearchparam', fieldName + '/' + suffix); + let params = { + fieldName: fieldName, + libraryID: this.item.libraryID + }; + params.itemID = itemID ? itemID : ''; + t.setAttribute( + 'autocompletesearchparam', JSON.stringify(params) + ); } var box = elem.parentNode; diff --git a/chrome/content/zotero/bindings/zoterosearch.xml b/chrome/content/zotero/bindings/zoterosearch.xml @@ -813,22 +813,20 @@ textbox.setAttribute('autocompletesearch', 'zotero'); textbox.setAttribute('timeout', '250'); - if (condition=='creator') - { - // 2 searches both single- and double-field creators - var autocompleteCondition = condition + '/2' + var autocompleteParams = { + fieldName: condition + }; + if (condition == 'creator') { + autocompleteParams.fieldMode = 2; } - else - { - var autocompleteCondition = condition; - } - - textbox.setAttribute('autocompletesearchparam', autocompleteCondition); + textbox.setAttribute( + 'autocompletesearchparam', + JSON.stringify(autocompleteParams) + ); } } - if (!autocompleteCondition) - { + if (!autocompleteParams) { var textbox = document.getAnonymousNodes(this)[0]; textbox.removeAttribute('type'); } diff --git a/chrome/content/zotero/browser.js b/chrome/content/zotero/browser.js @@ -804,16 +804,23 @@ Zotero_Browser.Tab.prototype._selectItems = function(obj, itemList, callback) { */ Zotero_Browser.Tab.prototype._translatorsAvailable = function(translate, translators) { if(translators && translators.length) { - // if there's already a scrapable page in the browser window, and it's - // still there, ensure it is actually part of the page, then return - if(this.page.translators && this.page.translators.length && this.page.document.location) { - if(this.page.document.defaultView && !this.page.document.defaultView.closed - && this.page.document.location.href != translate.document.location.href) { - // if it is still there, switch translation to take place on - if(!translators.length || this.page.translators[0].priority <= translators[0].priority) return; - } else { - this.clear(); - } + //see if we should keep the previous set of translators + if(//we already have a translator for part of this page + this.page.translators && this.page.translators.length && this.page.document.location + //and the page is still there + && this.page.document.defaultView && !this.page.document.defaultView.closed + //this set of translators is not targeting the same URL as a previous set of translators, + // because otherwise we want to use the newer set + && this.page.document.location.href != translate.document.location.href + //the previous set of translators targets the top frame or the current one does not either + && (this.page.document.defaultView == this.page.document.defaultView.top + || translate.document.defaultView !== this.page.document.defaultView.top) + //the best translator we had was of higher priority than the new set + && this.page.translators[0].priority <= translators[0].priority + ) { + return; //keep what we had + } else { + this.clear(); //clear URL bar icon } this.page.translate = translate; diff --git a/chrome/content/zotero/preferences/preferences_advanced.js b/chrome/content/zotero/preferences/preferences_advanced.js @@ -364,22 +364,30 @@ Zotero_Preferences.Attachment_Base_Directory = { .createInstance(Components.interfaces.nsILocalFile); for (let i=0; i<allAttachments.length; i++) { let attachmentID = allAttachments[i]; + let relPath = false try { let attachment = Zotero.Items.get(attachmentID); - attachmentFile.persistentDescriptor = attachment.attachmentPath; + // This will return FALSE for relative paths if base directory + // isn't currently set + attachmentFile = attachment.getFile(false, true); + // Get existing relative path + let path = attachment.attachmentPath; + if (path.indexOf(Zotero.Attachments.BASE_PATH_PLACEHOLDER) == 0) { + relPath = path.substr(Zotero.Attachments.BASE_PATH_PLACEHOLDER.length); + } } catch (e) { // Don't deal with bad attachment paths. Just skip them. + Zotero.debug(e, 2); continue; } // If a file with the same relative path exists within the new base directory, // don't touch the attachment, since it will continue to work - let isExistingRelativeAttachment = oldRelativeAttachmentIDs.indexOf(attachmentID) != -1; - if (isExistingRelativeAttachment && oldBasePathFile) { - let relFile = attachmentFile.clone(); - let relPath = attachmentFile.getRelativeDescriptor(oldBasePathFile); + if (relPath) { + let relFile = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); relFile.setRelativeDescriptor(newBasePathFile, relPath); if (relFile.exists()) { numNewAttachments++; @@ -390,14 +398,14 @@ Zotero_Preferences.Attachment_Base_Directory = { // Files within the new base directory need to be updated to use // relative paths (or, if the new base directory is an ancestor or // descendant of the old one, new relative paths) - if (Zotero.File.directoryContains(newBasePathFile, attachmentFile)) { - newAttachmentPaths[attachmentID] = isExistingRelativeAttachment + if (attachmentFile && Zotero.File.directoryContains(newBasePathFile, attachmentFile)) { + newAttachmentPaths[attachmentID] = relPath ? attachmentFile.persistentDescriptor : null; numNewAttachments++; } // Existing relative attachments not within the new base directory // will be converted to absolute paths - else if (isExistingRelativeAttachment && oldBasePathFile) { + else if (relPath && oldBasePathFile) { newAttachmentPaths[attachmentID] = attachmentFile.persistentDescriptor; numOldAttachments++; } @@ -464,7 +472,9 @@ Zotero_Preferences.Attachment_Base_Directory = { let attachment = Zotero.Items.get(id); if (newAttachmentPaths[id]) { attachment.attachmentPath = newAttachmentPaths[id]; - attachment.save(); + attachment.save({ + skipDateModifiedUpdate: true + }); } else { attachment.updateAttachmentPath(); diff --git a/chrome/content/zotero/preferences/preferences_advanced_standalone.xul b/chrome/content/zotero/preferences/preferences_advanced_standalone.xul @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<!-- + ***** BEGIN LICENSE BLOCK ***** + + Copyright © 2013 Center for History and New Media + George Mason University, Fairfax, Virginia, USA + http://zotero.org + + This file is part of Zotero. + + Zotero is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Zotero is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with Zotero. If not, see <http://www.gnu.org/licenses/>. + + ***** END LICENSE BLOCK ***** +--> +<!DOCTYPE prefwindow SYSTEM "chrome://zotero/locale/preferences.dtd"> + +<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <groupbox id="zotero-prefpane-advanced-miscellaneous"> + <hbox id="zotero-standalone-buttons"> + <button id="openAboutMemory" + label="&zotero.preferences.openAboutMemory;" + oncommand="Zotero_Preferences.openInViewer('about:memory')"/> + </hbox> + </groupbox> +</overlay> diff --git a/chrome/content/zotero/preferences/preferences_sync.js b/chrome/content/zotero/preferences/preferences_sync.js @@ -72,7 +72,7 @@ Zotero_Preferences.Sync = { } if (oldProtocol == 'zotero' && protocol == 'webdav') { - var sql = "SELECT COUNT(*) FROM version WHERE schema='storage_zfs'"; + var sql = "SELECT COUNT(*) FROM version WHERE schema LIKE 'storage_zfs%'"; if (Zotero.DB.valueQuery(sql)) { var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] .getService(Components.interfaces.nsIPromptService); diff --git a/chrome/content/zotero/rtfScan.js b/chrome/content/zotero/rtfScan.js @@ -529,13 +529,15 @@ var Zotero_RTFScan = new function() { itemIDs = [itemID for(itemID in itemIDs)]; Zotero.debug(itemIDs); - style.updateItems(itemIDs); + + // prepare the list of rendered citations + var citationResults = style.rebuildProcessorState(cslCitations, "rtf"); // format citations var contentArray = []; var lastEnd = 0; for(var i=0; i<citations.length; i++) { - var citation = style.appendCitationCluster(cslCitations[i], true)[0][1]; + var citation = citationResults[i][2]; Zotero.debug("Formatted "+citation); // if using notes, we might have to move the note after the punctuation diff --git a/chrome/content/zotero/tools/testTranslators/translatorTester.js b/chrome/content/zotero/tools/testTranslators/translatorTester.js @@ -334,7 +334,9 @@ Zotero_TranslatorTester.prototype._runTestsRecursively = function(testDoneCallba if(this.type === "web") { this.fetchPageAndRunTest(test, callback); } else { - this.runTest(test, null, callback); + (Zotero.setTimeout ? Zotero : window).setTimeout(function() { + me.runTest(test, null, callback); + }, 0); } (Zotero.setTimeout ? Zotero : window).setTimeout(function() { diff --git a/chrome/content/zotero/xpcom/attachments.js b/chrome/content/zotero/xpcom/attachments.js @@ -50,13 +50,7 @@ Zotero.Attachments = new function(){ function importFromFile(file, sourceItemID, libraryID) { Zotero.debug('Importing attachment from file'); - // Try decoding URI entities, since we're going to strip '%' - var newName = file.leafName; - try { - newName = decodeURIComponent(file.leafName); - } - catch (e) {} - newName = Zotero.File.getValidFileName(newName); + var newName = Zotero.File.getValidFileName(file.leafName); if (!file.isFile()) { throw ("'" + file.leafName + "' must be a file in Zotero.Attachments.importFromFile()"); @@ -82,14 +76,15 @@ Zotero.Attachments = new function(){ // Create directory for attachment files within storage directory var destDir = this.createDirectoryForItem(itemID); - file.copyTo(destDir, newName); // Point to copied file var newFile = destDir.clone(); newFile.append(newName); - var mimeType = Zotero.MIME.getMIMETypeFromFile(newFile); + // Copy file to unique filename, which automatically shortens long filenames + newFile = Zotero.File.copyToUnique(file, newFile); + var mimeType = Zotero.MIME.getMIMETypeFromFile(newFile); attachmentItem.attachmentMIMEType = mimeType; attachmentItem.attachmentPath = this.getPath(newFile, this.LINK_MODE_IMPORTED_FILE); @@ -1019,6 +1014,104 @@ Zotero.Attachments = new function(){ /** + * If file is within the attachment base directory, return a relative + * path prefixed by BASE_PATH_PLACEHOLDER. Otherwise, return unchanged. + */ + this.getBaseDirectoryRelativePath = function (path) { + if (!path || path.indexOf(this.BASE_PATH_PLACEHOLDER) == 0) { + return path; + } + + var basePath = Zotero.Prefs.get('baseAttachmentPath'); + if (!basePath) { + return path; + } + + // Get nsIFile for base directory + var baseDir = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + try { + baseDir.persistentDescriptor = basePath; + } + catch (e) { + Zotero.debug(e, 1); + Components.utils.reportError(e); + return path; + } + + // Get nsIFile for file + var attachmentFile = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + try { + attachmentFile.persistentDescriptor = path; + } + catch (e) { + Zotero.debug(e, 1); + Components.utils.reportError(e); + return path; + } + + if (Zotero.File.directoryContains(baseDir, attachmentFile)) { + path = this.BASE_PATH_PLACEHOLDER + + attachmentFile.getRelativeDescriptor(baseDir); + } + + return path; + } + + + /** + * Get a file from this path, if we can + * + * @param {String} path Absolute path or relative path prefixed + * by BASE_PATH_PLACEHOLDER + * @param {Boolean} asFile Return nsIFile instead of path + * @return {String|nsIFile|FALSE} Persistent descriptor string, file, + * of FALSE if no path + */ + this.resolveRelativePath = function (path) { + if (path.indexOf(Zotero.Attachments.BASE_PATH_PLACEHOLDER) != 0) { + return false; + } + + var basePath = Zotero.Prefs.get('baseAttachmentPath'); + if (!basePath) { + Zotero.debug("No base attachment path set -- can't resolve '" + path + "'", 2); + return false; + } + + // Get file from base directory + var baseDir = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + try { + baseDir.persistentDescriptor = basePath; + } + catch (e) { + Zotero.debug(e, 1); + Components.utils.reportError(e); + Zotero.debug("Invalid base attachment path -- can't resolve'" + row.path + "'", 2); + return false; + } + + // Get file from relative path + var relativePath = path.substr( + Zotero.Attachments.BASE_PATH_PLACEHOLDER.length + ); + var file = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + try { + file.setRelativeDescriptor(baseDir, relativePath); + } + catch (e) { + Zotero.debug("Invalid relative descriptor '" + relativePath + "'", 2); + return false; + } + + return file; + } + + + /** * Returns the number of files in the attachment directory * * Only counts if MIME type is text/html @@ -1394,6 +1487,7 @@ Zotero.Attachments = new function(){ */ this.isPDFJS = function(doc) { // pdf.js HACK + // This may no longer be necessary (as of Fx 23) if(doc.contentType === "text/html") { var win = doc.defaultView; if(win) { diff --git a/chrome/content/zotero/xpcom/citeproc.js b/chrome/content/zotero/xpcom/citeproc.js @@ -57,7 +57,9 @@ if (!Array.indexOf) { }; } var CSL = { - PROCESSOR_VERSION: "1.0.446", + PROCESSOR_VERSION: "1.0.451", + CONDITION_LEVEL_TOP: 1, + CONDITION_LEVEL_BOTTOM: 2, PLAIN_HYPHEN_REGEX: /(?:[^\\]-|\u2013)/, LOCATOR_LABELS_REGEXP: new RegExp("^((art|ch|Ch|subch|col|fig|l|n|no|op|p|pp|para|subpara|pt|r|sec|subsec|Sec|sv|sch|tit|vrs|vol)\\.)\\s+(.*)"), STATUTE_SUBDIV_GROUPED_REGEX: /((?:^| )(?:art|ch|Ch|subch|p|pp|para|subpara|pt|r|sec|subsec|Sec|sch|tit)\.)/g, @@ -348,7 +350,7 @@ var CSL = { ret[ret.length - 1] += str; return ret; }, - SKIP_WORDS: ["but", "or", "yet", "so", "for", "and", "nor", "a", "an", "the", "at", "by", "from", "in", "into", "of", "on", "to", "with", "up", "down", "as", "via", "onto", "over", "till"], + SKIP_WORDS: ["but", "or", "yet", "so", "for", "and", "nor", "a", "an", "the", "at", "by", "from", "in", "into", "of", "on", "to", "with", "up", "down", "as", "via", "onto", "over", "till", "de", "d'", "von", "van"], FORMAT_KEY_SEQUENCE: [ "@strip-periods", "@font-style", @@ -1273,6 +1275,13 @@ CSL.Output.Queue.prototype.string = function (state, myblobs, blob) { state.tmp.count_offset_characters = false; } } + for (i=0,ilen=ret.length - 1;i<ilen;i+=1) { + if ("number" === typeof ret[i].num && "number" === typeof ret[i+1].num && !ret[i+1].UGLY_DELIMITER_SUPPRESS_HACK) { + ret[i].strings.suffix = txt_esc(blob_delimiter); + ret[i+1].successor_prefix = ""; + ret[i+1].UGLY_DELIMITER_SUPPRESS_HACK = true; + } + } var span_split = 0; for (i = 0, ilen = ret.length; i < ilen; i += 1) { if ("string" === typeof ret[i]) { @@ -1280,7 +1289,6 @@ CSL.Output.Queue.prototype.string = function (state, myblobs, blob) { if (i < ret.length - 1 && "object" === typeof ret[i + 1]) { if (blob_delimiter && !ret[i + 1].UGLY_DELIMITER_SUPPRESS_HACK) { ret[i] += txt_esc(blob_delimiter); - } else { } ret[i + 1].UGLY_DELIMITER_SUPPRESS_HACK = true; } @@ -1289,7 +1297,7 @@ CSL.Output.Queue.prototype.string = function (state, myblobs, blob) { if (blob && (blob.decorations.length || blob.strings.suffix || blob.strings.prefix)) { span_split = ret.length; } - var blobs_start = state.output.renderBlobs(ret.slice(0, span_split), blob_delimiter); + var blobs_start = state.output.renderBlobs(ret.slice(0, span_split), blob_delimiter, true); if (blobs_start && blob && (blob.decorations.length || blob.strings.suffix || blob.strings.prefix)) { if (!state.tmp.suppress_decorations) { for (i = 0, ilen = blob.decorations.length; i < ilen; i += 1) { @@ -1336,19 +1344,15 @@ CSL.Output.Queue.prototype.string = function (state, myblobs, blob) { this.current.mystack = []; this.current.mystack.push(this.queue); if (state.tmp.suppress_decorations) { - ret = state.output.renderBlobs(ret); + ret = state.output.renderBlobs(ret, undefined, true); } } else if ("boolean" === typeof blob) { - ret = state.output.renderBlobs(ret); + ret = state.output.renderBlobs(ret, undefined, true); } if (blob && blob.new_locale) { state.opt.lang = blob.old_locale; } - if (blob) { - return ret; - } else { - return ret; - } + return ret; }; CSL.Output.Queue.prototype.clearlevel = function () { var blob, pos, len; @@ -1358,7 +1362,7 @@ CSL.Output.Queue.prototype.clearlevel = function () { blob.blobs.pop(); } }; -CSL.Output.Queue.prototype.renderBlobs = function (blobs, delim, has_more) { +CSL.Output.Queue.prototype.renderBlobs = function (blobs, delim, in_cite) { var state, ret, ret_last_char, use_delim, i, blob, pos, len, ppos, llen, pppos, lllen, res, str, params, txt_esc; txt_esc = CSL.getSafeEscape(this.state); if (!delim) { @@ -3365,7 +3369,7 @@ CSL.Engine.Citation = function (state) { this.opt["disambiguate-add-names"] = false; this.opt["disambiguate-add-givenname"] = false; this.opt["disambiguate-add-year-suffix"] = false; - this.opt["givenname-disambiguation-rule"] = "none"; + this.opt["givenname-disambiguation-rule"] = "by-cite"; this.opt["near-note-distance"] = 5; this.opt.topdecor = []; this.opt.layout_decorations = []; @@ -3440,7 +3444,6 @@ CSL.Engine.prototype.rebuildProcessorState = function (citations, mode, uncitedI } } this.updateItems(itemIDs); - this.updateUncitedItems(uncitedItemIDs); var pre = []; var post = []; var ret = []; @@ -3458,6 +3461,7 @@ CSL.Engine.prototype.rebuildProcessorState = function (citations, mode, uncitedI ]; } } + this.updateUncitedItems(uncitedItemIDs); this.setOutputFormat(oldMode); return ret; } @@ -4679,6 +4683,8 @@ CSL.getCite = function (Item, item, prevItemID) { return "" + Item.id; }; CSL.citeStart = function (Item, item) { + this.tmp.disambiguate_count = 0; + this.tmp.disambiguate_maxMax = 0; this.tmp.same_author_as_previous_cite = false; if (!this.tmp.suppress_decorations) { this.tmp.subsequent_author_substitute_ok = true; @@ -5438,8 +5444,19 @@ CSL.Node["else-if"] = { if (this.locale) { state.opt.lang = this.locale; } - if (! this.evaluator) { - this.evaluator = state.fun.match.any; + if (!this.evaluator) { + this.evaluator = function (token, state, Item, item) { + var record = function (result) { + if (result) { + state.tmp.jump.replace("succeed"); + return token.succeed; + } else { + state.tmp.jump.replace("fail"); + return token.fail; + } + } + return record(state.fun.match.any(token, state, token.tests, CSL.CONDITION_LEVEL_TOP)(Item, item)); + }; } } if (this.tokentype === CSL.END || this.tokentype === CSL.SINGLETON) { @@ -5601,7 +5618,18 @@ CSL.Node["if"] = { state.opt.lang = this.locale; } if (!this.evaluator) { - this.evaluator = state.fun.match.any; + this.evaluator = function (token, state, Item, item) { + var record = function (result) { + if (result) { + state.tmp.jump.replace("succeed"); + return token.succeed; + } else { + state.tmp.jump.replace("fail"); + return token.fail; + } + } + return record(state.fun.match.any(token, state, token.tests, CSL.CONDITION_LEVEL_TOP)(Item, item)); + }; } } if (this.tokentype === CSL.END || this.tokentype === CSL.SINGLETON) { @@ -6778,7 +6806,7 @@ CSL.NameOutput.prototype._runDisambigNames = function (lst, pos) { if (this.state.tmp.disambig_request) { var val = this.state.tmp.disambig_settings.givens[pos][i]; if (val === 1 && - this.state.opt["givenname-disambiguation-rule"] === "by-cite" && + this.state.citation.opt["givenname-disambiguation-rule"] === "by-cite" && ("undefined" === typeof this.name.strings["initialize-with"] || "undefined" === typeof lst[i].given)) { val = 2; @@ -6929,6 +6957,7 @@ CSL.NameOutput.prototype._imposeNameConstraints = function (lst, count, key, pos } } this.state.tmp.disambig_settings.names[pos] = lst[key].length; + this.state.disambiguate.padBase(this.state.tmp.disambig_settings); }; CSL.NameOutput.prototype.getEtAlConfig = function () { var item = this.item; @@ -8622,7 +8651,7 @@ CSL.Node.text = { flag[0] = true; state.tmp.group_context.replace(flag); } - if (!state.tmp.term_predecessor) { + if (!state.tmp.term_predecessor && !(state.opt["class"] === "in-text" && state.tmp.area === "citation")) { myterm = CSL.Output.Formatters["capitalize-first"](state, term); } else { myterm = term; @@ -8788,192 +8817,201 @@ CSL.Node.text = { } }; CSL.Attributes = {}; -CSL.Attributes["@gender"] = function (state, arg) { - this.gender = arg; -} -CSL.Attributes["@cslid"] = function (state, arg) { - this.cslid = parseInt(arg, 10); -}; -CSL.Attributes["@is-parallel"] = function (state, arg) { - var values = arg.split(" "); - for (var i = 0, ilen = values.length; i < ilen; i += 1) { - if (values[i] === "true") { - values[i] = true; - } else if (values[i] === "false") { - values[i] = false; - } +CSL.Attributes["@disambiguate"] = function (state, arg) { + if (arg === "true") { + state.opt.has_disambiguate = true; + var func = function (Item, item) { + var ret; + state.tmp.disambiguate_maxMax += 1; + if (state.tmp.disambig_settings.disambiguate + && state.tmp.disambiguate_count < state.tmp.disambig_settings.disambiguate) { + state.tmp.disambiguate_count += 1; + return true; + } + return false; + }; + this.tests.push(func); } - this.strings.set_parallel_condition = values; }; -CSL.Attributes["@is-plural"] = function (state, arg) { - var func = function (state, Item, item) { - var nameList = Item[arg]; - var ret = false; - if (nameList && nameList.length) { - var persons = 0; - var institutions = 0; - var last_is_person = false; - for (var i = 0, ilen = nameList.length; i < ilen; i += 1) { - if (nameList[i].isInstitution && (nameList[i].literal || (nameList[i].family && !nameList[i].given))) { - institutions += 1; - last_is_person = false; - } else { - persons += 1; - last_is_person = true; - } +CSL.Attributes["@is-numeric"] = function (state, arg) { + var variables = arg.split(/\s+/); + var reverses = CSL.Util.setReverseConditions.call(this, variables); + var maketest = function(variable, reverse) { + return function (Item, item) { + var myitem = Item; + var mytests = []; + if (["locator","locator-revision"].indexOf(variable) > -1) { + myitem = item; } - if (persons > 1) { - ret = true; - } else if (institutions > 1) { - ret = true; - } else if (institutions && last_is_person) { - ret = true; + if (CSL.NUMERIC_VARIABLES.indexOf(variable) > -1) { + if (!state.tmp.shadow_numbers[variable]) { + state.processNumber(false, myitem, variable, Item.type); + } + if (myitem[variable] && state.tmp.shadow_numbers[variable].numeric) { + return reverse ? false : true; + } + } else if (["title", "locator-revision","version"].indexOf(variable) > -1) { + if (myitem[variable]) { + if (myitem[variable].slice(-1) === "" + parseInt(myitem[variable].slice(-1), 10)) { + return reverse ? false : true; + } + } } + return reverse ? true : false; } - return ret; - }; + } + var mytests = []; + for (var i=0; i<variables.length; i+=1) { + mytests.push(maketest(variables[i], reverses[i])); + } + var func = state.fun.match[this.match](this, state, mytests, CSL.CONDITION_LEVEL_BOTTOM); this.tests.push(func); }; -CSL.Attributes["@subjurisdictions"] = function (state, arg) { - var trysubjurisdictions = parseInt(arg, 10); - var func = function (state, Item, item) { - var subjurisdictions = 0; - if (Item.jurisdiction) { - subjurisdictions = Item.jurisdiction.split(";").length; - } - if (subjurisdictions) { - subjurisdictions += -1; - } - var ret = false; - if (subjurisdictions >= trysubjurisdictions) { - ret = true; - } - return [ret]; - }; - this.tests.push(func); +CSL.Attributes["@is-numeric-any"] = function (state, arg) { + CSL.Attributes["@is-numeric"].call(this, state, arg, "any"); }; -CSL.Attributes["@label-form"] = function (state, arg) { - this.strings.label_form_override = arg; +CSL.Attributes["@is-numeric-all"] = function (state, arg) { + CSL.Attributes["@is-numeric"].call(this, state, arg, "all"); }; -CSL.Attributes["@has-year-only"] = function (state, arg) { - var trydates = arg.split(/\s+/); - var func = function (state, Item, item) { - var ret = []; - for (var i = 0, ilen = trydates.length; i < ilen; i += 1) { - var trydate = Item[trydates[i]]; - if (!trydate || trydate.month || trydate.season) { - ret.push(false); +CSL.Attributes["@is-uncertain-date"] = function (state, arg) { + var variables = arg.split(/\s+/); + var reverses = CSL.Util.setReverseConditions.call(this, variables); + var maketest = function (myvariable, reverse) { + return function(Item, item) { + if (Item[myvariable] && Item[myvariable].circa) { + return reverse ? false : true; } else { - ret.push(true); + return reverse ? true : false; } } - return ret; + } + var mytests = []; + for (var i=0,ilen=variables.length;i<ilen;i+=1) { + mytests.push(maketest(variables[i], reverses[i])); }; + var func = state.fun.match[this.match](this, state, mytests, CSL.CONDITION_LEVEL_BOTTOM); this.tests.push(func); }; -CSL.Attributes["@has-month-or-season-only"] = function (state, arg) { - var trydates = arg.split(/\s+/); - var func = function (state, Item, item) { - var ret = []; - for (var i = 0, ilen = trydates.length; i < ilen; i += 1) { - var trydate = Item[trydates[i]]; - if (!trydate || (!trydate.month && !trydate.season) || trydate.day) { - ret.push(false); +CSL.Attributes["@is-uncertain-date-any"] = function (state, arg) { + CSL.Attributes["@is-uncertain-date"].call(this, state, arg, "any"); +}; +CSL.Attributes["@is-uncertain-date-all"] = function (state, arg) { + CSL.Attributes["@is-uncertain-date"].call(this, state, arg, "all"); +}; +CSL.Attributes["@locator"] = function (state, arg) { + var trylabels = arg.replace("sub verbo", "sub-verbo"); + trylabels = trylabels.split(/\s+/); + var reverses = CSL.Util.setReverseConditions.call(this, trylabels); + var maketest = function (trylabel, reverse) { + return function(Item, item) { + var label; + if ("undefined" === typeof item || !item.label) { + label = "page"; + } else if (item.label === "sub verbo") { + label = "sub-verbo"; } else { - ret.push(true); + label = item.label; } - } - return ret; - }; - this.tests.push(func); -}; -CSL.Attributes["@has-day-only"] = function (state, arg) { - var trydates = arg.split(/\s+/); - var func = function (state, Item, item) { - var ret = []; - for (var i = 0, ilen = trydates.length; i < ilen; i += 1) { - var trydate = Item[trydates[i]]; - if (!trydate || !trydate.day) { - ret.push(false); + if (trylabel === label) { + return reverse ? false : true; } else { - ret.push(true); + return reverse ? true : false; } } - return ret; - }; - this.tests.push(func); -}; -CSL.Attributes["@part-separator"] = function (state, arg) { - this.strings["part-separator"] = arg; -}; -CSL.Attributes["@context"] = function (state, arg) { - var func = function (state, Item) { - var area = state.tmp.area.slice(0, arg.length); - var result = false; - if (area === arg) { - result = true; - } - return result; - }; + } + var mytests = []; + for (var i=0,ilen=trylabels.length;i<ilen;i+=1) { + mytests.push(maketest(trylabels[i], reverses[i])); + } + var func = state.fun.match[this.match](this, state, mytests, CSL.CONDITION_LEVEL_BOTTOM); this.tests.push(func); }; -CSL.Attributes["@leading-noise-words"] = function (state, arg) { - this["leading-noise-words"] = arg; -}; -CSL.Attributes["@class"] = function (state, arg) { - state.opt["class"] = arg; -}; -CSL.Attributes["@version"] = function (state, arg) { - state.opt.version = arg; -}; -CSL.Attributes["@value"] = function (state, arg) { - this.strings.value = arg; -}; -CSL.Attributes["@name"] = function (state, arg) { - this.strings.name = arg; -}; -CSL.Attributes["@form"] = function (state, arg) { - this.strings.form = arg; -}; -CSL.Attributes["@date-parts"] = function (state, arg) { - this.strings["date-parts"] = arg; -}; -CSL.Attributes["@range-delimiter"] = function (state, arg) { - this.strings["range-delimiter"] = arg; +CSL.Attributes["@locator-any"] = function (state, arg) { + CSL.Attributes["@locator"].call(this, state, arg, "any"); }; -CSL.Attributes["@macro"] = function (state, arg) { - this.postponed_macro = arg; +CSL.Attributes["@locator-all"] = function (state, arg) { + CSL.Attributes["@locator"].call(this, state, arg, "all"); }; -CSL.Attributes["@term"] = function (state, arg) { - if (arg === "sub verbo") { - this.strings.term = "sub-verbo"; - } else { - this.strings.term = arg; +CSL.Attributes["@position"] = function (state, arg) { + var tryposition; + state.opt.update_mode = CSL.POSITION; + state.parallel.use_parallels = true; + var trypositions = arg.split(/\s+/); + var maketest = function(tryposition) { + return function (Item, item) { + if (state.tmp.area === "bibliography") { + return false; + } + if (item && "undefined" === typeof item.position) { + item.position = 0; + } + if (item && typeof item.position === "number") { + if (item.position === 0 && tryposition === 0) { + return true; + } else if (tryposition > 0 && item.position >= tryposition) { + return true; + } + } else if (tryposition === 0) { + return true; + } + return false; + } } -}; -CSL.Attributes["@xmlns"] = function (state, arg) {}; -CSL.Attributes["@lang"] = function (state, arg) { - if (arg) { - state.build.lang = arg; + var mytests = []; + for (var i=0,ilen=trypositions.length;i<ilen;i+=1) { + var tryposition = trypositions[i]; + if (tryposition === "first") { + tryposition = CSL.POSITION_FIRST; + } else if (tryposition === "subsequent") { + tryposition = CSL.POSITION_SUBSEQUENT; + } else if (tryposition === "ibid") { + tryposition = CSL.POSITION_IBID; + } else if (tryposition === "ibid-with-locator") { + tryposition = CSL.POSITION_IBID_WITH_LOCATOR; + } + if ("near-note" === tryposition) { + mytests.push(function (Item, item) { + if (item && item.position === CSL.POSITION_SUBSEQUENT && item["near-note"]) { + return true; + } + return false; + }); + } else { + mytests.push(maketest(tryposition)); + } } + var func = state.fun.match[this.match](this, state, mytests, CSL.CONDITION_LEVEL_BOTTOM); + this.tests.push(func); }; CSL.Attributes["@type"] = function (state, arg) { - var types, ret, func, len, pos; - func = function (state, Item) { - types = arg.split(/\s+/); - ret = []; - len = types.length; - for (pos = 0; pos < len; pos += 1) { - ret.push(Item.type === types[pos]); + var types = arg.split(/\s+/); + var reverses = CSL.Util.setReverseConditions.call(this, types); + var maketest = function (mytype, reverse) { + return function(Item,item) { + var ret = (Item.type === mytype); + if (ret) { + return reverse ? false : true; + } else { + return reverse ? true : false; + } } - return ret; - }; + } + var mytests = []; + for (var i=0,ilen=types.length;i<ilen;i+=1) { + mytests.push(maketest(types[i], reverses[i])); + } + var func = state.fun.match[this.match](this, state, mytests, CSL.CONDITION_LEVEL_BOTTOM); this.tests.push(func); }; +CSL.Attributes["@type-any"] = function (state, arg) { + CSL.Attributes["@type"].call(this, state, arg, "any"); +}; +CSL.Attributes["@type-all"] = function (state, arg) { + CSL.Attributes["@type"].call(this, state, arg, "all"); +}; CSL.Attributes["@variable"] = function (state, arg) { - var variables, pos, len, func, output, variable, varlen, needlen, ret, myitem, key, flag; this.variables = arg.split(/\s+/); - this.variables_real = arg.split(/\s+/); + this.variables_real = this.variables.slice(); if ("label" === this.name && this.variables[0]) { this.strings.term = this.variables[0]; } else if (["names", "date", "text", "number"].indexOf(this.name) > -1) { @@ -9092,218 +9130,388 @@ CSL.Attributes["@variable"] = function (state, arg) { }; this.execs.push(func); } else if (["if", "else-if"].indexOf(this.name) > -1) { - func = function (state, Item, item) { - var key, x; - ret = []; - len = this.variables.length; - for (pos = 0; pos < len; pos += 1) { - variable = this.variables[pos]; - x = false; - myitem = Item; + var reverses = CSL.Util.setReverseConditions.call(this, this.variables); + var maketest = function (variable, reverse) { + return function(Item,item){ + var myitem = Item; if (item && ["locator", "locator-revision", "first-reference-note-number", "locator-date"].indexOf(variable) > -1) { myitem = item; } if (variable === "hereinafter" && state.sys.getAbbreviation && myitem.id) { if (state.transform.abbrevs["default"].hereinafter[myitem.id]) { - x = true; + return reverse ? false : true; } } else if (myitem[variable]) { if ("number" === typeof myitem[variable] || "string" === typeof myitem[variable]) { - x = true; + return reverse ? false : true; } else if ("object" === typeof myitem[variable]) { for (key in myitem[variable]) { if (myitem[variable][key]) { - x = true; - break; - } else { - x = false; + return reverse ? false : true; } } } } - ret.push(x); + return reverse ? true : false; } - return ret; - }; + } + var mytests = []; + for (var i=0,ilen=this.variables.length;i<ilen;i+=1) { + mytests.push(maketest(this.variables[i], reverses[i])); + } + var func = state.fun.match[this.match](this, state, mytests, CSL.CONDITION_LEVEL_BOTTOM); this.tests.push(func); } }; -CSL.Attributes["@lingo"] = function (state, arg) { +CSL.Attributes["@variable-any"] = function (state, arg) { + CSL.Attributes["@variable"].call(this, state, arg, "any"); }; -CSL.Attributes["@macro-has-date"] = function (state, arg) { - this["macro-has-date"] = true; +CSL.Attributes["@variable-all"] = function (state, arg) { + CSL.Attributes["@variable"].call(this, state, arg, "all"); }; -CSL.Attributes["@locale"] = function (state, arg) { - var func, ret, len, pos, variable, myitem, langspec, lang, lst, i, ilen, fallback; - if (this.name === "layout") { - this.locale_raw = arg; - } else { - lst = arg.split(/\s+/); - this.locale_bares = []; - for (i = 0, ilen = lst.length; i < ilen; i += 1) { - lang = lst[i]; - langspec = CSL.localeResolve(lang); - if (lst[i].length === 2) { - this.locale_bares.push(langspec.bare); +CSL.Attributes["@page"] = function (state, arg) { + var trylabels = arg.replace("sub verbo", "sub-verbo"); + trylabels = trylabels.split(/\s+/); + var reverses = CSL.Util.setReverseConditions.call(this, trylabels); + var maketest = function (trylabel, reverse) { + return function(Item, item) { + var label; + state.processNumber(false, Item, "page", Item.type); + if (!state.tmp.shadow_numbers.page.label) { + label = "page"; + } else if (state.tmp.shadow_numbers.page.label === "sub verbo") { + label = "sub-verbo"; + } else { + label = state.tmp.shadow_numbers.page.label; } - state.localeConfigure(langspec); - lst[i] = langspec; - } - this.locale_default = state.opt["default-locale"][0]; - this.locale = lst[0].best; - this.locale_list = lst.slice(); - func = function (state, Item, item) { - var key, res; - ret = []; - res = false; - var langspec = false; - if (Item.language) { - lang = Item.language; - langspec = CSL.localeResolve(lang); - if (langspec.best === state.opt["default-locale"][0]) { - langspec = false; - } - } - if (langspec) { - for (i = 0, ilen = this.locale_list.length; i < ilen; i += 1) { - if (langspec.best === this.locale_list[i].best) { - state.opt.lang = this.locale; - state.tmp.last_cite_locale = this.locale; - state.output.openLevel("empty"); - state.output.current.value().new_locale = this.locale; - res = true; - break; - } - } - if (!res && this.locale_bares.indexOf(langspec.bare) > -1) { - state.opt.lang = this.locale; - state.tmp.last_cite_locale = this.locale; - state.output.openLevel("empty"); - state.output.current.value().new_locale = this.locale; - res = true; - } + if (trylabel === label) { + return reverse ? false : true; + } else { + return reverse ? true : false; } - ret.push(res); - return ret; - }; - this.tests.push(func); + } + } + var mytests = []; + for (var i=0,ilen=trylabels.length;i<ilen;i+=1) { + mytests.push(maketest(trylabels[i], reverses[i])); } + var func = state.fun.match[this.match](this, state, mytests, CSL.CONDITION_LEVEL_BOTTOM); + this.tests.push(func); }; -CSL.Attributes["@suffix"] = function (state, arg) { - this.strings.suffix = arg; +CSL.Attributes["@page-any"] = function (state, arg) { + CSL.Attributes["@page"].call(this, state, arg, "any"); }; -CSL.Attributes["@prefix"] = function (state, arg) { - this.strings.prefix = arg; +CSL.Attributes["@page-all"] = function (state, arg) { + CSL.Attributes["@page"].call(this, state, arg, "all"); }; -CSL.Attributes["@delimiter"] = function (state, arg) { - if ("name" == this.name) { - this.strings.name_delimiter = arg; - } else { - this.strings.delimiter = arg; +CSL.Attributes["@jurisdiction"] = function (state, arg) { + var tryjurisdictions = arg.split(/\s+/); + var reverses = CSL.Util.setReverseConditions.call(this, tryjurisdictions); + for (var i=0,ilen=tryjurisdictions.length;i<ilen;i+=1) { + tryjurisdictions[i] = tryjurisdictions[i].split(";"); + } + var maketests = function (tryjurisdiction, reverse) { + return function(Item,item){ + if (!Item.jurisdiction) { + return reverse ? true : false; + } + var jurisdictions = Item.jurisdiction.split(";"); + for (var i=0,ilen=jurisdictions.length;i<ilen;i+=1) { + jurisdictions[i] = jurisdictions[i].split(";"); + } + for (i=tryjurisdiction.length;i>0;i+=-1) { + var tryjurisdictionStr = tryjurisdiction.slice(0,i).join(";"); + var jurisdiction = jurisdictions.slice(0,i).join(";"); + if (tryjurisdictionStr === jurisdiction) { + return reverse ? false : true; + } + } + return reverse ? true : false; + } + } + var mytests = []; + for (var i=0,ilen=tryjurisdictions.length;i<ilen;i+=1) { + var tryjurisdictionSlice = tryjurisdictions[i].slice(); + mytests.push(maketests(tryjurisdictionSlice, reverses[i])); } + var func = state.fun.match[this.match](this, state, mytests, CSL.CONDITION_LEVEL_BOTTOM); + this.tests.push(func); }; -CSL.Attributes["@match"] = function (state, arg) { - var evaluator; - if (this.tokentype === CSL.START || CSL.SINGLETON) { - if ("none" === arg) { - evaluator = state.fun.match.none; - } else if ("any" === arg) { - evaluator = state.fun.match.any; - } else if ("all" === arg) { - evaluator = state.fun.match.all; - } else { - throw "Unknown match condition \"" + arg + "\" in @match"; +CSL.Attributes["@jurisdiction-any"] = function (state, arg) { + CSL.Attributes["@jurisdiction"].call(this, state, arg, "any"); +}; +CSL.Attributes["@jurisdiction-all"] = function (state, arg) { + CSL.Attributes["@jurisdiction"].call(this, state, arg, "all"); +}; +CSL.Attributes["@context"] = function (state, arg) { + var func = function (Item, item) { + var area = state.tmp.area.slice(0, arg.length); + if (area === arg) { + return true; } - this.evaluator = evaluator; + return false; + }; + this.tests.push(func); +}; +CSL.Attributes["@has-year-only"] = function (state, arg) { + var trydates = arg.split(/\s+/); + var maketest = function (trydate) { + return function(Item,item){ + var date = Item[trydate]; + if (!date || date.month || date.season) { + return false; + } else { + return true; + } + } + } + var mytests = []; + for (var i=0,ilen=trydates.length;i<ilen;i+=1) { + mytests.push(maketest(trydates[i])); } + var func = state.fun.match[this.match](this, state, mytests); + this.tests.push(func); }; -CSL.Attributes["@jurisdiction"] = function (state, arg) { - var style_lexlst = arg.split(/\s+/); - var func = function (state, Item) { - var input_lex = false; - var ret = false; - if (Item.jurisdiction) { - input_lex = Item.jurisdiction; - } else if (Item.language) { - var m = Item.language.match(/^.*-x-lex-([.;a-zA-Z]+).*$/); - if (m) { - input_lex = m[1]; - } - } - if (input_lex) { - var input_lexlst = input_lex.split(";"); - outerLoop: for (var i = 0, ilen = style_lexlst.length; i < ilen; i += 1) { - var style_lexlst_subjur = style_lexlst[i].split(";"); - middleLoop: for (var j = 0, jlen = style_lexlst_subjur.length; j < jlen; j += 1) { - var style_lex_elem = style_lexlst_subjur[j]; - innerLoop: for (var k = 0, klen = input_lexlst.length; k < klen; k += 1) { - var input_lex_elem = input_lexlst[k]; - if (style_lex_elem === input_lex_elem && j === style_lexlst_subjur.length - 1) { - ret = true; - break outerLoop; - } - } - } +CSL.Attributes["@has-month-or-season-only"] = function (state, arg) { + var trydates = arg.split(/\s+/); + var maketest = function (trydate) { + return function(Item,item){ + var date = Item[trydate]; + if (!date || (!date.month && !date.season) || date.day) { + return false; + } else { + return true; } } - return ret; - }; + } + var mytests = []; + for (var i=0,ilen=trydates.length;i<ilen;i+=1) { + mytests.push(maketest(trydates[i])); + } + var func = state.fun.match[this.match](this, state, mytests); this.tests.push(func); }; -CSL.Attributes["@is-uncertain-date"] = function (state, arg) { - var variables, len, pos, func, variable, ret; - variables = arg.split(/\s+/); - len = variables.length; - func = function (state, Item) { - ret = []; - for (pos = 0; pos < len; pos += 1) { - variable = variables[pos]; - if (Item[variable] && Item[variable].circa) { - ret.push(true); +CSL.Attributes["@has-day-only"] = function (state, arg) { + var trydates = arg.split(/\s+/); + var maketest = function (trydate) { + return function(Item,item){ + var date = Item[trydate]; + if (!date || !date.day) { + return false; } else { - ret.push(false); + return true; } } - return ret; + } + var mytests = []; + for (var i=0,ilen=trydates.length;i<ilen;i+=1) { + mytests.push(maketest(trydates[i])); }; + var func = state.fun.match[this.match](this, state, mytests); this.tests.push(func); }; -CSL.Attributes["@is-numeric"] = function (state, arg) { - var variables, func, len, ret; - variables = arg.split(/\s+/); - len = variables.length; - func = function (state, Item, item) { - ret = []; - for (var i = 0; i < len; i += 1) { - var myitem = Item; - if (["locator","locator-revision"].indexOf(variables[i]) > -1) { - myitem = item; - } - if (CSL.NUMERIC_VARIABLES.indexOf(variables[i]) > -1) { - if (!state.tmp.shadow_numbers[variables[i]]) { - state.processNumber(false, myitem, variables[i], Item.type); - } - if (myitem[variables[i]] && state.tmp.shadow_numbers[variables[i]].numeric) { - ret.push(true); - } else { - ret.push(false); - } - } else if (["title", "locator-revision","version"].indexOf(variables[i]) > -1) { - if (myitem[variables[i]]) { - if (myitem[variables[i]].slice(-1) === "" + parseInt(myitem[variables[i]].slice(-1), 10)) { - ret.push(true); - } else { - ret.push(false); - } +CSL.Attributes["@subjurisdictions"] = function (state, arg) { + var trysubjurisdictions = parseInt(arg, 10); + var func = function (Item, item) { + var subjurisdictions = 0; + if (Item.jurisdiction) { + subjurisdictions = Item.jurisdiction.split(";").length; + } + if (subjurisdictions) { + subjurisdictions += -1; + } + if (subjurisdictions >= trysubjurisdictions) { + return true; + } + return false; + }; + this.tests.push(func); +}; +CSL.Attributes["@is-plural"] = function (state, arg) { + var func = function (Item, item) { + var nameList = Item[arg]; + if (nameList && nameList.length) { + var persons = 0; + var institutions = 0; + var last_is_person = false; + for (var i = 0, ilen = nameList.length; i < ilen; i += 1) { + if (nameList[i].isInstitution && (nameList[i].literal || (nameList[i].family && !nameList[i].given))) { + institutions += 1; + last_is_person = false; } else { - ret.push(false); + persons += 1; + last_is_person = true; } } + if (persons > 1) { + return true; + } else if (institutions > 1) { + return true; + } else if (institutions && last_is_person) { + return true; + } } - return ret; + return false; }; this.tests.push(func); }; +CSL.Attributes["@locale"] = function (state, arg) { + var func, ret, len, pos, variable, myitem, langspec, lang, lst, i, ilen, fallback; + if (this.name === "layout") { + this.locale_raw = arg; + } else { + lst = arg.split(/\s+/); + this.locale_bares = []; + for (i = 0, ilen = lst.length; i < ilen; i += 1) { + lang = lst[i]; + langspec = CSL.localeResolve(lang); + if (lst[i].length === 2) { + this.locale_bares.push(langspec.bare); + } + state.localeConfigure(langspec); + lst[i] = langspec; + } + this.locale_default = state.opt["default-locale"][0]; + this.locale = lst[0].best; + this.locale_list = lst.slice(); + var maketest = function (me) { + return function (Item, item) { + var key, res; + ret = []; + res = false; + var langspec = false; + if (Item.language) { + lang = Item.language; + langspec = CSL.localeResolve(lang); + if (langspec.best === state.opt["default-locale"][0]) { + langspec = false; + } + } + if (langspec) { + for (i = 0, ilen = me.locale_list.length; i < ilen; i += 1) { + if (langspec.best === me.locale_list[i].best) { + state.opt.lang = me.locale; + state.tmp.last_cite_locale = me.locale; + state.output.openLevel("empty"); + state.output.current.value().new_locale = me.locale; + res = true; + break; + } + } + if (!res && me.locale_bares.indexOf(langspec.bare) > -1) { + state.opt.lang = me.locale; + state.tmp.last_cite_locale = me.locale; + state.output.openLevel("empty"); + state.output.current.value().new_locale = me.locale; + res = true; + } + } + return res; + } + } + var me = this; + this.tests.push(maketest(me)); + } +}; +CSL.Attributes["@is-parallel"] = function (state, arg) { + var values = arg.split(" "); + for (var i = 0, ilen = values.length; i < ilen; i += 1) { + if (values[i] === "true") { + values[i] = true; + } else if (values[i] === "false") { + values[i] = false; + } + } + this.strings.set_parallel_condition = values; +}; +CSL.Attributes["@gender"] = function (state, arg) { + this.gender = arg; +} +CSL.Attributes["@cslid"] = function (state, arg) { + this.cslid = parseInt(arg, 10); +}; +CSL.Attributes["@label-form"] = function (state, arg) { + this.strings.label_form_override = arg; +}; +CSL.Attributes["@part-separator"] = function (state, arg) { + this.strings["part-separator"] = arg; +}; +CSL.Attributes["@leading-noise-words"] = function (state, arg) { + this["leading-noise-words"] = arg; +}; +CSL.Attributes["@class"] = function (state, arg) { + state.opt["class"] = arg; +}; +CSL.Attributes["@version"] = function (state, arg) { + state.opt.version = arg; +}; +CSL.Attributes["@value"] = function (state, arg) { + this.strings.value = arg; +}; +CSL.Attributes["@name"] = function (state, arg) { + this.strings.name = arg; +}; +CSL.Attributes["@form"] = function (state, arg) { + this.strings.form = arg; +}; +CSL.Attributes["@date-parts"] = function (state, arg) { + this.strings["date-parts"] = arg; +}; +CSL.Attributes["@range-delimiter"] = function (state, arg) { + this.strings["range-delimiter"] = arg; +}; +CSL.Attributes["@macro"] = function (state, arg) { + this.postponed_macro = arg; +}; +CSL.Attributes["@term"] = function (state, arg) { + if (arg === "sub verbo") { + this.strings.term = "sub-verbo"; + } else { + this.strings.term = arg; + } +}; +CSL.Attributes["@xmlns"] = function (state, arg) {}; +CSL.Attributes["@lang"] = function (state, arg) { + if (arg) { + state.build.lang = arg; + } +}; +CSL.Attributes["@lingo"] = function (state, arg) { +}; +CSL.Attributes["@macro-has-date"] = function (state, arg) { + this["macro-has-date"] = true; +}; +CSL.Attributes["@suffix"] = function (state, arg) { + this.strings.suffix = arg; +}; +CSL.Attributes["@prefix"] = function (state, arg) { + this.strings.prefix = arg; +}; +CSL.Attributes["@delimiter"] = function (state, arg) { + if ("name" == this.name) { + this.strings.name_delimiter = arg; + } else { + this.strings.delimiter = arg; + } +}; +CSL.Attributes["@match"] = function (state, arg) { + var match; + if (this.tokentype === CSL.START || CSL.SINGLETON) { + this.match = arg; + this.evaluator = function (token, state, Item, item) { + var record = function (result) { + if (result) { + state.tmp.jump.replace("succeed"); + return token.succeed; + } else { + state.tmp.jump.replace("fail"); + return token.fail; + } + } + return record(state.fun.match[arg](token, state, token.tests, CSL.CONDITION_LEVEL_TOP)(Item, item)); + }; + } +}; CSL.Attributes["@names-min"] = function (state, arg) { var val = parseInt(arg, 10); if (state.opt.max_number_of_names < val) { @@ -9335,61 +9543,6 @@ CSL.Attributes["@plural"] = function (state, arg) { this.strings.plural = false; } }; -CSL.Attributes["@locator"] = function (state, arg) { - var func; - var trylabels = arg.replace("sub verbo", "sub-verbo"); - trylabels = trylabels.split(/\s+/); - if (["if", "else-if"].indexOf(this.name) > -1) { - func = function (state, Item, item) { - var ret = []; - var label; - if ("undefined" === typeof item || !item.label) { - label = "page"; - } else if (item.label === "sub verbo") { - label = "sub-verbo"; - } else { - label = item.label; - } - for (var i = 0, ilen = trylabels.length; i < ilen; i += 1) { - if (trylabels[i] === label) { - ret.push(true); - } else { - ret.push(false); - } - } - return ret; - }; - this.tests.push(func); - } -}; -CSL.Attributes["@page"] = function (state, arg) { - var func; - var trylabels = arg.replace("sub verbo", "sub-verbo"); - trylabels = trylabels.split(/\s+/); - if (["if", "else-if"].indexOf(this.name) > -1) { - func = function (state, Item, item) { - var ret = []; - var label; - state.processNumber(false, Item, "page", Item.type); - if (!state.tmp.shadow_numbers.page.label) { - label = "page"; - } else if (state.tmp.shadow_numbers.page.label === "sub verbo") { - label = "sub-verbo"; - } else { - label = state.tmp.shadow_numbers.page.label; - } - for (var i = 0, ilen = trylabels.length; i < ilen; i += 1) { - if (trylabels[i] === label) { - ret.push(true); - } else { - ret.push(false); - } - } - return ret; - }; - this.tests.push(func); - } -}; CSL.Attributes["@number"] = function (state, arg) { var func; var trylabels = arg.replace("sub verbo", "sub-verbo"); @@ -9432,72 +9585,9 @@ CSL.Attributes["@publisher-and"] = function (state, arg) { }; CSL.Attributes["@newdate"] = function (state, arg) { }; -CSL.Attributes["@position"] = function (state, arg) { - var tryposition; - state.opt.update_mode = CSL.POSITION; - state.parallel.use_parallels = true; - if ("near-note" === arg) { - var near_note_func = function (state, Item, item) { - if (item && item.position === CSL.POSITION_SUBSEQUENT && item["near-note"]) { - return true; - } - return false; - }; - this.tests.push(near_note_func); - } else { - var factory = function (tryposition) { - return function (state, Item, item) { - if (state.tmp.area === "bibliography") { - return false; - } - if (item && "undefined" === typeof item.position) { - item.position = 0; - } - if (item && typeof item.position === "number") { - if (item.position === 0 && tryposition === 0) { - return true; - } else if (tryposition > 0 && item.position >= tryposition) { - return true; - } - } else if (tryposition === 0) { - return true; - } - return false; - }; - }; - var lst = arg.split(/\s+/); - for (var i = 0, ilen = lst.length; i < ilen; i += 1) { - if (lst[i] === "first") { - tryposition = CSL.POSITION_FIRST; - } else if (lst[i] === "subsequent") { - tryposition = CSL.POSITION_SUBSEQUENT; - } else if (lst[i] === "ibid") { - tryposition = CSL.POSITION_IBID; - } else if (lst[i] === "ibid-with-locator") { - tryposition = CSL.POSITION_IBID_WITH_LOCATOR; - } - var func = factory(tryposition); - this.tests.push(func); - } - } -}; -CSL.Attributes["@disambiguate"] = function (state, arg) { - if (this.tokentype === CSL.START && ["if", "else-if"].indexOf(this.name) > -1) { - if (arg === "true") { - state.opt.has_disambiguate = true; - var func = function (state, Item) { - if (state.tmp.disambig_settings.disambiguate) { - return true; - } - return false; - }; - this.tests.push(func); - } - } -}; CSL.Attributes["@givenname-disambiguation-rule"] = function (state, arg) { if (CSL.GIVENNAME_DISAMBIGUATION_RULES.indexOf(arg) > -1) { - state.opt["givenname-disambiguation-rule"] = arg; + state.citation.opt["givenname-disambiguation-rule"] = arg; } }; CSL.Attributes["@collapse"] = function (state, arg) { @@ -9767,88 +9857,57 @@ CSL.Stack.prototype.value = function () { CSL.Stack.prototype.length = function () { return this.mystack.length; }; -CSL.Util = {}; +CSL.Util = { + setReverseConditions: function (lst) { + reverses = []; + for (var i=0,ilen=lst.length;i<ilen;i+=1) { + if (lst[i].slice(0,4) === "not:") { + lst[i] = lst[i].slice(4); + reverses.push(true); + } else { + reverses.push(false); + } + } + return reverses; + } +}; CSL.Util.Match = function () { - this.any = function (token, state, Item, item) { - var ret = false; - for (var i = 0, ilen = token.tests.length; i < ilen; i += 1) { - var func = token.tests[i]; - var reslist = func.call(token, state, Item, item); - if ("object" !== typeof reslist) { - reslist = [reslist]; - } - for (var j = 0, jlen = reslist.length; j < jlen; j += 1) { - if (reslist[j]) { - ret = true; - break; + this.any = function (token, state, tests, level) { + return function (Item, item) { + for (var i=0, ilen=tests.length; i < ilen; i += 1) { + result = tests[i](Item, item); + if (result) { + return true; } } - if (ret) { - break; - } - } - if (ret) { - ret = token.succeed; - state.tmp.jump.replace("succeed"); - } else { - ret = token.fail; - state.tmp.jump.replace("fail"); - } - return ret; + return false; + }; }; - this.none = function (token, state, Item, item) { - var ret = true; - for (var i = 0, ilen = this.tests.length; i < ilen; i += 1) { - var func = this.tests[i]; - var reslist = func.call(token, state, Item, item); - if ("object" !== typeof reslist) { - reslist = [reslist]; - } - for (var j = 0, jlen = reslist.length; j < jlen; j += 1) { - if (reslist[j]) { - ret = false; - break; + this[undefined] = this.any; + this.none = function (token, state, tests, level) { + if (CSL.CONDITION_LEVEL_TOP !== level) { + return this.any(token, state, tests, level); + } + return function (Item, item) { + for (var i=0,ilen=tests.length;i<ilen;i+=1) { + result = tests[i](Item,item); + if (result) { + return false; } } - if (!ret) { - break; - } - } - if (ret) { - ret = token.succeed; - state.tmp.jump.replace("succeed"); - } else { - ret = token.fail; - state.tmp.jump.replace("fail"); - } - return ret; + return true; + }; }; - this.all = function (token, state, Item, item) { - var ret = true; - for (var i = 0, ilen = this.tests.length; i < ilen; i += 1) { - var func = this.tests[i]; - var reslist = func.call(token, state, Item, item); - if ("object" !== typeof reslist) { - reslist = [reslist]; - } - for (var j = 0, jlen = reslist.length; j < jlen; j += 1) { - if (!reslist[j]) { - ret = false; - break; + this.all = function (token, state, tests, level) { + return function (Item, item) { + for (var i=0,ilen=tests.length;i<ilen;i+=1) { + result = tests[i](Item,item); + if (!result) { + return false; } } - if (!ret) { - break; - } - } - if (ret) { - ret = token.succeed; - state.tmp.jump.replace("succeed"); - } else { - ret = token.fail; - state.tmp.jump.replace("fail"); - } - return ret; + return true; + }; }; }; CSL.Transform = function (state) { @@ -11255,14 +11314,25 @@ CSL.Util.substituteStart = function (state, target) { choose_start = new CSL.Token("choose", CSL.START); CSL.Node.choose.build.call(choose_start, state, target); if_start = new CSL.Token("if", CSL.START); - func = function (state, Item) { + func = function (Item,item) { if (state.tmp.can_substitute.value()) { return true; } return false; }; if_start.tests.push(func); - if_start.evaluator = state.fun.match.any; + if_start.evaluator = function (token, state, Item, item) { + var record = function (result) { + if (result) { + state.tmp.jump.replace("succeed"); + return token.succeed; + } else { + state.tmp.jump.replace("fail"); + return token.fail; + } + } + return record(state.fun.match.any(token, state, token.tests, CSL.CONDITION_LEVEL_BOTTOM)(Item, item)); + }; target.push(if_start); } }; @@ -11464,6 +11534,9 @@ CSL.Util.Ordinalizer.prototype.format = function (num, gender) { } } } else { + if (!gender) { + gender = undefined; + } this.state.fun.ordinalizer.init(); if ((num / 10) % 10 === 1 || (num > 10 && num < 20)) { suffix = this.suffixes[this.state.opt.lang][gender][3]; @@ -12652,7 +12725,7 @@ CSL.Registry.prototype.dodeletes = function (myhash) { mypos = this.ambigcites[ambig].indexOf(key); if (mypos > -1) { items = this.ambigcites[ambig].slice(); - this.ambigcites[ambig] = items.slice(0, mypos).concat(items.slice([(mypos + 1)], items.length)); + this.ambigcites[ambig] = items.slice(0, mypos).concat(items.slice(mypos+1, items.length)); } len = this.ambigcites[ambig].length; for (pos = 0; pos < len; pos += 1) { @@ -12859,6 +12932,13 @@ CSL.Registry.prototype.registerAmbigToken = function (akey, id, ambig_config) { if (new_names_params !== old_names_params) { this.state.tmp.taintedItemIDs[id] = true; } + for (var j=0,jlen=ambig_config.givens[i].length;j<jlen;j+=1) { + var new_gnames_params = ambig_config.givens[i][j]; + var old_gnames_params = this.registry[id].disambig.givens[i][j]; + if (new_gnames_params !== old_gnames_params) { + this.state.tmp.taintedItemIDs[id] = true; + } + } } } if (!this.ambigcites[akey]) { @@ -12916,7 +12996,7 @@ CSL.Registry.NameReg = function (state) { skey = skey.replace(/,\!* [^,]$/, ""); } ikey = CSL.Util.Names.initializeWith(state, skey, "%s"); - if (state.opt["givenname-disambiguation-rule"] === "by-cite") { + if (state.citation.opt["givenname-disambiguation-rule"] === "by-cite") { pkey = "" + itemid + pkey; } }; @@ -12930,7 +13010,7 @@ CSL.Registry.NameReg = function (state) { set_keys(this.state, "" + item_id, nameobj); param = 2; dagopt = state.opt["disambiguate-add-givenname"]; - gdropt = state.opt["givenname-disambiguation-rule"]; + gdropt = state.citation.opt["givenname-disambiguation-rule"]; var gdropt_orig = gdropt; if (gdropt === "by-cite") { gdropt = "all-names"; @@ -13055,8 +13135,8 @@ CSL.Registry.NameReg = function (state) { var i, ilen; var res = state.nameOutput.getName(nameobj, "locale-translit", true); nameobj = res.name; - if (state.opt["givenname-disambiguation-rule"] - && state.opt["givenname-disambiguation-rule"].slice(0, 8) === "primary-" + if (state.citation.opt["givenname-disambiguation-rule"] + && state.citation.opt["givenname-disambiguation-rule"].slice(0, 8) === "primary-" && pos !== 0) { return; } @@ -13220,16 +13300,20 @@ CSL.Disambiguation.prototype.disNames = function (ismax) { }; CSL.Disambiguation.prototype.disExtraText = function () { var pos, len, mybase; - if (!this.base.disambiguate) { - this.initVars(this.akey) + if (!this.base.disambiguate || this.state.tmp.disambiguate_count !== this.state.tmp.disambiguate_maxMax) { this.modeindex = 0; - this.base.disambiguate = true; - this.betterbase.disambiguate = true; - this.initGivens = true; - for (var i = 0, ilen = this.lists[this.listpos][1].length; i < ilen; i += 1) { - this.state.tmp.taintedItemIDs[this.lists[this.listpos][1][i].id] = true; + this.base.disambiguate = this.state.tmp.disambiguate_count; + this.betterbase.disambiguate = this.state.tmp.disambiguate_count; + if (!this.base.disambiguate) { + this.initGivens = true; + this.base.disambiguate = 1; + for (var i = 0, ilen = this.lists[this.listpos][1].length; i < ilen; i += 1) { + this.state.tmp.taintedItemIDs[this.lists[this.listpos][1][i].id] = true; + } + } else { + this.disNames(); } - } else if (this.lists[this.listpos][1].length > 1) { + } else if (this.state.tmp.disambiguate_count === this.state.tmp.disambiguate_maxMax) { if (this.modeindex === this.modes.length - 1) { var base = this.lists[this.listpos][0]; for (var i = 0, ilen = this.lists[this.listpos][1].length; i < ilen; i += 1) { @@ -13294,17 +13378,22 @@ CSL.Disambiguation.prototype.incrementDisambig = function () { increment_namesets = true; } if ("number" === typeof this.givensMax) { - if (this.base.givens[this.gnameset][this.gname] < this.givensMax) { + if (this.base.givens.length && this.base.givens[this.gnameset][this.gname] < this.givensMax) { this.base.givens[this.gnameset][this.gname] += 1; } else { increment_names = true; } } - if ("number" === typeof this.namesMax && increment_names) { - increment_namesets = false; - if (this.base.names[this.gnameset] < this.namesMax) { - this.base.names[this.gnameset] += 1; - this.gname += 1; + if ("number" === typeof this.namesMax + && increment_names) { + if (this.state.opt["disambiguate-add-names"]) { + increment_namesets = false; + if (this.base.names[this.gnameset] < this.namesMax) { + this.base.names[this.gnameset] += 1; + this.gname += 1; + } else { + increment_namesets = true; + } } else { increment_namesets = true; } @@ -13319,10 +13408,13 @@ CSL.Disambiguation.prototype.incrementDisambig = function () { } } if (("number" !== typeof this.namesetsMax || this.namesetsMax === -1 || this.gnameset === this.namesetsMax) - && ("number" !== typeof this.namesMax || this.base.names[this.gnameset] === this.namesMax) - && ("number" != typeof this.givensMax || "undefined" === typeof this.base.givens[this.gnameset][this.gname] || this.base.givens[this.gnameset][this.gname] === this.givensMax)) { + && (!this.state.opt["disambiguate-add-names"] || "number" !== typeof this.namesMax || this.base.names[this.gnameset] === this.namesMax) + && ("number" != typeof this.givensMax || "undefined" === typeof this.base.givens[this.gnameset] || "undefined" === typeof this.base.givens[this.gnameset][this.gname] || this.base.givens[this.gnameset][this.gname] === this.givensMax)) { maxed = true; } + } else if ("disExtraText" === this.modes[this.modeindex]) { + this.base.disambiguate += 1; + this.betterbase.disambiguate += 1; } return maxed; }; @@ -13376,29 +13468,43 @@ CSL.Disambiguation.prototype.initVars = function (akey) { this.Item = this.state.retrieveItem("" + myIds[0]); } this.modeindex = 0; - this.namesMax = this.maxNamesByItemId[this.Item.id][0]; - for (i = 0, ilen = this.base.givens.length; i < ilen; i += 1) { - for (var j = 0, jlen = this.namesMax; j < jlen; j += 1) { - if (!this.base.givens[i][j]) { - this.base.givens[i][j] = 0; - this.betterbase.givens[i][j] = 0; - } + if (this.state.citation.opt["disambiguate-add-names"] || true) { + this.namesMax = this.maxNamesByItemId[this.Item.id][0]; + } else { + var namesMax = this.base.names[0]; + for (var i=1,ilen=this.base.names.length;i<ilen;i+=1){ + namesMax = Math.max(namesMax,this.base.names.names[i]); } } + this.padBase(this.base); + this.padBase(this.betterbase); this.base.year_suffix = false; this.base.disambiguate = false; this.betterbase.year_suffix = false; this.betterbase.disambiguate = false; - if (this.state.opt["givenname-disambiguation-rule"] === "by-cite") { + if (this.state.citation.opt["givenname-disambiguation-rule"] === "by-cite" + && this.state.opt["disambiguate-add-givenname"]) { this.givensMax = 2; } return true; }; +CSL.Disambiguation.prototype.padBase = function (base) { + for (i = 0, ilen = base.names.length; i < ilen; i += 1) { + if (!base.givens[i]) { + base.givens[i] = []; + } + for (var j=0,jlen=base.names[i];j<jlen;j+=1) { + if (!base.givens[i][j]) { + base.givens[i][j] = 0; + } + } + } +} CSL.Disambiguation.prototype.configModes = function () { var dagopt, gdropt; this.modes = []; dagopt = this.state.opt["disambiguate-add-givenname"]; - gdropt = this.state.opt["givenname-disambiguation-rule"]; + gdropt = this.state.citation.opt["givenname-disambiguation-rule"]; if (this.state.opt['disambiguate-add-names'] || (dagopt && gdropt === "by-cite")) { this.modes.push("disNames"); } @@ -13415,6 +13521,9 @@ CSL.Disambiguation.prototype.getCiteData = function(Item, base) { base = CSL.getAmbigConfig.call(this.state); this.maxNamesByItemId[Item.id] = CSL.getMaxVals.call(this.state); this.state.registry.registry[Item.id].disambig.givens = this.state.tmp.disambig_settings.givens.slice(); + for (var i=0,ilen=this.state.registry.registry[Item.id].disambig.givens.length;i<ilen;i+=1) { + this.state.registry.registry[Item.id].disambig.givens[i] = this.state.tmp.disambig_settings.givens[i].slice(); + } this.namesetsMax = this.state.registry.registry[Item.id].disambig.names.length - 1; if (!this.base) { this.base = base; @@ -13426,9 +13535,12 @@ CSL.Disambiguation.prototype.getCiteData = function(Item, base) { var update = false; for (var i = 0, ilen = base.names.length; i < ilen; i += 1) { if (base.names[i] > this.base.names[i]) { - this.base.givens[i] = this.base.givens[i].concat(this.base.givens[i].slice(this.base.names[i])); + this.base.givens[i] = base.givens[i].slice(); this.base.names[i] = base.names[i]; this.betterbase.names = this.base.names.slice(); + this.betterbase.givens = this.base.givens.slice(); + this.padBase(this.base); + this.padBase(this.betterbase); } } this.betterbase.givens = this.base.givens.slice(); @@ -13438,7 +13550,7 @@ CSL.Disambiguation.prototype.getCiteData = function(Item, base) { } }; CSL.Disambiguation.prototype.captureStepToBase = function() { - if (this.state.opt["givenname-disambiguation-rule"] === "by-cite") { + if (this.state.citation.opt["givenname-disambiguation-rule"] === "by-cite") { this.betterbase.givens[this.gnameset][this.gname] = this.base.givens[this.gnameset][this.gname]; } this.betterbase.names[this.gnameset] = this.base.names[this.gnameset]; diff --git a/chrome/content/zotero/xpcom/connector/connector.js b/chrome/content/zotero/xpcom/connector/connector.js @@ -59,7 +59,14 @@ Zotero.Connector = new function() { var xdr = new XDomainRequest(); xdr.timeout = 700; xdr.open("POST", "http://127.0.0.1:23119/connector/ping", true); - xdr.onerror = xdr.ontimeout = fail + xdr.onerror = function() { + Zotero.debug("Connector: XDomainRequest to Zotero Standalone experienced an error"); + fail(); + }; + xdr.ontimeout = function() { + Zotero.debug("Connector: XDomainRequest to Zotero Standalone timed out"); + fail(); + }; xdr.onload = function() { if(me.isOnline !== null) return; me.isOnline = true; @@ -67,7 +74,8 @@ Zotero.Connector = new function() { _ieConnectorCallbacks = []; var listener = function(event) { - if(event.origin !== "http://127.0.0.1:23119") return; + if(event.origin !== "http://127.0.0.1:23119" + || event.source !== iframe.contentWindow) return; if(event.stopPropagation) { event.stopPropagation(); } else { diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js @@ -76,7 +76,6 @@ Zotero.Item.prototype._init = function () { this._changedSource = false; this._changedAttachmentData = false; - this._skipModTimeUpdate = false; this._previousData = {}; this._bestAttachmentState = null; @@ -1251,7 +1250,11 @@ Zotero.Item.prototype.removeRelatedItem = function (itemID) { * * Returns true on item update or itemID of new item */ -Zotero.Item.prototype.save = function() { +Zotero.Item.prototype.save = function(options) { + if (!options) { + options = {}; + } + Zotero.Items.editCheck(this); if (!this.hasChanged()) { @@ -1527,37 +1530,16 @@ Zotero.Item.prototype.save = function() { var path = this.attachmentPath; var syncState = this.attachmentSyncState; - // Save attachment within attachment base directory as relative path - if (this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE && path) { - let basePath = Zotero.Prefs.get('baseAttachmentPath'); - if (basePath != '' && Zotero.Prefs.get('saveRelativeAttachmentPath')) { - let baseDir = Components.classes["@mozilla.org/file/local;1"] - .createInstance(Components.interfaces.nsILocalFile); - try { - baseDir.persistentDescriptor = basePath; - } - catch (e) { - Zotero.debug(e, 1); - Components.utils.reportError(e); - baseDir = null; - } - - if (baseDir) { - let attachmentFile = Components.classes["@mozilla.org/file/local;1"] - .createInstance(Components.interfaces.nsILocalFile); - try { - attachmentFile.persistentDescriptor = path; - } - catch (e) { - Zotero.debug(e, 1); - Components.utils.reportError(e); - attachmentFile = null; - } - - if (attachmentFile && Zotero.File.directoryContains(baseDir, attachmentFile)) { - path = Zotero.Attachments.BASE_PATH_PLACEHOLDER - + attachmentFile.getRelativeDescriptor(baseDir); - } + if (this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE) { + // Save attachment within attachment base directory as relative path + if (Zotero.Prefs.get('saveRelativeAttachmentPath')) { + path = Zotero.Attachments.getBaseDirectoryRelativePath(path); + } + // If possible, convert relative path to absolute + else { + let file = Zotero.Attachments.resolveRelativePath(path); + if (file) { + path = file.persistentDescriptor; } } } @@ -1669,8 +1651,11 @@ Zotero.Item.prototype.save = function() { sql += field + '=?, '; sqlValues.push(this.getField(field)); } - else if ((field == 'dateModified' || field == 'clientDateModified') - && !this._skipModTimeUpdate) { + else if (field == 'dateModified' && !options.skipDateModifiedUpdate) { + sql += field + '=?, '; + sqlValues.push(Zotero.DB.transactionDateTime); + } + else if (field == 'clientDateModified' && !options.skipClientDateModifiedUpdate) { sql += field + '=?, '; sqlValues.push(Zotero.DB.transactionDateTime); } @@ -1962,37 +1947,16 @@ Zotero.Item.prototype.save = function() { var path = this.attachmentPath; var syncState = this.attachmentSyncState; - // Save attachment within attachment base directory as relative path - if (this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE && path) { - let basePath = Zotero.Prefs.get('baseAttachmentPath'); - if (basePath != '' && Zotero.Prefs.get('saveRelativeAttachmentPath')) { - let baseDir = Components.classes["@mozilla.org/file/local;1"] - .createInstance(Components.interfaces.nsILocalFile); - try { - baseDir.persistentDescriptor = basePath; - } - catch (e) { - Zotero.debug(e, 1); - Components.utils.reportError(e); - baseDir = null; - } - - if (baseDir) { - let attachmentFile = Components.classes["@mozilla.org/file/local;1"] - .createInstance(Components.interfaces.nsILocalFile); - try { - attachmentFile.persistentDescriptor = path; - } - catch (e) { - Zotero.debug(e, 1); - Components.utils.reportError(e); - attachmentFile = null; - } - - if (attachmentFile && Zotero.File.directoryContains(baseDir, attachmentFile)) { - path = Zotero.Attachments.BASE_PATH_PLACEHOLDER - + attachmentFile.getRelativeDescriptor(baseDir); - } + if (this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE) { + // Save attachment within attachment base directory as relative path + if (Zotero.Prefs.get('saveRelativeAttachmentPath')) { + path = Zotero.Attachments.getBaseDirectoryRelativePath(path); + } + // If possible, convert relative path to absolute + else { + let file = Zotero.Attachments.resolveRelativePath(path); + if (file) { + path = file.persistentDescriptor; } } } @@ -2864,6 +2828,7 @@ Zotero.Item.prototype.getFile = function(row, skipExistsCheck) { return false; } + // Imported file with relative path if (row.linkMode == Zotero.Attachments.LINK_MODE_IMPORTED_URL || row.linkMode == Zotero.Attachments.LINK_MODE_IMPORTED_FILE) { try { @@ -2913,6 +2878,15 @@ Zotero.Item.prototype.getFile = function(row, skipExistsCheck) { } } } + // Linked file with relative path + else if (row.linkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE && + row.path.indexOf(Zotero.Attachments.BASE_PATH_PLACEHOLDER) == 0) { + var file = Zotero.Attachments.resolveRelativePath(row.path); + if (!file) { + updateAttachmentStates(false); + return false; + } + } else { var file = Components.classes["@mozilla.org/file/local;1"]. createInstance(Components.interfaces.nsILocalFile); @@ -3073,11 +3047,10 @@ Zotero.Item.prototype.relinkAttachmentFile = function(file, skipItemUpdate) { var path = Zotero.Attachments.getPath(file, linkMode); this.attachmentPath = path; - if (skipItemUpdate) { - this._skipModTimeUpdate = true; - } - this.save(); - this._skipModTimeUpdate = false; + this.save({ + skipDateModifiedUpdate: true, + skipClientDateModifiedUpdate: skipItemUpdate + }); return false; } @@ -3274,58 +3247,20 @@ Zotero.Item.prototype.__defineGetter__('attachmentPath', function () { return undefined; } - var pathIsRelative = false; - if (this._attachmentPath !== null) { - pathIsRelative = this._attachmentPath.indexOf(Zotero.Attachments.BASE_PATH_PLACEHOLDER) == 0 - && this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE; - if (!pathIsRelative) { - return this._attachmentPath; - } - } - else if (!this.id) { - return ''; - } - else { - var sql = "SELECT path FROM itemAttachments WHERE itemID=?"; - var path = Zotero.DB.valueQuery(sql, this.id); - if (!path) { - this._attachmentPath = ''; - return this._attachmentPath; - } - - this._attachmentPath = path; - - pathIsRelative = path.indexOf(Zotero.Attachments.BASE_PATH_PLACEHOLDER) == 0 - && this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE; + return this._attachmentPath; } - if (pathIsRelative) { - var basePath = Zotero.Prefs.get('baseAttachmentPath'); - // If the base path has been cleared, don't try to recreate the full attachment path - if (basePath == '') { - return ''; - } - var baseDir = Components.classes["@mozilla.org/file/local;1"] - .createInstance(Components.interfaces.nsILocalFile); - try { - baseDir.persistentDescriptor = basePath; - } - catch (e) { - Zotero.debug(e, 1); - Components.utils.reportError(e); - return ''; - } - - var relativePath = this._attachmentPath.substr( - Zotero.Attachments.BASE_PATH_PLACEHOLDER.length - ); - var attachmentFile = Components.classes["@mozilla.org/file/local;1"] - .createInstance(Components.interfaces.nsILocalFile); - attachmentFile.setRelativeDescriptor(baseDir,relativePath); - return attachmentFile.persistentDescriptor; + if (!this.id) { + return ''; } + var sql = "SELECT path FROM itemAttachments WHERE itemID=?"; + var path = Zotero.DB.valueQuery(sql, this.id); + if (!path) { + path = ''; + } + this._attachmentPath = path; return path; }); @@ -3366,7 +3301,9 @@ Zotero.Item.prototype.updateAttachmentPath = function () { this._changedAttachmentData = {}; } this._changedAttachmentData.path = true; - this.save(); + this.save({ + skipDateModifiedUpdate: true + }); }; diff --git a/chrome/content/zotero/xpcom/data/notes.js b/chrome/content/zotero/xpcom/data/notes.js @@ -27,7 +27,7 @@ Zotero.Notes = new function() { this.noteToTitle = noteToTitle; - this.__defineGetter__("MAX_TITLE_LENGTH", function() { return 80; }); + this.__defineGetter__("MAX_TITLE_LENGTH", function() { return 120; }); this.__defineGetter__("defaultNote", function () '<div class="zotero-note znv1"></div>'); this.__defineGetter__("notePrefix", function () '<div class="zotero-note znv1">'); this.__defineGetter__("noteSuffix", function () '</div>'); diff --git a/chrome/content/zotero/xpcom/file.js b/chrome/content/zotero/xpcom/file.js @@ -39,7 +39,6 @@ Zotero.File = new function(){ this.putContents = putContents; this.getValidFileName = getValidFileName; this.truncateFileName = truncateFileName; - this.copyToUnique = this.copyToUnique; this.getCharsetFromFile = getCharsetFromFile; this.addCharsetListener = addCharsetListener; @@ -287,14 +286,14 @@ Zotero.File = new function(){ } - function copyToUnique(file, newFile) { + this.copyToUnique = function (file, newFile) { newFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644); var newName = newFile.leafName; newFile.remove(null); // Copy file to unique name file.copyTo(newFile.parent, newName); - return file; + return newFile; } @@ -361,7 +360,7 @@ Zotero.File = new function(){ function getValidFileName(fileName, skipXML) { // TODO: use space instead, and figure out what's doing extra // URL encode when saving attachments that trigger this - fileName = fileName.replace(/[\/\\\?%\*:|"<>]/g, ''); + fileName = fileName.replace(/[\/\\\?\*:|"<>]/g, ''); // Replace newlines and tabs (which shouldn't be in the string in the first place) with spaces fileName = fileName.replace(/[\r\n\t]+/g, ' '); // Replace various thin spaces diff --git a/chrome/content/zotero/xpcom/fulltext.js b/chrome/content/zotero/xpcom/fulltext.js @@ -575,8 +575,14 @@ Zotero.Fulltext = new function(){ flags += 'i'; } - var re = new RegExp(searchText, flags); - var matches = re(str); + try { + var re = new RegExp(searchText, flags); + var matches = re.exec(str); + } + catch (e) { + Zotero.debug(e, 1); + Components.utils.reportError(e); + } if (matches){ Zotero.debug("Text found"); return str.substr(matches.index, 50); diff --git a/chrome/content/zotero/xpcom/mimeTypeHandler.js b/chrome/content/zotero/xpcom/mimeTypeHandler.js @@ -57,8 +57,11 @@ Zotero.MIMETypeHandler = new function () { if(Zotero.Prefs.get("parseEndNoteMIMETypes")) { this.addHandler("application/x-endnote-refer", _importHandler, true); this.addHandler("application/x-research-info-systems", _importHandler, true); - // Add ISI this.addHandler("application/x-inst-for-scientific-info", _importHandler, true); + + this.addHandler("text/x-bibtex", _importHandler, true); + this.addHandler("application/x-bibtex", _importHandler, true); + // // And some non-standard ones // diff --git a/chrome/content/zotero/xpcom/schema.js b/chrome/content/zotero/xpcom/schema.js @@ -31,8 +31,8 @@ Zotero.Schema = new function(){ var _dbVersions = []; var _schemaVersions = []; var _repositoryTimer; - var _remoteUpdateInProgress = false, - _localUpdateInProgress = false; + var _remoteUpdateInProgress = false, _localUpdateInProgress = false; + var _renamedStylesByNew = null; var self = this; @@ -597,6 +597,8 @@ Zotero.Schema = new function(){ // Delete renamed/obsolete files case 'chicago-note.csl': case 'mhra_note_without_bibliography.csl': + case 'mhra.csl': + case 'mla.csl': toDelete.push(file); continue; @@ -1714,6 +1716,7 @@ Zotero.Schema = new function(){ xmlnode.normalize(); var uri = xmlnode.getAttribute('id'); + var shortName = uri.replace("http://www.zotero.org/styles/", ""); // Delete local style if CSL code is empty if (!xmlnode.firstChild) { @@ -1724,18 +1727,10 @@ Zotero.Schema = new function(){ return; } - // Remove renamed styles - if (uri == 'http://www.zotero.org/styles/american-medical-association') { - var oldID = 'http://www.zotero.org/styles/ama'; - var style = Zotero.Styles.get(oldID); - if (style && style.file.exists()) { - Zotero.debug("Deleting renamed style '" + oldID + "'"); - style.file.remove(false); - } - } - else if (uri == 'http://www.zotero.org/styles/national-library-of-medicine') { - var oldID = 'http://www.zotero.org/styles/nlm'; - var style = Zotero.Styles.get(oldID); + // Remove renamed styles, as instructed by the server + var oldID = xmlnode.getAttribute('oldID'); + if (oldID) { + var style = Zotero.Styles.get(oldID, true); if (style && style.file.exists()) { Zotero.debug("Deleting renamed style '" + oldID + "'"); style.file.remove(false); diff --git a/chrome/content/zotero/xpcom/server.js b/chrome/content/zotero/xpcom/server.js @@ -306,7 +306,8 @@ Zotero.Server.DataListener.prototype._generateResponse = function(status, conten if(!Zotero.isServer) { response += "X-Zotero-Version: "+Zotero.version+"\r\n"; response += "X-Zotero-Connector-API-Version: "+CONNECTOR_API_VERSION+"\r\n"; - if(this.origin === "https://www.zotero.org" || this.origin === "http://www.zotero.org") { + if(this.origin === ZOTERO_CONFIG.BOOKMARKLET_ORIGIN || + this.origin === ZOTERO_CONFIG.HTTP_BOOKMARKLET_ORIGIN) { response += "Access-Control-Allow-Origin: "+this.origin+"\r\n"; response += "Access-Control-Allow-Methods: POST, GET, OPTIONS\r\n"; response += "Access-Control-Allow-Headers: Content-Type,X-Zotero-Connector-API-Version,X-Zotero-Version\r\n"; diff --git a/chrome/content/zotero/xpcom/server_connector.js b/chrome/content/zotero/xpcom/server_connector.js @@ -55,6 +55,14 @@ Zotero.Server.Connector.AttachmentProgressManager = new function() { this.getProgressForID = function(progressID) { return progressID in attachmentProgress ? attachmentProgress[progressID] : 0; }; + + /** + * Check if we have received progress for a given attachment + */ + this.has = function(attachment) { + return attachmentsInProgress.has(attachment) + && attachmentsInProgress.get(attachment) in attachmentProgress; + } }; /** @@ -285,7 +293,6 @@ Zotero.Server.Connector.SavePage.prototype = { Zotero.Server.Connector.AttachmentProgressManager.onProgress(attachment, progress, error); }); translate.setHandler("itemsDone", function(obj, item) { - Zotero.Server.Connector.AttachmentProgressManager.add(item.attachments); Zotero.Browser.deleteHiddenBrowser(me._browser); if(jsonItems.length || me.selectedItems === false) { me.sendResponse(201, "application/json", JSON.stringify({"items":jsonItems})); @@ -340,11 +347,21 @@ Zotero.Server.Connector.SaveItem.prototype = { // save items var itemSaver = new Zotero.Translate.ItemSaver(libraryID, Zotero.Translate.ItemSaver.ATTACHMENT_MODE_DOWNLOAD, 1, undefined, cookieSandbox); - itemSaver.saveItems(data.items, function(returnValue, newItems) { + itemSaver.saveItems(data.items, function(returnValue, items) { if(returnValue) { try { - for each(var item in newItems) { - if(collection) collection.addItem(item.id); + // Remove attachments not being saved from item.attachments + for(var i=0; i<data.items.length; i++) { + var item = data.items[i]; + for(var j=0; j<item.attachments.length; j++) { + if(!Zotero.Server.Connector.AttachmentProgressManager.has(item.attachments[j])) { + item.attachments.splice(j--, 1); + } + } + } + + for(var i=0; i<items.length; i++) { + if(collection) collection.addItem(items[i].id); } sendResponseCallback(201, "application/json", JSON.stringify({"items":data.items})); diff --git a/chrome/content/zotero/xpcom/storage.js b/chrome/content/zotero/xpcom/storage.js @@ -242,7 +242,7 @@ Zotero.Sync.Storage = new function () { ); if (version == lastSyncTime) { Zotero.debug("Last " + libraryModes[libraryID].name - + " sync time hasn't changed for library " + + " sync id hasn't changed for library " + libraryID + " -- skipping file downloads"); downloadAll = false; } diff --git a/chrome/content/zotero/xpcom/storage/request.js b/chrome/content/zotero/xpcom/storage/request.js @@ -314,7 +314,7 @@ Zotero.Sync.Storage.Request.prototype.stop = function (force) { this._forceFinish = true; } - if (this.channel) { + if (this.channel && this.channel.isPending()) { this._stopping = true; try { diff --git a/chrome/content/zotero/xpcom/storage/webdav.js b/chrome/content/zotero/xpcom/storage/webdav.js @@ -33,6 +33,8 @@ Zotero.Sync.Storage.WebDAV = (function () { var _loginManagerHost = 'chrome://zotero'; var _loginManagerURL = 'Zotero Storage Server'; + var _lastSyncIDLength = 30; + // // Private methods // @@ -983,89 +985,116 @@ Zotero.Sync.Storage.WebDAV = (function () { obj._getLastSyncTime = function () { + var lastSyncURI = this.rootURI; + lastSyncURI.spec += "lastsync.txt"; + // Cache the credentials at the root URI var self = this; return Q.fcall(function () { return self._cacheCredentials(); }) - .then(function () { - var lastSyncURI = self.rootURI; + .then(function () { + return Zotero.HTTP.promise("GET", lastSyncURI, + { debug: true, successCodes: [200, 404] }); + }) + .then(function (req) { + if (req.status == 404) { + Zotero.debug("No last WebDAV sync file"); + + // If no lastsync.txt, check previously used 'lastsync', + // and then delete it + let lastSyncURI = self.rootURI; lastSyncURI.spec += "lastsync"; return Zotero.HTTP.promise("GET", lastSyncURI, - { debug: true, successCodes: [200, 404] }); - }) - .then(function (req) { - if (req.status == 404) { - Zotero.debug("No last WebDAV sync time"); - return null; - } - - var lastModified = req.getResponseHeader("Last-Modified"); - var date = new Date(lastModified); - Zotero.debug("Last successful WebDAV sync was " + date); - return Zotero.Date.toUnixTimestamp(date); - }) - .fail(function (e) { - if (e instanceof Zotero.HTTP.UnexpectedStatusException) { - if (e.status == 403) { - Zotero.debug("Clearing WebDAV authentication credentials", 2); - _cachedCredentials = false; - } - else { - throw("HTTP " + e.status + " error from WebDAV server " - + "for GET request"); + { debug: true, successCodes: [200, 404] }) + .then(function (req) { + if (req.status == 404) { + return null; } - return Q.reject(e); + Zotero.HTTP.promise("DELETE", lastSyncURI, + { debug: true, successCodes: [200, 204, 404] }) + .done(); + + var lastModified = req.getResponseHeader("Last-Modified"); + var date = new Date(lastModified); + Zotero.debug("Last successful WebDAV sync was " + date); + return Zotero.Date.toUnixTimestamp(date); + }); + } + + var lastModified = req.getResponseHeader("Last-Modified"); + var date = new Date(lastModified); + Zotero.debug("Last successful WebDAV sync was " + date); + + var re = new RegExp("^[a-zA-Z0-9]{" + _lastSyncIDLength + "}$"); + if (!re.test(req.responseText)) { + Zotero.HTTP.promise("DELETE", lastSyncURI, + { debug: true, successCodes: [200, 204, 404] }) + .done(); + + throw new Error("Invalid last sync id '" + req.responseText+ "'") + } + + return req.responseText; + }) + .catch(function (e) { + if (e instanceof Zotero.HTTP.UnexpectedStatusException) { + if (e.status == 403) { + Zotero.debug("Clearing WebDAV authentication credentials", 2); + _cachedCredentials = false; } - // TODO: handle browser offline exception else { - throw (e); + throw("HTTP " + e.status + " error from WebDAV server " + + "for GET request"); } - }); + + return Q.reject(e); + } + // TODO: handle browser offline exception + else { + throw (e); + } + }); }; - obj._setLastSyncTime = function (libraryID, localLastSyncTime) { + obj._setLastSyncTime = function (libraryID, localLastSyncID) { if (libraryID) { throw new Error("libraryID must be 0"); } // DEBUG: is this necessary for WebDAV? - if (localLastSyncTime) { + if (localLastSyncID) { var sql = "REPLACE INTO version VALUES (?, ?)"; Zotero.DB.query( - sql, ['storage_webdav_' + libraryID, { int: localLastSyncTime }] + sql, ['storage_webdav_' + libraryID, localLastSyncID] ); return; } var uri = this.rootURI; var successFileURI = uri.clone(); - successFileURI.spec += "lastsync"; + successFileURI.spec += "lastsync.txt"; - var self = this; + // Generate a random id for the last-sync id + var id = Zotero.Utilities.randomString(_lastSyncIDLength); - return Zotero.HTTP.promise("PUT", successFileURI, " ", - { debug: true, successCodes: [200, 201, 204] }) - .then(function () { - return self._getLastSyncTime() - .then(function (ts) { - if (ts) { - var sql = "REPLACE INTO version VALUES (?, ?)"; - Zotero.DB.query( - sql, ['storage_webdav_' + libraryID, { int: ts }] - ); - } - }); - }) - .catch(function (e) { - var msg = "HTTP " + req.status + " error from WebDAV server " - + "for PUT request"; - Zotero.debug(msg, 2); - Components.utils.reportError(msg); - throw Zotero.Sync.Storage.WebDAV.defaultError; - }); + return Zotero.HTTP.promise("PUT", successFileURI, + { body: id, debug: true, successCodes: [200, 201, 204] }) + .then(function () { + var sql = "REPLACE INTO version VALUES (?, ?)"; + Zotero.DB.query( + sql, ['storage_webdav_' + libraryID, id] + ); + }) + .catch(function (e) { + var msg = "HTTP " + req.status + " error from WebDAV server " + + "for PUT request"; + Zotero.debug(msg, 2); + Components.utils.reportError(msg); + throw Zotero.Sync.Storage.WebDAV.defaultError; + }); }; @@ -1182,7 +1211,7 @@ Zotero.Sync.Storage.WebDAV = (function () { case 207: // Test if Zotero directory is writable var testFileURI = uri.clone(); - testFileURI.spec += "zotero-test-file"; + testFileURI.spec += "zotero-test-file.prop"; Zotero.HTTP.WebDAV.doPut(testFileURI, " ", function (req) { Zotero.debug(req.responseText); Zotero.debug(req.status); @@ -1235,7 +1264,7 @@ Zotero.Sync.Storage.WebDAV = (function () { // data stores. // // This can also be from IIS 6+, which is configured - // not to serve extensionless files or .prop files + // not to serve .prop files. // http://support.microsoft.com/kb/326965 case 404: return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_FILE_MISSING_AFTER_UPLOAD]); diff --git a/chrome/content/zotero/xpcom/storage/zfs.js b/chrome/content/zotero/xpcom/storage/zfs.js @@ -1043,6 +1043,10 @@ Zotero.Sync.Storage.ZFS = (function () { */ obj._purgeDeletedStorageFiles = function () { return Q.fcall(function () { + // Cache the credentials at the root + return this._cacheCredentials(); + }.bind(this)) + then(function () { // If we don't have a user id we've never synced and don't need to bother if (!Zotero.userID) { return false; diff --git a/chrome/content/zotero/xpcom/style.js b/chrome/content/zotero/xpcom/style.js @@ -32,6 +32,8 @@ Zotero.Styles = new function() { var _initialized = false; var _styles, _visibleStyles, _cacheTranslatorData; + var _renamedStyles = null; + Components.utils.import("resource://zotero/q.js"); Components.utils.import("resource://gre/modules/Services.jsm"); @@ -116,22 +118,26 @@ Zotero.Styles = new function() { /** * Gets a style with a given ID * @param {String} id + * @param {Boolean} skipMappings Don't automatically return renamed style */ - this.get = function(id) { - // Map some obsolete styles to current ones - const MAPPINGS = { - "http://www.zotero.org/styles/chicago-note": "http://www.zotero.org/styles/chicago-note-bibliography", - "http://www.zotero.org/styles/mhra_note_without_bibliography": "http://www.zotero.org/styles/mhra", - "http://www.zotero.org/styles/aaa": "http://www.zotero.org/styles/american-anthropological-association", - "http://www.zotero.org/styles/ama": "http://www.zotero.org/styles/american-medical-association", - "http://www.zotero.org/styles/nlm": "http://www.zotero.org/styles/national-library-of-medicine" - }; - + this.get = function(id, skipMappings) { if(!_initialized) this.init(); - - if(MAPPINGS.hasOwnProperty(id) && _styles[MAPPINGS[id]]) { - Zotero.debug("Mapping " + id + " to " + MAPPINGS[id]); - return _styles[MAPPINGS[id]]; + + // Map some obsolete styles to current ones + if(!_renamedStyles) { + _renamedStyles = JSON.parse(Zotero.File.getContentsFromURL( + "resource://zotero/schema/renamed-styles.json" + )); + } + + if(!skipMappings) { + var prefix = "http://www.zotero.org/styles/"; + var shortName = id.replace(prefix, ""); + if(_renamedStyles.hasOwnProperty(shortName) && _styles[prefix + _renamedStyles[shortName]]) { + let newID = prefix + _renamedStyles[shortName]; + Zotero.debug("Mapping " + id + " to " + newID); + return _styles[newID]; + } } return _styles[id] || false; diff --git a/chrome/content/zotero/xpcom/sync.js b/chrome/content/zotero/xpcom/sync.js @@ -4019,7 +4019,9 @@ Zotero.Sync.Server.Data = new function() { var msg = Zotero.getString('sync.error.invalidCharsFilename', filename); var e = new Zotero.Error(msg, 0, { dialogButtonText: null }); throw (e); - + } + if (item.attachment.linkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE) { + path = Zotero.Attachments.getBaseDirectoryRelativePath(path); } var pathElem = doc.createElement('path'); pathElem.appendChild(doc.createTextNode(path)); diff --git a/chrome/content/zotero/xpcom/translation/translate.js b/chrome/content/zotero/xpcom/translation/translate.js @@ -2307,7 +2307,7 @@ Zotero.Translate.IO = { throw "DOMParser error: loading data into data store failed"; } - nodes.normalize(); + if("normalize" in nodes) nodes.normalize(); return nodes; }, diff --git a/chrome/content/zotero/xpcom/translation/translate_item.js b/chrome/content/zotero/xpcom/translation/translate_item.js @@ -285,45 +285,93 @@ Zotero.Translate.ItemSaver.prototype = { return newItem; }, - - "_parsePath":function(path) { - // generate nsIFile - var IOService = Components.classes["@mozilla.org/network/io-service;1"]. - getService(Components.interfaces.nsIIOService); + + "_parsePathURI":function(path) { try { - var uri = IOService.newURI(Zotero.File.encodeFilePath(path), "", this._baseURI); + var uri = Services.io.newURI(path, "", this._baseURI); + var file = uri.QueryInterface(Components.interfaces.nsIFileURL).file; + if(file.path != '/' && file.exists()) return file; } catch (e) { - var msg = "Error parsing attachment path: " + path + "\n" + e.message; - Zotero.logError(msg); - Zotero.debug("Translate: " + msg, 2); - return false; + Zotero.logError(e); } - + return false; + }, + + "_parseAbsolutePath":function(path) { try { - var file = uri.QueryInterface(Components.interfaces.nsIFileURL).file; - if (file.path == '/') { - var msg = "Error parsing attachment path: " + path + "\nRoot path returned."; - Zotero.logError(msg); - Zotero.debug("Translate: " + msg, 2); - return false; + // First, try to parse absolute paths using initWithPath + var file = Components.classes["@mozilla.org/file/local;1"]. + createInstance(Components.interfaces.nsILocalFile); + file.initWithPath(path); + if(file.exists()) return file; + } catch(e) { + Zotero.logError(e); + } + return false; + }, + + "_parseRelativePath":function(path) { + try { + var file = this._baseURI.QueryInterface(Components.interfaces.nsIFileURL).file.parent; + var splitPath = path.split(/\//g); + for(var i=0; i<splitPath.length; i++) { + if(splitPath[i] !== "") file.append(splitPath[i]); } + if(file.exists()) return file; + } catch(e) { + Zotero.logError(e); } - catch (e) { - var msg = "Error getting file from attachment path: " + path + "\n" + e.message; - Zotero.logError(msg); - Zotero.debug("Translate: " + msg, 2); - return false; + return false; + }, + + "_parsePath":function(path) { + var file; + + // First, try to parse as absolute path + if(((/[a-zA-Z]:\\/.test(path) && Zotero.isWin) || (path[0] === "/" && !Zotero.isWin)) + && (file = this._parseAbsolutePath(path))) { + Zotero.debug("Translate: Got file "+path+" as absolute path"); + return file; } - - if(file.exists()) { + + // Next, try to parse as URI + if((file = this._parsePathURI(path))) { + Zotero.debug("Translate: Got "+path+" as URI") return file; - } else if(path[0] !== "/" && path.substr(0, 5).toLowerCase() !== "file:") { - // This looks like a relative path, but it might actually be an absolute path, because - // some people are not quite there. - var newFile = this._parsePath("/"+path); - if(newFile && newFile.exists()) return newFile; + } else if(path.substr(0, 7) !== "file://") { + // If it was a fully qualified file URI, we can give up now + + // Next, try to parse as relative path, replacing backslashes with slashes + if((file = this._parseRelativePath(path.replace(/\\/g, "/")))) { + Zotero.debug("Translate: Got file "+path+" as relative path"); + return file; + } + + // Next, try to parse as relative path, without replacing backslashes with slashes + if((file = this._parseRelativePath(path))) { + Zotero.debug("Translate: Got file "+path+" as relative path"); + return file; + } + + if(path[0] !== "/") { + // Next, try to parse a path with no / as an absolute URI or path + if((file = this._parsePathURI("/"+path))) { + Zotero.debug("Translate: Got file "+path+" as broken URI"); + return file; + } + + if((file = this._parseAbsolutePath("/"+path))) { + Zotero.debug("Translate: Got file "+path+" as broken absolute path"); + return file; + } + + } } + + // Give up + Zotero.debug("Translate: Could not find file "+path) + return false; }, diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js @@ -35,6 +35,8 @@ const ZOTERO_CONFIG = { API_URL: 'https://api.zotero.org/', API_VERSION: 2, PREF_BRANCH: 'extensions.zotero.', + BOOKMARKLET_ORIGIN : 'https://www.zotero.org', + HTTP_BOOKMARKLET_ORIGIN : 'http://www.zotero.org', BOOKMARKLET_URL: 'https://www.zotero.org/bookmarklet/', VERSION: "4.1a1.SOURCE" }; diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js @@ -3087,7 +3087,8 @@ var ZoteroPane = new function() if (itemType == 'temporaryPDFHack') { itemType = null; var isPDF = false; - if (doc.title.indexOf('application/pdf') != -1 || Zotero.Attachments.isPDFJS(doc)) { + if (doc.title.indexOf('application/pdf') != -1 || Zotero.Attachments.isPDFJS(doc) + || doc.contentType == 'application/pdf') { isPDF = true; } else { @@ -3444,8 +3445,9 @@ var ZoteroPane = new function() } var file = item.getFile(); - Zotero.debug("Opening " + file.path); if (file) { + Zotero.debug("Opening " + file.path); + if(forceExternalViewer !== undefined) { var externalViewer = forceExternalViewer; } else { diff --git a/chrome/locale/en-US/zotero/preferences.dtd b/chrome/locale/en-US/zotero/preferences.dtd @@ -203,4 +203,5 @@ <!ENTITY zotero.preferences.openAboutConfig "Open about:config"> <!ENTITY zotero.preferences.openCSLEdit "Open CSL Editor"> -<!ENTITY zotero.preferences.openCSLPreview "Open CSL Preview"> -\ No newline at end of file +<!ENTITY zotero.preferences.openCSLPreview "Open CSL Preview"> +<!ENTITY zotero.preferences.openAboutMemory "Open about:memory"> +\ No newline at end of file diff --git a/chrome/skin/default/zotero/integration.css b/chrome/skin/default/zotero/integration.css @@ -107,7 +107,6 @@ } .quick-format-bubble { - -moz-border-radius: 8px; border-radius: 8px; background-color: #dee7f8; border-style: solid; @@ -124,7 +123,6 @@ } .quick-format-bubble[selected="true"] { - -moz-border-radius: 8px !important; border-radius: 8px !important; background-color: #598bec; color: #fff; diff --git a/chrome/skin/default/zotero/zotero.css b/chrome/skin/default/zotero/zotero.css @@ -179,7 +179,6 @@ label.zotero-text-link { .zotero-clicky { - -moz-border-radius: 6px; border-radius: 6px; border: 1px solid transparent; } diff --git a/components/zotero-autocomplete.js b/components/zotero-autocomplete.js @@ -44,7 +44,7 @@ function ZoteroAutoComplete() { } -ZoteroAutoComplete.prototype.startSearch = function(searchString, searchParam, previousResult, listener) { +ZoteroAutoComplete.prototype.startSearch = function(searchString, searchParams, previousResult, listener) { var result = Cc["@mozilla.org/autocomplete/simple-result;1"] .createInstance(Ci.nsIAutoCompleteSimpleResult); result.setSearchString(searchString); @@ -54,35 +54,35 @@ ZoteroAutoComplete.prototype.startSearch = function(searchString, searchParam, p this._listener = listener; this._cancelled = false; - this._zotero.debug("Starting autocomplete search of type '" - + searchParam + "'" + " with string '" + searchString + "'"); + this._zotero.debug("Starting autocomplete search with data '" + + searchParams + "'" + " and string '" + searchString + "'"); + + searchParams = JSON.parse(searchParams); + if (!searchParams) { + throw new Error("Invalid JSON passed to autocomplete"); + } + var [fieldName, , subField] = searchParams.fieldName.split("-"); this.stopSearch(); var self = this; var statement; - // Allow extra parameters to be passed in - var pos = searchParam.indexOf('/'); - if (pos!=-1){ - var extra = searchParam.substr(pos + 1); - var searchParam = searchParam.substr(0, pos); - } - - var searchParts = searchParam.split('-'); - searchParam = searchParts[0]; - - switch (searchParam) { + switch (fieldName) { case '': break; case 'tag': var sql = "SELECT DISTINCT name AS val, NULL AS comment FROM tags WHERE name LIKE ?"; var sqlParams = [searchString + '%']; - if (extra){ + if (typeof searchParams.libraryID != 'undefined') { + sql += " AND libraryID=?"; + sqlParams.push(searchParams.libraryID); + } + if (searchParams.itemID) { sql += " AND name NOT IN (SELECT name FROM tags WHERE tagID IN (" + "SELECT tagID FROM itemTags WHERE itemID = ?))"; - sqlParams.push(extra); + sqlParams.push(searchParams.itemID); } statement = this._zotero.DB.getStatement(sql, sqlParams); @@ -103,22 +103,24 @@ ZoteroAutoComplete.prototype.startSearch = function(searchString, searchParam, p // 0 == search two-field creators // 1 == search single-field creators // 2 == search both - var [fieldMode, itemID] = extra.split('-'); - - if (fieldMode==2) - { + if (searchParams.fieldMode == 2) { var sql = "SELECT DISTINCT CASE fieldMode WHEN 1 THEN lastName " + "WHEN 0 THEN firstName || ' ' || lastName END AS val, NULL AS comment " + "FROM creators NATURAL JOIN creatorData WHERE CASE fieldMode " + "WHEN 1 THEN lastName " + "WHEN 0 THEN firstName || ' ' || lastName END " - + "LIKE ? ORDER BY val"; - var sqlParams = searchString + '%'; + + "LIKE ? "; + var sqlParams = [searchString + '%']; + if (typeof searchParams.libraryID != 'undefined') { + sql += " AND libraryID=?"; + sqlParams.push(searchParams.libraryID); + } + sql += "ORDER BY val"; } else { var sql = "SELECT DISTINCT "; - if (fieldMode==1){ + if (searchParams.fieldMode == 1) { sql += "lastName AS val, creatorID || '-1' AS comment"; } // Retrieve the matches in the specified field @@ -138,22 +140,35 @@ ZoteroAutoComplete.prototype.startSearch = function(searchString, searchParam, p } var fromSQL = " FROM creators NATURAL JOIN creatorData " - + "WHERE " + searchParts[2] + " LIKE ?1 " + "AND fieldMode=?2"; - var sqlParams = [searchString + '%', - fieldMode ? parseInt(fieldMode) : 0]; - if (itemID){ + + "WHERE " + subField + " LIKE ?1 " + "AND fieldMode=?2"; + var sqlParams = [ + searchString + '%', + searchParams.fieldMode ? searchParams.fieldMode : 0 + ]; + if (searchParams.itemID) { fromSQL += " AND creatorID NOT IN (SELECT creatorID FROM " + "itemCreators WHERE itemID=?3)"; - sqlParams.push(itemID); + sqlParams.push(searchParams.itemID); + } + if (typeof searchParams.libraryID != 'undefined') { + if (searchParams.libraryID) { + fromSQL += " AND libraryID=?4"; + sqlParams.push(searchParams.libraryID); + } + // The db query code doesn't properly replace numbered + // parameters with "IS NULL" + else { + fromSQL += " AND libraryID IS NULL"; + } } sql += fromSQL; // If double-field mode, include matches for just this field // as well (i.e. "Shakespeare"), and group to collapse repeats - if (fieldMode!=1){ + if (searchParams.fieldMode != 1) { sql = "SELECT * FROM (" + sql + " UNION SELECT DISTINCT " - + searchParts[2] + " AS val, creatorID || '-1' AS comment" + + subField + " AS val, creatorID || '-1' AS comment" + fromSQL + ") GROUP BY val"; } @@ -165,8 +180,8 @@ ZoteroAutoComplete.prototype.startSearch = function(searchString, searchParam, p case 'dateModified': case 'dateAdded': - var sql = "SELECT DISTINCT DATE(" + searchParam + ", 'localtime') AS val, NULL AS comment FROM items " - + "WHERE " + searchParam + " LIKE ? ORDER BY " + searchParam; + var sql = "SELECT DISTINCT DATE(" + fieldName + ", 'localtime') AS val, NULL AS comment FROM items " + + "WHERE " + fieldName + " LIKE ? ORDER BY " + fieldName; var sqlParams = [searchString + '%']; statement = this._zotero.DB.getStatement(sql, sqlParams); break; @@ -181,9 +196,9 @@ ZoteroAutoComplete.prototype.startSearch = function(searchString, searchParam, p break; default: - var fieldID = this._zotero.ItemFields.getID(searchParam); + var fieldID = this._zotero.ItemFields.getID(fieldName); if (!fieldID) { - this._zotero.debug("'" + searchParam + "' is not a valid autocomplete scope", 1); + this._zotero.debug("'" + fieldName + "' is not a valid autocomplete scope", 1); this.updateResults([], false, Ci.nsIAutoCompleteResult.RESULT_IGNORED); return; } @@ -191,7 +206,7 @@ ZoteroAutoComplete.prototype.startSearch = function(searchString, searchParam, p // We don't use date autocomplete anywhere, but if we're not // disallowing it altogether, we should at least do it right and // use the user part of the multipart field - var valueField = searchParam=='date' ? 'SUBSTR(value, 12, 100)' : 'value'; + var valueField = fieldName == 'date' ? 'SUBSTR(value, 12, 100)' : 'value'; var sql = "SELECT DISTINCT " + valueField + " AS val, NULL AS comment " + "FROM itemData NATURAL JOIN itemDataValues " @@ -199,10 +214,10 @@ ZoteroAutoComplete.prototype.startSearch = function(searchString, searchParam, p + " LIKE ?2 " var sqlParams = [fieldID, searchString + '%']; - if (extra){ + if (searchParams.itemID) { sql += "AND value NOT IN (SELECT value FROM itemData " + "NATURAL JOIN itemDataValues WHERE fieldID=?1 AND itemID=?3) "; - sqlParams.push(extra); + sqlParams.push(searchParams.itemID); } sql += "ORDER BY value"; statement = this._zotero.DB.getStatement(sql, sqlParams); diff --git a/resource/schema/renamed-styles.json b/resource/schema/renamed-styles.json @@ -0,0 +1,162 @@ +{ + "aaa": "american-anthropological-association", + "advances-physiology-education": "advances-in-physiology-education", + "agriculture-ecosystems-environment": "agriculture-ecosystems-and-environment", + "ajp-heart-circulatory-physiology": "ajp-heart-and-circulatory-physiology", + "ajp-regulatory-integrative-comparative-physiology": "ajp-regulatory-integrative-and-comparative-physiology", + "ama": "american-medical-association", + "american-journal-of-cardiology": "the-american-journal-of-cardiology", + "american-journal-of-clinical-nutrition": "the-american-journal-of-clinical-nutrition", + "american-journal-of-emergency-medicine": "the-american-journal-of-emergency-medicine", + "american-journal-of-medicine": "the-american-journal-of-medicine", + "american-journal-of-pathology": "the-american-journal-of-pathology", + "american-journal-of-sports-medicine": "the-american-journal-of-sports-medicine", + "american-journal-of-surgery": "the-american-journal-of-surgery", + "american-journal-of-tropical-medicine-and-hygiene": "the-american-journal-of-tropical-medicine-and-hygiene", + "american-medical-writers-association": "american-medical-writers-association-journal", + "american-surgeon": " the-american-surgeon", + "amiens": "universite-de-picardie-jules-verne-ufr-de-medecine", + "annalen-des-naturhistorischen-museums-wien": "annalen-des-naturhistorischen-museums-in-wien", + "annals-of-allergy": "annals-of-allergy-asthma-and-immunology", + "annals-of-thoracic-surgery": "the-annals-of-thoracic-surgery", + "annual-reviews-alphabetically": "annual-reviews-alphabetical", + "annual-reviews-by-appearance": "annual-reviews", + "apa5th": "apa-5th-edition", + "apsa": "american-political-science-association", + "asa": "american-sociological-association", + "bba-biochimica-et-biophysica-acta": "biochimica-et-biophysica-acta", + "bio-medical-reviews": "biomedical-reviews", + "bmc-pharmacology": "bmc-pharmacology-and-toxicology", + "bmj-supportive-palliative-care": "bmj-supportive-and-palliative-care", + "brain-and-development-english-language": "brain-and-development", + "british-journal-of-medical-economics": "journal-of-medical-economics", + "british-volume-of-the-journal-of-bone-and-joint-surgery": "the-journal-of-bone-and-joint-surgery", + "bulletin-of-the-medical-library-association": "journal-of-the-medical-library-association", + "canadian-journal-of-anaesthesia": "canadian-journal-of-anesthesia", + "canadian-journal-of-hospital-pharmacy": "the-canadian-journal-of-hospital-pharmacy", + "canadian-medical-association-journal": "cmaj", + "canadian-veterinary-journal": "the-canadian-veterinary-journal", + "cancer-epidemiology-biomarkers-prevention": "cancer-epidemiology-biomarkers-and-prevention", + "cardiovascular-pharmacology-and-therapeutics": "journal-of-cardiovascular-pharmacology-and-therapeutics", + "central-african-journal-of-medicine": "the-central-african-journal-of-medicine", + "ceylon-journal-of-medical-science": "the-ceylon-journal-of-medical-science", + "ceylon-medical-journal": "the-ceylon-medical-journal", + "chicago-note": "chicago-note-bibliography", + "chronic-diseases-in-canada": "chronic-diseases-and-injuries-in-canada", + "college-of-physicians-and-surgeons-pakistan": "journal-of-the-college-of-physicians-and-surgeons-pakistan", + "cuadernos-filologia-clasica": "cuadernos-de-filologia-clasica", + "current-opinion-biotechnology": "current-opinion-in-biotechnology", + "current-opinion-cell-biology": "current-opinion-in-cell-biology", + "current-opinion-chemical-biology": "current-opinion-in-chemical-biology", + "current-opinion-environmental-sustainability": "current-opinion-in-environmental-sustainability", + "current-opinion-genetics-development": "current-opinion-in-genetics-development", + "current-opinion-immunology": "current-opinion-in-immunology", + "current-opinion-microbiology": "current-opinion-in-microbiology", + "current-opinion-neurobiology": "current-opinion-in-neurobiology", + "current-opinion-pharmacology": "current-opinion-in-pharmacology", + "current-opinion-plant-biology": "current-opinion-in-plant-biology", + "current-opinion-structural-biology": "current-opinion-in-structural-biology", + "danish-dental-journal": "tandlaegebladet", + "diabetes-vascular-disease-research": "diabetes-and-vascular-disease-research", + "disease-models-mechanisms": "disease-models-and-mechanisms", + "diseases-aquatic-organisms": "diseases-of-aquatic-organisms", + "edizioni-minerva-medica": "minerva-medica", + "ethics-science-environmental-politics": "ethics-in-science-and-environmental-politics", + "f1000-research": "f1000research", + "febs-journal": "the-febs-journal", + "fems": "federation-of-european-microbiological-societies", + "firstmonday": "first-monday", + "future-science": "future-science-journals", + "geological-society-america-bulletin": "geological-society-of-america-bulletin", + "geological-society-of-america": "the-geological-society-of-america", + "gost-r-7-0-5-2008-csl-1-0": "gost-r-7-0-5-2008", + "graefes-archive-and-experimental-ophthalmology": "graefes-archive-for-clinical-and-experimental-ophthalmology", + "harvard-anglia-ruskin": "harvard-anglia-ruskin-university", + "harvard-sheffield": "harvard-the-university-of-sheffield-town-and-regional-planning", + "harvard-sheffield1": "harvard-the-university-of-sheffield-school-of-east-asian-studies", + "harvard-university-of-northampton": "harvard-the-university-of-northampton", + "harvard-university-west-london": "harvard-university-of-west-london", + "harvard1-unisa-gbfe": "harvard-gesellschaft-fur-bildung-und-forschung-in-europa", + "harvard3": "harvard-swinburne-university-of-technology", + "hbp": "hpb", + "hwr-berlin": "hochschule-fur-wirtschaft-und-recht-berlin", + "ices-jms": "ices-journal-of-marine-science", + "ieee-w-url": "ieee-with-url", + "institute-of-electronics-information-and-communication-engineers": "the-institute-of-electronics-information-and-communication-engineers", + "international-journal-cross-cultural-management": "international-journal-of-cross-cultural-management", + "international-journal-of-psychiatry-in-medicine": "the-international-journal-of-psychiatry-in-medicine", + "international-journal-of-psychoanalysis": "the-international-journal-of-psychoanalysis", + "international-journal-of-tropical-biology-and-conservation": "revista-de-biologia-tropical", + "iso690-author-date-fr-without-abstract": "iso690-author-date-fr-no-abstract", + "jid-symposium-proceedings": "journal-of-investigative-dermatology-symposium-proceedings", + "journal-of-aapos": "journal-of-american-association-for-pediatric-ophthalmology-and-strabismus", + "journal-of-allergy-and-clinical-immunology": "the-journal-of-allergy-and-clinical-immunology", + "journal-of-bone-and-joint-surgery": "the-journal-of-bone-and-joint-surgery", + "journal-of-cardiovascular-surgery": "the-journal-of-cardiovascular-surgery", + "journal-of-cell-biology": "the-journal-of-cell-biology", + "journal-of-chemical-physics": "the-journal-of-chemical-physics", + "journal-of-clinical-endocrinology-and-metabolism": "the-journal-of-clinical-endocrinology-and-metabolism", + "journal-of-clinical-investigation": "the-journal-of-clinical-investigation", + "journal-of-clinical-psychiatry": "the-journal-of-clinical-psychiatry", + "journal-of-experimental-medicine": "the-journal-of-experimental-medicine", + "journal-of-general-physiology": "the-journal-of-general-physiology", + "journal-of-hand-surgery": "the-journal-of-hand-surgery", + "journal-of-heart-and-lung-transplantation": "the-journal-of-heart-and-lung-transplantation", + "journal-of-hellenic-studies": "the-journal-of-hellenic-studies", + "journal-of-hong-kong-medical-association": "hong-kong-medical-journal", + "journal-of-indian-prosthodontic-society": "the-journal-of-indian-prosthodontic-society", + "journal-of-juristic-papyrology": "the-journal-of-juristic-papyrology", + "journal-of-medieval-and-early-modern-studies": "the-journal-of-medieval-and-early-modern-studies", + "journal-of-modern-history": "the-journal-of-modern-history", + "journal-of-nuclear-medicine": "the-journal-of-nuclear-medicine", + "journal-of-organic-chemistry": "the-journal-of-organic-chemistry", + "journal-of-pediatrics": "the-journal-of-pediatrics", + "journal-of-pharmacology-and-experimental-therapeutics": "the-journal-of-pharmacology-and-experimental-therapeutics", + "journal-of-pharmacy-technology": "the-journal-of-pharmacy-technology", + "journal-of-physical-chemistry": "the-journal-of-physical-chemistry-a", + "journal-of-prosthetic-dentistry": "the-journal-of-prosthetic-dentistry", + "journal-of-the-american-academy-of-physician-assistants": "jaapa", + "journal-of-the-american-dental-association": "the-journal-of-the-american-dental-association", + "journal-of-the-american-medical-association": "jama", + "journal-of-the-american-osteopathic-association": "the-journal-of-the-american-osteopathic-association", + "journal-of-the-indian-society-of-pedodontics-and-preventative-dentistry": "journal-of-the-indian-society-of-pedodontics-and-preventive-dentistry", + "journal-of-the-institute-of-medicine": "journal-of-institute-of-medicine", + "journal-of-the-torrey-botanical-society": "the-journal-of-the-torrey-botanical-society", + "journal-of-thoracic-and-cardiovascular-surgery": "the-journal-of-thoracic-and-cardiovascular-surgery", + "journal-of-wildlife-management": "the-journal-of-wildlife-management", + "juristische-zitierweise-deutsch": "juristische-zitierweise", + "korean-journal-of-gynecologic-oncology": "journal-of-gynecologic-oncology", + "lancet-infectious-diseases": "the-lancet-infectious-diseases", + "lancet-neurology": "the-lancet-neurology", + "lancet-oncology": "the-lancet-oncology", + "lancet": "the-lancet", + "lichenologist": "the-lichenologist", + "lncs": "springer-lecture-notes-in-computer-science", + "lncs2": "springer-lecture-notes-in-computer-science-alphabetical", + "malaysian-journal-of-pathology": "the-malaysian-journal-of-pathology", + "manedsskrift-for-praktk-laegegerning": "manedsskrift-for-almen-praksis", + "medical-journal-of-australia": "the-medical-journal-of-australia", + "medicina-militar": "sanidad-militar", + "methods-information-medicine": "methods-of-information-in-medicine", + "mhra_note_without_bibliography": "modern-humanities-research-association", + "mhra-author-date": "modern-humanities-research-association-author-date", + "mhra": "modern-humanities-research-association", + "mla-notes": "modern-language-association-note", + "mla-underline": "modern-language-association-underline", + "mla-url": "modern-language-association-with-url", + "mla": "modern-language-association", + "molecular-biochemical-parasitology": "molecular-and-biochemical-parasitology", + "netherlands-journal-of-medicine": "the-netherlands-journal-of-medicine", + "neumologica-y-cirugia-de-torax-neurofibromatosis": "neumologia-y-cirugia-de-torax", + "new-iraqi-journal-of-medicine": "the-new-iraqi-journal-of-medicine", + "new-zealand-journal-of-medical-laboratory-technology": "new-zealand-journal-of-medical-laboratory-science", + "new-zealand-medical-journal": "the-new-zealand-medical-journal", + "nlm": "national-library-of-medicine", + "physiological-biochemical-zoology": "physiological-and-biochemical-zoology", + "quaderni-avogadro-colloquia": "quaderni-degli-avogadro-colloquia", + "taylor-and-francis-reference-style-f": "taylor-and-francis-chicago-f", + "ulster-medical-journal": "the-ulster-medical-journal", + "uni-freiburg-geschichte-autor-jahr": "universitat-freiburg-geschichte", + "uqam-universite-du-quebec-a-montreal": "universite-du-quebec-a-montreal", + "world-health-organization-journals": "world-health-organization" +} +\ No newline at end of file diff --git a/resource/schema/repotime.txt b/resource/schema/repotime.txt @@ -1 +1 @@ -2013-04-07 18:45:00 +2013-04-15 18:15:00