Merge branch '3.0'

Conflicts:
	chrome/content/zotero/overlay.js
	chrome/content/zotero/xpcom/schema.js
This commit is contained in:
Simon Kornblith 2012-02-28 17:22:34 -05:00
commit b3f9f5102b
28 changed files with 1103 additions and 378 deletions

View file

@ -152,10 +152,10 @@ var ZoteroOverlay = new function()
// save current state // save current state
_stateBeforeReload = !zoteroPane.hidden && !zoteroPane.collapsed; _stateBeforeReload = !zoteroPane.hidden && !zoteroPane.collapsed;
// ensure pane is closed // ensure pane is closed
if(!zoteroPane.collapsed) ZoteroOverlay.toggleDisplay(false); if(!zoteroPane.collapsed) ZoteroOverlay.toggleDisplay(false, true);
} else { } else {
// reopen pane if it was open before // reopen pane if it was open before
ZoteroOverlay.toggleDisplay(_stateBeforeReload); ZoteroOverlay.toggleDisplay(_stateBeforeReload, true);
} }
}); });
@ -202,9 +202,13 @@ var ZoteroOverlay = new function()
/** /**
* Hides/displays the Zotero interface * Hides/displays the Zotero interface
* @param {Boolean} makeVisible Whether or not Zotero interface should be visible
* @param {Boolean} dontRefocus If true, don't focus content when closing Zotero pane. Used
* when closing pane because Zotero Standalone is being opened, to avoid pulling Firefox to
* the foreground.
*/ */
this.toggleDisplay = function(makeVisible) this.toggleDisplay = function(makeVisible, dontRefocus)
{ {
if(!Zotero || !Zotero.initialized) { if(!Zotero || !Zotero.initialized) {
ZoteroPane.displayStartupError(); ZoteroPane.displayStartupError();
return; return;
@ -271,6 +275,11 @@ var ZoteroOverlay = new function()
zoteroPane.height = 0; zoteroPane.height = 0;
document.getElementById('content').setAttribute('collapsed', false); document.getElementById('content').setAttribute('collapsed', false);
if(!dontRefocus) {
// Return focus to the browser content pane
window.content.window.focus();
}
} }
} }

View file

@ -604,7 +604,9 @@ function populateQuickCopyList() {
menulist.setAttribute('preference', "pref-quickCopy-setting"); menulist.setAttribute('preference', "pref-quickCopy-setting");
updateQuickCopyHTMLCheckbox(); updateQuickCopyHTMLCheckbox();
refreshQuickCopySiteList(); if (!Zotero.isStandalone) {
refreshQuickCopySiteList();
}
} }
@ -776,11 +778,18 @@ function deleteSelectedQuickCopySite() {
function updateQuickCopyInstructions() { function updateQuickCopyInstructions() {
var prefix = Zotero.isMac ? 'Cmd+Shift+' : 'Ctrl+Alt+'; var prefix = Zotero.isMac ? 'Cmd+Shift+' : 'Ctrl+Alt+';
var key = Zotero.Prefs.get('keys.copySelectedItemsToClipboard'); var key = Zotero.Prefs.get('keys.copySelectedItemsToClipboard');
var instr = document.getElementById('quickCopy-instructions');
var str = Zotero.getString('zotero.preferences.export.quickCopy.instructions', prefix + key); var str = Zotero.getString('zotero.preferences.export.quickCopy.instructions', prefix + key);
var instr = document.getElementById('quickCopy-instructions');
while (instr.hasChildNodes()) {
instr.removeChild(instr.firstChild);
}
instr.appendChild(document.createTextNode(str));
var key = Zotero.Prefs.get('keys.copySelectedItemCitationsToClipboard');
var str = Zotero.getString('zotero.preferences.export.quickCopy.citationInstructions', prefix + key);
var instr = document.getElementById('quickCopy-citationInstructions');
while (instr.hasChildNodes()) { while (instr.hasChildNodes()) {
instr.removeChild(instr.firstChild); instr.removeChild(instr.firstChild);
} }
@ -1258,6 +1267,55 @@ function runIntegrityCheck() {
var ok = Zotero.DB.integrityCheck(); var ok = Zotero.DB.integrityCheck();
if (ok) { if (ok) {
ok = Zotero.Schema.integrityCheck(); ok = Zotero.Schema.integrityCheck();
if (!ok) {
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
var index = ps.confirmEx(window,
Zotero.getString('general.failed'),
Zotero.getString('db.integrityCheck.failed') + "\n\n" +
Zotero.getString('db.integrityCheck.repairAttempt') + " " +
Zotero.getString('db.integrityCheck.appRestartNeeded', Zotero.appName),
buttonFlags,
Zotero.getString('db.integrityCheck.fixAndRestart', Zotero.appName),
null, null, null, {}
);
if (index == 0) {
// Safety first
Zotero.DB.backupDatabase();
// Fix the errors
Zotero.Schema.integrityCheck(true);
// And run the check again
ok = Zotero.Schema.integrityCheck();
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING);
if (ok) {
var str = 'success';
var msg = Zotero.getString('db.integrityCheck.errorsFixed');
}
else {
var str = 'failed';
var msg = Zotero.getString('db.integrityCheck.errorsNotFixed')
+ "\n\n" + Zotero.getString('db.integrityCheck.reportInForums');
}
ps.confirmEx(window,
Zotero.getString('general.' + str),
msg,
buttonFlags,
Zotero.getString('general.restartApp', Zotero.appName),
null, null, null, {}
);
var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
.getService(Components.interfaces.nsIAppStartup);
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit
| Components.interfaces.nsIAppStartup.eRestart);
}
return;
}
} }
var str = ok ? 'passed' : 'failed'; var str = ok ? 'passed' : 'failed';

View file

@ -522,39 +522,24 @@ To add a new preference:
<preference id="pref-quickCopy-dragLimit" name="extensions.zotero.export.quickCopy.dragLimit" type="int"/> <preference id="pref-quickCopy-dragLimit" name="extensions.zotero.export.quickCopy.dragLimit" type="int"/>
</preferences> </preferences>
<groupbox> <groupbox id="zotero-prefpane-export-groupbox">
<caption label="&zotero.preferences.quickCopy.caption;"/> <caption label="&zotero.preferences.quickCopy.caption;"/>
<label id="quickCopy-instructions"/> <label id="quickCopy-instructions"/>
<separator class="thin"/>
<label id="quickCopy-citationInstructions"/>
<separator/> <separator/>
<label value="&zotero.preferences.quickCopy.defaultOutputFormat;" control="quickCopy-menu"/> <label value="&zotero.preferences.quickCopy.defaultOutputFormat;" control="quickCopy-menu"/>
<menulist id="zotero-quickCopy-menu"/> <menulist id="zotero-quickCopy-menu"/>
<separator/> <separator class="thin"/>
<checkbox id="zotero-quickCopy-copyAsHTML" label="&zotero.preferences.quickCopy.copyAsHTML;" <checkbox id="zotero-quickCopy-copyAsHTML" label="&zotero.preferences.quickCopy.copyAsHTML;"
oncommand="buildQuickCopyFormatDropDown(document.getElementById('zotero-quickCopy-menu'), this.checked ? 'html' : '');"/> oncommand="buildQuickCopyFormatDropDown(document.getElementById('zotero-quickCopy-menu'), this.checked ? 'html' : '');"/>
<separator/> <vbox id="zotero-prefpane-export-siteSettings"/>
<label value="&zotero.preferences.quickCopy.siteEditor.setings;" control="quickCopy-siteSettings"/>
<tree flex="1" id="quickCopy-siteSettings" hidecolumnpicker="true" rows="6" seltype="single"
ondblclick="showQuickCopySiteEditor(this.currentIndex)"
onkeypress="if (event.keyCode == event.DOM_VK_DELETE) { deleteSelectedQuickCopySite(); }">
<treecols>
<treecol id="quickCopy-urlColumn" label="&zotero.preferences.quickCopy.siteEditor.domainPath;" flex="1"/>
<treecol id="quickCopy-formatColumn" label="&zotero.preferences.quickCopy.siteEditor.outputFormat;" flex="2"/>
<treecol id="quickCopy-copyAsHTML" label="HTML"/>
</treecols>
<treechildren id="quickCopy-siteSettings-rows"/>
</tree>
<separator class="thin"/>
<hbox pack="end">
<button label="-" onclick="deleteSelectedQuickCopySite()"/>
<button label="+" onclick="showQuickCopySiteEditor()"/>
</hbox>
<hbox align="center"> <hbox align="center">
<label value="&zotero.preferences.quickCopy.dragLimit;"/> <label value="&zotero.preferences.quickCopy.dragLimit;"/>

View file

@ -76,6 +76,35 @@ To add a new preference:
</grid> </grid>
</groupbox> </groupbox>
</prefpane> </prefpane>
<prefpane id="zotero-prefpane-export"
label="&zotero.preferences.prefpane.export;"
image="chrome://zotero/skin/prefs-export.png"
helpTopic="export">
<groupbox id="zotero-prefpane-export-groupbox">
<vbox id="zotero-prefpane-export-siteSettings">
<separator/>
<label value="&zotero.preferences.quickCopy.siteEditor.setings;" control="quickCopy-siteSettings"/>
<tree flex="1" id="quickCopy-siteSettings" hidecolumnpicker="true" rows="6" seltype="single"
ondblclick="showQuickCopySiteEditor(this.currentIndex)"
onkeypress="if (event.keyCode == event.DOM_VK_DELETE) { deleteSelectedQuickCopySite(); }">
<treecols>
<treecol id="quickCopy-urlColumn" label="&zotero.preferences.quickCopy.siteEditor.domainPath;" flex="1"/>
<treecol id="quickCopy-formatColumn" label="&zotero.preferences.quickCopy.siteEditor.outputFormat;" flex="2"/>
<treecol id="quickCopy-copyAsHTML" label="HTML"/>
</treecols>
<treechildren id="quickCopy-siteSettings-rows"/>
</tree>
<separator class="thin"/>
<hbox pack="end">
<button label="-" onclick="deleteSelectedQuickCopySite()"/>
<button label="+" onclick="showQuickCopySiteEditor()"/>
</hbox>
</vbox>
</groupbox>
</prefpane>
<prefpane id="zotero-prefpane-proxies" <prefpane id="zotero-prefpane-proxies"
label="&zotero.preferences.prefpane.proxies;" label="&zotero.preferences.prefpane.proxies;"
image="chrome://zotero/skin/prefs-proxies.png" position="6" image="chrome://zotero/skin/prefs-proxies.png" position="6"

View file

@ -8,6 +8,7 @@ table {
border-width: 0 0 1px 1px; border-width: 0 0 1px 1px;
border-style: solid; border-style: solid;
border-collapse: collapse; border-collapse: collapse;
width: 100%;
} }
td, th { td, th {
@ -18,16 +19,19 @@ td, th {
} }
.th-translator { .th-translator {
width: 500px;
max-width: 500px;
} }
.th-status { .th-status {
width: 100px; width: 100px;
max-width: 100px;
} }
.th-pending, .th-supported, .th-succeeded, .th-failed, .th-unknown { .th-pending, .th-supported, .th-succeeded, .th-failed, .th-mismatch {
width: 75px; width: 75px;
max-width: 75px;
}
.th-issues {
} }
.status-succeeded, .supported-yes { .status-succeeded, .supported-yes {
@ -38,7 +42,7 @@ td, th {
background-color: #ff9090; background-color: #ff9090;
} }
.status-unknown { .status-mismatch {
background-color: #FFB; background-color: #FFB;
} }
@ -50,6 +54,10 @@ td, th {
background-color: #9FF; background-color: #9FF;
} }
.status-partial-failure {
background-color: rgb(249, 180, 98);
}
tr.output-displayed > td { tr.output-displayed > td {
background-color: #b4d5ff !important; background-color: #b4d5ff !important;
} }

View file

@ -25,16 +25,64 @@
const NUM_CONCURRENT_TESTS = 6; const NUM_CONCURRENT_TESTS = 6;
const TRANSLATOR_TYPES = ["Web", "Import", "Export", "Search"]; const TRANSLATOR_TYPES = ["Web", "Import", "Export", "Search"];
const TABLE_COLUMNS = ["Translator", "Supported", "Status", "Pending", "Succeeded", "Failed", "Unknown"]; const TABLE_COLUMNS = ["Translator", "Supported", "Status", "Pending", "Succeeded", "Failed", "Mismatch", "Issues"];
var translatorTables = {}, var translatorTables = {},
translatorTestViews = {}, translatorTestViews = {},
translatorTestViewsToRun = {}, translatorTestViewsToRun = {},
translatorTestStats = {},
translatorBox, translatorBox,
outputBox, outputBox,
allOutputView, allOutputView,
currentOutputView, currentOutputView,
viewerMode = true; viewerMode = true;
/**
* Fetches issue information from GitHub
*/
var Issues = new function() {
var _executeWhenRetrieved = [];
var githubInfo;
/**
* Gets issues for a specific translator
* @param {String} translatorLabel Gets issues starting with translatorLabel
* @param {Function} callback Function to call when issue information is available
*/
this.getFor = function(translatorLabel, callback) {
translatorLabel = translatorLabel.toLowerCase();
var whenRetrieved = function() {
var issues = [];
for(var i=0; i<githubInfo.length; i++) {
var issue = githubInfo[i];
if(issue.title.substr(0, translatorLabel.length).toLowerCase() === translatorLabel) {
issues.push(issue);
}
}
callback(issues);
};
if(githubInfo) {
whenRetrieved();
} else {
_executeWhenRetrieved.push(whenRetrieved);
}
};
var req = new XMLHttpRequest();
req.open("GET", "https://api.github.com/repos/zotero/translators/issues", true);
req.onreadystatechange = function(e) {
if(req.readyState != 4) return;
githubInfo = JSON.parse(req.responseText);
for(var i=0; i<_executeWhenRetrieved.length; i++) {
_executeWhenRetrieved[i]();
}
_executeWhenRetrieved = [];
};
req.send();
}
/** /**
* Handles adding debug output to the output box * Handles adding debug output to the output box
* @param {HTMLElement} el An element to add class="selected" to when this outputView is displayed * @param {HTMLElement} el An element to add class="selected" to when this outputView is displayed
@ -89,7 +137,7 @@ var TranslatorTestView = function(translator, type) {
this._status = document.createElement("td"); this._status = document.createElement("td");
row.appendChild(this._status); row.appendChild(this._status);
// Unknown // Pending
this._pending = document.createElement("td"); this._pending = document.createElement("td");
row.appendChild(this._pending); row.appendChild(this._pending);
@ -101,10 +149,14 @@ var TranslatorTestView = function(translator, type) {
this._failed = document.createElement("td"); this._failed = document.createElement("td");
row.appendChild(this._failed); row.appendChild(this._failed);
// Unknown // Mismatch
this._unknown = document.createElement("td"); this._unknown = document.createElement("td");
row.appendChild(this._unknown); row.appendChild(this._unknown);
// Issues
this._issues = document.createElement("td");
row.appendChild(this._issues);
// create output view and debug function // create output view and debug function
var outputView = this._outputView = new OutputView(row); var outputView = this._outputView = new OutputView(row);
this._debug = function(obj, msg, level) { this._debug = function(obj, msg, level) {
@ -125,21 +177,48 @@ var TranslatorTestView = function(translator, type) {
this.isRunning = false; this.isRunning = false;
} }
/**
* Sets the label and retrieves corresponding GitHub issues
*/
TranslatorTestView.prototype.setLabel = function(label) {
this._label.appendChild(document.createTextNode(label));
var issuesNode = this._issues;
Issues.getFor(label, function(issues) {
for(var i=0; i<issues.length; i++) {
var issue = issues[i];
var div = document.createElement("div"),
a = document.createElement("a");
var date = issue.updated_at;
date = new Date(Date.UTC(date.substr(0, 4), date.substr(5, 2)-1, date.substr(8, 2),
date.substr(11, 2), date.substr(14, 2), date.substr(17, 2)));
if("toLocaleFormat" in date) {
date = date.toLocaleFormat("%x");
} else {
date = date.getFullYear()+"-"+date.getMonth()+"-"+date.getDate();
}
a.textContent = issue.title+" (#"+issue.number+"; "+date+")";
a.setAttribute("href", issue.html_url);
a.setAttribute("target", "_blank");
div.appendChild(a);
issuesNode.appendChild(div);
}
});
}
/** /**
* Initializes TranslatorTestView given a translator and its type * Initializes TranslatorTestView given a translator and its type
*/ */
TranslatorTestView.prototype.initWithTranslatorAndType = function(translator, type) { TranslatorTestView.prototype.initWithTranslatorAndType = function(translator, type) {
this._label.appendChild(document.createTextNode(translator.label)); this.setLabel(translator.label);
this.isSupported = translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER;
this._supported.appendChild(document.createTextNode(this.isSupported ? "Yes" : "No"));
this._supported.className = this.isSupported ? "supported-yes" : "supported-no";
this._translatorTester = new Zotero_TranslatorTester(translator, type, this._debug); this._translatorTester = new Zotero_TranslatorTester(translator, type, this._debug);
this.canRun = !!this._translatorTester.tests.length; this.canRun = !!this._translatorTester.tests.length;
this.updateStatus(this._translatorTester); this.updateStatus(this._translatorTester);
this._type = type; this._type = type;
translatorTestViews[type].push(this);
translatorTables[this._type].appendChild(this._row); translatorTables[this._type].appendChild(this._row);
} }
@ -148,16 +227,13 @@ TranslatorTestView.prototype.initWithTranslatorAndType = function(translator, ty
*/ */
TranslatorTestView.prototype.unserialize = function(serializedData) { TranslatorTestView.prototype.unserialize = function(serializedData) {
this._outputView.addOutput(serializedData.output); this._outputView.addOutput(serializedData.output);
this._label.appendChild(document.createTextNode(serializedData.label)); this.setLabel(serializedData.label);
this.isSupported = serializedData.isSupported; this._type = serializedData.type;
this._supported.appendChild(document.createTextNode(this.isSupported ? "Yes" : "No")); translatorTestViews[serializedData.type].push(this);
this._supported.className = this.isSupported ? "supported-yes" : "supported-no";
this.canRun = false; this.canRun = false;
this.updateStatus(serializedData); this.updateStatus(serializedData);
this._type = serializedData.type;
translatorTables[this._type].appendChild(this._row); translatorTables[this._type].appendChild(this._row);
} }
@ -165,16 +241,7 @@ TranslatorTestView.prototype.unserialize = function(serializedData) {
* Initializes TranslatorTestView given a JSON-ified translatorTester * Initializes TranslatorTestView given a JSON-ified translatorTester
*/ */
TranslatorTestView.prototype.serialize = function(serializedData) { TranslatorTestView.prototype.serialize = function(serializedData) {
return { return this._translatorTester.serialize();
"type":this._type,
"output":this._outputView.getOutput(),
"label":this._label.textContent,
"isSupported":this.isSupported,
"pending":parseInt(this._pending.textContent),
"failed":parseInt(this._failed.textContent),
"succeeded":parseInt(this._succeeded.textContent),
"unknown":parseInt(this._unknown.textContent)
};
} }
/** /**
@ -185,6 +252,9 @@ TranslatorTestView.prototype.updateStatus = function(obj, status) {
this._status.removeChild(this._status.firstChild); this._status.removeChild(this._status.firstChild);
} }
this._supported.textContent = obj.isSupported ? "Yes" : "No";
this._supported.className = obj.isSupported ? "supported-yes" : "supported-no";
var pending = typeof obj.pending === "object" ? obj.pending.length : obj.pending; var pending = typeof obj.pending === "object" ? obj.pending.length : obj.pending;
var succeeded = typeof obj.succeeded === "object" ? obj.succeeded.length : obj.succeeded; var succeeded = typeof obj.succeeded === "object" ? obj.succeeded.length : obj.succeeded;
var failed = typeof obj.failed === "object" ? obj.failed.length : obj.failed; var failed = typeof obj.failed === "object" ? obj.failed.length : obj.failed;
@ -212,15 +282,18 @@ TranslatorTestView.prototype.updateStatus = function(obj, status) {
} else { } else {
this._status.textContent = "Not Run"; this._status.textContent = "Not Run";
} }
} else if((succeeded || unknown) && failed) {
this._status.className = "status-partial-failure";
this._status.textContent = "Partial Failure";
} else if(failed) { } else if(failed) {
this._status.className = "status-failed"; this._status.className = "status-failed";
this._status.textContent = "Failed"; this._status.textContent = "Failure";
} else if(unknown) { } else if(unknown) {
this._status.className = "status-unknown"; this._status.className = "status-mismatch";
this._status.textContent = "Unknown"; this._status.textContent = "Data Mismatch";
} else { } else {
this._status.className = "status-succeeded"; this._status.className = "status-succeeded";
this._status.textContent = "Succeeded"; this._status.textContent = "Success";
} }
} else { } else {
this._status.className = "status-untested"; this._status.className = "status-untested";
@ -231,6 +304,8 @@ TranslatorTestView.prototype.updateStatus = function(obj, status) {
this._succeeded.textContent = succeeded; this._succeeded.textContent = succeeded;
this._failed.textContent = failed; this._failed.textContent = failed;
this._unknown.textContent = unknown; this._unknown.textContent = unknown;
if(this._type) translatorTestStats[this._type].update();
} }
/** /**
@ -255,6 +330,44 @@ TranslatorTestView.prototype.runTests = function(doneCallback) {
this._translatorTester.runTests(newCallback); this._translatorTester.runTests(newCallback);
} }
/**
* Gets overall stats for translators
*/
var TranslatorTestStats = function(translatorType) {
this.translatorType = translatorType
this.node = document.createElement("p");
};
TranslatorTestStats.prototype.update = function() {
var types = {
"Success":0,
"Data Mismatch":0,
"Partial Failure":0,
"Failure":0,
"Untested":0,
"Running":0,
"Pending":0,
"Not Run":0
};
var testViews = translatorTestViews[this.translatorType];
for(var i in testViews) {
var status = testViews[i]._status ? testViews[i]._status.textContent : "Not Run";
if(status in types) {
types[status] += 1;
}
}
var typeInfo = [];
for(var i in types) {
if(types[i]) {
typeInfo.push(i+": "+types[i]);
}
}
this.node.textContent = typeInfo.join(" | ");
};
/** /**
* Called when loaded * Called when loaded
*/ */
@ -308,6 +421,8 @@ function init() {
var displayType = TRANSLATOR_TYPES[i]; var displayType = TRANSLATOR_TYPES[i];
var translatorType = displayType.toLowerCase(); var translatorType = displayType.toLowerCase();
translatorTestViews[translatorType] = [];
// create header // create header
var h1 = document.createElement("h1"); var h1 = document.createElement("h1");
h1.appendChild(document.createTextNode(displayType+" Translators ")); h1.appendChild(document.createTextNode(displayType+" Translators "));
@ -321,13 +436,7 @@ function init() {
var type = translatorType; var type = translatorType;
return function(e) { return function(e) {
e.preventDefault(); e.preventDefault();
for(var i in translatorTestViewsToRun[type]) { runTranslatorTests(type);
var testView = translatorTestViewsToRun[type][i];
testView.updateStatus(testView._translatorTester, "pending");
}
for(var i=0; i<NUM_CONCURRENT_TESTS; i++) {
runTranslatorTests(type);
}
} }
}, false); }, false);
h1.appendChild(runAll); h1.appendChild(runAll);
@ -339,6 +448,9 @@ function init() {
var translatorTable = document.createElement("table"); var translatorTable = document.createElement("table");
translatorTables[translatorType] = translatorTable; translatorTables[translatorType] = translatorTable;
translatorTestStats[translatorType] = new TranslatorTestStats(translatorType);
translatorBox.appendChild(translatorTestStats[translatorType].node);
// add headings to table // add headings to table
var headings = document.createElement("tr"); var headings = document.createElement("tr");
for(var j in TABLE_COLUMNS) { for(var j in TABLE_COLUMNS) {
@ -366,16 +478,34 @@ function init() {
if(viewerMode) { if(viewerMode) {
// if no Zotero object, try to unserialize data // if no Zotero object, try to unserialize data
var req = new XMLHttpRequest(); var req = new XMLHttpRequest();
req.open("GET", "testResults.json", true); var loc = "testResults.json";
if(window.location.hash) {
var hashVars = {};
var hashVarsSplit = window.location.hash.substr(1).split("&");
for(var i=0; i<hashVarsSplit.length; i++) {
var myVar = hashVarsSplit[i];
var index = myVar.indexOf("=");
hashVars[myVar.substr(0, index)] = myVar.substr(index+1);
}
if(hashVars["browser"] && /^[a-z]$/.test(hashVars["browser"])
&& hashVars["version"] && /^[0-9a-zA-Z\-._]/.test(hashVars["version"])) {
loc = "testResults-"+hashVars["browser"]+"-"+hashVars["version"]+".json";
}
if(hashVars["date"] && /^[0-9\-]+$/.test(hashVars["date"])) {
loc = hashVars["date"]+"/"+loc;
}
}
req.open("GET", loc, true);
req.overrideMimeType("text/plain"); req.overrideMimeType("text/plain");
req.onreadystatechange = function(e) { req.onreadystatechange = function(e) {
if(req.readyState != 4) return; if(req.readyState != 4) return;
if(req.responseText) { // success; unserialize if(req.status === 200 && req.responseText) { // success; unserialize
var data = JSON.parse(req.responseText); var data = JSON.parse(req.responseText);
for(var i=0, n=data.length; i<n; i++) { for(var i=0, n=data.results.length; i<n; i++) {
var translatorTestView = new TranslatorTestView(); var translatorTestView = new TranslatorTestView();
translatorTestView.unserialize(data[i]); translatorTestView.unserialize(data.results[i]);
} }
} else { } else {
jsonNotFound("XMLHttpRequest returned "+req.status); jsonNotFound("XMLHttpRequest returned "+req.status);
@ -393,13 +523,12 @@ function init() {
var serialize = document.createElement("a"); var serialize = document.createElement("a");
serialize.href = "#"; serialize.href = "#";
serialize.appendChild(document.createTextNode("Serialize Results")); serialize.appendChild(document.createTextNode("Serialize Results"));
serialize.addEventListener("click", serializeAll, false); serialize.addEventListener("click", serializeToDownload, false);
lastP.appendChild(serialize); lastP.appendChild(serialize);
translatorBox.appendChild(lastP); translatorBox.appendChild(lastP);
} }
} }
/** /**
* Indicates no JSON file could be found. * Indicates no JSON file could be found.
*/ */
@ -413,7 +542,6 @@ function jsonNotFound(str) {
* Called after translators are returned from main script * Called after translators are returned from main script
*/ */
function haveTranslators(translators, type) { function haveTranslators(translators, type) {
translatorTestViews[type] = [];
translatorTestViewsToRun[type] = []; translatorTestViewsToRun[type] = [];
translators = translators.sort(function(a, b) { translators = translators.sort(function(a, b) {
@ -423,38 +551,62 @@ function haveTranslators(translators, type) {
for(var i in translators) { for(var i in translators) {
var translatorTestView = new TranslatorTestView(); var translatorTestView = new TranslatorTestView();
translatorTestView.initWithTranslatorAndType(translators[i], type); translatorTestView.initWithTranslatorAndType(translators[i], type);
translatorTestViews[type].push(translatorTestView);
if(translatorTestView.canRun) { if(translatorTestView.canRun) {
translatorTestViewsToRun[type].push(translatorTestView); translatorTestViewsToRun[type].push(translatorTestView);
} }
} }
translatorTestStats[type].update();
var ev = document.createEvent('HTMLEvents');
ev.initEvent('ZoteroHaveTranslators-'+type, true, true);
document.dispatchEvent(ev);
} }
/** /**
* Runs translator tests recursively, after translatorTestViews has been populated * Begin running all translator tests of a given type
*/ */
function runTranslatorTests(type, callback, runCallbackIfComplete) { function runTranslatorTests(type, callback) {
for(var i in translatorTestViewsToRun[type]) {
var testView = translatorTestViewsToRun[type][i];
testView.updateStatus(testView._translatorTester, "pending");
}
for(var i=0; i<NUM_CONCURRENT_TESTS; i++) {
initTests(type, callback);
}
}
/**
* Run translator tests recursively, after translatorTestViews has been populated
*/
function initTests(type, callback, runCallbackIfComplete) {
if(translatorTestViewsToRun[type].length) { if(translatorTestViewsToRun[type].length) {
if(translatorTestViewsToRun[type].length === 1) runCallbackIfComplete = true; if(translatorTestViewsToRun[type].length === 1) runCallbackIfComplete = true;
var translatorTestView = translatorTestViewsToRun[type].shift(); var translatorTestView = translatorTestViewsToRun[type].shift();
translatorTestView.runTests(function() { runTranslatorTests(type, callback, runCallbackIfComplete) }); translatorTestView.runTests(function() { initTests(type, callback, runCallbackIfComplete) });
} else if(callback && runCallbackIfComplete) { } else if(callback && runCallbackIfComplete) {
callback(); callback();
} }
} }
/** /**
* Serializes all run translator tests * Serializes translator tests to JSON
*/ */
function serializeAll(e) { function serializeToJSON() {
var serializedData = []; var serializedData = {"browser":Zotero.browser, "version":Zotero.version, "results":[]};
for(var i in translatorTestViews) { for(var i in translatorTestViews) {
var n = translatorTestViews[i].length; var n = translatorTestViews[i].length;
for(var j=0; j<n; j++) { for(var j=0; j<n; j++) {
serializedData.push(translatorTestViews[i][j].serialize()); serializedData.results.push(translatorTestViews[i][j].serialize());
} }
} }
return serializedData;
}
/**
* Serializes all run translator tests
*/
function serializeToDownload(e) {
var serializedData = serializeToJSON();
document.location.href = "data:application/octet-stream,"+encodeURIComponent(JSON.stringify(serializedData, null, "\t")); document.location.href = "data:application/octet-stream,"+encodeURIComponent(JSON.stringify(serializedData, null, "\t"));
e.preventDefault(); e.preventDefault();
} }

View file

@ -23,7 +23,107 @@
***** END LICENSE BLOCK ***** ***** END LICENSE BLOCK *****
*/ */
var Zotero_TranslatorTester_IGNORE_FIELDS = ["complete", "accessDate", "checkFields"]; // Timeout for test to complete
const TEST_RUN_TIMEOUT = 600000;
var EXPORTED_SYMBOLS = ["Zotero_TranslatorTesters"];
try {
Zotero;
} catch(e) {
var Zotero;
}
Zotero_TranslatorTesters = new function() {
const TEST_TYPES = ["web", "import", "export", "search"];
/**
* Runs all tests
*/
this.runAllTests = function(numConcurrentTests, skipTranslators, doneCallback) {
if(!Zotero) {
Zotero = Components.classes["@zotero.org/Zotero;1"]
.getService(Components.interfaces.nsISupports).wrappedJSObject;
}
var testers = [];
var waitingForTranslators = TEST_TYPES.length;
for(var i=0; i<TEST_TYPES.length; i++) {
Zotero.Translators.getAllForType(TEST_TYPES[i], new function() {
var type = TEST_TYPES[i];
return function(translators) {
for(var i=0; i<translators.length; i++) {
if(skipTranslators && !skipTranslators[translators[i].translatorID]) {
testers.push(new Zotero_TranslatorTester(translators[i], type));
}
};
if(!(--waitingForTranslators)) {
runTesters(testers, numConcurrentTests, doneCallback);
}
};
}, true);
};
};
/**
* Runs a specific set of tests
*/
function runTesters(testers, numConcurrentTests, doneCallback) {
var testersRunning = 0;
var results = [];
if("getLocaleCollation" in Zotero) {
var collation = Zotero.getLocaleCollation();
strcmp = function(a, b) {
return collation.compareString(1, a, b);
};
} else {
strcmp = function (a, b) {
return a.localeCompare(b);
};
}
var testerDoneCallback = function(tester) {
if(tester.pending.length) return;
Zotero.debug("Done testing "+tester.translator.label);
// Done translating, so serialize test results
testersRunning--;
results.push(tester.serialize());
if(testers.length) {
// Run next tester if one is available
runNextTester();
} else if(testersRunning === 0) {
// Testing is done, so sort results
results = results.sort(function(a, b) {
if(a.type !== b.type) {
return TEST_TYPES.indexOf(a.type) - TEST_TYPES.indexOf(b.type);
}
return strcmp(a.label, b.label);
});
// Call done callback
doneCallback({
"browser":Zotero.browser,
"version":Zotero.version,
"results":results
});
}
};
var runNextTester = function() {
testersRunning++;
Zotero.debug("Testing "+testers[0].translator.label);
testers.shift().runTests(testerDoneCallback);
};
for(var i=0; i<numConcurrentTests; i++) {
runNextTester();
};
}
}
/** /**
* A tool to run unit tests for a given translator * A tool to run unit tests for a given translator
@ -36,13 +136,14 @@ var Zotero_TranslatorTester_IGNORE_FIELDS = ["complete", "accessDate", "checkFie
* @constructor * @constructor
* @param {Zotero.Translator[]} translator The translator for which to run tests * @param {Zotero.Translator[]} translator The translator for which to run tests
* @param {String} type The type of tests to run (web, import, export, or search) * @param {String} type The type of tests to run (web, import, export, or search)
* @param {Function} [debug] A function to call to write debug output. If not present, Zotero.debug * @param {Function} [debugCallback] A function to call to write debug output. If not present,
* will be used. * Zotero.debug will be used.
*/ */
Zotero_TranslatorTester = function(translator, type, debug) { Zotero_TranslatorTester = function(translator, type, debugCallback) {
this.type = type; this.type = type;
this.translator = translator; this.translator = translator;
this._debug = debug ? debug : function(obj, a, b) { Zotero.debug(a, b) }; this.output = "";
this.isSupported = this.translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER;
this.tests = []; this.tests = [];
this.pending = []; this.pending = [];
@ -50,6 +151,16 @@ Zotero_TranslatorTester = function(translator, type, debug) {
this.failed = []; this.failed = [];
this.unknown = []; this.unknown = [];
var me = this;
this._debug = function(obj, a, b) {
me.output += me.output ? "\n"+a : a;
if(debugCallback) {
debugCallback(me, a, b);
} else {
Zotero.debug(a, b);
}
};
var code = translator.code; var code = translator.code;
var testStart = code.indexOf("/** BEGIN TEST CASES **/"); var testStart = code.indexOf("/** BEGIN TEST CASES **/");
var testEnd = code.indexOf("/** END TEST CASES **/"); var testEnd = code.indexOf("/** END TEST CASES **/");
@ -82,25 +193,50 @@ Zotero_TranslatorTester._sanitizeItem = function(item, forSave) {
if(item.attachments && item.attachments.length) { if(item.attachments && item.attachments.length) {
// don't actually test URI equality // don't actually test URI equality
for (var i=0; i<item.attachments.length; i++) { for (var i=0; i<item.attachments.length; i++) {
if(item.attachments[i].document) { var attachment = item.attachments[i];
item.attachments[i].document = false; if(attachment.document) {
} else if(item.attachments[i].url) { delete attachment.document;
item.attachments[i].url = false; }
if(attachment.url) {
delete attachment.url;
}
if(attachment.complete) {
delete attachment.complete;
} }
} }
} }
// try to convert to JSON and back to get rid of undesirable undeletable elements; this may fail
try {
item = JSON.parse(JSON.stringify(item));
} catch(e) {};
// remove fields to be ignored // remove fields to be ignored
for(var j=0, n=Zotero_TranslatorTester_IGNORE_FIELDS.length; j<n; j++) { const IGNORE_FIELDS = ["complete", "accessDate", "checkFields"];
if(forSave) { for(var j=0, n=IGNORE_FIELDS.length; j<n; j++) {
delete item[Zotero_TranslatorTester_IGNORE_FIELDS[j]] delete item[IGNORE_FIELDS[j]];
} else {
item[Zotero_TranslatorTester_IGNORE_FIELDS[j]] = false;
}
} }
return item; return item;
}; };
/**
* Serializes translator tester results to JSON
*/
Zotero_TranslatorTester.prototype.serialize = function() {
return {
"translatorID":this.translator.translatorID,
"type":this.type,
"output":this.output,
"label":this.translator.label,
"isSupported":this.isSupported,
"pending":this.pending,
"failed":this.failed,
"succeeded":this.succeeded,
"unknown":this.unknown
};
};
/** /**
* Sets tests for this translatorTester * Sets tests for this translatorTester
@ -137,16 +273,20 @@ Zotero_TranslatorTester.prototype.runTests = function(testDoneCallback, recursiv
* @param {Function} testDoneCallback A callback to be executed each time a test is complete * @param {Function} testDoneCallback A callback to be executed each time a test is complete
*/ */
Zotero_TranslatorTester.prototype._runTestsRecursively = function(testDoneCallback) { Zotero_TranslatorTester.prototype._runTestsRecursively = function(testDoneCallback) {
var test = this.pending.shift(); var test = this.pending.shift();
var testNumber = this.tests.length-this.pending.length; var testNumber = this.tests.length-this.pending.length;
var me = this; var me = this;
this._debug(this, "\nTranslatorTester: Running "+this.translator.label+" Test "+testNumber); this._debug(this, "\nTranslatorTester: Running "+this.translator.label+" Test "+testNumber);
var executedCallback = false;
var callback = function(obj, test, status, message) { var callback = function(obj, test, status, message) {
if(executedCallback) return;
executedCallback = true;
me._debug(this, "TranslatorTester: "+me.translator.label+" Test "+testNumber+": "+status+" ("+message+")"); me._debug(this, "TranslatorTester: "+me.translator.label+" Test "+testNumber+": "+status+" ("+message+")");
me[status].push(test); me[status].push(test);
test.message = message;
if(testDoneCallback) testDoneCallback(me, test, status, message); if(testDoneCallback) testDoneCallback(me, test, status, message);
me.runTests(testDoneCallback, true); me.runTests(testDoneCallback, true);
}; };
@ -156,6 +296,10 @@ Zotero_TranslatorTester.prototype._runTestsRecursively = function(testDoneCallba
} else { } else {
this.runTest(test, null, callback); this.runTest(test, null, callback);
} }
(Zotero.setTimeout ? Zotero : window).setTimeout(function() {
callback(me, test, "failed", "Test timed out after "+TEST_RUN_TIMEOUT/1000+" seconds");
}, TEST_RUN_TIMEOUT);
}; };
/** /**
@ -167,13 +311,31 @@ Zotero_TranslatorTester.prototype._runTestsRecursively = function(testDoneCallba
* @param {Function} testDoneCallback A callback to be executed when test is complete * @param {Function} testDoneCallback A callback to be executed when test is complete
*/ */
Zotero_TranslatorTester.prototype.fetchPageAndRunTest = function(test, testDoneCallback) { Zotero_TranslatorTester.prototype.fetchPageAndRunTest = function(test, testDoneCallback) {
var timer = Components.classes["@mozilla.org/timer;1"].
createInstance(Components.interfaces.nsITimer);
timer.initWithCallback({"notify":function() {
try {
Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
} catch(e) {}
}}, TEST_RUN_TIMEOUT, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
var me = this; var me = this;
var runTest = function(doc) {
me.runTest(test, doc, function(obj, test, status, message) {
try {
timer.cancel();
} catch(e) {};
if(hiddenBrowser) Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
testDoneCallback(obj, test, status, message);
});
};
var hiddenBrowser = Zotero.HTTP.processDocuments(test.url, var hiddenBrowser = Zotero.HTTP.processDocuments(test.url,
function(doc) { function(doc) {
me.runTest(test, doc, function(obj, test, status, message) { if(test.defer) {
if(hiddenBrowser) Zotero.Browser.deleteHiddenBrowser(hiddenBrowser); Zotero.setTimeout(function() { runTest(doc) }, 10000, true);
testDoneCallback(obj, test, status, message); } else {
}); runTest(doc);
}
}, },
null, null,
function(e) { function(e) {
@ -190,7 +352,7 @@ Zotero_TranslatorTester.prototype.fetchPageAndRunTest = function(test, testDoneC
* @param {Function} testDoneCallback A callback to be executed when test is complete * @param {Function} testDoneCallback A callback to be executed when test is complete
*/ */
Zotero_TranslatorTester.prototype.runTest = function(test, doc, testDoneCallback) { Zotero_TranslatorTester.prototype.runTest = function(test, doc, testDoneCallback) {
this._debug(this, "TranslatorTester: Translating "+test.url); this._debug(this, "TranslatorTester: Translating"+(test.url ? " "+test.url : ""));
var me = this; var me = this;
var translate = Zotero.Translate.newInstance(this.type); var translate = Zotero.Translate.newInstance(this.type);
@ -207,8 +369,12 @@ Zotero_TranslatorTester.prototype.runTest = function(test, doc, testDoneCallback
me._runTestTranslate(translate, translators, test, testDoneCallback); me._runTestTranslate(translate, translators, test, testDoneCallback);
}); });
translate.setHandler("debug", this._debug); translate.setHandler("debug", this._debug);
var errorReturned;
translate.setHandler("error", function(obj, err) {
errorReturned = err;
});
translate.setHandler("done", function(obj, returnValue) { translate.setHandler("done", function(obj, returnValue) {
me._checkResult(test, obj, returnValue, testDoneCallback); me._checkResult(test, obj, returnValue, errorReturned, testDoneCallback);
}); });
translate.setHandler("select", function(obj, items, callback) { translate.setHandler("select", function(obj, items, callback) {
if(test.items !== "multiple" && test.items.length <= 1) { if(test.items !== "multiple" && test.items.length <= 1) {
@ -265,9 +431,23 @@ Zotero_TranslatorTester.prototype._runTestTranslate = function(translate, transl
* @param {Object} test Test that was executed * @param {Object} test Test that was executed
* @param {Zotero.Translate} translate The Zotero.Translate instance * @param {Zotero.Translate} translate The Zotero.Translate instance
* @param {Boolean} returnValue Whether translation completed successfully * @param {Boolean} returnValue Whether translation completed successfully
* @param {Error} error Error code, if one was specified
* @param {Function} testDoneCallback A callback to be executed when test is complete * @param {Function} testDoneCallback A callback to be executed when test is complete
*/ */
Zotero_TranslatorTester.prototype._checkResult = function(test, translate, returnValue, testDoneCallback) { Zotero_TranslatorTester.prototype._checkResult = function(test, translate, returnValue, error, testDoneCallback) {
if(error) {
var errorString = "Translation failed: "+error.toString();
if(typeof error === "object") {
for(var i in error) {
if(typeof(error[i]) != "object") {
errorString += "\n"+i+' => '+error[i];
}
}
}
testDoneCallback(this, test, "failed", errorString);
return;
}
if(!returnValue) { if(!returnValue) {
testDoneCallback(this, test, "failed", "Translation failed; examine debug output for errors"); testDoneCallback(this, test, "failed", "Translation failed; examine debug output for errors");
return; return;
@ -289,6 +469,12 @@ Zotero_TranslatorTester.prototype._checkResult = function(test, translate, retur
var translatedItem = Zotero_TranslatorTester._sanitizeItem(translate.newItems[i]); var translatedItem = Zotero_TranslatorTester._sanitizeItem(translate.newItems[i]);
if(!this._compare(testItem, translatedItem)) { if(!this._compare(testItem, translatedItem)) {
var m = translate.newItems.length;
test.itemsReturned = new Array(m);
for(var j=0; j<m; j++) {
test.itemsReturned[j] = Zotero_TranslatorTester._sanitizeItem(translate.newItems[i], true);
}
testDoneCallback(this, test, "unknown", "Item "+i+" does not match"); testDoneCallback(this, test, "unknown", "Item "+i+" does not match");
return; return;
} }
@ -347,7 +533,7 @@ Zotero_TranslatorTester.prototype._createTest = function(translate, multipleMode
if(multipleMode) { if(multipleMode) {
var items = "multiple"; var items = "multiple";
} else { } else {
for(var i=0, n=translate.newItems; i<n; i++) { for(var i=0, n=translate.newItems.length; i<n; i++) {
Zotero_TranslatorTester._sanitizeItem(translate.newItems[i], true); Zotero_TranslatorTester._sanitizeItem(translate.newItems[i], true);
} }
var items = translate.newItems; var items = translate.newItems;
@ -409,17 +595,10 @@ Zotero_TranslatorTester.prototype._objectCompare = function(x, y) {
if(y[p] || y[p] === 0) { if(y[p] || y[p] === 0) {
switch(typeof(y[p])) { switch(typeof(y[p])) {
case 'object': case 'object':
if (!this._objectCompare(y[p],x[p])) { if (!this._objectCompare(x[p],y[p])) {
return false; return false;
}; };
break; break;
case 'function':
if (typeof(x[p])=='undefined'
|| (y[p].toString() != x[p].toString())) {
this._debug(this, "TranslatorTester: Function "+p+" defined in y, not in x, or definitions differ");
return false;
}
break;
default: default:
if (y[p] != x[p] && x[p] !== false) { // special exemption: x (test item) if (y[p] != x[p] && x[p] !== false) { // special exemption: x (test item)
// can have a property set to false // can have a property set to false

View file

@ -102,6 +102,10 @@ Zotero.Attachments = new function(){
// hmph // hmph
Zotero.DB.rollbackTransaction(); Zotero.DB.rollbackTransaction();
var msg = "Failed importing file " + file.path;
Components.utils.reportError(msg);
Zotero.debug(msg, 1);
try { try {
// Clean up // Clean up
if (itemID) { if (itemID) {

View file

@ -178,16 +178,16 @@ var CSL = {
PREFIX_PUNCTUATION: /[.;:]\s*$/, PREFIX_PUNCTUATION: /[.;:]\s*$/,
SUFFIX_PUNCTUATION: /^\s*[.;:,\(\)]/, SUFFIX_PUNCTUATION: /^\s*[.;:,\(\)]/,
NUMBER_REGEXP: /(?:^\d+|\d+$)/, NUMBER_REGEXP: /(?:^\d+|\d+$)/,
NAME_INITIAL_REGEXP: /^([A-Z\u0080-\u017f\u0400-\u042f])([a-zA-Z\u0080-\u017f\u0400-\u052f]*|)/, NAME_INITIAL_REGEXP: /^([A-Z\u0080-\u017f\u0400-\u042f\u0600-\u06ff])([a-zA-Z\u0080-\u017f\u0400-\u052f\u0600-\u06ff]*|)/,
ROMANESQUE_REGEXP: /[a-zA-Z\u0080-\u017f\u0400-\u052f\u0386-\u03fb\u1f00-\u1ffe]/, ROMANESQUE_REGEXP: /[a-zA-Z\u0080-\u017f\u0400-\u052f\u0386-\u03fb\u1f00-\u1ffe\u0600-\u06ff\u200c\u200d\u200e\u202a-\u202e]/,
ROMANESQUE_NOT_REGEXP: /[^a-zA-Z\u0080-\u017f\u0400-\u052f\u0386-\u03fb\u1f00-\u1ffe]/g, ROMANESQUE_NOT_REGEXP: /[^a-zA-Z\u0080-\u017f\u0400-\u052f\u0386-\u03fb\u1f00-\u1ffe\u0600-\u06ff\u200c\u200d\u200e\u202a-\u202e]/g,
STARTSWITH_ROMANESQUE_REGEXP: /^[&a-zA-Z\u0080-\u017f\u0400-\u052f\u0386-\u03fb\u1f00-\u1ffe]/, STARTSWITH_ROMANESQUE_REGEXP: /^[&a-zA-Z\u0080-\u017f\u0400-\u052f\u0386-\u03fb\u1f00-\u1ffe\u0600-\u06ff\u200c\u200d\u200e\u202a-\u202e]/,
ENDSWITH_ROMANESQUE_REGEXP: /[.;:&a-zA-Z\u0080-\u017f\u0400-\u052f\u0386-\u03fb\u1f00-\u1ffe]$/, ENDSWITH_ROMANESQUE_REGEXP: /[.;:&a-zA-Z\u0080-\u017f\u0400-\u052f\u0386-\u03fb\u1f00-\u1ffe\u0600-\u06ff\u200c\u200d\u200e\u202a-\u202e]$/,
ALL_ROMANESQUE_REGEXP: /^[a-zA-Z\u0080-\u017f\u0400-\u052f\u0386-\u03fb\u1f00-\u1ffe]+$/, ALL_ROMANESQUE_REGEXP: /^[a-zA-Z\u0080-\u017f\u0400-\u052f\u0386-\u03fb\u1f00-\u1ffe\u0600-\u06ff\u200c\u200d\u200e\u202a-\u202e]+$/,
VIETNAMESE_SPECIALS: /[\u00c0-\u00c3\u00c8-\u00ca\u00cc\u00cd\u00d2-\u00d5\u00d9\u00da\u00dd\u00e0-\u00e3\u00e8-\u00ea\u00ec\u00ed\u00f2-\u00f5\u00f9\u00fa\u00fd\u0101\u0103\u0110\u0111\u0128\u0129\u0168\u0169\u01a0\u01a1\u01af\u01b0\u1ea0-\u1ef9]/, VIETNAMESE_SPECIALS: /[\u00c0-\u00c3\u00c8-\u00ca\u00cc\u00cd\u00d2-\u00d5\u00d9\u00da\u00dd\u00e0-\u00e3\u00e8-\u00ea\u00ec\u00ed\u00f2-\u00f5\u00f9\u00fa\u00fd\u0101\u0103\u0110\u0111\u0128\u0129\u0168\u0169\u01a0\u01a1\u01af\u01b0\u1ea0-\u1ef9]/,
VIETNAMESE_NAMES: /^(?:(?:[.AaBbCcDdEeGgHhIiKkLlMmNnOoPpQqRrSsTtUuVvXxYy \u00c0-\u00c3\u00c8-\u00ca\u00cc\u00cd\u00d2-\u00d5\u00d9\u00da\u00dd\u00e0-\u00e3\u00e8-\u00ea\u00ec\u00ed\u00f2-\u00f5\u00f9\u00fa\u00fd\u0101\u0103\u0110\u0111\u0128\u0129\u0168\u0169\u01a0\u01a1\u01af\u01b0\u1ea0-\u1ef9]{2,6})(\s+|$))+$/, VIETNAMESE_NAMES: /^(?:(?:[.AaBbCcDdEeGgHhIiKkLlMmNnOoPpQqRrSsTtUuVvXxYy \u00c0-\u00c3\u00c8-\u00ca\u00cc\u00cd\u00d2-\u00d5\u00d9\u00da\u00dd\u00e0-\u00e3\u00e8-\u00ea\u00ec\u00ed\u00f2-\u00f5\u00f9\u00fa\u00fd\u0101\u0103\u0110\u0111\u0128\u0129\u0168\u0169\u01a0\u01a1\u01af\u01b0\u1ea0-\u1ef9]{2,6})(\s+|$))+$/,
NOTE_FIELDS_REGEXP: /\{:[\-a-z]+:[^\}]+\}/g, NOTE_FIELDS_REGEXP: /\{:[\-_a-z]+:[^\}]+\}/g,
NOTE_FIELD_REGEXP: /\{:([\-a-z]+):\s*([^\}]+)\}/, NOTE_FIELD_REGEXP: /\{:([\-_a-z]+):\s*([^\}]+)\}/,
DISPLAY_CLASSES: ["block", "left-margin", "right-inline", "indent"], DISPLAY_CLASSES: ["block", "left-margin", "right-inline", "indent"],
NAME_VARIABLES: [ NAME_VARIABLES: [
"author", "author",
@ -302,6 +302,7 @@ var CSL = {
es: "es_ES", es: "es_ES",
et: "et_EE", et: "et_EE",
fa: "fa_FA", fa: "fa_FA",
fi: "fi_FI",
fr: "fr_FR", fr: "fr_FR",
he: "he_IL", he: "he_IL",
hu: "hu_HU", hu: "hu_HU",
@ -455,6 +456,11 @@ var CSL = {
locale_opts: {}, locale_opts: {},
locale_dates: {} locale_dates: {}
}; };
if (typeof require !== "undefined" && typeof module !== 'undefined' && "exports" in module) {
var CSL_IS_NODEJS = true;
var CSL_NODEJS = require("./csl_nodejs_jsdom").CSL_NODEJS_JSDOM;
exports.CSL = CSL;
}
CSL.TERMINAL_PUNCTUATION_REGEXP = new RegExp("^([" + CSL.TERMINAL_PUNCTUATION.slice(0, -1).join("") + "])(.*)"); CSL.TERMINAL_PUNCTUATION_REGEXP = new RegExp("^([" + CSL.TERMINAL_PUNCTUATION.slice(0, -1).join("") + "])(.*)");
CSL.CLOSURES = new RegExp(".*[\\]\\)]"); CSL.CLOSURES = new RegExp(".*[\\]\\)]");
CSL.debug = function (str) { CSL.debug = function (str) {
@ -839,7 +845,6 @@ CSL_CHROME.prototype.flagDateMacros = function(myxml) {
CSL.getSortCompare = function () { CSL.getSortCompare = function () {
var strcmp; var strcmp;
try { try {
var Components;
var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"] var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
.getService(Components.interfaces.nsILocaleService); .getService(Components.interfaces.nsILocaleService);
var collationFactory = Components.classes["@mozilla.org/intl/collation-factory;1"] var collationFactory = Components.classes["@mozilla.org/intl/collation-factory;1"]
@ -2148,7 +2153,7 @@ CSL.DateParser = function () {
}; };
CSL.Engine = function (sys, style, lang, forceLang) { CSL.Engine = function (sys, style, lang, forceLang) {
var attrs, langspec, localexml, locale; var attrs, langspec, localexml, locale;
this.processor_version = "1.0.285"; this.processor_version = "1.0.295";
this.csl_version = "1.0"; this.csl_version = "1.0";
this.sys = sys; this.sys = sys;
this.sys.xml = new CSL.System.Xml.Parsing(); this.sys.xml = new CSL.System.Xml.Parsing();
@ -2493,7 +2498,7 @@ CSL.Engine.prototype.retrieveItem = function (id) {
if (this.opt.development_extensions.jurisdiction_subfield && Item.jurisdiction) { if (this.opt.development_extensions.jurisdiction_subfield && Item.jurisdiction) {
var subjurisdictions = Item.jurisdiction.split(";"); var subjurisdictions = Item.jurisdiction.split(";");
if (subjurisdictions.length > 1) { if (subjurisdictions.length > 1) {
Item.subjurisdiction = subjurisdictions.slice(0,2).join(";"); Item.subjurisdiction = subjurisdictions.join(";");
} }
} }
for (var i = 1, ilen = CSL.DATE_VARIABLES.length; i < ilen; i += 1) { for (var i = 1, ilen = CSL.DATE_VARIABLES.length; i < ilen; i += 1) {
@ -2510,7 +2515,7 @@ CSL.Engine.prototype.retrieveItem = function (id) {
return Item; return Item;
}; };
CSL.Engine.prototype.setOpt = function (token, name, value) { CSL.Engine.prototype.setOpt = function (token, name, value) {
if (token.name === "style") { if (token.name === "style" || token.name === "cslstyle") {
this.opt[name] = value; this.opt[name] = value;
} else if (["citation", "bibliography"].indexOf(token.name) > -1) { } else if (["citation", "bibliography"].indexOf(token.name) > -1) {
this[token.name].opt[name] = value; this[token.name].opt[name] = value;
@ -2690,7 +2695,20 @@ CSL.Engine.prototype.setAbbreviations = function (arg) {
if (this.sys.setAbbreviations) { if (this.sys.setAbbreviations) {
this.sys.setAbbreviations(arg); this.sys.setAbbreviations(arg);
} }
} };
CSL.Engine.prototype.setEnglishLocaleEscapes = function (arg) {
if ("string" === typeof arg) {
arg = arg.split(/\s+,\s+/);
}
if (!arg || !arg.length) {
arg = [];
}
for (var i = 0, ilen = arg.length; i < ilen; i += 1) {
if (this.opt.english_locale_escapes.indexOf(arg[i]) === -1) {
this.opt.english_locale_escapes.push(arg[i]);
}
}
};
CSL.Engine.Opt = function () { CSL.Engine.Opt = function () {
this.has_disambiguate = false; this.has_disambiguate = false;
this.mode = "html"; this.mode = "html";
@ -2713,6 +2731,7 @@ CSL.Engine.Opt = function () {
this.citation_number_slug = false; this.citation_number_slug = false;
this.max_number_of_names = 0; this.max_number_of_names = 0;
this.trigraph = "Aaaa00:AaAa00:AaAA00:AAAA00"; this.trigraph = "Aaaa00:AaAa00:AaAA00:AAAA00";
this.english_locale_escapes = [];
this.development_extensions = {}; this.development_extensions = {};
this.development_extensions.field_hack = true; this.development_extensions.field_hack = true;
this.development_extensions.locator_date_and_revision = true; this.development_extensions.locator_date_and_revision = true;
@ -2933,6 +2952,7 @@ CSL.Engine.prototype.restoreProcessorState = function (citations) {
} else { } else {
this.registry = new CSL.Registry(this); this.registry = new CSL.Registry(this);
this.tmp = new CSL.Engine.Tmp(); this.tmp = new CSL.Engine.Tmp();
this.disambiguate = new CSL.Disambiguation(this);
} }
return ret; return ret;
}; };
@ -3240,6 +3260,7 @@ CSL.getBibliographyEntries = function (bibsection) {
this.parallel.ComposeSet(); this.parallel.ComposeSet();
this.parallel.PruneOutputQueue(); this.parallel.PruneOutputQueue();
} else if (!this.registry.registry[item.id].siblings) { } else if (!this.registry.registry[item.id].siblings) {
this.parallel.StartCitation(sortedItems);
this.tmp.term_predecessor = false; this.tmp.term_predecessor = false;
entry_item_ids.push("" + CSL.getCite.call(this, item)); entry_item_ids.push("" + CSL.getCite.call(this, item));
} }
@ -3387,11 +3408,12 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre,
if (this.opt.update_mode === CSL.POSITION) { if (this.opt.update_mode === CSL.POSITION) {
textCitations = []; textCitations = [];
noteCitations = []; noteCitations = [];
var citationsInNote = {};
} }
var update_items = []; var update_items = [];
for (i = 0, ilen = citationByIndex.length; i < ilen; i += 1) { for (i = 0, ilen = citationByIndex.length; i < ilen; i += 1) {
citationByIndex[i].properties.index = i; citationByIndex[i].properties.index = i;
for (j = 0, jlen = citationByIndex[i].sortedItems.length; j < jlen; j += 1) { for (j = 0, jlen = citationByIndex[i].sortedItems.length; j < jlen; j += 1) {
item = citationByIndex[i].sortedItems[j]; item = citationByIndex[i].sortedItems[j];
if (!this.registry.citationreg.citationsByItemId[item[1].id]) { if (!this.registry.citationreg.citationsByItemId[item[1].id]) {
this.registry.citationreg.citationsByItemId[item[1].id] = []; this.registry.citationreg.citationsByItemId[item[1].id] = [];
@ -3405,6 +3427,7 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre,
if (citationByIndex[i].properties.noteIndex) { if (citationByIndex[i].properties.noteIndex) {
noteCitations.push(citationByIndex[i]); noteCitations.push(citationByIndex[i]);
} else { } else {
citationByIndex[i].properties.noteIndex = 0;
textCitations.push(citationByIndex[i]); textCitations.push(citationByIndex[i]);
} }
} }
@ -3446,20 +3469,20 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre,
} }
var citations; var citations;
if (this.opt.update_mode === CSL.POSITION) { if (this.opt.update_mode === CSL.POSITION) {
var citationsInNote = {};
for (i = 0; i < 2; i += 1) { for (i = 0; i < 2; i += 1) {
citations = [textCitations, noteCitations][i]; citations = [textCitations, noteCitations][i];
var first_ref = {}; var first_ref = {};
var last_ref = {}; var last_ref = {};
for (j = 0, jlen = citations.length; j < jlen; j += 1) { for (j = 0, jlen = citations.length; j < jlen; j += 1) {
var onecitation = citations[j]; var onecitation = citations[j];
if (!onecitation.properties.noteIndex) { for (var k = 0, klen = onecitation.sortedItems.length; k < klen; k += 1) {
onecitation.properties.noteIndex = 0; if (!this.registry.registry[onecitation.sortedItems[k][1].id].parallel) {
} if (!citationsInNote[onecitation.properties.noteIndex]) {
if (!citationsInNote[onecitation.properties.noteIndex]) { citationsInNote[onecitation.properties.noteIndex] = 1;
citationsInNote[onecitation.properties.noteIndex] = 1; } else {
} else { citationsInNote[onecitation.properties.noteIndex] += 1;
citationsInNote[onecitation.properties.noteIndex] += 1; }
}
} }
for (k = 0, klen = citations[j].sortedItems.length; k < klen; k += 1) { for (k = 0, klen = citations[j].sortedItems.length; k < klen; k += 1) {
item = citations[j].sortedItems[k]; item = citations[j].sortedItems[k];
@ -3491,7 +3514,7 @@ CSL.Engine.prototype.processCitationCluster = function (citation, citationsPre,
var items = citations[(j - 1)].sortedItems; var items = citations[(j - 1)].sortedItems;
var useme = false; var useme = false;
if ((citations[(j - 1)].sortedItems[0][1].id == item[1].id && citations[j - 1].properties.noteIndex >= (citations[j].properties.noteIndex - 1)) || citations[(j - 1)].sortedItems[0][1].id == this.registry.registry[item[1].id].parallel) { if ((citations[(j - 1)].sortedItems[0][1].id == item[1].id && citations[j - 1].properties.noteIndex >= (citations[j].properties.noteIndex - 1)) || citations[(j - 1)].sortedItems[0][1].id == this.registry.registry[item[1].id].parallel) {
if (citationsInNote[citations[j - 1].properties.noteIndex] === 1 || citations[j - 1].properties.noteIndex === 0) { if (citationsInNote[citations[j - 1].properties.noteIndex] == 1 || citations[j - 1].properties.noteIndex == 0) {
useme = true; useme = true;
} }
} }
@ -4226,17 +4249,22 @@ CSL.Engine.prototype.localeSet = function (myxml, lang_in, lang_out) {
} }
for (termname in this.locale[lang_out].terms) { for (termname in this.locale[lang_out].terms) {
if (this.locale[lang_out].terms.hasOwnProperty(termname)) { if (this.locale[lang_out].terms.hasOwnProperty(termname)) {
for (i = 0, ilen = 2; i < ilen; i += 1) { for (i = 0, ilen = 2; i < ilen; i += 1) {
genderform = CSL.GENDERS[i]; genderform = CSL.GENDERS[i];
if (this.locale[lang_out].terms[termname][genderform]) { if (this.locale[lang_out].terms[termname][genderform]) {
for (form in this.locale[lang_out].terms[termname]) { for (form in this.locale[lang_out].terms[termname]) {
if (!this.locale[lang_out].terms[termname][genderform][form]) { if (!this.locale[lang_out].terms[termname][genderform][form]) {
this.locale[lang_out].terms[termname][genderform][form] = this.locale[lang_out].terms[termname][form]; this.locale[lang_out].terms[termname][genderform][form] = this.locale[lang_out].terms[termname][form];
}
} }
} }
} }
} }
} }
if (lang_out && ["fr", "pt"].indexOf(lang_out.slice(0, 2).toLowerCase()) > -1) {
this.locale[lang_out].terms["page-range-delimiter"] = "-";
} else {
this.locale[lang_out].terms["page-range-delimiter"] = "\u2013";
} }
nodes = this.sys.xml.getNodesByName(locale, 'style-options'); nodes = this.sys.xml.getNodesByName(locale, 'style-options');
for (pos = 0, len = this.sys.xml.numberofnodes(nodes); pos < len; pos += 1) { for (pos = 0, len = this.sys.xml.numberofnodes(nodes); pos < len; pos += 1) {
@ -5334,15 +5362,17 @@ CSL.NameOutput.prototype.outputNames = function () {
var blob = this.state.output.pop(); var blob = this.state.output.pop();
this.state.output.append(blob, this.names); this.state.output.append(blob, this.names);
this.state.tmp.name_node.top = this.state.output.current.value(); this.state.tmp.name_node.top = this.state.output.current.value();
var oldSuppressDecorations = this.state.tmp.suppress_decorations; if (variables[0] !== "authority") {
this.state.tmp.suppress_decorations = true; var oldSuppressDecorations = this.state.tmp.suppress_decorations;
var lastBlob = this.state.tmp.name_node.top.blobs.pop(); this.state.tmp.suppress_decorations = true;
var name_node_string = this.state.output.string(this.state, lastBlob.blobs, false); var lastBlob = this.state.tmp.name_node.top.blobs.pop();
this.state.tmp.name_node.top.blobs.push(lastBlob); var name_node_string = this.state.output.string(this.state, lastBlob.blobs, false);
if (name_node_string) { this.state.tmp.name_node.top.blobs.push(lastBlob);
this.state.tmp.name_node.string = name_node_string; if (name_node_string) {
this.state.tmp.name_node.string = name_node_string;
}
this.state.tmp.suppress_decorations = oldSuppressDecorations;
} }
this.state.tmp.suppress_decorations = oldSuppressDecorations;
if (this.state.tmp.name_node.string && !this.state.tmp.first_name_string) { if (this.state.tmp.name_node.string && !this.state.tmp.first_name_string) {
this.state.tmp.first_name_string = this.state.tmp.name_node.string; this.state.tmp.first_name_string = this.state.tmp.name_node.string;
} }
@ -5813,6 +5843,9 @@ CSL.NameOutput.prototype.disambigNames = function () {
CSL.NameOutput.prototype._runDisambigNames = function (lst, pos) { CSL.NameOutput.prototype._runDisambigNames = function (lst, pos) {
var chk, myform, myinitials, param, i, ilen, paramx; var chk, myform, myinitials, param, i, ilen, paramx;
for (i = 0, ilen = lst.length; i < ilen; i += 1) { for (i = 0, ilen = lst.length; i < ilen; i += 1) {
if (!lst[i].given || !lst[i].family) {
continue;
}
this.state.registry.namereg.addname("" + this.Item.id, lst[i], i); this.state.registry.namereg.addname("" + this.Item.id, lst[i], i);
chk = this.state.tmp.disambig_settings.givens[pos]; chk = this.state.tmp.disambig_settings.givens[pos];
if ("undefined" === typeof chk) { if ("undefined" === typeof chk) {
@ -7260,6 +7293,9 @@ CSL.Node.number = {
state.processNumber(node, Item, varname); state.processNumber(node, Item, varname);
} }
} }
if (varname === "locator") {
state.tmp.done_vars.push("locator");
}
var values = state.tmp.shadow_numbers[varname].values; var values = state.tmp.shadow_numbers[varname].values;
var blob; var blob;
var newstr = "" var newstr = ""
@ -7273,18 +7309,20 @@ CSL.Node.number = {
if (newstr && !newstr.match(/^[-.\u20130-9]+$/)) { if (newstr && !newstr.match(/^[-.\u20130-9]+$/)) {
state.output.append(newstr, this); state.output.append(newstr, this);
} else { } else {
state.output.openLevel("empty"); if (values.length) {
for (var i = 0, ilen = values.length; i < ilen; i += 1) { state.output.openLevel("empty");
var blob = new CSL[values[i][0]](values[i][1], values[i][2], Item.id); for (var i = 0, ilen = values.length; i < ilen; i += 1) {
if (i > 0) { var blob = new CSL[values[i][0]](values[i][1], values[i][2], Item.id);
blob.strings.prefix = blob.strings.prefix.replace(/^\s*/, ""); if (i > 0) {
blob.strings.prefix = blob.strings.prefix.replace(/^\s*/, "");
}
if (i < values.length - 1) {
blob.strings.suffix = blob.strings.suffix.replace(/\s*$/, "");
}
state.output.append(blob, "literal", false, false, true);
} }
if (i < values.length - 1) { state.output.closeLevel("empty");
blob.strings.suffix = blob.strings.suffix.replace(/\s*$/, "");
}
state.output.append(blob, "literal", false, false, true);
} }
state.output.closeLevel("empty");
} }
state.parallel.CloseVariable("number"); state.parallel.CloseVariable("number");
}; };
@ -7500,9 +7538,6 @@ CSL.Node.text = {
} else { } else {
state.transform.setTransformFallback(true); state.transform.setTransformFallback(true);
state.transform.setAbbreviationFallback(true); state.transform.setAbbreviationFallback(true);
if (this.variables_real[0] === "subjurisdiction") {
state.transform.setSuppressMonitor("container-title");
}
func = state.transform.getOutputFunction(this.variables); func = state.transform.getOutputFunction(this.variables);
} }
if (this.variables_real[0] === "container-title") { if (this.variables_real[0] === "container-title") {
@ -7518,7 +7553,7 @@ CSL.Node.text = {
func = function (state, Item, item) { func = function (state, Item, item) {
if (item && item[this.variables[0]]) { if (item && item[this.variables[0]]) {
var locator = "" + item[this.variables[0]]; var locator = "" + item[this.variables[0]];
locator = locator.replace(/([^\\])--*/g,"$1\u2013"); locator = locator.replace(/([^\\])--*/g,"$1"+state.getTerm("page-range-delimiter"));
locator = locator.replace(/\\-/g,"-"); locator = locator.replace(/\\-/g,"-");
state.output.append(locator, this, false, false, true); state.output.append(locator, this, false, false, true);
} }
@ -7528,6 +7563,7 @@ CSL.Node.text = {
var idx, value; var idx, value;
value = state.getVariable(Item, "page", form); value = state.getVariable(Item, "page", form);
if (value) { if (value) {
value = ""+value;
value = value.replace("\u2013", "-", "g"); value = value.replace("\u2013", "-", "g");
idx = value.indexOf("-"); idx = value.indexOf("-");
if (idx > -1) { if (idx > -1) {
@ -7540,7 +7576,8 @@ CSL.Node.text = {
func = function (state, Item) { func = function (state, Item) {
var value = state.getVariable(Item, "page", form); var value = state.getVariable(Item, "page", form);
if (value) { if (value) {
value = value.replace(/([^\\])--*/g,"$1\u2013"); value = ""+value;
value = value.replace(/([^\\])--*/g,"$1"+state.getTerm("page-range-delimiter"));
value = value.replace(/\\-/g,"-"); value = value.replace(/\\-/g,"-");
value = state.fun.page_mangler(value); value = state.fun.page_mangler(value);
state.output.append(value, this, false, false, true); state.output.append(value, this, false, false, true);
@ -8363,18 +8400,22 @@ CSL.Attributes["@text-case"] = function (state, arg) {
this.strings["text-case"] = arg; this.strings["text-case"] = arg;
if (arg === "title") { if (arg === "title") {
var m = false; var m = false;
var default_locale = state.opt["default-locale"][0].slice(0, 2);
if (Item.language) { if (Item.language) {
m = Item.language.match(/^\s*([a-z]{2})(?:$|-| )/); m = Item.language.match(/^\s*([A-Za-z]{2})(?:$|-| )/);
} if (!m) {
if (state.opt["default-locale"][0].slice(0, 2) === "en") {
if (m && m[1] !== "en") {
this.strings["text-case"] = "passthrough"; this.strings["text-case"] = "passthrough";
} else if (m[1].toLowerCase() !== "en") {
this.strings["text-case"] = "passthrough";
for (var i = 0, ilen = state.opt.english_locale_escapes.length; i < ilen; i += 1) {
var escaper = state.opt.english_locale_escapes[i];
if (m[1].slice(0, escaper.length).toLowerCase() === escaper) {
this.strings["text-case"] = arg;
}
}
} }
} else { } else if (default_locale !== "en") {
this.strings["text-case"] = "passthrough"; this.strings["text-case"] = "passthrough";
if (m && m[1] === "en") {
this.strings["text-case"] = arg;
}
} }
} }
}; };
@ -8448,10 +8489,9 @@ CSL.Attributes["@display"] = function (state, arg) {
this.strings.cls = arg; this.strings.cls = arg;
}; };
var XML_PARSING; var XML_PARSING;
var CSL_E4X; if ("undefined" !== typeof CSL_IS_NODEJS) {
var CSL_CHROME; XML_PARSING = CSL_NODEJS;
var DOMParser; } else if ("undefined" !== typeof CSL_E4X) {
if ("undefined" !== typeof CSL_E4X) {
XML_PARSING = CSL_E4X; XML_PARSING = CSL_E4X;
} else { } else {
XML_PARSING = CSL_CHROME; XML_PARSING = CSL_CHROME;
@ -8590,8 +8630,7 @@ CSL.Transform = function (state) {
opt = { opt = {
abbreviation_fallback: false, abbreviation_fallback: false,
alternative_varname: false, alternative_varname: false,
transform_fallback: false, transform_fallback: false
suppress_monitor: false
}; };
} }
this.init = init; this.init = init;
@ -8667,10 +8706,6 @@ CSL.Transform = function (state) {
opt.abbreviation_fallback = b; opt.abbreviation_fallback = b;
} }
this.setAbbreviationFallback = setAbbreviationFallback; this.setAbbreviationFallback = setAbbreviationFallback;
function setSuppressMonitor(b) {
opt.suppress_monitor = b;
}
this.setSuppressMonitor = setSuppressMonitor;
function setAlternativeVariableName(s) { function setAlternativeVariableName(s) {
opt.alternative_varname = s; opt.alternative_varname = s;
} }
@ -8744,7 +8779,6 @@ CSL.Transform = function (state) {
var abbreviation_fallback = opt.abbreviation_fallback; var abbreviation_fallback = opt.abbreviation_fallback;
var alternative_varname = opt.alternative_varname; var alternative_varname = opt.alternative_varname;
var transform_fallback = opt.transform_fallback; var transform_fallback = opt.transform_fallback;
var suppress_monitor = opt.suppress_monitor;
var localesets; var localesets;
var langPrefs = CSL.LangPrefsMap[myfieldname]; var langPrefs = CSL.LangPrefsMap[myfieldname];
if (!langPrefs) { if (!langPrefs) {
@ -8808,10 +8842,13 @@ CSL.Transform = function (state) {
} }
if (myabbrev_family) { if (myabbrev_family) {
primary = abbreviate(state, Item, alternative_varname, primary, myabbrev_family, true); primary = abbreviate(state, Item, alternative_varname, primary, myabbrev_family, true);
if (suppress_monitor && primary) { if (primary) {
suppressing_partner = abbreviate(state, Item, false, Item["container-title"], "container-title", true); var m = primary.match(/^!([-_a-z]+)<<</);
if (suppressing_partner && suppressing_partner.slice(0, primary.length) === primary) { if (m) {
return null; primary = primary.slice(m[0].length);
if (state.tmp.done_vars.indexOf(m[1]) === -1) {
state.tmp.done_vars.push(m[1]);
}
} }
} }
secondary = abbreviate(state, Item, false, secondary, myabbrev_family, true); secondary = abbreviate(state, Item, false, secondary, myabbrev_family, true);
@ -10092,10 +10129,10 @@ CSL.Engine.prototype.processNumber = function (node, ItemObject, variable) {
&& elements[i].match(/^[0-9]+/) && elements[i].match(/^[0-9]+/)
&& parseInt(elements[i - 2]) < parseInt(elements[i].replace(/[^0-9].*/,""))) { && parseInt(elements[i - 2]) < parseInt(elements[i].replace(/[^0-9].*/,""))) {
var start = this.tmp.shadow_numbers[variable].values.slice(-2); var start = this.tmp.shadow_numbers[variable].values.slice(-2);
middle[0][1] = "\u2013"; middle[0][1] = this.getTerm("page-range-delimiter");
if (this.opt["page-range-format"] ) { if (this.opt["page-range-format"] ) {
var newstr = this.fun.page_mangler(start[0][1] +"-"+elements[i]); var newstr = this.fun.page_mangler(start[0][1] +"-"+elements[i]);
newstr = newstr.split(/\u2013/); newstr = newstr.split(this.getTerm("page-range-delimiter"));
elements[i] = newstr[1]; elements[i] = newstr[1];
} }
count = count + 1; count = count + 1;
@ -10162,7 +10199,7 @@ CSL.Engine.prototype.processNumber = function (node, ItemObject, variable) {
CSL.Util.PageRangeMangler = {}; CSL.Util.PageRangeMangler = {};
CSL.Util.PageRangeMangler.getFunction = function (state) { CSL.Util.PageRangeMangler.getFunction = function (state) {
var rangerex, pos, len, stringify, listify, expand, minimize, minimize_internal, chicago, lst, m, b, e, ret, begin, end, ret_func, ppos, llen; var rangerex, pos, len, stringify, listify, expand, minimize, minimize_internal, chicago, lst, m, b, e, ret, begin, end, ret_func, ppos, llen;
var range_delimiter = state.getTerm("range-delimiter"); var range_delimiter = state.getTerm("page-range-delimiter");
rangerex = /([a-zA-Z]*)([0-9]+)\s*-\s*([a-zA-Z]*)([0-9]+)/; rangerex = /([a-zA-Z]*)([0-9]+)\s*-\s*([a-zA-Z]*)([0-9]+)/;
stringify = function (lst) { stringify = function (lst) {
len = lst.length; len = lst.length;
@ -10172,7 +10209,7 @@ CSL.Util.PageRangeMangler.getFunction = function (state) {
} }
} }
var ret = lst.join(""); var ret = lst.join("");
ret = ret.replace(/([0-9])\-/, "$1\u2013", "g").replace(/\-([0-9])/, "\u2013$1", "g") ret = ret.replace(/([0-9])\-/, "$1"+state.getTerm("page-range-delimiter"), "g").replace(/\-([0-9])/, state.getTerm("page-range-delimiter")+"$1", "g")
return ret; return ret;
}; };
listify = function (str, hyphens) { listify = function (str, hyphens) {

View file

@ -141,38 +141,40 @@ Zotero.CookieSandbox.Observer = new function() {
notificationCallbacks = channel.notificationCallbacks; notificationCallbacks = channel.notificationCallbacks;
// try the notification callbacks // try the notification callbacks
trackedBy = this.trackedInterfaceRequestors.get(notificationCallbacks); if(notificationCallbacks) {
if(trackedBy) { trackedBy = this.trackedInterfaceRequestors.get(notificationCallbacks);
tested = true; if(trackedBy) {
} else {
// try the browser
try {
browser = notificationCallbacks.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell).chromeEventHandler;
} catch(e) {}
if(browser) {
tested = true; tested = true;
trackedBy = this.trackedBrowsers.get(browser);
} else { } else {
// try the document for the load group // try the browser
try { try {
browser = channel.loadGroup.notificationCallbacks.getInterface(Ci.nsIWebNavigation) browser = notificationCallbacks.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell).chromeEventHandler; .QueryInterface(Ci.nsIDocShell).chromeEventHandler;
} catch(e) {} } catch(e) {}
if(browser) { if(browser) {
tested = true; tested = true;
trackedBy = this.trackedBrowsers.get(browser); trackedBy = this.trackedBrowsers.get(browser);
} else { } else {
// try getting as an XHR or nsIWBP // try the document for the load group
try { try {
notificationCallbacks.QueryInterface(Components.interfaces.nsIXMLHttpRequest); browser = channel.loadGroup.notificationCallbacks.getInterface(Ci.nsIWebNavigation)
tested = true; .QueryInterface(Ci.nsIDocShell).chromeEventHandler;
} catch(e) {} } catch(e) {}
if(!tested) { if(browser) {
tested = true;
trackedBy = this.trackedBrowsers.get(browser);
} else {
// try getting as an XHR or nsIWBP
try { try {
notificationCallbacks.QueryInterface(Components.interfaces.nsIWebBrowserPersist); notificationCallbacks.QueryInterface(Components.interfaces.nsIXMLHttpRequest);
tested = true; tested = true;
} catch(e) {} } catch(e) {}
if(!tested) {
try {
notificationCallbacks.QueryInterface(Components.interfaces.nsIWebBrowserPersist);
tested = true;
} catch(e) {}
}
} }
} }
} }

View file

@ -273,7 +273,7 @@ Zotero.ItemTypes = new function() {
mru = mru.split(',').slice(0, limit); mru = mru.split(',').slice(0, limit);
for (var i=0, len=mru.length; i<len; i++) { for (var i=0, len=mru.length; i<len; i++) {
var id = parseInt(mru[i]); var id = parseInt(mru[i]);
if (!isNaN(id)) { if (!isNaN(id) && id != 13) { // ignore 'webpage' item type
params.push(id); params.push(id);
} }
} }

View file

@ -227,6 +227,9 @@ Zotero.Creator.prototype.save = function () {
if (!creatorDataID) { if (!creatorDataID) {
var creatorDataID = Zotero.Creators.getDataID(this, true); var creatorDataID = Zotero.Creators.getDataID(this, true);
if (creatorDataID != this.creatorDataID) {
this._creatorDataID = creatorDataID;
}
} }
var columns = [ var columns = [

View file

@ -4333,7 +4333,7 @@ Zotero.Item.prototype.erase = function() {
catch (e) { catch (e) {
// If deletion fails, try to correct a few things that have come up before // If deletion fails, try to correct a few things that have come up before
Zotero.debug("Item deletion failed -- trying to fix", 2); Zotero.debug("Item deletion failed -- trying to fix", 2);
Zotero.DB.query('DELETE FROM fulltextItemWords WHERE itemID=?', this.id); Zotero.Fulltext.clearItemWords(this.id);
Zotero.DB.query('DELETE FROM itemTags WHERE itemID=?', this.id); Zotero.DB.query('DELETE FROM itemTags WHERE itemID=?', this.id);
// And then try again // And then try again

View file

@ -62,7 +62,8 @@ Zotero.Debug = new function () {
break; break;
} }
} }
else if (typeof message != 'string') {
if (typeof message != 'string') {
message = Zotero.Utilities.varDump(message); message = Zotero.Utilities.varDump(message);
} }
@ -152,10 +153,14 @@ Zotero.Debug = new function () {
} }
} }
return Zotero.getErrors(true).join('\n\n') + if(Zotero.getErrors) {
"\n\n" + Zotero.getSystemInfo() + "\n\n" + return Zotero.getErrors(true).join('\n\n') +
"=========================================================\n\n" + "\n\n" + Zotero.getSystemInfo() + "\n\n" +
output; "=========================================================\n\n" +
output;
} else {
return output;
}
} }

View file

@ -372,8 +372,9 @@ Zotero.File = new function(){
var checkFileWindows = "Check that the file is not currently " var checkFileWindows = "Check that the file is not currently "
+ "in use and that it is not marked as read-only. To check " + "in use and that it is not marked as read-only. To check "
+ "all files in your Zotero data directory, right-click on " + "all files in your Zotero data directory, right-click on "
+ "the 'zotero' directory, click Properties, and ensure that " + "the 'zotero' directory, click Properties, clear "
+ "the Read-Only checkbox is empty."; + "the Read-Only checkbox, and apply the change to all folders "
+ "and files in the directory.";
var checkFileOther = "Check that the file is not currently " var checkFileOther = "Check that the file is not currently "
+ "in use and that its permissions allow write access."; + "in use and that its permissions allow write access.";
var msg = str + " " var msg = str + " "

View file

@ -507,12 +507,13 @@ Zotero.HTTP = new function() {
* @inner * @inner
*/ */
var onLoad = function() { var onLoad = function() {
if(hiddenBrowser.contentDocument.location.href == "about:blank") return; var doc = hiddenBrowser.contentDocument,
Zotero.debug(hiddenBrowser.contentDocument.location.href+" has been loaded"); url = doc.location.href.toString();
if(hiddenBrowser.contentDocument.location.href != prevUrl) { // Just in case it fires too many times if(url == "about:blank" || doc.readyState === "loading") return;
prevUrl = hiddenBrowser.contentDocument.location.href; if(url !== prevUrl) { // Just in case it fires too many times
prevUrl = url;
try { try {
processor(hiddenBrowser.contentDocument); processor(doc);
} catch(e) { } catch(e) {
removeListeners(); removeListeners();
if(exception) { if(exception) {

View file

@ -1256,7 +1256,10 @@ Zotero.Integration.Fields.prototype._retrieveFields = function() {
* Shows an error if a field code is corrupted * Shows an error if a field code is corrupted
* @param {Exception} e The exception thrown * @param {Exception} e The exception thrown
* @param {Field} field The Zotero field object * @param {Field} field The Zotero field object
* @param {Function} callback The callback passed to updateSession
* @param {Function} errorCallback The error callback passed to updateSession
* @param {Integer} i The field index * @param {Integer} i The field index
* @return {Boolean} Whether to continue updating the session
*/ */
Zotero.Integration.Fields.prototype._showCorruptFieldError = function(e, field, callback, errorCallback, i) { Zotero.Integration.Fields.prototype._showCorruptFieldError = function(e, field, callback, errorCallback, i) {
Zotero.logError(e); Zotero.logError(e);
@ -1287,6 +1290,58 @@ Zotero.Integration.Fields.prototype._showCorruptFieldError = function(e, field,
} }
} }
/**
* Shows an error if a field code is missing
* @param {Exception} e The exception thrown
* @param {Exception} e The exception thrown
* @param {Field} field The Zotero field object
* @param {Function} callback The callback passed to updateSession
* @param {Function} errorCallback The error callback passed to updateSession
* @param {Integer} i The field index
* @return {Boolean} Whether to continue updating the session
*/
Zotero.Integration.Fields.prototype._showMissingItemError = function(e, field, callback, errorCallback, i) {
// First, check if we've already decided to remove field codes from these
var reselect = true;
for each(var reselectKey in e.reselectKeys) {
if(this._deleteKeys[reselectKey]) {
this._removeCodeFields.push(i);
return true;
}
}
// Ask user what to do with this item
if(e.citationLength == 1) {
var msg = Zotero.getString("integration.missingItem.single");
} else {
var msg = Zotero.getString("integration.missingItem.multiple", (e.citationIndex+1).toString());
}
msg += '\n\n'+Zotero.getString('integration.missingItem.description');
field.select();
this._doc.activate();
var result = this._doc.displayAlert(msg, 1, 3);
if(result == 0) { // Cancel
throw new Zotero.Integration.UserCancelledException();
} else if(result == 1) { // No
for each(var reselectKey in e.reselectKeys) {
this._deleteKeys[reselectKey] = true;
}
this._removeCodeFields.push(i);
return true;
} else { // Yes
// Display reselect item dialog
var me = this;
var oldCurrentWindow = Zotero.Integration.currentWindow;
this._session.reselectItem(this._doc, e, function() {
// Now try again
Zotero.Integration.currentWindow = oldCurrentWindow;
me._doc.activate();
me._processFields(me._fields, callback, errorCallback, i);
});
return false;
}
}
/** /**
* Updates Zotero.Integration.Session attached to Zotero.Integration.Fields in line with document * Updates Zotero.Integration.Session attached to Zotero.Integration.Fields in line with document
*/ */
@ -1315,23 +1370,28 @@ Zotero.Integration.Fields.prototype.updateSession = function(callback, errorCall
try { try {
me._session.loadBibliographyData(me._bibliographyData); me._session.loadBibliographyData(me._bibliographyData);
} catch(e) { } catch(e) {
if(errorCallback) { var defaultHandler = function() {
errorCallback(e); if(e instanceof Zotero.Integration.CorruptFieldException) {
} else if(e instanceof Zotero.Integration.CorruptFieldException) { var msg = Zotero.getString("integration.corruptBibliography")+'\n\n'+
var msg = Zotero.getString("integration.corruptBibliography")+'\n\n'+ Zotero.getString('integration.corruptBibliography.description');
Zotero.getString('integration.corruptBibliography.description'); var result = me._doc.displayAlert(msg,
var result = me._doc.displayAlert(msg, Components.interfaces.zoteroIntegrationDocument.DIALOG_ICON_CAUTION,
Components.interfaces.zoteroIntegrationDocument.DIALOG_ICON_CAUTION, Components.interfaces.zoteroIntegrationDocument.DIALOG_BUTTONS_OK_CANCEL);
Components.interfaces.zoteroIntegrationDocument.DIALOG_BUTTONS_OK_CANCEL); if(result == 0) {
if(result == 0) { throw e;
throw e; } else {
me._bibliographyData = "";
me._session.bibliographyHasChanged = true;
me._session.bibliographyDataHasChanged = true;
}
} else { } else {
me._bibliographyData = ""; throw e;
me._session.bibliographyHasChanged = true;
me._session.bibliographyDataHasChanged = true;
} }
} else { };
throw e; if(errorCallback) {
if(!errorCallback(e, defaultHandler)) return;
} else if(!defaultHandler()) {
return;
} }
} }
} }
@ -1362,13 +1422,26 @@ Zotero.Integration.Fields.prototype.updateSession = function(callback, errorCall
Zotero.Integration.Fields.prototype._processFields = function(fields, callback, errorCallback, i) { Zotero.Integration.Fields.prototype._processFields = function(fields, callback, errorCallback, i) {
if(!i) i = 0; if(!i) i = 0;
var me = this;
for(var n = fields.length; i<n; i++) { for(var n = fields.length; i<n; i++) {
var field = fields[i]; var field = fields[i];
try { try {
var fieldCode = field.getCode(); var fieldCode = field.getCode();
} catch(e) { } catch(e) {
if(!this._showCorruptFieldError(e, field, callback, errorCallback, i)) return; var defaultHandler = function() {
return me._showCorruptFieldError(e, field, callback, errorCallback, i);
};
if(errorCallback) {
if(errorCallback(e, defaultHandler)) {
continue;
} else {
return;
}
} else if(!defaultHandler()) {
return;
}
} }
var [type, content] = this.getCodeTypeAndContent(fieldCode); var [type, content] = this.getCodeTypeAndContent(fieldCode);
@ -1377,54 +1450,24 @@ Zotero.Integration.Fields.prototype._processFields = function(fields, callback,
try { try {
this._session.addCitation(i, noteIndex, content); this._session.addCitation(i, noteIndex, content);
} catch(e) { } catch(e) {
var defaultHandler = function() {
if(e instanceof Zotero.Integration.MissingItemException) {
return me._showMissingItemError(e, field, callback, errorCallback, i);
} else if(e instanceof Zotero.Integration.CorruptFieldException) {
return me._showCorruptFieldError(e, field, callback, errorCallback, i);
} else {
throw e;
}
};
if(errorCallback) { if(errorCallback) {
errorCallback(e); if(errorCallback(e, defaultHandler)) {
} else if(e instanceof Zotero.Integration.MissingItemException) { continue;
// First, check if we've already decided to remove field codes from these } else {
var reselect = true; return;
for each(var reselectKey in e.reselectKeys) {
if(this._deleteKeys[reselectKey]) {
this._removeCodeFields.push(i);
reselect = false;
break;
}
} }
} if(!defaultHandler()) {
if(reselect) { return;
// Ask user what to do with this item
if(e.citationLength == 1) {
var msg = Zotero.getString("integration.missingItem.single");
} else {
var msg = Zotero.getString("integration.missingItem.multiple", (e.citationIndex+1).toString());
}
msg += '\n\n'+Zotero.getString('integration.missingItem.description');
field.select();
this._doc.activate();
var result = this._doc.displayAlert(msg, 1, 3);
if(result == 0) { // Cancel
throw new Zotero.Integration.UserCancelledException();
} else if(result == 1) { // No
for each(var reselectKey in e.reselectKeys) {
this._deleteKeys[reselectKey] = true;
}
this._removeCodeFields.push(i);
} else { // Yes
// Display reselect item dialog
var me = this;
var oldCurrentWindow = Zotero.Integration.currentWindow;
this._session.reselectItem(this._doc, e, function() {
// Now try again
Zotero.Integration.currentWindow = oldCurrentWindow;
me._doc.activate();
me._processFields(fields, callback, errorCallback, i);
});
return;
}
}
} else if(e instanceof Zotero.Integration.CorruptFieldException) {
if(!this._showCorruptFieldError(e, field, callback, errorCallback, i)) return;
} else {
throw e;
} }
} }
} else if(type === INTEGRATION_TYPE_BIBLIOGRAPHY) { } else if(type === INTEGRATION_TYPE_BIBLIOGRAPHY) {
@ -1447,12 +1490,17 @@ Zotero.Integration.Fields.prototype._processFields = function(fields, callback,
Zotero.Integration.Fields.prototype.updateDocument = function(forceCitations, forceBibliography, Zotero.Integration.Fields.prototype.updateDocument = function(forceCitations, forceBibliography,
ignoreCitationChanges, callback) { ignoreCitationChanges, callback) {
// update citations // update citations
this._session.updateUpdateIndices(forceCitations); try {
var me = this; this._session.updateUpdateIndices(forceCitations);
var deleteCitations = Zotero.pumpGenerator(this._session.updateCitations(function(deleteCitations) { var me = this;
Zotero.pumpGenerator(me._updateDocument(forceCitations, forceBibliography, var deleteCitations = Zotero.pumpGenerator(this._session.updateCitations(function(deleteCitations) {
ignoreCitationChanges, deleteCitations, callback)); Zotero.pumpGenerator(me._updateDocument(forceCitations, forceBibliography,
})); ignoreCitationChanges, deleteCitations, callback));
}));
} catch(e) {
Zotero.logError(e);
Zotero.Integration.handleError(e, this._doc);
}
} }
/** /**
@ -1722,6 +1770,26 @@ Zotero.Integration.CitationEditInterface = function(citation, field, fields, ses
} }
Zotero.Integration.CitationEditInterface.prototype = { Zotero.Integration.CitationEditInterface.prototype = {
/**
* Handles an error in updateSession
*/
"_errorHandler":function(e, defaultHandler) {
Zotero.debug('Integration.CitationEditInterface: Error "'+e.toString()+'" caught by handler');
if(this._haveAccepted) {
try {
return defaultHandler();
} catch(e) {
if(e instanceof Zotero.Integration.UserCancelledException) {
this._field.delete();
}
throw e;
}
} else {
this._errorOccurred = true;
return true;
}
},
/** /**
* Run a function when the session information has been updated * Run a function when the session information has been updated
* @param {Function} sessionUpdatedCallback * @param {Function} sessionUpdatedCallback
@ -1743,12 +1811,7 @@ Zotero.Integration.CitationEditInterface.prototype = {
} }
me._sessionUpdated = true; me._sessionUpdated = true;
delete me._sessionCallbackQueue; delete me._sessionCallbackQueue;
}, function(e) { }, function(e, defaultHandler) { return me._errorHandler(e, defaultHandler) });
if(e instanceof Zotero.Integration.MissingItemException
|| e instanceof Zotero.Integration.CorruptFieldException) {
me._errorOccurred = true;
}
});
} }
}, },
@ -1795,8 +1858,9 @@ Zotero.Integration.CitationEditInterface.prototype = {
Zotero.setTimeout(function() { Zotero.setTimeout(function() {
me._fields.updateSession(function() { me._fields.updateSession(function() {
me._errorOccurred = false; me._errorOccurred = false;
me._sessionUpdated = true;
me.accept(progressCallback, true); me.accept(progressCallback, true);
}) }, function(e, defaultHandler) { return me._errorHandler(e, defaultHandler) });
}, 0); }, 0);
return; return;
} }

View file

@ -114,11 +114,11 @@ Zotero.IPC = new function() {
close = lib.declare("close", ctypes.default_abi, ctypes.int, ctypes.int); close = lib.declare("close", ctypes.default_abi, ctypes.int, ctypes.int);
} }
// On OS X, O_NONBLOCK = 0x0004 // On OS X and FreeBSD, O_NONBLOCK = 0x0004
// On Linux, O_NONBLOCK = 00004000 // On Linux, O_NONBLOCK = 00004000
// On both, O_WRONLY = 0x0001 // On both, O_WRONLY = 0x0001
var mode = 0x0001; var mode = 0x0001;
if(!block) mode = mode | (Zotero.isMac ? 0x0004 : 00004000); if(!block) mode = mode | (Zotero.isLinux ? 00004000 : 0x0004);
var fd = open(pipe.path, mode); var fd = open(pipe.path, mode);
if(fd === -1) return false; if(fd === -1) return false;

View file

@ -2452,6 +2452,34 @@ Zotero.ItemTreeView.prototype.canDrop = function(row, orient, dragData)
return false; return false;
} }
// Don't allow children to be dragged within their own parents
var parentItemID = item.getSource();
var parentIndex = this._itemRowMap[parentItemID];
if (this.getLevel(row) > 0) {
if (this._getItemAtRow(this.getParentIndex(row)).ref.id == parentItemID) {
return false;
}
}
// Including immediately after the parent
if (orient == 1) {
if (row == parentIndex) {
return false;
}
}
// And immediately before the next parent
if (orient == -1) {
var nextParentIndex = null;
for (var i = parentIndex + 1; i < this.rowCount; i++) {
if (this.getLevel(i) == 0) {
nextParentIndex = i;
break;
}
}
if (row === nextParentIndex) {
return false;
}
}
// Disallow cross-library child drag // Disallow cross-library child drag
if (item.libraryID != itemGroup.ref.libraryID) { if (item.libraryID != itemGroup.ref.libraryID) {
return false; return false;

View file

@ -39,6 +39,11 @@ Zotero.MIMETypeHandler = new function () {
getService(Components.interfaces.nsIObserverService). getService(Components.interfaces.nsIObserverService).
addObserver(_Observer, "http-on-examine-response", false); addObserver(_Observer, "http-on-examine-response", false);
this.initializeHandlers(); this.initializeHandlers();
Zotero.addShutdownListener(function() {
Components.classes["@mozilla.org/observer-service;1"].
getService(Components.interfaces.nsIObserverService).
removeObserver(_Observer, "http-on-examine-response", false);
});
} }
/** /**

View file

@ -206,20 +206,15 @@ Zotero.Schema = new function(){
Zotero.debug(e); Zotero.debug(e);
} }
} }
try {
var up4 = this.updateBundledFiles(null, null, up2 || up3);
}
catch (e) {
Zotero.debug(e);
Zotero.logError(e);
}
} }
finally { finally {
Zotero.UnresponsiveScriptIndicator.enable(); Zotero.UnresponsiveScriptIndicator.enable();
} }
return up1 || up2 || up3 || up4; // After a delay, start update of bundled files and repo updates
setTimeout(function () {
Zotero.Schema.updateBundledFiles(null, null, up2 || up3);
}, 5000);
} }
@ -1119,59 +1114,205 @@ Zotero.Schema = new function(){
} }
this.integrityCheck = function () { this.integrityCheck = function (fix) {
// There should be an equivalent SELECT COUNT(*) statement for every // There should be an equivalent SELECT COUNT(*) statement for every
// statement run by the DB Repair Tool // statement run by the DB Repair Tool
var queries = [ var queries = [
"SELECT COUNT(*) FROM annotations WHERE itemID NOT IN (SELECT itemID FROM items)", [
"SELECT COUNT(*) FROM collectionItems WHERE itemID NOT IN (SELECT itemID FROM items)", "SELECT COUNT(*) FROM annotations WHERE itemID NOT IN (SELECT itemID FROM items)",
"SELECT COUNT(*) FROM fulltextItems WHERE itemID NOT IN (SELECT itemID FROM items)", "DELETE FROM annotations WHERE itemID NOT IN (SELECT itemID FROM items)"
"SELECT COUNT(*) FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM items)", ],
"SELECT COUNT(*) FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM fulltextItems)", [
"SELECT COUNT(*) FROM highlights WHERE itemID NOT IN (SELECT itemID FROM items)", "SELECT COUNT(*) FROM collectionItems WHERE itemID NOT IN (SELECT itemID FROM items)",
"SELECT COUNT(*) FROM itemAttachments WHERE itemID NOT IN (SELECT itemID FROM items)", "DELETE FROM collectionItems WHERE itemID NOT IN (SELECT itemID FROM items)"
"SELECT COUNT(*) FROM itemCreators WHERE itemID NOT IN (SELECT itemID FROM items)", ],
"SELECT COUNT(*) FROM itemData WHERE itemID NOT IN (SELECT itemID FROM items)", [
"SELECT COUNT(*) FROM itemNotes WHERE itemID NOT IN (SELECT itemID FROM items)", "SELECT COUNT(*) FROM fulltextItems WHERE itemID NOT IN (SELECT itemID FROM items)",
"SELECT COUNT(*) FROM itemSeeAlso WHERE itemID NOT IN (SELECT itemID FROM items)", "DELETE FROM fulltextItems WHERE itemID NOT IN (SELECT itemID FROM items)"
"SELECT COUNT(*) FROM itemSeeAlso WHERE linkedItemID NOT IN (SELECT itemID FROM items)", ],
"SELECT COUNT(*) FROM itemTags WHERE itemID NOT IN (SELECT itemID FROM items)", [
"SELECT COUNT(*) FROM itemTags WHERE tagID NOT IN (SELECT tagID FROM tags)", "SELECT COUNT(*) FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM items)",
"SELECT COUNT(*) FROM savedSearchConditions WHERE savedSearchID NOT IN (select savedSearchID FROM savedSearches)", "DELETE FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM items)",
"SELECT COUNT(*) FROM items WHERE itemTypeID IS NULL", ],
[
"SELECT COUNT(*) FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM fulltextItems)",
"DELETE FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM fulltextItems)",
],
[
"SELECT COUNT(*) FROM highlights WHERE itemID NOT IN (SELECT itemID FROM items)",
"DELETE FROM highlights WHERE itemID NOT IN (SELECT itemID FROM items)",
],
[
"SELECT COUNT(*) FROM itemAttachments WHERE itemID NOT IN (SELECT itemID FROM items)",
"DELETE FROM itemAttachments WHERE itemID NOT IN (SELECT itemID FROM items)",
],
[
"SELECT COUNT(*) FROM itemCreators WHERE itemID NOT IN (SELECT itemID FROM items)",
"DELETE FROM itemCreators WHERE itemID NOT IN (SELECT itemID FROM items)",
],
[
"SELECT COUNT(*) FROM itemData WHERE itemID NOT IN (SELECT itemID FROM items)",
"DELETE FROM itemData WHERE itemID NOT IN (SELECT itemID FROM items)",
],
[
"SELECT COUNT(*) FROM itemNotes WHERE itemID NOT IN (SELECT itemID FROM items)",
"DELETE FROM itemNotes WHERE itemID NOT IN (SELECT itemID FROM items)",
],
[
"SELECT COUNT(*) FROM itemSeeAlso WHERE itemID NOT IN (SELECT itemID FROM items)",
"DELETE FROM itemSeeAlso WHERE itemID NOT IN (SELECT itemID FROM items)",
],
[
"SELECT COUNT(*) FROM itemSeeAlso WHERE linkedItemID NOT IN (SELECT itemID FROM items)",
"DELETE FROM itemSeeAlso WHERE linkedItemID NOT IN (SELECT itemID FROM items)",
],
[
"SELECT COUNT(*) FROM itemTags WHERE itemID NOT IN (SELECT itemID FROM items)",
"DELETE FROM itemTags WHERE itemID NOT IN (SELECT itemID FROM items)",
],
[
"SELECT COUNT(*) FROM itemTags WHERE tagID NOT IN (SELECT tagID FROM tags)",
"DELETE FROM itemTags WHERE tagID NOT IN (SELECT tagID FROM tags)",
],
[
"SELECT COUNT(*) FROM savedSearchConditions WHERE savedSearchID NOT IN (select savedSearchID FROM savedSearches)",
"DELETE FROM savedSearchConditions WHERE savedSearchID NOT IN (select savedSearchID FROM savedSearches)",
],
[
"SELECT COUNT(*) FROM items WHERE itemTypeID IS NULL",
"DELETE FROM items WHERE itemTypeID IS NULL",
],
"SELECT COUNT(*) FROM itemData WHERE valueID NOT IN (SELECT valueID FROM itemDataValues)",
"SELECT COUNT(*) FROM fulltextItemWords WHERE wordID NOT IN (SELECT wordID FROM fulltextWords)",
"SELECT COUNT(*) FROM collectionItems WHERE collectionID NOT IN (SELECT collectionID FROM collections)",
"SELECT COUNT(*) FROM itemCreators WHERE creatorID NOT IN (SELECT creatorID FROM creators)",
"SELECT COUNT(*) FROM itemTags WHERE tagID NOT IN (SELECT tagID FROM tags)",
"SELECT COUNT(*) FROM itemData WHERE fieldID NOT IN (SELECT fieldID FROM fields)",
"SELECT COUNT(*) FROM itemData WHERE valueID NOT IN (SELECT valueID FROM itemDataValues)",
"SELECT COUNT(*) FROM itemData WHERE fieldID NOT IN (SELECT fieldID FROM itemTypeFields WHERE itemTypeID=(SELECT itemTypeID FROM items WHERE itemID=itemData.itemID))", [
"SELECT COUNT(*) FROM itemData WHERE valueID NOT IN (SELECT valueID FROM itemDataValues)",
"DELETE FROM itemData WHERE valueID NOT IN (SELECT valueID FROM itemDataValues)",
],
[
"SELECT COUNT(*) FROM fulltextItemWords WHERE wordID NOT IN (SELECT wordID FROM fulltextWords)",
"DELETE FROM fulltextItemWords WHERE wordID NOT IN (SELECT wordID FROM fulltextWords)",
],
[
"SELECT COUNT(*) FROM collectionItems WHERE collectionID NOT IN (SELECT collectionID FROM collections)",
"DELETE FROM collectionItems WHERE collectionID NOT IN (SELECT collectionID FROM collections)",
],
[
"SELECT COUNT(*) FROM itemCreators WHERE creatorID NOT IN (SELECT creatorID FROM creators)",
"DELETE FROM itemCreators WHERE creatorID NOT IN (SELECT creatorID FROM creators)",
],
[
"SELECT COUNT(*) FROM itemData WHERE fieldID NOT IN (SELECT fieldID FROM fields)",
"DELETE FROM itemData WHERE fieldID NOT IN (SELECT fieldID FROM fields)",
],
[
"SELECT COUNT(*) FROM itemData WHERE valueID NOT IN (SELECT valueID FROM itemDataValues)",
"DELETE FROM itemData WHERE valueID NOT IN (SELECT valueID FROM itemDataValues)",
],
"SELECT COUNT(*) FROM items WHERE itemTypeID=14 AND itemID NOT IN (SELECT itemID FROM itemAttachments)",
"SELECT COUNT(*) FROM itemAttachments WHERE sourceItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))", // Attachments row with itemTypeID != 14
"SELECT COUNT(*) FROM itemNotes WHERE sourceItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))", [
"SELECT COUNT(*) FROM itemAttachments JOIN items USING (itemID) WHERE itemTypeID != 14",
"UPDATE items SET itemTypeID=14, clientDateModified=CURRENT_TIMESTAMP WHERE itemTypeID != 14 AND itemID IN (SELECT itemID FROM itemAttachments)",
],
// Fields not in type
[
"SELECT COUNT(*) FROM itemData WHERE fieldID NOT IN (SELECT fieldID FROM itemTypeFields WHERE itemTypeID=(SELECT itemTypeID FROM items WHERE itemID=itemData.itemID))",
"DELETE FROM itemData WHERE fieldID NOT IN (SELECT fieldID FROM itemTypeFields WHERE itemTypeID=(SELECT itemTypeID FROM items WHERE itemID=itemData.itemID))",
],
// Missing itemAttachments row
[
"SELECT COUNT(*) FROM items WHERE itemTypeID=14 AND itemID NOT IN (SELECT itemID FROM itemAttachments)",
"INSERT INTO itemAttachments (itemID, linkMode) SELECT itemID, 0 FROM items WHERE itemTypeID=14 AND itemID NOT IN (SELECT itemID FROM itemAttachments)",
],
// Note/child parents
[
"SELECT COUNT(*) FROM itemAttachments WHERE sourceItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
"UPDATE itemAttachments SET sourceItemID=NULL WHERE sourceItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
],
[
"SELECT COUNT(*) FROM itemNotes WHERE sourceItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
"UPDATE itemNotes SET sourceItemID=NULL WHERE sourceItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
],
"SELECT COUNT(*) FROM tags NATURAL JOIN itemTags JOIN items USING (itemID) WHERE IFNULL(tags.libraryID, 0)!=IFNULL(items.libraryID,0)", // Wrong library tags
[
"SELECT COUNT(*) FROM itemTags WHERE tagID IS NULL", "SELECT COUNT(*) FROM tags NATURAL JOIN itemTags JOIN items USING (itemID) WHERE IFNULL(tags.libraryID, 0)!=IFNULL(items.libraryID,0)",
"SELECT COUNT(*) FROM itemAttachments WHERE charsetID='NULL'", [
"CREATE TEMPORARY TABLE tmpWrongLibraryTags AS SELECT itemTags.ROWID AS tagRowID, tagID, name, itemID, IFNULL(tags.libraryID,0) AS tagLibraryID, IFNULL(items.libraryID,0) AS itemLibraryID FROM tags NATURAL JOIN itemTags JOIN items USING (itemID) WHERE IFNULL(tags.libraryID, 0)!=IFNULL(items.libraryID,0)",
"DELETE FROM itemTags WHERE ROWID IN (SELECT tagRowID FROM tmpWrongLibraryTags)",
"DROP TABLE tmpWrongLibraryTags"
]
],
[
"SELECT COUNT(*) FROM itemTags WHERE tagID IS NULL",
"DELETE FROM itemTags WHERE tagID IS NULL",
],
[
"SELECT COUNT(*) FROM itemAttachments WHERE charsetID='NULL'",
"UPDATE itemAttachments SET charsetID=NULL WHERE charsetID='NULL'",
],
// Reported by one user
// http://forums.zotero.org/discussion/19347/continual-synching-error-message/
// TODO: check 'libraries', not 'groups', but first add a // TODO: check 'libraries', not 'groups', but first add a
// migration step to delete 'libraries' rows not in 'groups' // migration step to delete 'libraries' rows not in 'groups'
//"SELECT COUNT(*) FROM syncDeleteLog WHERE libraryID != 0 AND libraryID NOT IN (SELECT libraryID FROM libraries)" //"SELECT COUNT(*) FROM syncDeleteLog WHERE libraryID != 0 AND libraryID NOT IN (SELECT libraryID FROM libraries)"
"SELECT COUNT(*) FROM syncDeleteLog WHERE libraryID != 0 AND libraryID NOT IN (SELECT libraryID FROM groups)", [
"SELECT COUNT(*) FROM syncDeleteLog WHERE libraryID != 0 AND libraryID NOT IN (SELECT libraryID FROM groups)",
"DELETE FROM syncDeleteLog WHERE libraryID != 0 AND libraryID NOT IN (SELECT libraryID FROM libraries)",
],
"SELECT COUNT(*) FROM creatorData WHERE firstName='' AND lastName=''",
"SELECT COUNT(*) FROM itemAttachments JOIN items USING (itemID) WHERE itemTypeID != 14" // Delete empty creators
// This may cause itemCreator gaps, but that's better than empty creators
[
"SELECT COUNT(*) FROM creatorData WHERE firstName='' AND lastName=''",
[
"DELETE FROM itemCreators WHERE creatorID IN (SELECT creatorID FROM creators WHERE creatorDataID IN (SELECT creatorDataID FROM creatorData WHERE firstName='' AND lastName=''))",
"DELETE FROM creators WHERE creatorDataID IN (SELECT creatorDataID FROM creatorData WHERE firstName='' AND lastName='')",
"DELETE FROM creatorData WHERE firstName='' AND lastName=''"
],
],
// Non-attachment items in the full-text index
[
"SELECT COUNT(*) FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=14)",
[
"DELETE FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=14)",
"SELECT 1"
]
],
[
"SELECT COUNT(*) FROM fulltextItems WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=14)",
"DELETE FROM fulltextItems WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=14)"
]
]; ];
for each(var sql in queries) { for each(var sql in queries) {
if (Zotero.DB.valueQuery(sql)) { if (Zotero.DB.valueQuery(sql[0])) {
Zotero.debug("Test failed!", 1);
if (fix) {
try {
// Single query
if (typeof sql[1] == 'string') {
Zotero.DB.valueQuery(sql[1]);
}
// Multiple queries
else {
for each(var s in sql[1]) {
Zotero.DB.valueQuery(s);
}
}
continue;
}
catch (e) {
Zotero.debug(e);
Components.utils.reportError(e);
}
}
return false; return false;
} }
} }
@ -1180,7 +1321,6 @@ Zotero.Schema = new function(){
} }
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// //
// Private methods // Private methods

View file

@ -53,8 +53,8 @@ Zotero.Sync.Storage = new function () {
// TEMP // TEMP
// TODO: localize // TODO: localize
this.defaultError = "A file sync error occurred. Please try syncing again.\n\nIf you receive this message repeatedly, restart " + Zotero.appName + " and/or your computer and try again. If you continue to receive the message, submit an error report and post the Report ID to a new thread in the Zotero Forums."; this.__defineGetter__("defaultError", function () "A file sync error occurred. Please try syncing again.\n\nIf you receive this message repeatedly, restart " + Zotero.appName + " and/or your computer and try again. If you continue to receive the message, submit an error report and post the Report ID to a new thread in the Zotero Forums.");
this.defaultErrorRestart = "A file sync error occurred. Please restart " + Zotero.appName + " and/or your computer and try syncing again.\n\nIf you receive this message repeatedly, submit an error report and post the Report ID to a new thread in the Zotero Forums."; this.__defineGetter__("defaultErrorRestart", function () "A file sync error occurred. Please restart " + Zotero.appName + " and/or your computer and try syncing again.\n\nIf you receive this message repeatedly, submit an error report and post the Report ID to a new thread in the Zotero Forums.");
// //
// Public properties // Public properties
@ -1339,7 +1339,10 @@ Zotero.Sync.Storage = new function () {
if (windowsLength) { if (windowsLength) {
var pathLength = destFile.path.length - destFile.leafName.length; var pathLength = destFile.path.length - destFile.leafName.length;
var newLength = 254 - pathLength; // Limit should be 255, but a shorter limit seems to be
// enforced for nsIZipReader.extract() below on
// non-English systems
var newLength = 240 - pathLength;
// Require 40 available characters in path -- this is arbitrary, // Require 40 available characters in path -- this is arbitrary,
// but otherwise filenames are going to end up being cut off // but otherwise filenames are going to end up being cut off
if (newLength < 40) { if (newLength < 40) {
@ -1351,7 +1354,7 @@ Zotero.Sync.Storage = new function () {
} }
} }
else { else {
var newLength = 254; var newLength = 240;
} }
// Shorten file if it's too long -- we don't relink it, but this should // Shorten file if it's too long -- we don't relink it, but this should
@ -1415,6 +1418,7 @@ Zotero.Sync.Storage = new function () {
zipReader.extract(entryName, destFile); zipReader.extract(entryName, destFile);
} }
catch (e) { catch (e) {
Zotero.debug(destFile.path);
Zotero.File.checkFileAccessError(e, destFile, 'create'); Zotero.File.checkFileAccessError(e, destFile, 'create');
} }

View file

@ -124,6 +124,7 @@ Zotero.Translate.Sandbox = {
for(var j=0; j<nAttachments; j++) { for(var j=0; j<nAttachments; j++) {
if(attachments[j].document) { if(attachments[j].document) {
attachments[j].url = attachments[j].document.location.href; attachments[j].url = attachments[j].document.location.href;
attachments[j].mimeType = "text/html";
delete attachments[j].document; delete attachments[j].document;
} }
} }

View file

@ -646,7 +646,6 @@ const ZOTERO_CONFIG = {
} }
Zotero.DB.startDummyStatement(); Zotero.DB.startDummyStatement();
Zotero.Schema.updateFromRepository();
// Populate combined tables for custom types and fields -- this is likely temporary // Populate combined tables for custom types and fields -- this is likely temporary
if (!upgraded && !updated) { if (!upgraded && !updated) {
@ -2303,6 +2302,7 @@ Zotero.VersionHeader = {
if (Zotero.Prefs.get("zoteroDotOrgVersionHeader")) { if (Zotero.Prefs.get("zoteroDotOrgVersionHeader")) {
this.register(); this.register();
} }
Zotero.addShutdownListener(this.unregister);
}, },
// Called from this.init() and Zotero.Prefs.observe() // Called from this.init() and Zotero.Prefs.observe()
@ -2327,7 +2327,7 @@ Zotero.VersionHeader = {
unregister: function () { unregister: function () {
var observerService = Components.classes["@mozilla.org/observer-service;1"] var observerService = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService); .getService(Components.interfaces.nsIObserverService);
observerService.removeObserver(this, "http-on-modify-request"); observerService.removeObserver(Zotero.VersionHeader, "http-on-modify-request");
} }
} }

View file

@ -269,7 +269,7 @@ var ZoteroPane = new function()
menuitem.setAttribute("label", itemTypes[i].localized); menuitem.setAttribute("label", itemTypes[i].localized);
menuitem.setAttribute("tooltiptext", ""); menuitem.setAttribute("tooltiptext", "");
let type = itemTypes[i].id; let type = itemTypes[i].id;
menuitem.addEventListener("command", function() { ZoteroPane_Local.newItem(type); }, false); menuitem.addEventListener("command", function() { ZoteroPane_Local.newItem(type, {}, null, true); }, false);
moreMenu.appendChild(menuitem); moreMenu.appendChild(menuitem);
} }
} }
@ -307,7 +307,7 @@ var ZoteroPane = new function()
menuitem.setAttribute("label", itemTypes[i].localized); menuitem.setAttribute("label", itemTypes[i].localized);
menuitem.setAttribute("tooltiptext", ""); menuitem.setAttribute("tooltiptext", "");
let type = itemTypes[i].id; let type = itemTypes[i].id;
menuitem.addEventListener("command", function() { ZoteroPane_Local.newItem(type); }, false); menuitem.addEventListener("command", function() { ZoteroPane_Local.newItem(type, {}, null, true); }, false);
menuitem.className = "zotero-tb-add"; menuitem.className = "zotero-tb-add";
addMenu.insertBefore(menuitem, separator); addMenu.insertBefore(menuitem, separator);
} }
@ -658,7 +658,7 @@ var ZoteroPane = new function()
* *
* _data_ is an optional object with field:value for itemData * _data_ is an optional object with field:value for itemData
*/ */
function newItem(typeID, data, row) function newItem(typeID, data, row, manual)
{ {
if (!Zotero.stateCheck()) { if (!Zotero.stateCheck()) {
this.displayErrorMessage(true); this.displayErrorMessage(true);
@ -675,7 +675,7 @@ var ZoteroPane = new function()
} }
} }
if (row !== undefined) { if (row !== undefined && row !== null) {
var itemGroup = this.collectionsView._getItemAtRow(row); var itemGroup = this.collectionsView._getItemAtRow(row);
var libraryID = itemGroup.ref.libraryID; var libraryID = itemGroup.ref.libraryID;
} }
@ -703,19 +703,21 @@ var ZoteroPane = new function()
document.getElementById('zotero-view-item').selectedIndex = 0; document.getElementById('zotero-view-item').selectedIndex = 0;
// Update most-recently-used list for New Item menu // Update most-recently-used list for New Item menu
var mru = Zotero.Prefs.get('newItemTypeMRU'); if (manual) {
if (mru) { var mru = Zotero.Prefs.get('newItemTypeMRU');
var mru = mru.split(','); if (mru) {
var pos = mru.indexOf(typeID + ''); var mru = mru.split(',');
if (pos != -1) { var pos = mru.indexOf(typeID + '');
mru.splice(pos, 1); if (pos != -1) {
mru.splice(pos, 1);
}
mru.unshift(typeID);
} }
mru.unshift(typeID); else {
var mru = [typeID + ''];
}
Zotero.Prefs.set('newItemTypeMRU', mru.slice(0, 5).join(','));
} }
else {
var mru = [typeID + ''];
}
Zotero.Prefs.set('newItemTypeMRU', mru.slice(0, 5).join(','));
return Zotero.Items.get(itemID); return Zotero.Items.get(itemID);
} }

View file

@ -174,7 +174,7 @@
<!ENTITY zotero.integration.prefs.formatUsing.label "Format Using:"> <!ENTITY zotero.integration.prefs.formatUsing.label "Format Using:">
<!ENTITY zotero.integration.prefs.bookmarks.label "Bookmarks"> <!ENTITY zotero.integration.prefs.bookmarks.label "Bookmarks">
<!ENTITY zotero.integration.prefs.bookmarks.caption "Bookmarks are preserved across Microsoft Word and OpenOffice, but may be accidentally modified. For &#xA;compatibility reasons, citations cannot be inserted into footnotes or endnotes when this option is selected."> <!ENTITY zotero.integration.prefs.bookmarks.caption "Bookmarks are preserved across Microsoft Word and LibreOffice, but may be accidentally modified. For &#xA;compatibility reasons, citations cannot be inserted into footnotes or endnotes when this option is selected.">
<!ENTITY zotero.integration.prefs.storeReferences.label "Store references in document"> <!ENTITY zotero.integration.prefs.storeReferences.label "Store references in document">
<!ENTITY zotero.integration.prefs.storeReferences.caption "Storing references in your document slightly increases file size, but will allow you to share your document with others without using a Zotero group. Zotero 3.0 or later is required to update documents created with this option."> <!ENTITY zotero.integration.prefs.storeReferences.caption "Storing references in your document slightly increases file size, but will allow you to share your document with others without using a Zotero group. Zotero 3.0 or later is required to update documents created with this option.">

View file

@ -11,6 +11,7 @@ general.restartRequiredForChange = %S must be restarted for the change to take e
general.restartRequiredForChanges = %S must be restarted for the changes to take effect. general.restartRequiredForChanges = %S must be restarted for the changes to take effect.
general.restartNow = Restart now general.restartNow = Restart now
general.restartLater = Restart later general.restartLater = Restart later
general.restartApp = Restart %S
general.errorHasOccurred = An error has occurred. general.errorHasOccurred = An error has occurred.
general.unknownErrorOccurred = An unknown error occurred. general.unknownErrorOccurred = An unknown error occurred.
general.restartFirefox = Please restart %S. general.restartFirefox = Please restart %S.
@ -426,8 +427,14 @@ db.dbRestored = The Zotero database '%1$S' appears to have become corrupted.
db.dbRestoreFailed = The Zotero database '%S' appears to have become corrupted, and an attempt to restore from the last automatic backup failed.\n\nA new database file has been created. The damaged file was saved in your Zotero directory. db.dbRestoreFailed = The Zotero database '%S' appears to have become corrupted, and an attempt to restore from the last automatic backup failed.\n\nA new database file has been created. The damaged file was saved in your Zotero directory.
db.integrityCheck.passed = No errors were found in the database. db.integrityCheck.passed = No errors were found in the database.
db.integrityCheck.failed = Errors were found in the Zotero database! db.integrityCheck.failed = Errors were found in your Zotero database.
db.integrityCheck.dbRepairTool = You can use the database repair tool at http://zotero.org/utils/dbfix to attempt to correct these errors. db.integrityCheck.dbRepairTool = You can use the database repair tool at http://zotero.org/utils/dbfix to attempt to correct these errors.
db.integrityCheck.repairAttempt = Zotero can attempt to correct these errors.
db.integrityCheck.appRestartNeeded = %S will need to be restarted.
db.integrityCheck.fixAndRestart = Fix Errors and Restart %S
db.integrityCheck.errorsFixed = The errors in your Zotero database have been corrected.
db.integrityCheck.errorsNotFixed = Zotero was unable to correct all the errors in your database.
db.integrityCheck.reportInForums = You can report this problem in the Zotero Forums.
zotero.preferences.update.updated = Updated zotero.preferences.update.updated = Updated
zotero.preferences.update.upToDate = Up to date zotero.preferences.update.upToDate = Up to date
@ -460,7 +467,8 @@ zotero.preferences.search.pdf.toolsDownloadError = An error occurred while at
zotero.preferences.search.pdf.tryAgainOrViewManualInstructions = Please try again later, or view the documentation for manual installation instructions. zotero.preferences.search.pdf.tryAgainOrViewManualInstructions = Please try again later, or view the documentation for manual installation instructions.
zotero.preferences.export.quickCopy.bibStyles = Bibliographic Styles zotero.preferences.export.quickCopy.bibStyles = Bibliographic Styles
zotero.preferences.export.quickCopy.exportFormats = Export Formats zotero.preferences.export.quickCopy.exportFormats = Export Formats
zotero.preferences.export.quickCopy.instructions = Quick Copy allows you to copy selected references to the clipboard by pressing a shortcut key (%S) or dragging items into a text box on a web page. zotero.preferences.export.quickCopy.instructions = Quick Copy allows you to copy selected items to the clipboard by pressing %S or dragging items into a text box on a web page.
zotero.preferences.export.quickCopy.citationInstructions = For bibliography styles, you can copy citations or footnotes by pressing %S or holding down Shift before dragging items.
zotero.preferences.styles.addStyle = Add Style zotero.preferences.styles.addStyle = Add Style
zotero.preferences.advanced.resetTranslatorsAndStyles = Reset Translators and Styles zotero.preferences.advanced.resetTranslatorsAndStyles = Reset Translators and Styles
@ -581,7 +589,7 @@ integration.revertAll.button = Revert All
integration.revert.title = Are you sure you want to revert this edit? integration.revert.title = Are you sure you want to revert this edit?
integration.revert.body = If you choose to continue, the text of the bibliography entries corresponded to the selected item(s) will be replaced with the unmodified text specified by the selected style. integration.revert.body = If you choose to continue, the text of the bibliography entries corresponded to the selected item(s) will be replaced with the unmodified text specified by the selected style.
integration.revert.button = Revert integration.revert.button = Revert
integration.removeBibEntry.title = The selected references is cited within your document. integration.removeBibEntry.title = The selected reference is cited within your document.
integration.removeBibEntry.body = Are you sure you want to omit it from your bibliography? integration.removeBibEntry.body = Are you sure you want to omit it from your bibliography?
integration.cited = Cited integration.cited = Cited
@ -602,7 +610,7 @@ integration.error.cannotInsertHere = Zotero fields cannot be inserted here.
integration.error.notInCitation = You must place the cursor in a Zotero citation to edit it. integration.error.notInCitation = You must place the cursor in a Zotero citation to edit it.
integration.error.noBibliography = The current bibliographic style does not define a bibliography. If you wish to add a bibliography, please choose another style. integration.error.noBibliography = The current bibliographic style does not define a bibliography. If you wish to add a bibliography, please choose another style.
integration.error.deletePipe = The pipe that Zotero uses to communicate with the word processor could not be initialized. Would you like Zotero to attempt to correct this error? You will be prompted for your password. integration.error.deletePipe = The pipe that Zotero uses to communicate with the word processor could not be initialized. Would you like Zotero to attempt to correct this error? You will be prompted for your password.
integration.error.invalidStyle = The style you have selected does not appear to be valid. If you have created this style yourself, please ensure that it passes validation as described at http://zotero.org/support/dev/citation_styles. Alternatively, try selecting another style. integration.error.invalidStyle = The style you have selected does not appear to be valid. If you have created this style yourself, please ensure that it passes validation as described at https://github.com/citation-style-language/styles/wiki/Validation. Alternatively, try selecting another style.
integration.error.fieldTypeMismatch = Zotero cannot update this document because it was created by a different word processing application with an incompatible field encoding. In order to make a document compatible with both Word and OpenOffice.org/LibreOffice/NeoOffice, open the document in the word processor with which it was originally created and switch the field type to Bookmarks in the Zotero Document Preferences. integration.error.fieldTypeMismatch = Zotero cannot update this document because it was created by a different word processing application with an incompatible field encoding. In order to make a document compatible with both Word and OpenOffice.org/LibreOffice/NeoOffice, open the document in the word processor with which it was originally created and switch the field type to Bookmarks in the Zotero Document Preferences.
integration.replace = Replace this Zotero field? integration.replace = Replace this Zotero field?
@ -617,7 +625,7 @@ integration.corruptField.description = Clicking "No" will delete the field codes
integration.corruptBibliography = The Zotero field code for your bibliography is corrupted. Should Zotero clear this field code and generate a new bibliography? integration.corruptBibliography = The Zotero field code for your bibliography is corrupted. Should Zotero clear this field code and generate a new bibliography?
integration.corruptBibliography.description = All items cited in the text will appear in the new bibliography, but modifications you made in the "Edit Bibliography" dialog will be lost. integration.corruptBibliography.description = All items cited in the text will appear in the new bibliography, but modifications you made in the "Edit Bibliography" dialog will be lost.
integration.citationChanged = You have modified this citation since Zotero generated it. Do you want to keep your modifications and prevent future updates? integration.citationChanged = You have modified this citation since Zotero generated it. Do you want to keep your modifications and prevent future updates?
integration.citationChanged.description = Clicking "Yes" will prevent Zotero from updating this citation if you add additional citations, switch styles, or modify the reference to which it refers. Clicking "No" will erase your changes. integration.citationChanged.description = Clicking "Yes" will prevent Zotero from updating this citation if you add additional citations, switch styles, or modify the item to which it refers. Clicking "No" will erase your changes.
integration.citationChanged.edit = You have modified this citation since Zotero generated it. Editing will clear your modifications. Do you want to continue? integration.citationChanged.edit = You have modified this citation since Zotero generated it. Editing will clear your modifications. Do you want to continue?
styles.installStyle = Install style "%1$S" from %2$S? styles.installStyle = Install style "%1$S" from %2$S?
@ -758,7 +766,7 @@ standalone.addonInstallationFailed.body = The add-on "%S" could not be installe
connector.error.title = Zotero Connector Error connector.error.title = Zotero Connector Error
connector.standaloneOpen = Your database cannot be accessed because Zotero Standalone is currently open. Please view your items in Zotero Standalone. connector.standaloneOpen = Your database cannot be accessed because Zotero Standalone is currently open. Please view your items in Zotero Standalone.
firstRunGuidance.saveIcon = Zotero can recognize a reference on this page. Click this icon in the address bar to save the reference to your Zotero library. firstRunGuidance.saveIcon = Zotero has found a reference on this page. Click this icon in the address bar to save the reference to your Zotero library.
firstRunGuidance.authorMenu = Zotero lets you specify editors and translators, too. You can turn an author into an editor or translator by selecting from this menu. firstRunGuidance.authorMenu = Zotero lets you specify editors and translators, too. You can turn an author into an editor or translator by selecting from this menu.
firstRunGuidance.quickFormat = Type a title or author to search for a reference.\n\nAfter you've made your selection, click the bubble or press Ctrl-\u2193 to add page numbers, prefixes, or suffixes. You can also include a page number along with your search terms to add it directly.\n\nYou can edit citations directly in the word processor document. firstRunGuidance.quickFormat = Type a title or author to search for a reference.\n\nAfter you've made your selection, click the bubble or press Ctrl-\u2193 to add page numbers, prefixes, or suffixes. You can also include a page number along with your search terms to add it directly.\n\nYou can edit citations directly in the word processor document.
firstRunGuidance.quickFormatMac = Type a title or author to search for a reference.\n\nAfter you've made your selection, click the bubble or press Cmd-\u2193 to add page numbers, prefixes, or suffixes. You can also include a page number along with your search terms to add it directly.\n\nYou can edit citations directly in the word processor document. firstRunGuidance.quickFormatMac = Type a title or author to search for a reference.\n\nAfter you've made your selection, click the bubble or press Cmd-\u2193 to add page numbers, prefixes, or suffixes. You can also include a page number along with your search terms to add it directly.\n\nYou can edit citations directly in the word processor document.

@ -1 +1 @@
Subproject commit 1ba73cb10ad0c77c171a389dd60bad78ea6a007f Subproject commit 7b8cb18ea06006a89cf1afb94bb481cebed3e43c