Merge branch 'fx60'
This commit is contained in:
commit
d4f682aa88
152 changed files with 13336 additions and 5410 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -22,3 +22,6 @@
|
|||
path = test/resource/chai-as-promised
|
||||
url = https://github.com/domenic/chai-as-promised.git
|
||||
branch = master
|
||||
[submodule "resource/schema/global"]
|
||||
path = resource/schema/global
|
||||
url = git://github.com/zotero/zotero-schema.git
|
||||
|
|
10
.travis.yml
10
.travis.yml
|
@ -10,7 +10,7 @@ env:
|
|||
global:
|
||||
secure: "NxvkbZ7/Op7BTGQRR3C4q8lLoO29f8WtyNN27NSH7AO3H0vBr1Vp5xO8gn+H2qHEug5HvM+YrZ/xAkNXaZVbOInmBmKVMxqVvdpKp9JM1Amf+gzsXWQphfySvs6iqzyP6cwU/jspdvX/WSakgU5v7PWXxtUIaKxdANt6Rw7W+Pc="
|
||||
matrix:
|
||||
- FX_VERSION="52.0.3"
|
||||
- FX_VERSION="60.8.0esr"
|
||||
matrix:
|
||||
fast_finish: true
|
||||
#allow_failures:
|
||||
|
@ -24,15 +24,13 @@ addons:
|
|||
services:
|
||||
- xvfb
|
||||
install:
|
||||
- if [ $FX_VERSION = "52.0.3" ]; then
|
||||
wget -O tarball "https://archive.mozilla.org/pub/firefox/tinderbox-builds/mozilla-release-linux64-add-on-devel/1491732920/firefox-52.0.3.en-US.linux-x86_64-add-on-devel.tar.bz2";
|
||||
fi
|
||||
- wget -O tarball "https://zotero-download.s3.us-east-1.amazonaws.com/dev/firefox-60.8.0esr-x86_64-modified.tar.gz";
|
||||
- tar xf tarball
|
||||
before_script:
|
||||
- npm i
|
||||
- npm run build
|
||||
- if [[ $TRAVIS_REPO_SLUG = "zotero/zotero" &&
|
||||
($TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = *-hotfix) &&
|
||||
($TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = *-hotfix || $TRAVIS_BRANCH = "fx60") &&
|
||||
$TRAVIS_PULL_REQUEST = "false" ]]; then
|
||||
mkdir build-zip;
|
||||
cd build;
|
||||
|
@ -51,4 +49,4 @@ before_script:
|
|||
# Fix warnings in output
|
||||
- dbus-launch
|
||||
script:
|
||||
- test/runtests.sh -x firefox/firefox -f
|
||||
- test/runtests.sh -x firefox-x86_64/firefox -f
|
||||
|
|
9
chrome/content/scaffold/ace/ace.html
Normal file
9
chrome/content/scaffold/ace/ace.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script type="text/javascript" src="chrome://scaffold/content/ace/ace.js"></script>
|
||||
<script type="text/javascript" src="chrome://scaffold/content/ace/mode-javascript.js"></script>
|
||||
<script type="text/javascript" src="chrome://scaffold/content/aceWrapper.js"></script>
|
||||
</head>
|
||||
<body id="body"></body>
|
||||
</html>
|
File diff suppressed because it is too large
Load diff
|
@ -45,7 +45,6 @@ background-color: white;\
|
|||
color: black;\
|
||||
border: 1px solid #cbcbcb;\
|
||||
border-right: 0 none;\
|
||||
box-sizing: border-box!important;\
|
||||
outline: 0;\
|
||||
padding: 0;\
|
||||
font-size: inherit;\
|
||||
|
@ -54,6 +53,8 @@ line-height: inherit;\
|
|||
padding: 0 6px;\
|
||||
min-width: 17em;\
|
||||
vertical-align: top;\
|
||||
min-height: 1.8em;\
|
||||
box-sizing: content-box;\
|
||||
}\
|
||||
.ace_searchbtn {\
|
||||
border: 1px solid #cbcbcb;\
|
||||
|
@ -66,7 +67,6 @@ border-left: 1px solid #dcdcdc;\
|
|||
cursor: pointer;\
|
||||
margin: 0;\
|
||||
position: relative;\
|
||||
box-sizing: content-box!important;\
|
||||
color: #666;\
|
||||
}\
|
||||
.ace_searchbtn:last-child {\
|
||||
|
@ -162,39 +162,38 @@ var MAX_COUNT = 999;
|
|||
|
||||
dom.importCssString(searchboxCss, "ace_searchbox");
|
||||
|
||||
var html = '<div class="ace_search right">\
|
||||
<span action="hide" class="ace_searchbtn_close"></span>\
|
||||
<div class="ace_search_form">\
|
||||
<input class="ace_search_field" placeholder="Search for" spellcheck="false"></input>\
|
||||
<span action="findPrev" class="ace_searchbtn prev"></span>\
|
||||
<span action="findNext" class="ace_searchbtn next"></span>\
|
||||
<span action="findAll" class="ace_searchbtn" title="Alt-Enter">All</span>\
|
||||
</div>\
|
||||
<div class="ace_replace_form">\
|
||||
<input class="ace_search_field" placeholder="Replace with" spellcheck="false"></input>\
|
||||
<span action="replaceAndFindNext" class="ace_searchbtn">Replace</span>\
|
||||
<span action="replaceAll" class="ace_searchbtn">All</span>\
|
||||
</div>\
|
||||
<div class="ace_search_options">\
|
||||
<span action="toggleReplace" class="ace_button" title="Toggel Replace mode"\
|
||||
style="float:left;margin-top:-2px;padding:0 5px;">+</span>\
|
||||
<span class="ace_search_counter"></span>\
|
||||
<span action="toggleRegexpMode" class="ace_button" title="RegExp Search">.*</span>\
|
||||
<span action="toggleCaseSensitive" class="ace_button" title="CaseSensitive Search">Aa</span>\
|
||||
<span action="toggleWholeWords" class="ace_button" title="Whole Word Search">\\b</span>\
|
||||
<span action="searchInSelection" class="ace_button" title="Search In Selection">S</span>\
|
||||
</div>\
|
||||
</div>'.replace(/> +/g, ">");
|
||||
|
||||
var SearchBox = function(editor, range, showReplaceForm) {
|
||||
var div = dom.createElement("div");
|
||||
div.innerHTML = html;
|
||||
dom.buildDom(["div", {class:"ace_search right"},
|
||||
["span", {action: "hide", class: "ace_searchbtn_close"}],
|
||||
["div", {class: "ace_search_form"},
|
||||
["input", {class: "ace_search_field", placeholder: "Search for", spellcheck: "false"}],
|
||||
["span", {action: "findPrev", class: "ace_searchbtn prev"}, "\u200b"],
|
||||
["span", {action: "findNext", class: "ace_searchbtn next"}, "\u200b"],
|
||||
["span", {action: "findAll", class: "ace_searchbtn", title: "Alt-Enter"}, "All"]
|
||||
],
|
||||
["div", {class: "ace_replace_form"},
|
||||
["input", {class: "ace_search_field", placeholder: "Replace with", spellcheck: "false"}],
|
||||
["span", {action: "replaceAndFindNext", class: "ace_searchbtn"}, "Replace"],
|
||||
["span", {action: "replaceAll", class: "ace_searchbtn"}, "All"]
|
||||
],
|
||||
["div", {class: "ace_search_options"},
|
||||
["span", {action: "toggleReplace", class: "ace_button", title: "Toggle Replace mode",
|
||||
style: "float:left;margin-top:-2px;padding:0 5px;"}, "+"],
|
||||
["span", {class: "ace_search_counter"}],
|
||||
["span", {action: "toggleRegexpMode", class: "ace_button", title: "RegExp Search"}, ".*"],
|
||||
["span", {action: "toggleCaseSensitive", class: "ace_button", title: "CaseSensitive Search"}, "Aa"],
|
||||
["span", {action: "toggleWholeWords", class: "ace_button", title: "Whole Word Search"}, "\\b"],
|
||||
["span", {action: "searchInSelection", class: "ace_button", title: "Search In Selection"}, "S"]
|
||||
]
|
||||
], div);
|
||||
this.element = div.firstChild;
|
||||
|
||||
this.setSession = this.setSession.bind(this);
|
||||
|
||||
this.$init();
|
||||
this.setEditor(editor);
|
||||
dom.importCssString(searchboxCss, "ace_searchbox", editor.container);
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
@ -205,10 +204,9 @@ var SearchBox = function(editor, range, showReplaceForm) {
|
|||
};
|
||||
|
||||
this.setSession = function(e) {
|
||||
debugger
|
||||
this.searchRange = null;
|
||||
this.$syncOptions(true);
|
||||
}
|
||||
};
|
||||
|
||||
this.$initElements = function(sb) {
|
||||
this.searchBox = sb.querySelector(".ace_search_form");
|
||||
|
@ -287,6 +285,8 @@ var SearchBox = function(editor, range, showReplaceForm) {
|
|||
sb.searchInput.focus();
|
||||
},
|
||||
"Ctrl-H|Command-Option-F": function(sb) {
|
||||
if (sb.editor.getReadOnly())
|
||||
return;
|
||||
sb.replaceOption.checked = true;
|
||||
sb.$syncOptions();
|
||||
sb.replaceInput.focus();
|
||||
|
@ -364,7 +364,7 @@ var SearchBox = function(editor, range, showReplaceForm) {
|
|||
this.editor.session.removeMarker(this.searchRangeMarker);
|
||||
this.searchRangeMarker = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.$syncOptions = function(preventScroll) {
|
||||
dom.setCssClass(this.replaceOption, "checked", this.searchRange);
|
||||
|
@ -373,13 +373,15 @@ var SearchBox = function(editor, range, showReplaceForm) {
|
|||
dom.setCssClass(this.regExpOption, "checked", this.regExpOption.checked);
|
||||
dom.setCssClass(this.wholeWordOption, "checked", this.wholeWordOption.checked);
|
||||
dom.setCssClass(this.caseSensitiveOption, "checked", this.caseSensitiveOption.checked);
|
||||
this.replaceBox.style.display = this.replaceOption.checked ? "" : "none";
|
||||
var readOnly = this.editor.getReadOnly();
|
||||
this.replaceOption.style.display = readOnly ? "none" : "";
|
||||
this.replaceBox.style.display = this.replaceOption.checked && !readOnly ? "" : "none";
|
||||
this.find(false, false, preventScroll);
|
||||
};
|
||||
|
||||
this.highlight = function(re) {
|
||||
this.editor.session.highlight(re || this.editor.$search.$options.re);
|
||||
this.editor.renderer.updateBackMarkers()
|
||||
this.editor.renderer.updateBackMarkers();
|
||||
};
|
||||
this.find = function(skipCurrent, backwards, preventScroll) {
|
||||
var range = this.editor.find(this.searchInput.value, {
|
||||
|
@ -402,7 +404,7 @@ var SearchBox = function(editor, range, showReplaceForm) {
|
|||
var editor = this.editor;
|
||||
var regex = editor.$search.$options.re;
|
||||
var all = 0;
|
||||
var before = 0
|
||||
var before = 0;
|
||||
if (regex) {
|
||||
var value = this.searchRange
|
||||
? editor.session.getTextRange(this.searchRange)
|
||||
|
@ -420,7 +422,7 @@ var SearchBox = function(editor, range, showReplaceForm) {
|
|||
if (last <= offset)
|
||||
before++;
|
||||
if (all > MAX_COUNT)
|
||||
break
|
||||
break;
|
||||
if (!m[0]) {
|
||||
regex.lastIndex = last += 1;
|
||||
if (last >= value.length)
|
||||
|
@ -455,7 +457,7 @@ var SearchBox = function(editor, range, showReplaceForm) {
|
|||
this.replaceAndFindNext = function() {
|
||||
if (!this.editor.getReadOnly()) {
|
||||
this.editor.replace(this.replaceInput.value);
|
||||
this.findNext()
|
||||
this.findNext();
|
||||
}
|
||||
};
|
||||
this.replaceAll = function() {
|
||||
|
@ -465,7 +467,7 @@ var SearchBox = function(editor, range, showReplaceForm) {
|
|||
|
||||
this.hide = function() {
|
||||
this.active = false;
|
||||
this.setSearchRange(null)
|
||||
this.setSearchRange(null);
|
||||
this.editor.off("changeSession", this.setSession);
|
||||
|
||||
this.element.style.display = "none";
|
||||
|
@ -492,7 +494,7 @@ var SearchBox = function(editor, range, showReplaceForm) {
|
|||
this.isFocused = function() {
|
||||
var el = document.activeElement;
|
||||
return el == this.searchInput || el == this.replaceInput;
|
||||
}
|
||||
};
|
||||
}).call(SearchBox.prototype);
|
||||
|
||||
exports.SearchBox = SearchBox;
|
||||
|
@ -502,8 +504,11 @@ exports.Search = function(editor, isReplace) {
|
|||
sb.show(editor.session.getTextRange(), isReplace);
|
||||
};
|
||||
|
||||
});
|
||||
(function() {
|
||||
window.require(["ace/ext/searchbox"], function() {});
|
||||
}); (function() {
|
||||
window.require(["ace/ext/searchbox"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
@ -18,7 +18,7 @@ oop.inherits(Occur, Search);
|
|||
var translatedPos = this.originalToOccurPosition(editor.session, pos);
|
||||
editor.moveCursorToPosition(translatedPos);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
this.exit = function(editor, options) {
|
||||
var pos = options.translatePosition && editor.getCursorPosition();
|
||||
var translatedPos = pos && this.occurToOriginalPosition(editor.session, pos);
|
||||
|
@ -26,14 +26,14 @@ oop.inherits(Occur, Search);
|
|||
if (translatedPos)
|
||||
editor.moveCursorToPosition(translatedPos);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
this.highlight = function(sess, regexp) {
|
||||
var hl = sess.$occurHighlight = sess.$occurHighlight || sess.addDynamicMarker(
|
||||
new SearchHighlight(null, "ace_occur-highlight", "text"));
|
||||
hl.setRegexp(regexp);
|
||||
sess._emit("changeBackMarker"); // force highlight layer redraw
|
||||
}
|
||||
};
|
||||
|
||||
this.displayOccurContent = function(editor, options) {
|
||||
this.$originalSession = editor.session;
|
||||
|
@ -47,12 +47,12 @@ oop.inherits(Occur, Search);
|
|||
occurSession.$useEmacsStyleLineStart = this.$useEmacsStyleLineStart;
|
||||
this.highlight(occurSession, options.re);
|
||||
occurSession._emit('changeBackMarker');
|
||||
}
|
||||
};
|
||||
|
||||
this.displayOriginalContent = function(editor) {
|
||||
editor.setSession(this.$originalSession);
|
||||
this.$originalSession.$useEmacsStyleLineStart = this.$useEmacsStyleLineStart;
|
||||
}
|
||||
};
|
||||
this.originalToOccurPosition = function(session, pos) {
|
||||
var lines = session.$occurMatchingLines;
|
||||
var nullPos = {row: 0, column: 0};
|
||||
|
@ -62,13 +62,13 @@ oop.inherits(Occur, Search);
|
|||
return {row: i, column: pos.column};
|
||||
}
|
||||
return nullPos;
|
||||
}
|
||||
};
|
||||
this.occurToOriginalPosition = function(session, pos) {
|
||||
var lines = session.$occurMatchingLines;
|
||||
if (!lines || !lines[pos.row])
|
||||
return pos;
|
||||
return {row: lines[pos.row].row, column: pos.column};
|
||||
}
|
||||
};
|
||||
|
||||
this.matchingLines = function(session, options) {
|
||||
options = oop.mixin({}, options);
|
||||
|
@ -82,7 +82,7 @@ oop.inherits(Occur, Search);
|
|||
lines :
|
||||
lines.concat({row: row, content: session.getLine(row)});
|
||||
}, []);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(Occur.prototype);
|
||||
|
||||
|
@ -92,8 +92,6 @@ dom.importCssString(".ace_occur-highlight {\n\
|
|||
background-color: rgba(87, 255, 8, 0.25);\n\
|
||||
position: absolute;\n\
|
||||
z-index: 4;\n\
|
||||
-moz-box-sizing: border-box;\n\
|
||||
-webkit-box-sizing: border-box;\n\
|
||||
box-sizing: border-box;\n\
|
||||
box-shadow: 0 0 4px rgb(91, 255, 50);\n\
|
||||
}\n\
|
||||
|
@ -158,13 +156,13 @@ oop.inherits(OccurKeyboardHandler, HashHandler);
|
|||
this.attach = function(editor) {
|
||||
HashHandler.call(this, occurCommands, editor.commands.platform);
|
||||
this.$editor = editor;
|
||||
}
|
||||
};
|
||||
|
||||
var handleKeyboard$super = this.handleKeyboard;
|
||||
this.handleKeyboard = function(data, hashId, key, keyCode) {
|
||||
var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode);
|
||||
return (cmd && cmd.command) ? cmd : undefined;
|
||||
}
|
||||
};
|
||||
|
||||
}).call(OccurKeyboardHandler.prototype);
|
||||
|
||||
|
@ -172,14 +170,14 @@ OccurKeyboardHandler.installIn = function(editor) {
|
|||
var handler = new this();
|
||||
editor.keyBinding.addKeyboardHandler(handler);
|
||||
editor.commands.addCommands(occurCommands);
|
||||
}
|
||||
};
|
||||
|
||||
OccurKeyboardHandler.uninstallFrom = function(editor) {
|
||||
editor.commands.removeCommands(occurCommands);
|
||||
var handler = editor.getKeyboardHandler();
|
||||
if (handler.isOccurHandler)
|
||||
editor.keyBinding.removeKeyboardHandler(handler);
|
||||
}
|
||||
};
|
||||
|
||||
exports.occurStartCommand = occurStartCommand;
|
||||
|
||||
|
@ -393,7 +391,7 @@ function regExpToObject(re) {
|
|||
return {
|
||||
expression: string.slice(start+1, flagStart),
|
||||
flags: string.slice(flagStart+1)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function stringToRegExp(string, flags) {
|
||||
|
@ -565,8 +563,6 @@ dom.importCssString && dom.importCssString("\
|
|||
.ace_marker-layer .ace_isearch-result {\
|
||||
position: absolute;\
|
||||
z-index: 6;\
|
||||
-moz-box-sizing: border-box;\
|
||||
-webkit-box-sizing: border-box;\
|
||||
box-sizing: border-box;\
|
||||
}\
|
||||
div.ace_isearch-result {\
|
||||
|
@ -612,19 +608,6 @@ require("../incremental_search");
|
|||
var iSearchCommandModule = require("../commands/incremental_search_commands");
|
||||
|
||||
|
||||
var screenToTextBlockCoordinates = function(x, y) {
|
||||
var canvasPos = this.scroller.getBoundingClientRect();
|
||||
|
||||
var col = Math.floor(
|
||||
(x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth
|
||||
);
|
||||
var row = Math.floor(
|
||||
(y + this.scrollTop - canvasPos.top) / this.lineHeight
|
||||
);
|
||||
|
||||
return this.session.screenToDocumentPosition(row, col);
|
||||
};
|
||||
|
||||
var HashHandler = require("./hash_handler").HashHandler;
|
||||
exports.handler = new HashHandler();
|
||||
|
||||
|
@ -641,8 +624,6 @@ exports.handler.attach = function(editor) {
|
|||
dom.importCssString('\
|
||||
.emacs-mode .ace_cursor{\
|
||||
border: 1px rgba(50,250,50,0.8) solid!important;\
|
||||
-moz-box-sizing: border-box!important;\
|
||||
-webkit-box-sizing: border-box!important;\
|
||||
box-sizing: border-box!important;\
|
||||
background-color: rgba(0,250,0,0.9);\
|
||||
opacity: 0.5;\
|
||||
|
@ -712,11 +693,11 @@ exports.handler.attach = function(editor) {
|
|||
replacement : undefined);
|
||||
}
|
||||
return lastMark;
|
||||
}
|
||||
};
|
||||
|
||||
editor.on("click", $resetMarkMode);
|
||||
editor.on("changeSession", $kbSessionChange);
|
||||
editor.renderer.screenToTextCoordinates = screenToTextBlockCoordinates;
|
||||
editor.renderer.$blockCursor = true;
|
||||
editor.setStyle("emacs-mode");
|
||||
editor.commands.addCommands(commands);
|
||||
exports.handler.platform = editor.commands.platform;
|
||||
|
@ -726,7 +707,7 @@ exports.handler.attach = function(editor) {
|
|||
};
|
||||
|
||||
exports.handler.detach = function(editor) {
|
||||
delete editor.renderer.screenToTextCoordinates;
|
||||
editor.renderer.$blockCursor = false;
|
||||
editor.session.$selectLongWords = $formerLongWords;
|
||||
editor.session.$useEmacsStyleLineStart = $formerLineStart;
|
||||
editor.removeEventListener("click", $resetMarkMode);
|
||||
|
@ -809,7 +790,7 @@ exports.handler.getStatusText = function(editor, data) {
|
|||
if (data.count)
|
||||
str += data.count;
|
||||
if (data.keyChain)
|
||||
str += " " + data.keyChain
|
||||
str += " " + data.keyChain;
|
||||
return str;
|
||||
};
|
||||
|
||||
|
@ -871,7 +852,7 @@ exports.handler.handleKeyboard = function(data, hashId, key, keyCode) {
|
|||
data.lastCommand = null;
|
||||
|
||||
if (!command.readOnly && editor.emacsMark())
|
||||
editor.setEmacsMark(null)
|
||||
editor.setEmacsMark(null);
|
||||
|
||||
if (data.count) {
|
||||
var count = data.count;
|
||||
|
@ -1068,7 +1049,7 @@ exports.handler.addCommands({
|
|||
var range = editor.getSelectionRange();
|
||||
var line = editor.session.getLine(range.start.row);
|
||||
range.end.column = line.length;
|
||||
line = line.substr(range.start.column)
|
||||
line = line.substr(range.start.column);
|
||||
|
||||
var foldLine = editor.session.getFoldLine(range.start.row);
|
||||
if (foldLine && range.end.row != foldLine.end.row) {
|
||||
|
@ -1128,6 +1109,7 @@ exports.handler.addCommands({
|
|||
editor.$handlesEmacsOnCopy = false;
|
||||
if (editor.inMultiSelectMode) editor.forEachSelection({exec: deselect});
|
||||
else deselect();
|
||||
editor.setEmacsMark(null);
|
||||
editor.session.$emacsMarkRing = marks.concat(deselectedMarks.reverse());
|
||||
}, 0);
|
||||
},
|
||||
|
@ -1178,4 +1160,11 @@ exports.killRing = {
|
|||
}
|
||||
};
|
||||
|
||||
});
|
||||
}); (function() {
|
||||
window.require(["ace/keyboard/emacs"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -102,4 +102,11 @@ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgb
|
|||
|
||||
var dom = require("../lib/dom");
|
||||
dom.importCssString(exports.cssText, exports.cssClass);
|
||||
});
|
||||
}); (function() {
|
||||
window.require(["ace/theme/monokai"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
@ -134,7 +134,7 @@ window.define = function(id, deps, factory) {
|
|||
exports: {},
|
||||
factory: function() {
|
||||
var module = this;
|
||||
var returnExports = factory.apply(this, deps.map(function(dep) {
|
||||
var returnExports = factory.apply(this, deps.slice(0, factory.length).map(function(dep) {
|
||||
switch (dep) {
|
||||
// Because "require", "exports" and "module" aren't actual
|
||||
// dependencies, we must handle them seperately.
|
||||
|
@ -217,7 +217,7 @@ window.onmessage = function(e) {
|
|||
};
|
||||
})(this);
|
||||
|
||||
define("ace/lib/oop",["require","exports","module"], function(require, exports, module) {
|
||||
define("ace/lib/oop",[], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
exports.inherits = function(ctor, superCtor) {
|
||||
|
@ -245,7 +245,7 @@ exports.implement = function(proto, mixin) {
|
|||
|
||||
});
|
||||
|
||||
define("ace/range",["require","exports","module"], function(require, exports, module) {
|
||||
define("ace/range",[], function(require, exports, module) {
|
||||
"use strict";
|
||||
var comparePoints = function(p1, p2) {
|
||||
return p1.row - p2.row || p1.column - p2.column;
|
||||
|
@ -484,7 +484,7 @@ Range.comparePoints = function(p1, p2) {
|
|||
exports.Range = Range;
|
||||
});
|
||||
|
||||
define("ace/apply_delta",["require","exports","module"], function(require, exports, module) {
|
||||
define("ace/apply_delta",[], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
function throwDeltaError(delta, errorText){
|
||||
|
@ -549,7 +549,7 @@ exports.applyDelta = function(docLines, delta, doNotValidate) {
|
|||
};
|
||||
});
|
||||
|
||||
define("ace/lib/event_emitter",["require","exports","module"], function(require, exports, module) {
|
||||
define("ace/lib/event_emitter",[], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EventEmitter = {};
|
||||
|
@ -599,10 +599,15 @@ EventEmitter._signal = function(eventName, e) {
|
|||
|
||||
EventEmitter.once = function(eventName, callback) {
|
||||
var _self = this;
|
||||
callback && this.addEventListener(eventName, function newCallback() {
|
||||
this.addEventListener(eventName, function newCallback() {
|
||||
_self.removeEventListener(eventName, newCallback);
|
||||
callback.apply(null, arguments);
|
||||
});
|
||||
if (!callback) {
|
||||
return new Promise(function(resolve) {
|
||||
callback = resolve;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -630,7 +635,6 @@ EventEmitter.removeDefaultHandler = function(eventName, callback) {
|
|||
var disabled = handlers._disabled_[eventName];
|
||||
|
||||
if (handlers[eventName] == callback) {
|
||||
var old = handlers[eventName];
|
||||
if (disabled)
|
||||
this.setDefaultHandler(eventName, disabled.pop());
|
||||
} else if (disabled) {
|
||||
|
@ -675,7 +679,7 @@ exports.EventEmitter = EventEmitter;
|
|||
|
||||
});
|
||||
|
||||
define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) {
|
||||
define("ace/anchor",[], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
|
@ -800,7 +804,7 @@ var Anchor = exports.Anchor = function(doc, row, column) {
|
|||
|
||||
});
|
||||
|
||||
define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) {
|
||||
define("ace/document",[], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
|
@ -1091,28 +1095,23 @@ var Document = function(textOrLines) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (isInsert && delta.lines.length > 20000)
|
||||
if (isInsert && delta.lines.length > 20000) {
|
||||
this.$splitAndapplyLargeDelta(delta, 20000);
|
||||
applyDelta(this.$lines, delta, doNotValidate);
|
||||
this._signal("change", delta);
|
||||
}
|
||||
else {
|
||||
applyDelta(this.$lines, delta, doNotValidate);
|
||||
this._signal("change", delta);
|
||||
}
|
||||
};
|
||||
|
||||
this.$splitAndapplyLargeDelta = function(delta, MAX) {
|
||||
var lines = delta.lines;
|
||||
var l = lines.length;
|
||||
var l = lines.length - MAX + 1;
|
||||
var row = delta.start.row;
|
||||
var column = delta.start.column;
|
||||
var from = 0, to = 0;
|
||||
do {
|
||||
from = to;
|
||||
for (var from = 0, to = 0; from < l; from = to) {
|
||||
to += MAX - 1;
|
||||
var chunk = lines.slice(from, to);
|
||||
if (to > l) {
|
||||
delta.lines = chunk;
|
||||
delta.start.row = row + from;
|
||||
delta.start.column = column;
|
||||
break;
|
||||
}
|
||||
chunk.push("");
|
||||
this.applyDelta({
|
||||
start: this.pos(row + from, column),
|
||||
|
@ -1120,7 +1119,11 @@ var Document = function(textOrLines) {
|
|||
action: delta.action,
|
||||
lines: chunk
|
||||
}, true);
|
||||
} while(true);
|
||||
}
|
||||
delta.lines = lines.slice(from);
|
||||
delta.start.row = row + from;
|
||||
delta.start.column = column;
|
||||
this.applyDelta(delta, true);
|
||||
};
|
||||
this.revertDelta = function(delta) {
|
||||
this.applyDelta({
|
||||
|
@ -1138,7 +1141,7 @@ var Document = function(textOrLines) {
|
|||
if (index < 0)
|
||||
return {row: i, column: index + lines[i].length + newlineLength};
|
||||
}
|
||||
return {row: l-1, column: lines[l-1].length};
|
||||
return {row: l-1, column: index + lines[l-1].length + newlineLength};
|
||||
};
|
||||
this.positionToIndex = function(pos, startRow) {
|
||||
var lines = this.$lines || this.getAllLines();
|
||||
|
@ -1156,7 +1159,7 @@ var Document = function(textOrLines) {
|
|||
exports.Document = Document;
|
||||
});
|
||||
|
||||
define("ace/lib/lang",["require","exports","module"], function(require, exports, module) {
|
||||
define("ace/lib/lang",[], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
exports.last = function(a) {
|
||||
|
@ -1258,7 +1261,7 @@ exports.escapeRegExp = function(str) {
|
|||
};
|
||||
|
||||
exports.escapeHTML = function(str) {
|
||||
return str.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<");
|
||||
return ("" + str).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<");
|
||||
};
|
||||
|
||||
exports.getMatchOffsets = function(string, regExp) {
|
||||
|
@ -1344,7 +1347,7 @@ exports.delayedCall = function(fcn, defaultTimeout) {
|
|||
};
|
||||
});
|
||||
|
||||
define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"], function(require, exports, module) {
|
||||
define("ace/worker/mirror",[], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var Range = require("../range").Range;
|
||||
|
@ -1406,7 +1409,7 @@ var Mirror = exports.Mirror = function(sender) {
|
|||
|
||||
});
|
||||
|
||||
define("ace/mode/javascript/jshint",["require","exports","module"], function(require, exports, module) {
|
||||
define("ace/mode/javascript/jshint",[], function(require, exports, module) {
|
||||
module.exports = (function outer (modules, cache, entry) {
|
||||
var previousRequire = typeof require == "function" && require;
|
||||
function newRequire(name, jumped){
|
||||
|
@ -11683,7 +11686,7 @@ exports.jasmine = {
|
|||
|
||||
});
|
||||
|
||||
define("ace/mode/javascript_worker",["require","exports","module","ace/lib/oop","ace/worker/mirror","ace/mode/javascript/jshint"], function(require, exports, module) {
|
||||
define("ace/mode/javascript_worker",[], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
|
@ -11830,7 +11833,7 @@ oop.inherits(JavaScriptWorker, Mirror);
|
|||
|
||||
});
|
||||
|
||||
define("ace/lib/es5-shim",["require","exports","module"], function(require, exports, module) {
|
||||
define("ace/lib/es5-shim",[], function(require, exports, module) {
|
||||
|
||||
function Empty() {}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
import FilePicker from 'zotero/filePicker';
|
||||
|
||||
var Zotero = Components.classes["@zotero.org/Zotero;1"]
|
||||
// Currently uses only nsISupports
|
||||
|
@ -70,7 +71,7 @@ var Scaffold = new function() {
|
|||
'textbox-hidden-prefs':'hiddenPrefs'
|
||||
};
|
||||
|
||||
this.onLoad = function (e) {
|
||||
this.onLoad = async function (e) {
|
||||
if(e.target !== document) return;
|
||||
_document = document;
|
||||
|
||||
|
@ -145,7 +146,7 @@ var Scaffold = new function() {
|
|||
}
|
||||
|
||||
if (!Scaffold_Translators.getDirectory()) {
|
||||
if (!this.promptForTranslatorsDirectory()) {
|
||||
if (!await this.promptForTranslatorsDirectory()) {
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
|
@ -155,7 +156,7 @@ var Scaffold = new function() {
|
|||
_translatorProvider = Scaffold_Translators.getProvider();
|
||||
};
|
||||
|
||||
this.promptForTranslatorsDirectory = function () {
|
||||
this.promptForTranslatorsDirectory = async function () {
|
||||
var ps = Services.prompt;
|
||||
var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING
|
||||
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_IS_STRING
|
||||
|
@ -171,7 +172,7 @@ var Scaffold = new function() {
|
|||
);
|
||||
// Revert to home directory
|
||||
if (index == 0) {
|
||||
let dir = this.setTranslatorsDirectory();
|
||||
let dir = await this.setTranslatorsDirectory();
|
||||
if (dir) {
|
||||
return true;
|
||||
}
|
||||
|
@ -182,23 +183,22 @@ var Scaffold = new function() {
|
|||
return false;
|
||||
};
|
||||
|
||||
this.setTranslatorsDirectory = function () {
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
|
||||
this.setTranslatorsDirectory = async function () {
|
||||
var fp = new FilePicker();
|
||||
var oldPath = Zotero.Prefs.get('scaffold.translatorsDir');
|
||||
if (oldPath) {
|
||||
fp.displayDirectory = Zotero.File.pathToFile(oldPath);
|
||||
fp.displayDirectory = oldPath;
|
||||
}
|
||||
fp.init(
|
||||
window,
|
||||
"Select Translators Directory",
|
||||
nsIFilePicker.modeGetFolder
|
||||
fp.modeGetFolder
|
||||
);
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
if (fp.show() != nsIFilePicker.returnOK) {
|
||||
fp.appendFilters(fp.filterAll);
|
||||
if (await fp.show() != fp.returnOK) {
|
||||
return false;
|
||||
}
|
||||
var path = OS.Path.normalize(fp.file.path);
|
||||
var path = OS.Path.normalize(fp.file);
|
||||
if (oldPath == path) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -190,7 +190,7 @@
|
|||
</menupopup>
|
||||
</toolbarbutton>
|
||||
</hbox>
|
||||
<iframe src="data:text/html,%3C!DOCTYPE%20html%20PUBLIC%20%22-//W3C//DTD%20XHTML%201.1//EN%22%20%22http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd%22%3E%3Chtml%20xmlns=%22http://www.w3.org/1999/xhtml%22%3E%3Chead%3E%3Cscript%20type=%22text/javascript%22%20src=%22chrome://scaffold/content/ace/ace.js%22%3E%3C/script%3E%3Cscript%20type=%22text/javascript%22%20src=%22chrome://scaffold/content/ace/mode-javascript.js%22%3E%3C/script%3E%3Cscript%20type=%22text/javascript%22%20src=%22chrome://scaffold/content/aceWrapper.js%22%3E%3C/script%3E%3C/head%3E%3Cbody%20id=%22body%22%3E%3C/body%3E%3C/html%3E" id="editor-code" flex="1"/>
|
||||
<iframe src="chrome://scaffold/content/ace/ace.html" id="editor-code" flex="1"/>
|
||||
<hbox id="editor-external-box" align="center">
|
||||
<checkbox id="checkbox-editor-external"/>
|
||||
<label class="label-metadata" value="&scaffold.editor.external.label;" control="checkbox-editor-external"/>
|
||||
|
@ -198,10 +198,10 @@
|
|||
</vbox>
|
||||
</tabpanel>
|
||||
<tabpanel flex="1" id="tabpanel-import">
|
||||
<iframe src="data:text/html,%3C!DOCTYPE%20html%20PUBLIC%20%22-//W3C//DTD%20XHTML%201.1//EN%22%20%22http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd%22%3E%3Chtml%20xmlns=%22http://www.w3.org/1999/xhtml%22%3E%3Chead%3E%3Cscript%20type=%22text/javascript%22%20src=%22chrome://scaffold/content/ace/ace.js%22%3E%3C/script%3E%3Cscript%20type=%22text/javascript%22%20src=%22chrome://scaffold/content/ace/mode-javascript.js%22%3E%3C/script%3E%3Cscript%20type=%22text/javascript%22%20src=%22chrome://scaffold/content/aceWrapper.js%22%3E%3C/script%3E%3C/head%3E%3Cbody%20id=%22body%22%3E%3C/body%3E%3C/html%3E" id="editor-import" flex="1"/>
|
||||
<iframe src="chrome://scaffold/content/ace/ace.html" id="editor-import" flex="1"/>
|
||||
</tabpanel>
|
||||
<tabpanel flex="1" id="tabpanel-tests">
|
||||
<iframe src="data:text/html,%3C!DOCTYPE%20html%20PUBLIC%20%22-//W3C//DTD%20XHTML%201.1//EN%22%20%22http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd%22%3E%3Chtml%20xmlns=%22http://www.w3.org/1999/xhtml%22%3E%3Chead%3E%3Cscript%20type=%22text/javascript%22%20src=%22chrome://scaffold/content/ace/ace.js%22%3E%3C/script%3E%3Cscript%20type=%22text/javascript%22%20src=%22chrome://scaffold/content/ace/mode-javascript.js%22%3E%3C/script%3E%3Cscript%20type=%22text/javascript%22%20src=%22chrome://scaffold/content/aceWrapper.js%22%3E%3C/script%3E%3C/head%3E%3Cbody%20id=%22body%22%3E%3C/body%3E%3C/html%3E" id="editor-tests" flex="1"/>
|
||||
<iframe src="chrome://scaffold/content/ace/ace.html" id="editor-tests" flex="1"/>
|
||||
</tabpanel>
|
||||
<tabpanel flex="1" id="tabpanel-testing">
|
||||
<vbox flex="1"><hbox><description>&scaffold.testing.description;</description></hbox>
|
||||
|
|
|
@ -22,52 +22,46 @@ var Scaffold_Translators = {
|
|||
var dir = this.getDirectory();
|
||||
var numLoaded = 0;
|
||||
var deletedTranslators = new Set(this._translatorFiles.keys());
|
||||
await Zotero.File.iterateDirectory(dir, function* (iterator) {
|
||||
while (true) {
|
||||
let entries = yield iterator.nextBatch(50);
|
||||
if (!entries.length) break;
|
||||
for (let entry of entries) {
|
||||
if (entry.isDir || entry.name.startsWith('.') || !entry.name.endsWith('.js')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
deletedTranslators.delete(entry.name);
|
||||
|
||||
try {
|
||||
let fmtime;
|
||||
if ('winLastWriteDate' in entry) {
|
||||
fmtime = entry.winLastWriteDate.getTime();
|
||||
}
|
||||
else {
|
||||
fmtime = (yield OS.File.stat(entry.path)).lastModificationDate.getTime();
|
||||
}
|
||||
let translatorID = this._translatorFiles.get(entry.name);
|
||||
let loadFile = true;
|
||||
// If translator is already loaded, see if mtime has changed
|
||||
if (translatorID) {
|
||||
let mtime = this._translators.get(translatorID).mtime;
|
||||
if (mtime == fmtime) {
|
||||
loadFile = false;
|
||||
}
|
||||
}
|
||||
if (loadFile) {
|
||||
let translator = yield Zotero.Translators.loadFromFile(entry.path);
|
||||
this._translators.set(
|
||||
translator.translatorID,
|
||||
{
|
||||
translator,
|
||||
filename: entry.name,
|
||||
mtime: fmtime,
|
||||
}
|
||||
);
|
||||
this._translatorFiles.set(entry.name, translator.translatorID);
|
||||
numLoaded++;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
await Zotero.File.iterateDirectory(dir, async function (entry) {
|
||||
if (entry.isDir || entry.name.startsWith('.') || !entry.name.endsWith('.js')) {
|
||||
return;
|
||||
}
|
||||
|
||||
deletedTranslators.delete(entry.name);
|
||||
|
||||
try {
|
||||
let fmtime;
|
||||
if ('winLastWriteDate' in entry) {
|
||||
fmtime = entry.winLastWriteDate.getTime();
|
||||
}
|
||||
else {
|
||||
fmtime = (await OS.File.stat(entry.path)).lastModificationDate.getTime();
|
||||
}
|
||||
let translatorID = this._translatorFiles.get(entry.name);
|
||||
let loadFile = true;
|
||||
// If translator is already loaded, see if mtime has changed
|
||||
if (translatorID) {
|
||||
let mtime = this._translators.get(translatorID).mtime;
|
||||
if (mtime == fmtime) {
|
||||
loadFile = false;
|
||||
}
|
||||
}
|
||||
if (loadFile) {
|
||||
let translator = await Zotero.Translators.loadFromFile(entry.path);
|
||||
this._translators.set(
|
||||
translator.translatorID,
|
||||
{
|
||||
translator,
|
||||
filename: entry.name,
|
||||
mtime: fmtime,
|
||||
}
|
||||
);
|
||||
this._translatorFiles.set(entry.name, translator.translatorID);
|
||||
numLoaded++;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
#zotero-splitter
|
||||
{
|
||||
border-top: none;
|
||||
border-bottom: 1px solid #A3A3A3;
|
||||
min-height: 1px !important;
|
||||
max-height: 1px !important;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
#zotero-items-toolbar[state=collapsed]
|
||||
{
|
||||
margin-left: -8px !important;
|
||||
|
@ -107,11 +98,6 @@
|
|||
padding: 2px 0px 2px 8px !important;
|
||||
}
|
||||
|
||||
#zotero-close-button {
|
||||
margin: 0px !important;
|
||||
padding: 0px 0px 0px 10px !important;
|
||||
}
|
||||
|
||||
#zotero-tb-sync {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
BIN
chrome/content/zotero-platform/mac/panebutton-active.png
Normal file
BIN
chrome/content/zotero-platform/mac/panebutton-active.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 400 B |
BIN
chrome/content/zotero-platform/mac/panebutton-inactive.png
Normal file
BIN
chrome/content/zotero-platform/mac/panebutton-inactive.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 257 B |
138
chrome/content/zotero-platform/mac/preferences.css
Normal file
138
chrome/content/zotero-platform/mac/preferences.css
Normal file
|
@ -0,0 +1,138 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
prefwindow,
|
||||
prefwindow:root /* override :root from above */ {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-mac.xml#prefwindow");
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
prefpane {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-mac.xml#prefpane");
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
prefwindow > .paneDeckContainer {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
prefpane > .content-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] > .paneDeckContainer {
|
||||
overflow: -moz-hidden-unscrollable;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] > prefpane > .content-box {
|
||||
-moz-box-flex: 1;
|
||||
overflow: -moz-hidden-unscrollable;
|
||||
}
|
||||
|
||||
preferences {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-mac.xml#preferences");
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
preference {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-mac.xml#preference");
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
radio[pane] {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-mac.xml#panebutton") !important;
|
||||
-moz-box-orient: vertical;
|
||||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
prefwindow[chromehidden~="toolbar"] .chromeclass-toolbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
prefwindow {
|
||||
padding: 0;
|
||||
font: -moz-dialog !important;
|
||||
|
||||
-moz-appearance: dialog;
|
||||
color: -moz-DialogText;
|
||||
}
|
||||
|
||||
prefpane {
|
||||
padding: 12px 12px 0 12px;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] > prefpane {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.prefWindow-dlgbuttons {
|
||||
margin: 0 12px 12px;
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
.paneSelector {
|
||||
font: message-box;
|
||||
padding: 1px 4px;
|
||||
-moz-appearance: toolbar;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
radio[pane] {
|
||||
border: solid transparent;
|
||||
border-width: 0 2px;
|
||||
padding: 5px 4px 3px;
|
||||
margin: 0;
|
||||
-moz-appearance: none;
|
||||
text-shadow: rgba(255, 255, 255, 0.4) 0 1px;
|
||||
}
|
||||
|
||||
radio[pane]:active:hover {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
radio[pane]:active:hover > .paneButtonIcon {
|
||||
filter: brightness(0.55);
|
||||
}
|
||||
|
||||
radio[pane][selected="true"] {
|
||||
-moz-border-image: url("chrome://zotero-platform/content/panebutton-active.png") 0 2 fill repeat stretch;
|
||||
}
|
||||
|
||||
radio[pane][selected="true"]:-moz-window-inactive {
|
||||
-moz-border-image: url("chrome://zotero-platform/content/panebutton-inactive.png") 0 2 fill repeat stretch;
|
||||
}
|
||||
|
||||
.paneButtonLabel {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
groupbox {
|
||||
padding: 5px 1px 1px;
|
||||
padding-inline-start: 0;
|
||||
margin: 6px;
|
||||
}
|
||||
|
||||
.groupbox-title {
|
||||
border-bottom: #b5b5b5 1px solid;
|
||||
}
|
||||
|
||||
.groupbox-body {
|
||||
-moz-appearance: groupbox;
|
||||
padding: 8px 8px 3px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-inline-start: 4px;
|
||||
padding-bottom: 1px;
|
||||
font: caption;
|
||||
}
|
||||
|
||||
/* !important is needed to override label in global.css */
|
||||
.caption-text {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
margin-inline-start: 1px !important;
|
||||
}
|
|
@ -124,7 +124,7 @@
|
|||
</menupopup>
|
||||
</rule>
|
||||
</template>
|
||||
<menupopup id="menu_windowPopup">
|
||||
<menupopup id="windowPopup">
|
||||
<menuitem command="minimizeWindow" label="&minimizeWindow.label;" key="key_minimizeWindow"/>
|
||||
<menuitem command="zoomWindow" label="&zoomWindow.label;"/>
|
||||
<!-- decomment when "BringAllToFront" is implemented
|
||||
|
|
|
@ -61,9 +61,6 @@ tab {
|
|||
border-top: 1px solid hsla(0, 0%, 0%, 0.2);
|
||||
border-right: 1px solid hsla(0, 0%, 0%, 0.2);
|
||||
border-left: 1px solid hsla(0, 0%, 0%, 0.2);
|
||||
-moz-border-top-colors: none;
|
||||
-moz-border-right-colors: none;
|
||||
-moz-border-left-colors: none;
|
||||
}
|
||||
/* Fixes misc Ubuntu 16.10 rendering issue fixes. */
|
||||
#zotero-prefs menulist dropmarker{
|
||||
|
|
107
chrome/content/zotero-platform/unix/preferences.css
Normal file
107
chrome/content/zotero-platform/unix/preferences.css
Normal file
|
@ -0,0 +1,107 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
prefwindow,
|
||||
prefwindow:root /* override :root from above */ {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-unix.xml#prefwindow");
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
prefpane {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-unix.xml#prefpane");
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
prefwindow > .paneDeckContainer {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
prefpane > .content-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] > .paneDeckContainer {
|
||||
overflow: -moz-hidden-unscrollable;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] > prefpane > .content-box {
|
||||
-moz-box-flex: 1;
|
||||
overflow: -moz-hidden-unscrollable;
|
||||
}
|
||||
|
||||
preferences {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-unix.xml#preferences");
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
preference {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-unix.xml#preference");
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
radio[pane] {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-unix.xml#panebutton") !important;
|
||||
-moz-box-orient: vertical;
|
||||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
prefwindow[chromehidden~="toolbar"] .chromeclass-toolbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
prefwindow {
|
||||
padding: 0px;
|
||||
|
||||
-moz-appearance: window;
|
||||
background-color: -moz-Dialog;
|
||||
color: -moz-DialogText;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
prefpane {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] > prefpane {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.prefWindow-dlgbuttons {
|
||||
padding-bottom: 8px;
|
||||
padding-inline-start: 8px;
|
||||
padding-inline-end: 8px;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] .prefWindow-dlgbuttons {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
radio[pane] {
|
||||
-moz-appearance: none;
|
||||
min-width: 4.5em;
|
||||
margin: 0;
|
||||
padding: 3px;
|
||||
color: -moz-FieldText;
|
||||
}
|
||||
|
||||
.paneSelector {
|
||||
-moz-appearance: listbox;
|
||||
margin: 8px 8px 0 8px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.paneButtonIcon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
radio[pane][selected="true"] {
|
||||
background-color: Highlight;
|
||||
color: HighlightText;
|
||||
}
|
|
@ -105,10 +105,6 @@
|
|||
border-color: #818790;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-moz-border-top-colors: none;
|
||||
-moz-border-bottom-colors: none;
|
||||
-moz-border-right-colors: none;
|
||||
-moz-border-left-colors: none;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-twisty {
|
||||
|
|
121
chrome/content/zotero-platform/win/preferences.css
Normal file
121
chrome/content/zotero-platform/win/preferences.css
Normal file
|
@ -0,0 +1,121 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
prefwindow,
|
||||
prefwindow:root /* override :root from above */ {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-win.xml#prefwindow");
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
prefpane {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-win.xml#prefpane");
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
prefwindow > .paneDeckContainer {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
prefpane > .content-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] > .paneDeckContainer {
|
||||
overflow: -moz-hidden-unscrollable;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] > prefpane > .content-box {
|
||||
-moz-box-flex: 1;
|
||||
overflow: -moz-hidden-unscrollable;
|
||||
}
|
||||
|
||||
preferences {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-win.xml#preferences");
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
preference {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-win.xml#preference");
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
radio[pane] {
|
||||
-moz-binding: url("chrome://zotero/content/bindings/preferences-win.xml#panebutton") !important;
|
||||
-moz-box-orient: vertical;
|
||||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
prefwindow[chromehidden~="toolbar"] .chromeclass-toolbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
prefwindow {
|
||||
padding: 0px;
|
||||
|
||||
-moz-appearance: window;
|
||||
background-color: -moz-Dialog;
|
||||
color: -moz-DialogText;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
prefpane {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 10px;
|
||||
padding-inline-start: 8px;
|
||||
padding-inline-end: 10px;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 10px;
|
||||
padding-inline-start: 8px;
|
||||
padding-inline-end: 10px;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] > prefpane {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.prefWindow-dlgbuttons {
|
||||
padding-bottom: 10px;
|
||||
padding-inline-start: 8px;
|
||||
padding-inline-end: 10px;
|
||||
}
|
||||
|
||||
prefwindow[type="child"] .prefWindow-dlgbuttons {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
radio[pane] {
|
||||
-moz-appearance: none;
|
||||
margin: 0px 1px 0px 1px;
|
||||
padding: 1px 3px 1px 3px;
|
||||
min-width: 4.5em;
|
||||
}
|
||||
|
||||
.paneSelector {
|
||||
border-bottom: 2px groove ThreeDFace;
|
||||
margin: 0px;
|
||||
padding-inline-start: 10px;
|
||||
background-color: -moz-Field;
|
||||
color: -moz-FieldText;
|
||||
}
|
||||
|
||||
.paneButtonIcon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
radio[pane]:hover {
|
||||
background-color: #E0E8F6;
|
||||
color: black;
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
radio[pane][selected="true"] {
|
||||
background-color: #C1D2EE;
|
||||
color: black;
|
||||
-moz-appearance: none;
|
||||
}
|
|
@ -172,10 +172,6 @@ var ZoteroAdvancedSearch = new function() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (lastWin.ZoteroOverlay) {
|
||||
lastWin.ZoteroOverlay.toggleDisplay(true);
|
||||
}
|
||||
|
||||
lastWin.ZoteroPane.selectItem(item.getID(), false, true);
|
||||
lastWin.focus();
|
||||
}
|
||||
|
|
|
@ -387,9 +387,7 @@
|
|||
|
||||
if (fieldIsClickable
|
||||
&& !Zotero.Items.isPrimaryField(fieldName)
|
||||
&& (Zotero.ItemFields.isFieldOfBase(Zotero.ItemFields.getID(fieldName), 'date')
|
||||
// TEMP - filingDate
|
||||
|| fieldName == 'filingDate')
|
||||
&& Zotero.ItemFields.isDate(fieldName)
|
||||
// TEMP - NSF
|
||||
&& fieldName != 'dateSent') {
|
||||
this.addDateRow(fieldNames[i], this.item.getField(fieldName, true), tabindex);
|
||||
|
@ -414,7 +412,7 @@
|
|||
|
||||
if (fieldName) {
|
||||
label.setAttribute("value", prefix +
|
||||
Zotero.ItemFields.getLocalizedString(this.item.itemTypeID, fieldName));
|
||||
Zotero.ItemFields.getLocalizedString(fieldName));
|
||||
}
|
||||
|
||||
// TEMP - NSF (homepage)
|
||||
|
@ -897,7 +895,7 @@
|
|||
<body>
|
||||
<![CDATA[
|
||||
var label = document.createElement("label");
|
||||
label.setAttribute("value", Zotero.ItemFields.getLocalizedString(this.item.itemTypeID, field));
|
||||
label.setAttribute("value", Zotero.ItemFields.getLocalizedString(field));
|
||||
label.setAttribute("fieldname", field);
|
||||
label.setAttribute("onclick", "this.nextSibling.firstChild.blur()");
|
||||
|
||||
|
@ -1158,7 +1156,7 @@
|
|||
var fieldNames = "";
|
||||
for (var i=0; i<fieldsToDelete.length; i++) {
|
||||
fieldNames += "\n - " +
|
||||
Zotero.ItemFields.getLocalizedString(this.item.itemTypeID, fieldsToDelete[i]);
|
||||
Zotero.ItemFields.getLocalizedString(fieldsToDelete[i]);
|
||||
}
|
||||
|
||||
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
|
@ -1215,7 +1213,7 @@
|
|||
);
|
||||
valueElement.parentNode.replaceChild(newValueElement, valueElement);
|
||||
|
||||
var text = Zotero.ItemFields.getLocalizedString(this.item.itemTypeID, 'abstractNote');
|
||||
var text = Zotero.ItemFields.getLocalizedString('abstractNote');
|
||||
// Add '(...)' before "Abstract" for collapsed abstracts
|
||||
if (valueText && cur) {
|
||||
text = '(\u2026) ' + text;
|
||||
|
|
|
@ -511,10 +511,6 @@
|
|||
var lastWin = window.open();
|
||||
}
|
||||
|
||||
if (lastWin.ZoteroOverlay && !lastWin.ZoteroPane.isShowing()) {
|
||||
lastWin.ZoteroOverlay.toggleDisplay(true);
|
||||
}
|
||||
|
||||
var zp = lastWin.ZoteroPane;
|
||||
}
|
||||
|
||||
|
|
1358
chrome/content/zotero/bindings/preferences-mac.xml
Normal file
1358
chrome/content/zotero/bindings/preferences-mac.xml
Normal file
File diff suppressed because it is too large
Load diff
1358
chrome/content/zotero/bindings/preferences-unix.xml
Normal file
1358
chrome/content/zotero/bindings/preferences-unix.xml
Normal file
File diff suppressed because it is too large
Load diff
1358
chrome/content/zotero/bindings/preferences-win.xml
Normal file
1358
chrome/content/zotero/bindings/preferences-win.xml
Normal file
File diff suppressed because it is too large
Load diff
|
@ -644,14 +644,12 @@
|
|||
// for read-only mode
|
||||
var htmlFile = this.mode + (this.getAttribute('readonly') != 'true' ? "" : "view");
|
||||
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
var uri = ios.newURI("resource://zotero/tinymce/" + htmlFile + ".html", null, null);
|
||||
|
||||
// Pass directionality (LTR/RTL) and locale in URL
|
||||
uri.spec += "?locale=" + encodeURIComponent(Zotero.locale)
|
||||
var url = `resource://zotero/tinymce/${htmlFile}.html`
|
||||
// Pass directionality (LTR/RTL) and locale in URL
|
||||
+ "?locale=" + encodeURIComponent(Zotero.locale)
|
||||
+ "&dir=" + Zotero.dir;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
var uri = Services.io.newURI(url, null, null);
|
||||
|
||||
Zotero.debug("Loading " + uri.spec);
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
<body><![CDATA[
|
||||
return Zotero.spawn(function* () {
|
||||
if (type == 'setting') {
|
||||
if (ids.some(function (val) val.split("/")[1] == 'tagColors') && this.item) {
|
||||
if (ids.some(val => val.split("/")[1] == 'tagColors') && this.item) {
|
||||
this.reload();
|
||||
return;
|
||||
}
|
||||
|
@ -227,7 +227,7 @@
|
|||
|
||||
// Sort tags alphabetically
|
||||
var collation = Zotero.getLocaleCollation();
|
||||
tags.sort(function (a, b) collation.compareString(1, a.tag, b.tag));
|
||||
tags.sort((a, b) => collation.compareString(1, a.tag, b.tag));
|
||||
|
||||
for (let i=0; i<tags.length; i++) {
|
||||
this.addDynamicRow(tags[i], i+1);
|
||||
|
@ -682,7 +682,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
var tags = value.split(/\r\n?|\n/).map(function (val) val.trim());
|
||||
var tags = value.split(/\r\n?|\n/).map(val => val.trim());
|
||||
|
||||
// Modifying existing tag with a single new one
|
||||
if (!isNew && tags.length < 2) {
|
||||
|
|
|
@ -333,7 +333,7 @@
|
|||
if (!this.id(condition.name + '-tooltip')) {
|
||||
var fieldName = null;
|
||||
try {
|
||||
fieldName = Zotero.ItemFields.getLocalizedString(null, condition.name);
|
||||
fieldName = Zotero.ItemFields.getLocalizedString(condition.name);
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
background: white;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
header {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm")
|
||||
import FilePicker from 'zotero/filePicker';
|
||||
|
||||
/****Zotero_File_Exporter****
|
||||
**
|
||||
|
@ -44,9 +45,9 @@ var Zotero_File_Exporter = function() {
|
|||
*
|
||||
* @return {Promise}
|
||||
**/
|
||||
Zotero_File_Exporter.prototype.save = Zotero.Promise.coroutine(function* () {
|
||||
Zotero_File_Exporter.prototype.save = async function () {
|
||||
var translation = new Zotero.Translate.Export();
|
||||
var translators = yield translation.getTranslators();
|
||||
var translators = await translation.getTranslators();
|
||||
|
||||
// present options dialog
|
||||
var io = {translators:translators}
|
||||
|
@ -56,17 +57,15 @@ Zotero_File_Exporter.prototype.save = Zotero.Promise.coroutine(function* () {
|
|||
return false;
|
||||
}
|
||||
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString("fileInterface.export"), nsIFilePicker.modeSave);
|
||||
var fp = new FilePicker();
|
||||
fp.init(window, Zotero.getString("fileInterface.export"), fp.modeSave);
|
||||
|
||||
// set file name and extension
|
||||
if(io.displayOptions.exportFileData) {
|
||||
// if the result will be a folder, don't append any extension or use
|
||||
// filters
|
||||
fp.defaultString = this.name;
|
||||
fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
|
||||
fp.appendFilters(fp.filterAll);
|
||||
} else {
|
||||
// if the result will be a file, append an extension and use filters
|
||||
fp.defaultString = this.name+(io.selectedTranslator.target ? "."+io.selectedTranslator.target : "");
|
||||
|
@ -74,8 +73,8 @@ Zotero_File_Exporter.prototype.save = Zotero.Promise.coroutine(function* () {
|
|||
fp.appendFilter(io.selectedTranslator.label, "*."+(io.selectedTranslator.target ? io.selectedTranslator.target : "*"));
|
||||
}
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv != nsIFilePicker.returnOK && rv != nsIFilePicker.returnReplace) {
|
||||
var rv = await fp.show();
|
||||
if (rv != fp.returnOK && rv != fp.returnReplace) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -89,7 +88,7 @@ Zotero_File_Exporter.prototype.save = Zotero.Promise.coroutine(function* () {
|
|||
translation.setLibraryID(this.libraryID);
|
||||
}
|
||||
|
||||
translation.setLocation(fp.file);
|
||||
translation.setLocation(Zotero.File.pathToFile(fp.file));
|
||||
translation.setTranslator(io.selectedTranslator);
|
||||
translation.setDisplayOptions(io.displayOptions);
|
||||
translation.setHandler("itemDone", function () {
|
||||
|
@ -100,7 +99,7 @@ Zotero_File_Exporter.prototype.save = Zotero.Promise.coroutine(function* () {
|
|||
Zotero.getString("fileInterface.itemsExported")
|
||||
);
|
||||
translation.translate()
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Closes the items exported indicator
|
||||
|
@ -238,19 +237,16 @@ var Zotero_File_Interface = new function() {
|
|||
Zotero.debug(`${dir} does not exist`);
|
||||
return dbs;
|
||||
}
|
||||
await Zotero.File.iterateDirectory(dir, function* (iterator) {
|
||||
while (true) {
|
||||
let entry = yield iterator.next();
|
||||
if (entry.isDir) continue;
|
||||
// online.sqlite, counterintuitively, is the default database before you sign in
|
||||
if (entry.name == 'online.sqlite' || entry.name.endsWith('@www.mendeley.com.sqlite')) {
|
||||
dbs.push({
|
||||
name: entry.name,
|
||||
path: entry.path,
|
||||
lastModified: null,
|
||||
size: null
|
||||
});
|
||||
}
|
||||
await Zotero.File.iterateDirectory(dir, function (entry) {
|
||||
if (entry.isDir) return;
|
||||
// online.sqlite, counterintuitively, is the default database before you sign in
|
||||
if (entry.name == 'online.sqlite' || entry.name.endsWith('@www.mendeley.com.sqlite')) {
|
||||
dbs.push({
|
||||
name: entry.name,
|
||||
path: entry.path,
|
||||
lastModified: null,
|
||||
size: null
|
||||
});
|
||||
}
|
||||
});
|
||||
for (let i = 0; i < dbs.length; i++) {
|
||||
|
@ -596,7 +592,7 @@ var Zotero_File_Interface = new function() {
|
|||
/**
|
||||
* Creates a bibliography from a collection or saved search
|
||||
*/
|
||||
this.bibliographyFromCollection = function () {
|
||||
this.bibliographyFromCollection = async function () {
|
||||
var items = ZoteroPane.getSortedItems();
|
||||
|
||||
// Find collection name
|
||||
|
@ -612,17 +608,17 @@ var Zotero_File_Interface = new function() {
|
|||
}
|
||||
}
|
||||
|
||||
_doBibliographyOptions(name, items);
|
||||
await _doBibliographyOptions(name, items);
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a bibliography from a items
|
||||
*/
|
||||
function bibliographyFromItems() {
|
||||
async function bibliographyFromItems() {
|
||||
var items = ZoteroPane_Local.getSelectedItems();
|
||||
if(!items || !items.length) throw("no items currently selected");
|
||||
|
||||
_doBibliographyOptions(Zotero.getString("fileInterface.untitledBibliography"), items);
|
||||
await _doBibliographyOptions(Zotero.getString("fileInterface.untitledBibliography"), items);
|
||||
}
|
||||
|
||||
|
||||
|
@ -691,7 +687,7 @@ var Zotero_File_Interface = new function() {
|
|||
/*
|
||||
* Shows bibliography options and creates a bibliography
|
||||
*/
|
||||
function _doBibliographyOptions(name, items) {
|
||||
async function _doBibliographyOptions(name, items) {
|
||||
// make sure at least one item is not a standalone note or attachment
|
||||
var haveRegularItem = false;
|
||||
for (let item of items) {
|
||||
|
@ -782,7 +778,7 @@ var Zotero_File_Interface = new function() {
|
|||
browser.loadURIWithFlags("data:text/html;charset=utf-8,"+encodeURI(bibliography),
|
||||
Components.interfaces.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY, null, "utf-8", null);
|
||||
} else if(io.method == "save-as-html") {
|
||||
var fStream = _saveBibliography(name, "HTML");
|
||||
let fStream = await _saveBibliography(name, "HTML");
|
||||
|
||||
if(fStream !== false) {
|
||||
var html = "";
|
||||
|
@ -808,7 +804,7 @@ var Zotero_File_Interface = new function() {
|
|||
fStream.close();
|
||||
}
|
||||
} else if(io.method == "save-as-rtf") {
|
||||
var fStream = _saveBibliography(name, "RTF");
|
||||
let fStream = await _saveBibliography(name, "RTF");
|
||||
if(fStream !== false) {
|
||||
fStream.write(bibliography, bibliography.length);
|
||||
fStream.close();
|
||||
|
@ -817,29 +813,31 @@ var Zotero_File_Interface = new function() {
|
|||
}
|
||||
|
||||
|
||||
function _saveBibliography(name, format) {
|
||||
async function _saveBibliography(name, format) {
|
||||
// saveable bibliography, using a file stream
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, "Save Bibliography", nsIFilePicker.modeSave);
|
||||
var fp = new FilePicker();
|
||||
fp.init(window, "Save Bibliography", fp.modeSave);
|
||||
|
||||
if(format == "RTF") {
|
||||
var extension = "rtf";
|
||||
fp.appendFilter("RTF", "*.rtf");
|
||||
} else {
|
||||
var extension = "html";
|
||||
fp.appendFilters(nsIFilePicker.filterHTML);
|
||||
fp.appendFilters(fp.filterHTML);
|
||||
}
|
||||
|
||||
fp.defaultString = name+"."+extension;
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
|
||||
var rv = await fp.show();
|
||||
if (rv == fp.returnOK || rv == fp.returnReplace) {
|
||||
// open file
|
||||
var fStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
fStream.init(fp.file, 0x02 | 0x08 | 0x20, 0o664, 0); // write, create, truncate
|
||||
fStream.init(
|
||||
Zotero.File.pathToFile(fp.file),
|
||||
0x02 | 0x08 | 0x20, 0o664, // write, create, truncate
|
||||
0
|
||||
);
|
||||
return fStream;
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import FilePicker from 'zotero/filePicker';
|
||||
|
||||
var Zotero_Import_Wizard = {
|
||||
_wizard: null,
|
||||
_dbs: null,
|
||||
|
@ -95,12 +97,10 @@ var Zotero_Import_Wizard = {
|
|||
chooseFile: async function (translation) {
|
||||
var translation = new Zotero.Translate.Import();
|
||||
var translators = await translation.getTranslators();
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString("fileInterface.import"), nsIFilePicker.modeOpen);
|
||||
var fp = new FilePicker();
|
||||
fp.init(window, Zotero.getString("fileInterface.import"), fp.modeOpen);
|
||||
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
fp.appendFilters(fp.filterAll);
|
||||
|
||||
var collation = Zotero.getLocaleCollation();
|
||||
|
||||
|
@ -117,14 +117,14 @@ var Zotero_Import_Wizard = {
|
|||
fp.appendFilter(filter.label, "*." + filter.target);
|
||||
}
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv !== nsIFilePicker.returnOK && rv !== nsIFilePicker.returnReplace) {
|
||||
var rv = await fp.show();
|
||||
if (rv !== fp.returnOK && rv !== fp.returnReplace) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Zotero.debug(`File is ${fp.file.path}`);
|
||||
Zotero.debug(`File is ${fp.file}`);
|
||||
|
||||
this._file = fp.file.path;
|
||||
this._file = fp.file;
|
||||
this._wizard.canAdvance = true;
|
||||
this._wizard.goTo('page-options');
|
||||
},
|
||||
|
@ -151,16 +151,14 @@ var Zotero_Import_Wizard = {
|
|||
*/
|
||||
chooseMendeleyDB: async function () {
|
||||
document.getElementById('file-list').selectedIndex = -1;
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString('fileInterface.import'), nsIFilePicker.modeOpen);
|
||||
var fp = new FilePicker();
|
||||
fp.init(window, Zotero.getString('fileInterface.import'), fp.modeOpen);
|
||||
fp.appendFilter("Mendeley Database", "*.sqlite"); // TODO: Localize
|
||||
var rv = fp.show();
|
||||
if (rv != nsIFilePicker.returnOK) {
|
||||
var rv = await fp.show();
|
||||
if (rv != fp.returnOK) {
|
||||
return false;
|
||||
}
|
||||
this._file = fp.file.path;
|
||||
this._file = fp.file;
|
||||
this._wizard.canAdvance = true;
|
||||
this._wizard.advance();
|
||||
},
|
||||
|
|
|
@ -1208,19 +1208,16 @@ Zotero_Import_Mendeley.prototype.deleteNonPrimaryFiles = async function () {
|
|||
let filename = row.path.substr(8);
|
||||
|
||||
Zotero.debug(`Checking for extra files in ${dir}`);
|
||||
await Zotero.File.iterateDirectory(dir, function* (iterator) {
|
||||
while (true) {
|
||||
let entry = yield iterator.next();
|
||||
if (entry.name.startsWith('.zotero') || entry.name == filename) {
|
||||
continue;
|
||||
}
|
||||
Zotero.debug(`Deleting ${entry.path}`);
|
||||
try {
|
||||
yield OS.File.remove(entry.path);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
await Zotero.File.iterateDirectory(dir, async function (entry) {
|
||||
if (entry.name.startsWith('.zotero') || entry.name == filename) {
|
||||
return;
|
||||
}
|
||||
Zotero.debug(`Deleting ${entry.path}`);
|
||||
try {
|
||||
await OS.File.remove(entry.path);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -80,6 +80,12 @@ var Zotero_QuickFormat = new function () {
|
|||
}
|
||||
}
|
||||
|
||||
// With fx60 and drawintitlebar=true Firefox calculates the minHeight
|
||||
// as titlebar+maincontent, so we have hack around that here.
|
||||
if (Zotero.isMac && Zotero.platformMajorVersion >= 60) {
|
||||
qfb.style.marginBottom = "-22px";
|
||||
}
|
||||
|
||||
// add labels to popup
|
||||
var locators = Zotero.Cite.labels;
|
||||
var menu = document.getElementById("locator-label");
|
||||
|
@ -807,11 +813,21 @@ var Zotero_QuickFormat = new function () {
|
|||
qfs.setAttribute("multiline", true);
|
||||
qfs.style.height = ((Zotero.isMac ? 6 : 4)+qfe.scrollHeight)+"px";
|
||||
window.sizeToContent();
|
||||
// the above line causes drawing artifacts to appear due to a bug with drawintitle property
|
||||
// in fx60. this fixes the artifacting
|
||||
if (Zotero.isMac && Zotero.platformMajorVersion >= 60) {
|
||||
document.children[0].setAttribute('drawintitlebar', 'false');
|
||||
document.children[0].setAttribute('drawintitlebar', 'true');
|
||||
}
|
||||
} else {
|
||||
delete qfs.style.height;
|
||||
qfe.removeAttribute("multiline");
|
||||
qfs.removeAttribute("multiline");
|
||||
window.sizeToContent();
|
||||
if (Zotero.isMac && Zotero.platformMajorVersion >= 60) {
|
||||
document.children[0].setAttribute('drawintitlebar', 'false');
|
||||
document.children[0].setAttribute('drawintitlebar', 'true');
|
||||
}
|
||||
}
|
||||
var panelShowing = referencePanel.state === "open" || referencePanel.state === "showing";
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@
|
|||
onunload="Zotero_QuickFormat.onUnload()">
|
||||
|
||||
<script src="../include.js"/>
|
||||
<script src="windowDraggingUtils.js" type="text/javascript;version=1.8"/>
|
||||
<script src="quickFormat.js" type="text/javascript;version=1.8"/>
|
||||
<script src="windowDraggingUtils.js" type="text/javascript"/>
|
||||
<script src="quickFormat.js" type="text/javascript"/>
|
||||
|
||||
<box orient="horizontal" id="quick-format-entry">
|
||||
<deck id="quick-format-deck" selectedIndex="0" flex="1">
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script src="include.js"/>
|
||||
<script src="itemPane.js" type="application/javascript;version=1.8"/>
|
||||
<script src="itemPane.js" type="application/javascript"/>
|
||||
|
||||
<vbox id="zotero-item-pane" zotero-persist="width height">
|
||||
<!-- My Publications -->
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<!DOCTYPE prefwindow SYSTEM "chrome://zotero/locale/preferences.dtd">
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="chrome://zotero-platform/content/preferences.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
|
||||
<?xml-stylesheet href="chrome://zotero/skin/preferences.css"?>
|
||||
|
||||
|
|
201
chrome/content/zotero/modules/filePicker.js
Normal file
201
chrome/content/zotero/modules/filePicker.js
Normal file
|
@ -0,0 +1,201 @@
|
|||
import { Cc, Ci, Cu } from 'chrome';
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
/**
|
||||
* Interface to the system filepicker.
|
||||
*
|
||||
* Based on Mozilla's nsIFilePicker, with minor modifications (e.g., strings paths instead nsIFile,
|
||||
* promise-returning show()).
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class FilePicker {
|
||||
constructor() {
|
||||
this._fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Window} parentWindow
|
||||
* @param {String} title
|
||||
* @param {Integer} mode - One of the mode constants, indicating the type of picker to create
|
||||
*/
|
||||
init(parentWindow, title, mode) {
|
||||
this._fp.init(parentWindow, title, mode);
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends a custom file extension filter to the dialog. The filter appended first will be used when
|
||||
* the dialog is initially opened. The user may then select another from the list.
|
||||
*
|
||||
* @param {String} title - The title of the filter
|
||||
* @param {String} filter - The filter string. Multiple extensions may be included, separated by a
|
||||
* semicolon and a space.
|
||||
*/
|
||||
appendFilter(title, filter) {
|
||||
this._fp.appendFilter(title, filter);
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends a list of file extension filters, from the predefined list, to the dialog
|
||||
*
|
||||
* @param {Integer} filterMask - A combination of the filters you wish to use. You may OR multiple
|
||||
* filters together; for example <code>filterAll | filterHTML</code>.
|
||||
*/
|
||||
appendFilters(filterMask) {
|
||||
this._fp.appendFilters(filterMask);
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the dialog
|
||||
*
|
||||
* @return {Promise<Integer>} One of the return constants
|
||||
*/
|
||||
async show() {
|
||||
return new Zotero.Promise(function (resolve) {
|
||||
this._fp.open(returnConstant => resolve(returnConstant));
|
||||
}.bind(this));
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/** @const {Integer} FilePicker#modeOpen - Load a file */
|
||||
/** @const {Integer} FilePicker#modeSave - Save a file */
|
||||
/** @const {Integer} FilePicker#modeGetFolder - Select a folder/directory */
|
||||
/** @const {Integer} FilePicker#modeOpenMultiple - Load multiple files */
|
||||
FilePicker.prototype.modeOpen = 0;
|
||||
FilePicker.prototype.modeSave = 1;
|
||||
FilePicker.prototype.modeGetFolder = 2;
|
||||
FilePicker.prototype.modeOpenMultiple = 3;
|
||||
|
||||
/** @const {Integer} FilePicker#returnOK - The file picker dialog was closed by the user hitting 'OK' */
|
||||
/** @const {Integer} FilePicker#returnCancel - The file picker dialog was closed by the user hitting 'Cancel' */
|
||||
/** @const {Integer} FilePicker#returnReplace - The user chose an existing file and acknowledged that they want to overwrite the file */
|
||||
FilePicker.prototype.returnOK = 0;
|
||||
FilePicker.prototype.returnCancel = 1;
|
||||
FilePicker.prototype.returnReplace = 2;
|
||||
|
||||
/** @const {Integer} FilePicker#filterAll - All files */
|
||||
/** @const {Integer} FilePicker#filterHTML - HTML files */
|
||||
/** @const {Integer} FilePicker#filterText - Text files */
|
||||
/** @const {Integer} FilePicker#filterImages - Image files */
|
||||
/** @const {Integer} FilePicker#filterXML - XML files */
|
||||
/** @const {Integer} FilePicker#filterApps - Platform-specific application filter */
|
||||
/** @const {Integer} FilePicker#filterAllowURLs - Allow URLs */
|
||||
/** @const {Integer} FilePicker#filterAudio - Audio files */
|
||||
/** @const {Integer} FilePicker#filterVideo - Video files */
|
||||
FilePicker.prototype.filterAll = 0x001;
|
||||
FilePicker.prototype.filterHTML = 0x002;
|
||||
FilePicker.prototype.filterText = 0x004;
|
||||
FilePicker.prototype.filterImages = 0x008;
|
||||
FilePicker.prototype.filterXML = 0x010;
|
||||
FilePicker.prototype.filterApps = 0x040;
|
||||
FilePicker.prototype.filterAllowURLs = 0x80;
|
||||
FilePicker.prototype.filterAudio = 0x100;
|
||||
FilePicker.prototype.filterVideo = 0x200;
|
||||
|
||||
['addToRecentDocs', 'defaultExtension', 'defaultString', 'displayDirectory', 'filterIndex'].forEach((prop) => {
|
||||
/**
|
||||
* @name FilePicker#addToRecentDocs
|
||||
* @type Boolean
|
||||
* @default false
|
||||
* @desc If true, the file is added to the operating system's "recent documents" list (if the
|
||||
* operating system has one; nothing happens if there is no such concept on the user's platform).
|
||||
*/
|
||||
/**
|
||||
* @name FilePicker#defaultExtension
|
||||
* @type String
|
||||
* @desc The extension for the type of files you want to work with. On some platforms, this is
|
||||
* automatically appended to filenames the user enters, if required. Specify it without a
|
||||
* leading dot, for example "jpg".
|
||||
*/
|
||||
/**
|
||||
* @name FilePicker#defaultString
|
||||
* @type String
|
||||
* @desc The filename, including extension, that should be suggested to the user as a default.
|
||||
* This should be set before calling show().
|
||||
*/
|
||||
/**
|
||||
* @name FilePicker#displayDirectory
|
||||
* @type String
|
||||
* @desc The filename, including extension, that should be suggested to the user as a default.
|
||||
* This should be set before calling show().
|
||||
*/
|
||||
/**
|
||||
* @name FilePicker#filterIndex
|
||||
* @type Integer
|
||||
* @desc The (0-based) index of the filter which is currently selected in the file picker dialog.
|
||||
* Set this to choose a particular filter to be selected by default.
|
||||
*/
|
||||
Object.defineProperty(FilePicker.prototype, prop, {
|
||||
// TODO: Others
|
||||
get: function () {
|
||||
var val = this._fp[prop];
|
||||
if (prop == 'displayDirectory') {
|
||||
// Convert from nsIFile
|
||||
val = val.path;
|
||||
}
|
||||
return val;
|
||||
},
|
||||
set: function (val) {
|
||||
if (prop == 'displayDirectory') {
|
||||
// Convert to nsIFile
|
||||
val = Zotero.File.pathToFile(val);
|
||||
}
|
||||
this._fp[prop] = val;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
});
|
||||
|
||||
// Read-only properties
|
||||
['file', 'files', 'fileURL'].forEach((prop) => {
|
||||
/**
|
||||
* @name FilePicker#file
|
||||
* @type String
|
||||
* @readonly
|
||||
* @desc The selected file or directory.
|
||||
*/
|
||||
/**
|
||||
* @name FilePicker#files
|
||||
* @type String[]
|
||||
* @readonly
|
||||
* @desc An array of the selected files. Only works with `modeOpenMultiple` mode.
|
||||
*/
|
||||
/**
|
||||
* @name FilePicker#fileURL
|
||||
* @type String
|
||||
* @readonly
|
||||
* @desc The URI of the selected file or directory.
|
||||
*/
|
||||
Object.defineProperty(FilePicker.prototype, prop, {
|
||||
get: function () {
|
||||
var val = this._fp[prop];
|
||||
switch (prop) {
|
||||
case 'file':
|
||||
// Convert from nsIFile
|
||||
val = OS.Path.normalize(val.path);
|
||||
break;
|
||||
|
||||
case 'files':
|
||||
var files = [];
|
||||
while (val.hasMoreElements()) {
|
||||
let file = val.getNext();
|
||||
file.QueryInterface(Ci.nsIFile);
|
||||
files.push(file.path);
|
||||
}
|
||||
val = files;
|
||||
break;
|
||||
|
||||
case 'fileURL':
|
||||
val = val.spec;
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
});
|
||||
|
||||
Object.freeze(FilePicker.prototype);
|
||||
|
||||
export default FilePicker;
|
|
@ -23,166 +23,42 @@
|
|||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/*
|
||||
* This object contains the various functions for the interface
|
||||
*/
|
||||
var ZoteroOverlay = new function()
|
||||
{
|
||||
const DEFAULT_ZPANE_HEIGHT = 300;
|
||||
var toolbarCollapseState;
|
||||
var zoteroPane, zoteroSplitter;
|
||||
|
||||
this.isTab = false;
|
||||
|
||||
this.onLoad = function () {
|
||||
Zotero.spawn(function* () {
|
||||
try {
|
||||
//
|
||||
// Code that runs in both full and connector mode
|
||||
//
|
||||
zoteroPane = document.getElementById('zotero-pane-stack');
|
||||
zoteroSplitter = document.getElementById('zotero-splitter');
|
||||
|
||||
if (!Zotero) {
|
||||
throw new Error("No Zotero object");
|
||||
}
|
||||
if (Zotero.skipLoading) {
|
||||
throw new Error("Skipping loading");
|
||||
}
|
||||
|
||||
ZoteroPane_Overlay = ZoteroPane;
|
||||
|
||||
// TODO: Add only when progress window is open
|
||||
document.getElementById('appcontent').addEventListener('mousemove', Zotero.ProgressWindowSet.updateTimers, false);
|
||||
|
||||
// Perform additional initialization for full mode
|
||||
if (!Zotero.isConnector) {
|
||||
yield _onLoadFull();
|
||||
}
|
||||
var ZoteroOverlay = new function () {
|
||||
this.onLoad = async function () {
|
||||
try {
|
||||
if (!Zotero) {
|
||||
throw new Error("No Zotero object");
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug(e, 1);
|
||||
throw e;
|
||||
if (Zotero.skipLoading) {
|
||||
throw new Error("Skipping loading");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize overlay in new windows in full mode
|
||||
*
|
||||
* This is never run in Zotero for Firefox if Standalone is open first and Z4Fx is opened
|
||||
* second, but we don't care.
|
||||
*/
|
||||
var _onLoadFull = function () {
|
||||
return Zotero.spawn(function* () {
|
||||
yield Zotero.Promise.all([Zotero.initializationPromise, Zotero.unlockPromise]);
|
||||
|
||||
await Zotero.Promise.all([Zotero.initializationPromise, Zotero.unlockPromise]);
|
||||
|
||||
Zotero.debug("Initializing overlay");
|
||||
|
||||
if (Zotero.skipLoading) {
|
||||
throw new Error("Skipping loading");
|
||||
}
|
||||
|
||||
|
||||
ZoteroPane.init();
|
||||
|
||||
// Clear old Zotero icon pref
|
||||
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefService)
|
||||
.getBranch('extensions.zotero.');
|
||||
prefBranch.clearUserPref('statusBarIcon');
|
||||
|
||||
// Used for loading pages from upgrade wizard
|
||||
if (Zotero.initialURL) {
|
||||
setTimeout(function () {
|
||||
Zotero.launchURL(ZOTERO_CONFIG.START_URL);
|
||||
Zotero.initialURL = null;
|
||||
}, 1);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug(e, 1);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.onUnload = function() {
|
||||
ZoteroPane.destroy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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, dontRefocus)
|
||||
{
|
||||
if (!Zotero || Zotero.startupError || Zotero.skipLoading) {
|
||||
ZoteroPane.displayStartupError();
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't do anything if pane is already showing
|
||||
if (makeVisible && ZoteroPane.isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(makeVisible === undefined) makeVisible = zoteroPane.hidden || zoteroPane.collapsed;
|
||||
|
||||
/*
|
||||
Zotero.debug("zoteroPane.boxObject.height: " + zoteroPane.boxObject.height);
|
||||
Zotero.debug("zoteroPane.getAttribute('height'): " + zoteroPane.getAttribute('height'));
|
||||
Zotero.debug("zoteroPane.getAttribute('minheight'): " + zoteroPane.getAttribute('minheight'));
|
||||
Zotero.debug("savedHeight: " + savedHeight);
|
||||
*/
|
||||
|
||||
if(makeVisible) {
|
||||
zoteroSplitter.setAttribute('hidden', false);
|
||||
zoteroPane.setAttribute('hidden', false);
|
||||
zoteroPane.setAttribute('collapsed', false);
|
||||
|
||||
// Get saved height (makeVisible() may change it)
|
||||
if (zoteroPane.hasAttribute('savedHeight')) {
|
||||
var savedHeight = zoteroPane.getAttribute('savedHeight');
|
||||
}
|
||||
else {
|
||||
var savedHeight = DEFAULT_ZPANE_HEIGHT;
|
||||
}
|
||||
|
||||
// Restore height
|
||||
var max = document.getElementById('appcontent').boxObject.height
|
||||
- zoteroSplitter.boxObject.height;
|
||||
zoteroPane.setAttribute('height', Math.min(savedHeight, max));
|
||||
|
||||
// Make visible
|
||||
ZoteroPane.makeVisible();
|
||||
|
||||
// Warn about unsafe data directory on first display
|
||||
Zotero.DataDirectory.checkForUnsafeLocation(Zotero.DataDirectory.dir); // async
|
||||
|
||||
// Make sure tags splitter isn't missing for people upgrading from <2.0b7
|
||||
document.getElementById('zotero-tags-splitter').collapsed = false;
|
||||
} else {
|
||||
ZoteroPane.makeHidden();
|
||||
|
||||
// Collapse pane
|
||||
zoteroSplitter.setAttribute('hidden', true);
|
||||
zoteroPane.setAttribute('collapsed', true);
|
||||
zoteroPane.height = 0;
|
||||
|
||||
document.getElementById('content').setAttribute('collapsed', false);
|
||||
|
||||
if(!dontRefocus) {
|
||||
// Return focus to the browser content pane
|
||||
window.content.window.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("load", function(e) {
|
||||
window.addEventListener("load", async function(e) {
|
||||
try {
|
||||
ZoteroOverlay.onLoad(e);
|
||||
await ZoteroOverlay.onLoad(e);
|
||||
await ZoteroPane.makeVisible();
|
||||
}
|
||||
catch (e) {
|
||||
Components.utils.reportError(e);
|
||||
|
|
|
@ -41,10 +41,6 @@
|
|||
<toolbar id="zotero-toolbar" nowindowdrag="true"/>
|
||||
|
||||
<vbox id="appcontent">
|
||||
<!-- onmouseup shouldn't be necessary but seems to help prevent tag selector from sometimes going off the screen -->
|
||||
<splitter id="zotero-splitter" resizebefore="closest" resizeafter="closest" hidden="true"
|
||||
onmouseup="ZoteroPane.updateTagSelectorSize()"/>
|
||||
|
||||
<stack id="zotero-pane-stack" persist="savedHeight" savedHeight="300" hidden="true"/>
|
||||
<stack id="zotero-pane-stack"/>
|
||||
</vbox>
|
||||
</overlay>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<!DOCTYPE prefwindow SYSTEM "chrome://zotero/locale/preferences.dtd">
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="chrome://zotero-platform/content/preferences.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
|
||||
<?xml-stylesheet href="chrome://zotero/skin/preferences.css"?>
|
||||
<?xml-stylesheet href="chrome://zotero/skin/zotero.css"?>
|
||||
|
@ -83,5 +84,5 @@
|
|||
observerService.notifyObservers(null, "charsetmenu-selected", "other");
|
||||
]]>
|
||||
</script>
|
||||
<script src="preferences.js" type="application/javascript;version=1.8"/>
|
||||
<script src="preferences.js" type="application/javascript"/>
|
||||
</prefwindow>
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
import FilePicker from 'zotero/filePicker';
|
||||
|
||||
Zotero_Preferences.Advanced = {
|
||||
_openURLResolvers: null,
|
||||
|
@ -554,25 +555,20 @@ Zotero_Preferences.Attachment_Base_Directory = {
|
|||
},
|
||||
|
||||
|
||||
choosePath: Zotero.Promise.coroutine(function* () {
|
||||
choosePath: async function () {
|
||||
var oldPath = this.getPath();
|
||||
|
||||
//Prompt user to choose new base path
|
||||
var fp = new FilePicker();
|
||||
if (oldPath) {
|
||||
var oldPathFile = Zotero.File.pathToFile(oldPath);
|
||||
fp.displayDirectory = oldPath;
|
||||
}
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
if (oldPathFile) {
|
||||
fp.displayDirectory = oldPathFile;
|
||||
}
|
||||
fp.init(window, Zotero.getString('attachmentBasePath.selectDir'), nsIFilePicker.modeGetFolder);
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
if (fp.show() != nsIFilePicker.returnOK) {
|
||||
fp.init(window, Zotero.getString('attachmentBasePath.selectDir'), fp.modeGetFolder);
|
||||
fp.appendFilters(fp.filterAll);
|
||||
if (await fp.show() != fp.returnOK) {
|
||||
return false;
|
||||
}
|
||||
var newPath = OS.Path.normalize(fp.file.path);
|
||||
var newPath = fp.file;
|
||||
|
||||
if (oldPath && oldPath == newPath) {
|
||||
Zotero.debug("Base directory hasn't changed");
|
||||
|
@ -580,7 +576,7 @@ Zotero_Preferences.Attachment_Base_Directory = {
|
|||
}
|
||||
|
||||
return this.changePath(newPath);
|
||||
}),
|
||||
},
|
||||
|
||||
|
||||
changePath: Zotero.Promise.coroutine(function* (basePath) {
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
<preference id="pref-openURL-resolver" name="extensions.zotero.openURL.resolver" type="string"/>
|
||||
<preference id="pref-openURL-version" name="extensions.zotero.openURL.version" type="string"/>
|
||||
|
||||
<preference id="pref-keys-openZotero" name="extensions.zotero.keys.openZotero" type="string"/>
|
||||
<preference id="pref-keys-saveToZotero" name="extensions.zotero.keys.saveToZotero" type="string"/>
|
||||
<preference id="pref-keys-library" name="extensions.zotero.keys.library" type="string"/>
|
||||
<preference id="pref-keys-quicksearch" name="extensions.zotero.keys.quicksearch" type="string"/>
|
||||
|
@ -341,5 +340,5 @@
|
|||
<separator/>
|
||||
</prefpane>
|
||||
|
||||
<script src="preferences_advanced.js" type="application/javascript;version=1.8"/>
|
||||
<script src="preferences_advanced.js" type="application/javascript"/>
|
||||
</overlay>
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
import FilePicker from 'zotero/filePicker';
|
||||
|
||||
Zotero_Preferences.Cite = {
|
||||
wordPluginIDs: new Set([
|
||||
'zoteroOpenOfficeIntegration@zotero.org',
|
||||
|
@ -123,8 +125,11 @@ Zotero_Preferences.Cite = {
|
|||
// (The first two aren't sent to the client normally, but hide anyway in case they are.)
|
||||
var style = doc.createElement('style');
|
||||
style.type = 'text/css';
|
||||
style.innerHTML = 'h1, #intro, .style-individual-link, .style-view-source { display: none !important; }';
|
||||
Zotero.debug(doc.documentElement.innerHTML);
|
||||
style.innerHTML = 'h1, #intro, .style-individual-link, .style-view-source { display: none !important; }'
|
||||
// TEMP: Default UA styles that aren't being included in Firefox 60 for some reason
|
||||
+ 'html { background: #fff; }'
|
||||
+ 'a { color: rgb(0, 0, 238) !important; text-decoration: underline; }'
|
||||
+ 'a:active { color: rgb(238, 0, 0) !important; }';
|
||||
doc.getElementsByTagName('head')[0].appendChild(style);
|
||||
});
|
||||
},
|
||||
|
@ -133,21 +138,27 @@ Zotero_Preferences.Cite = {
|
|||
/**
|
||||
* Adds a new style to the style pane
|
||||
**/
|
||||
addStyle: function () {
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString("zotero.preferences.styles.addStyle"), nsIFilePicker.modeOpen);
|
||||
addStyle: async function () {
|
||||
var fp = new FilePicker();
|
||||
fp.init(window, Zotero.getString("zotero.preferences.styles.addStyle"), fp.modeOpen);
|
||||
|
||||
fp.appendFilter("CSL Style", "*.csl");
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
|
||||
Zotero.Styles.install({ file: fp.file }, fp.file.path, true)
|
||||
.catch(function (e) {
|
||||
var rv = await fp.show();
|
||||
if (rv == fp.returnOK || rv == fp.returnReplace) {
|
||||
try {
|
||||
await Zotero.Styles.install(
|
||||
{
|
||||
file: Zotero.File.pathToFile(fp.file)
|
||||
},
|
||||
fp.file,
|
||||
true
|
||||
);
|
||||
}
|
||||
catch (e) {
|
||||
(new Zotero.Exception.Alert("styles.install.unexpectedError",
|
||||
fp.file.path, "styles.install.title", e)).present()
|
||||
});
|
||||
fp.file, "styles.install.title", e)).present()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -110,5 +110,5 @@
|
|||
</tabbox>
|
||||
</prefpane>
|
||||
|
||||
<script src="preferences_cite.js" type="application/javascript;version=1.8"/>
|
||||
<script src="preferences_cite.js" type="application/javascript"/>
|
||||
</overlay>
|
||||
|
|
|
@ -111,6 +111,6 @@
|
|||
<separator/>
|
||||
<separator/>
|
||||
|
||||
<script src="preferences_export.js" type="application/javascript;version=1.8"/>
|
||||
<script src="preferences_export.js" type="application/javascript"/>
|
||||
</prefpane>
|
||||
</overlay>
|
||||
|
|
|
@ -90,6 +90,6 @@
|
|||
<separator/>
|
||||
</prefpane>
|
||||
|
||||
<script src="preferences_proxies.js" type="application/javascript;version=1.8"/>
|
||||
<script src="preferences_proxies.js" type="application/javascript"/>
|
||||
</prefwindow>
|
||||
</overlay>
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
import FilePicker from 'zotero/filePicker';
|
||||
|
||||
Zotero_Preferences.General = {
|
||||
init: function () {
|
||||
|
@ -51,28 +52,25 @@ Zotero_Preferences.General = {
|
|||
//
|
||||
// File handlers
|
||||
//
|
||||
chooseFileHandler: function (type) {
|
||||
chooseFileHandler: async function (type) {
|
||||
var pref = this._getFileHandlerPref(type);
|
||||
var currentPath = Zotero.Prefs.get(pref);
|
||||
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
var fp = new FilePicker();
|
||||
if (currentPath) {
|
||||
fp.displayDirectory = Zotero.File.pathToFile(OS.Path.dirname(currentPath));
|
||||
fp.displayDirectory = OS.Path.dirname(currentPath);
|
||||
}
|
||||
fp.init(
|
||||
window,
|
||||
Zotero.getString('zotero.preferences.chooseApplication'),
|
||||
nsIFilePicker.modeOpen
|
||||
fp.modeOpen
|
||||
);
|
||||
fp.appendFilters(nsIFilePicker.filterApps);
|
||||
if (fp.show() != nsIFilePicker.returnOK) {
|
||||
fp.appendFilters(fp.filterApps);
|
||||
if (await fp.show() != fp.returnOK) {
|
||||
this._updateFileHandlerUI();
|
||||
return false;
|
||||
}
|
||||
var newPath = OS.Path.normalize(fp.file.path);
|
||||
this.setFileHandler(type, newPath);
|
||||
this.setFileHandler(type, fp.file);
|
||||
},
|
||||
|
||||
setFileHandler: function (type, handler) {
|
||||
|
|
|
@ -104,5 +104,5 @@
|
|||
<separator/>
|
||||
</prefpane>
|
||||
|
||||
<script src="preferences_general.js" type="application/javascript;version=1.8"/>
|
||||
<script src="preferences_general.js" type="application/javascript"/>
|
||||
</overlay>
|
||||
|
|
|
@ -93,5 +93,5 @@
|
|||
<separator/>
|
||||
</prefpane>
|
||||
|
||||
<script src="preferences_search.js" type="application/javascript;version=1.8"/>
|
||||
<script src="preferences_search.js" type="application/javascript"/>
|
||||
</overlay>
|
||||
|
|
|
@ -326,5 +326,5 @@
|
|||
<separator/>
|
||||
</prefpane>
|
||||
|
||||
<script src="preferences_sync.js" type="application/javascript;version=1.8"/>
|
||||
<script src="preferences_sync.js" type="application/javascript"/>
|
||||
</overlay>
|
||||
|
|
|
@ -26,8 +26,9 @@
|
|||
/**
|
||||
* @fileOverview Tools for automatically retrieving a citation for the given PDF
|
||||
*/
|
||||
|
||||
|
||||
|
||||
import FilePicker from 'zotero/filePicker';
|
||||
|
||||
/**
|
||||
* Front end for recognizing PDFs
|
||||
* @namespace
|
||||
|
@ -50,13 +51,11 @@ var Zotero_RTFScan = new function() {
|
|||
this.introPageShowing = function() {
|
||||
var path = Zotero.Prefs.get("rtfScan.lastInputFile");
|
||||
if(path) {
|
||||
inputFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
|
||||
inputFile.initWithPath(path);
|
||||
inputFile = Zotero.File.pathToFile(path);
|
||||
}
|
||||
var path = Zotero.Prefs.get("rtfScan.lastOutputFile");
|
||||
if(path) {
|
||||
outputFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
|
||||
outputFile.initWithPath(path);
|
||||
outputFile = Zotero.File.pathToFile(path);
|
||||
}
|
||||
_updatePath();
|
||||
document.getElementById("choose-input-file").focus();
|
||||
|
@ -73,19 +72,17 @@ var Zotero_RTFScan = new function() {
|
|||
/**
|
||||
* Called to select the file to be processed
|
||||
*/
|
||||
this.chooseInputFile = function() {
|
||||
this.chooseInputFile = async function () {
|
||||
// display file picker
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString("rtfScan.openTitle"), nsIFilePicker.modeOpen);
|
||||
var fp = new FilePicker();
|
||||
fp.init(window, Zotero.getString("rtfScan.openTitle"), fp.modeOpen);
|
||||
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
fp.appendFilters(fp.filterAll);
|
||||
fp.appendFilter(Zotero.getString("rtfScan.rtf"), "*.rtf");
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
|
||||
inputFile = fp.file;
|
||||
var rv = await fp.show();
|
||||
if (rv == fp.returnOK || rv == fp.returnReplace) {
|
||||
inputFile = Zotero.File.pathToFile(fp.file);
|
||||
_updatePath();
|
||||
}
|
||||
}
|
||||
|
@ -93,11 +90,9 @@ var Zotero_RTFScan = new function() {
|
|||
/**
|
||||
* Called to select the output file
|
||||
*/
|
||||
this.chooseOutputFile = function() {
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString("rtfScan.saveTitle"), nsIFilePicker.modeSave);
|
||||
this.chooseOutputFile = async function () {
|
||||
var fp = new FilePicker();
|
||||
fp.init(window, Zotero.getString("rtfScan.saveTitle"), fp.modeSave);
|
||||
fp.appendFilter(Zotero.getString("rtfScan.rtf"), "*.rtf");
|
||||
if(inputFile) {
|
||||
var leafName = inputFile.leafName;
|
||||
|
@ -110,9 +105,9 @@ var Zotero_RTFScan = new function() {
|
|||
fp.defaultString = "Untitled.rtf";
|
||||
}
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
|
||||
outputFile = fp.file;
|
||||
var rv = await fp.show();
|
||||
if (rv == fp.returnOK || rv == fp.returnReplace) {
|
||||
outputFile = Zotero.File.pathToFile(fp.file);
|
||||
_updatePath();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
]>
|
||||
|
||||
<window id="main-window" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript">
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
</script>
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
||||
<script>
|
||||
// Equivalent to Zotero.openMainWindow()
|
||||
|
|
|
@ -446,14 +446,11 @@ const ZoteroStandalone = new function() {
|
|||
|
||||
|
||||
this.updateAddonsPane = function (doc) {
|
||||
// Hide unsigned add-on verification warnings
|
||||
//
|
||||
// This only works for the initial load of the window. If the user switches to Appearance
|
||||
// or Plugins and then back to Extensions, the warnings will appear again. A better way to
|
||||
// disable this might be discoverable by studying
|
||||
// https://dxr.mozilla.org/mozilla-central/source/toolkit/mozapps/extensions/content/extensions.js
|
||||
var addonList = doc.getElementById('addon-list');
|
||||
setTimeout(function () {
|
||||
// Unsigned add-on warnings are hidden by default in extensions.css (via style rules added
|
||||
// by fetch_xulrunner.sh), but allow other warnings
|
||||
function updateExtensions () {
|
||||
var addonList = doc.getElementById('addon-list');
|
||||
|
||||
for (let i = 0; i < addonList.itemCount; i++) {
|
||||
let richListItem = addonList.getItemAtIndex(i);
|
||||
let container = doc.getAnonymousElementByAttribute(
|
||||
|
@ -463,13 +460,16 @@ const ZoteroStandalone = new function() {
|
|||
let link = doc.getAnonymousElementByAttribute(
|
||||
richListItem, 'anonid', 'warning-link'
|
||||
);
|
||||
if (link && link.href.indexOf('unsigned-addons') != -1) {
|
||||
richListItem.removeAttribute('notification');
|
||||
container.hidden = true;
|
||||
if (link) {
|
||||
if (!link.href.includes('unsigned-addons')) {
|
||||
container.classList.add('allowed-warning');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
doc.getElementById('category-extension').onclick = updateExtensions;
|
||||
setTimeout(updateExtensions);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -713,30 +713,43 @@ ZoteroStandalone.DebugOutput = {
|
|||
|
||||
|
||||
function toJavaScriptConsole() {
|
||||
toOpenWindowByType("global:console", "chrome://global/content/console.xul");
|
||||
openWindowByType('chrome://global/content/console.xul', 'global:console');
|
||||
}
|
||||
|
||||
function openRunJSWindow() {
|
||||
window.open('chrome://zotero/content/runJS.html', 'run-js', 'width=900,height=700,resizable');
|
||||
openWindowByType(
|
||||
'chrome://zotero/content/runJS.html',
|
||||
'zotero:run-js',
|
||||
'chrome,width=900,height=700,resizable,centerscreen'
|
||||
);
|
||||
}
|
||||
|
||||
function openStyleEditor() {
|
||||
window.open('chrome://zotero/content/tools/csledit.xul', 'style-editor', 'width=950,height=700,resizable');
|
||||
openWindowByType(
|
||||
'chrome://zotero/content/tools/csledit.xul',
|
||||
'zotero:style-editor',
|
||||
'chrome,width=950,height=700,resizable'
|
||||
);
|
||||
}
|
||||
|
||||
function openScaffold() {
|
||||
window.open('chrome://scaffold/content/scaffold.xul', 'scaffold', 'chrome,resizable');
|
||||
openWindowByType(
|
||||
'chrome://scaffold/content/scaffold.xul',
|
||||
'zotero:scaffold',
|
||||
'chrome,resizable'
|
||||
);
|
||||
}
|
||||
|
||||
function toOpenWindowByType(inType, uri, features)
|
||||
{
|
||||
var topWindow = Services.wm.getMostRecentWindow(inType);
|
||||
function openWindowByType(uri, type, features) {
|
||||
var win = Services.wm.getMostRecentWindow(type);
|
||||
|
||||
if (topWindow) {
|
||||
topWindow.focus();
|
||||
} else if(features) {
|
||||
if (win) {
|
||||
win.focus();
|
||||
}
|
||||
else if (features) {
|
||||
window.open(uri, "_blank", features);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
window.open(uri, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -300,7 +300,12 @@
|
|||
</menupopup>
|
||||
</menu>
|
||||
|
||||
<menu id="windowMenu" />
|
||||
<menu id="windowMenu"
|
||||
label="&windowMenu.label;"
|
||||
onpopupshowing="macWindowMenuDidShow();"
|
||||
onpopuphidden="macWindowMenuDidHide();"
|
||||
>
|
||||
</menu>
|
||||
|
||||
<menu id="helpMenu"
|
||||
label="&helpMenu.label;"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
style="padding:2em">
|
||||
|
||||
<script src="../include.js"/>
|
||||
<script type="application/javascript;version=1.8" src="test.js"/>
|
||||
<script type="application/javascript" src="test.js"/>
|
||||
|
||||
<hbox><label>This is a test page.</label></hbox>
|
||||
</window>
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
<p id="result"></p>
|
||||
<script src="../include.js"></script>
|
||||
<script type="text/javascript">
|
||||
Zotero.Promise.coroutine(function* (){
|
||||
import FilePicker from 'zotero/filePicker';
|
||||
|
||||
(async function () {
|
||||
// Create schema
|
||||
var schema = {"itemTypes":{}, "creatorTypes":{}, "fields":{}};
|
||||
var types = Zotero.ItemTypes.getTypes();
|
||||
|
||||
var fieldIDs = yield Zotero.DB.columnQueryAsync("SELECT fieldID FROM fieldsCombined");
|
||||
var fieldIDs = await Zotero.DB.columnQueryAsync("SELECT fieldID FROM fieldsCombined");
|
||||
var baseMappedFields = Zotero.ItemFields.getBaseMappedFields();
|
||||
|
||||
for (let fieldID of fieldIDs) {
|
||||
|
@ -70,19 +72,20 @@
|
|||
}
|
||||
|
||||
// Write to file
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString('dataDir.selectDir'), nsIFilePicker.modeGetFolder);
|
||||
var fp = new FilePicker();
|
||||
fp.init(window, Zotero.getString('dataDir.selectDir'), fp.modeGetFolder);
|
||||
|
||||
let resultElem = document.getElementById('result');
|
||||
if (fp.show() != nsIFilePicker.returnOK) {
|
||||
if (await fp.show() != fp.returnOK) {
|
||||
result.innerHTML = '<p>Failed.</p>';
|
||||
} else {
|
||||
let schemaFile = fp.file;
|
||||
schemaFile.append("connectorTypeSchemaData.js");
|
||||
Zotero.File.putContents(schemaFile, `Zotero.Connector_Types.schema = ${JSON.stringify(schema)}`);
|
||||
result.innerHTML = `<p>Wrote ${schemaFile.path} successfully.</p>`;
|
||||
await Zotero.File.putContentsAsync(
|
||||
schemaFile,
|
||||
`Zotero.Connector_Types.schema = ${JSON.stringify(schema)}`
|
||||
);
|
||||
result.innerHTML = `<p>Wrote ${schemaFile} successfully.</p>`;
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
import FilePicker from 'zotero/filePicker';
|
||||
|
||||
var Zotero_CSL_Editor = new function() {
|
||||
this.init = init;
|
||||
this.handleKeyPress = handleKeyPress;
|
||||
|
@ -83,13 +85,11 @@ var Zotero_CSL_Editor = new function() {
|
|||
this.generateBibliography(this.loadStyleFromEditor());
|
||||
}
|
||||
|
||||
this.save = function() {
|
||||
this.save = async function () {
|
||||
var editor = document.getElementById('zotero-csl-editor');
|
||||
var style = editor.value;
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString('styles.editor.save'), nsIFilePicker.modeSave);
|
||||
var fp = new FilePicker();
|
||||
fp.init(window, Zotero.getString('styles.editor.save'), fp.modeSave);
|
||||
fp.appendFilter("Citation Style Language", "*.csl");
|
||||
//get the filename from the id; we could consider doing even more here like creating the id from filename.
|
||||
var parser = new DOMParser();
|
||||
|
@ -102,10 +102,10 @@ var Zotero_CSL_Editor = new function() {
|
|||
else {
|
||||
fp.defaultString = "untitled.csl";
|
||||
}
|
||||
var rv = fp.show();
|
||||
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
|
||||
var outputFile = fp.file;
|
||||
Zotero.File.putContents(outputFile, style);
|
||||
var rv = await fp.show();
|
||||
if (rv == fp.returnOK || rv == fp.returnReplace) {
|
||||
let outputFile = fp.file;
|
||||
Zotero.File.putContentsAsync(outputFile, style);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -858,15 +858,11 @@ Zotero.Attachments = new function(){
|
|||
}
|
||||
|
||||
wbp.progressListener = new Zotero.WebProgressFinishListener(() => resolve());
|
||||
|
||||
var nsIURL = Components.classes["@mozilla.org/network/standard-url;1"]
|
||||
.createInstance(Components.interfaces.nsIURL);
|
||||
nsIURL.spec = url;
|
||||
var headers = {};
|
||||
if (options.referrer) {
|
||||
headers.Referer = options.referrer;
|
||||
}
|
||||
Zotero.Utilities.Internal.saveURI(wbp, nsIURL, path, headers);
|
||||
Zotero.Utilities.Internal.saveURI(wbp, url, path, headers);
|
||||
});
|
||||
|
||||
if (options.isPDF) {
|
||||
|
@ -2114,21 +2110,15 @@ Zotero.Attachments = new function(){
|
|||
var parent = OS.Path.dirname(path);
|
||||
var iterator = new OS.File.DirectoryIterator(parent);
|
||||
try {
|
||||
while (true) {
|
||||
let entry = yield iterator.next();
|
||||
yield iterator.forEach((entry) => {
|
||||
if (entry.name.startsWith('.')) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
numFiles++;
|
||||
if (numFiles > 1) {
|
||||
break;
|
||||
iterator.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
if (e != StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
finally {
|
||||
iterator.close();
|
||||
|
@ -2427,53 +2417,43 @@ Zotero.Attachments = new function(){
|
|||
|
||||
|
||||
this._getFileNameFromURL = function(url, contentType) {
|
||||
var nsIURL = Components.classes["@mozilla.org/network/standard-url;1"]
|
||||
.createInstance(Components.interfaces.nsIURL);
|
||||
nsIURL.spec = url;
|
||||
url = Zotero.Utilities.parseURL(url);
|
||||
|
||||
var ext = Zotero.MIME.getPrimaryExtension(contentType, nsIURL.fileExtension);
|
||||
var fileBaseName = url.fileBaseName;
|
||||
var fileExt = Zotero.MIME.getPrimaryExtension(contentType, url.fileExtension);
|
||||
|
||||
if (!nsIURL.fileName) {
|
||||
var matches = nsIURL.directory.match(/\/([^\/]+)\/$/);
|
||||
if (!fileBaseName) {
|
||||
let matches = url.pathname.match(/\/([^\/]+)\/$/);
|
||||
// If no filename, use the last part of the path if there is one
|
||||
if (matches) {
|
||||
nsIURL.fileName = matches[1];
|
||||
fileBaseName = matches[1];
|
||||
}
|
||||
// Or just use the host
|
||||
else {
|
||||
nsIURL.fileName = nsIURL.host;
|
||||
var tld = nsIURL.fileExtension;
|
||||
fileBaseName = url.hostname;
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a better extension, use that
|
||||
if (ext && (!nsIURL.fileExtension || nsIURL.fileExtension != ext)) {
|
||||
nsIURL.fileExtension = ext;
|
||||
}
|
||||
|
||||
// If we replaced the TLD (which would've been interpreted as the extension), add it back
|
||||
if (tld && tld != nsIURL.fileExtension) {
|
||||
nsIURL.fileBaseName = nsIURL.fileBaseName + '.' + tld;
|
||||
}
|
||||
|
||||
// Test unencoding fileBaseName
|
||||
try {
|
||||
decodeURIComponent(nsIURL.fileBaseName);
|
||||
decodeURIComponent(fileBaseName);
|
||||
}
|
||||
catch (e) {
|
||||
if (e.name == 'URIError') {
|
||||
// If we got a 'malformed URI sequence' while decoding,
|
||||
// use MD5 of fileBaseName
|
||||
nsIURL.fileBaseName = Zotero.Utilities.Internal.md5(nsIURL.fileBaseName, false);
|
||||
fileBaseName = Zotero.Utilities.Internal.md5(fileBaseName, false);
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
var fileName = fileBaseName + (fileExt ? '.' + fileExt : '');
|
||||
|
||||
// Pass unencoded name to getValidFileName() so that percent-encoded
|
||||
// characters aren't stripped to just numbers
|
||||
return Zotero.File.getValidFileName(decodeURIComponent(nsIURL.fileName));
|
||||
return Zotero.File.getValidFileName(decodeURIComponent(fileName));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -673,23 +673,8 @@ Zotero.Cite.Locale = {
|
|||
if (str) {
|
||||
return str;
|
||||
}
|
||||
var uri = `chrome://zotero/content/locale/csl/locales-${locale}.xml`;
|
||||
try {
|
||||
let protHandler = Components.classes["@mozilla.org/network/protocol;1?name=chrome"]
|
||||
.createInstance(Components.interfaces.nsIProtocolHandler);
|
||||
let channel = protHandler.newChannel(protHandler.newURI(uri));
|
||||
let cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
cstream.init(channel.open(), "UTF-8", 0, 0);
|
||||
let obj = {};
|
||||
let read = 0;
|
||||
let str = "";
|
||||
do {
|
||||
// Read as much as we can and put it in obj.value
|
||||
read = cstream.readString(0xffffffff, obj);
|
||||
str += obj.value;
|
||||
} while (read != 0);
|
||||
cstream.close();
|
||||
str = Zotero.File.getResource(`chrome://zotero/content/locale/csl/locales-${locale}.xml`);
|
||||
this._cache.set(locale, str);
|
||||
return str;
|
||||
}
|
||||
|
|
|
@ -221,7 +221,7 @@ Zotero.CookieSandbox.prototype = {
|
|||
*/
|
||||
"getCookiesForURI": function(uri) {
|
||||
var hostParts = Zotero.CookieSandbox.normalizeHost(uri.host).split('.'),
|
||||
pathParts = Zotero.CookieSandbox.normalizePath(uri.path).split('/'),
|
||||
pathParts = Zotero.CookieSandbox.normalizePath(uri.filePath || uri.pathQueryRef).split('/'),
|
||||
cookies = {}, found = false, secure = uri.scheme.toUpperCase() == 'HTTPS';
|
||||
|
||||
// Fetch cookies starting from the highest level domain
|
||||
|
|
|
@ -239,6 +239,7 @@ Zotero.CreatorTypes = new function() {
|
|||
var sql = "SELECT itemTypeID, creatorTypeID AS id, creatorType AS name, primaryField "
|
||||
+ "FROM itemTypeCreatorTypes NATURAL JOIN creatorTypes";
|
||||
var rows = yield Zotero.DB.queryAsync(sql);
|
||||
_creatorTypesByItemType = {};
|
||||
for (let i=0; i<rows.length; i++) {
|
||||
let row = rows[i];
|
||||
let itemTypeID = row.itemTypeID;
|
||||
|
@ -307,7 +308,8 @@ Zotero.CreatorTypes = new function() {
|
|||
|
||||
|
||||
this.getLocalizedString = function(idOrName) {
|
||||
return Zotero.getString("creatorTypes."+this.getName(idOrName));
|
||||
var name = this.getName(idOrName);
|
||||
return Zotero.Schema.globalSchemaLocale.creatorTypes[name];
|
||||
}
|
||||
|
||||
|
||||
|
@ -437,7 +439,7 @@ Zotero.ItemTypes = new function() {
|
|||
return _customLabels[id];
|
||||
}
|
||||
|
||||
return Zotero.getString("itemTypes." + typeName);
|
||||
return Zotero.Schema.globalSchemaLocale.itemTypes[typeName];
|
||||
}
|
||||
|
||||
this.getImageSrc = function (itemType) {
|
||||
|
|
|
@ -699,7 +699,25 @@ Zotero.Collection.prototype.serialize = function(nested) {
|
|||
*
|
||||
* If this object is identified (has an id or library/key), loadAllData() must have been called.
|
||||
*/
|
||||
Zotero.Collection.prototype.fromJSON = function (json) {
|
||||
Zotero.Collection.prototype.fromJSON = function (json, options = {}) {
|
||||
if (options.strict) {
|
||||
for (let prop in json) {
|
||||
switch (prop) {
|
||||
case 'key':
|
||||
case 'version':
|
||||
case 'name':
|
||||
case 'parentCollection':
|
||||
case 'relations':
|
||||
break;
|
||||
|
||||
default:
|
||||
let e = new Error(`Unknown collection property '${prop}'`);
|
||||
e.name = "ZoteroInvalidDataError";
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!json.name) {
|
||||
throw new Error("'name' property not provided for collection");
|
||||
}
|
||||
|
|
|
@ -171,7 +171,7 @@ Zotero.Creators = new function() {
|
|||
},
|
||||
|
||||
|
||||
this.cleanData = function (data) {
|
||||
this.cleanData = function (data, options = {}) {
|
||||
// Validate data
|
||||
if (data.name === undefined && data.lastName === undefined) {
|
||||
throw new Error("Creator data must contain either 'name' or 'firstName'/'lastName' properties");
|
||||
|
@ -227,9 +227,12 @@ Zotero.Creators = new function() {
|
|||
if (creatorType) {
|
||||
cleanedData.creatorTypeID = Zotero.CreatorTypes.getID(creatorType);
|
||||
if (!cleanedData.creatorTypeID) {
|
||||
let msg = "'" + creatorType + "' isn't a valid creator type";
|
||||
Zotero.debug(msg, 2);
|
||||
Components.utils.reportError(msg);
|
||||
if (options.strict) {
|
||||
let e = new Error(`Unknown creator type '${creatorType}'`);
|
||||
e.name = "ZoteroInvalidDataError";
|
||||
throw e;
|
||||
}
|
||||
Zotero.warn(`'${creatorType}' isn't a valid creator type`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ Zotero.DataObjectUtilities = {
|
|||
delete target[i];
|
||||
}
|
||||
}
|
||||
// If field from base doesn't exist in new version, clear it
|
||||
// Field from base doesn't exist in new version
|
||||
else {
|
||||
switch (i) {
|
||||
// When changing an item from top-level to child, the collections property is
|
||||
|
@ -137,14 +137,17 @@ Zotero.DataObjectUtilities = {
|
|||
case 'collections':
|
||||
break;
|
||||
|
||||
// Set known boolean fields to false
|
||||
case 'deleted':
|
||||
case 'parentItem':
|
||||
case 'inPublications':
|
||||
target[i] = false;
|
||||
break;
|
||||
|
||||
// Skip other fields. This prevents us from clearing fields in the pristine JSON
|
||||
// that aren't handled here.
|
||||
default:
|
||||
target[i] = '';
|
||||
delete target[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -272,8 +272,7 @@ Zotero.Item.prototype.getField = function(field, unformatted, includeBaseMapped)
|
|||
|
||||
if (!unformatted) {
|
||||
// Multipart date fields
|
||||
// TEMP - filingDate
|
||||
if (Zotero.ItemFields.isFieldOfBase(fieldID, 'date') || field == 'filingDate') {
|
||||
if (Zotero.ItemFields.isDate(fieldID)) {
|
||||
value = Zotero.Date.multipartToStr(value);
|
||||
}
|
||||
}
|
||||
|
@ -283,9 +282,8 @@ Zotero.Item.prototype.getField = function(field, unformatted, includeBaseMapped)
|
|||
|
||||
|
||||
Zotero.Item.prototype.getExtraField = function (fieldName) {
|
||||
var fields = Zotero.Utilities.Internal.extractExtraFields(this.getField('extra'));
|
||||
var doi = fields.get(fieldName);
|
||||
return (doi && doi.value) ? doi.value : '';
|
||||
var { fields } = Zotero.Utilities.Internal.extractExtraFields(this.getField('extra'));
|
||||
return fields.get(fieldName) || '';
|
||||
};
|
||||
|
||||
|
||||
|
@ -577,7 +575,6 @@ Zotero.Item.prototype.setType = function(itemTypeID, loadIn) {
|
|||
*/
|
||||
Zotero.Item.prototype.getFieldsNotInType = function (itemTypeID, allowBaseConversion) {
|
||||
var fieldIDs = [];
|
||||
|
||||
for (var field in this._itemData) {
|
||||
if (this._itemData[field]) {
|
||||
var fieldID = Zotero.ItemFields.getID(field);
|
||||
|
@ -598,32 +595,9 @@ Zotero.Item.prototype.getFieldsNotInType = function (itemTypeID, allowBaseConver
|
|||
fieldIDs.push(fieldID);
|
||||
}
|
||||
}
|
||||
/*
|
||||
var sql = "SELECT fieldID FROM itemTypeFields WHERE itemTypeID=?1 AND "
|
||||
+ "fieldID IN (SELECT fieldID FROM itemData WHERE itemID=?2) AND "
|
||||
+ "fieldID NOT IN (SELECT fieldID FROM itemTypeFields WHERE itemTypeID=?3)";
|
||||
|
||||
if (allowBaseConversion) {
|
||||
// Not the type-specific field for a base field in the new type
|
||||
sql += " AND fieldID NOT IN (SELECT fieldID FROM baseFieldMappings "
|
||||
+ "WHERE itemTypeID=?1 AND baseFieldID IN "
|
||||
+ "(SELECT fieldID FROM itemTypeFields WHERE itemTypeID=?3)) AND ";
|
||||
// And not a base field with a type-specific field in the new type
|
||||
sql += "fieldID NOT IN (SELECT baseFieldID FROM baseFieldMappings "
|
||||
+ "WHERE itemTypeID=?3) AND ";
|
||||
// And not the type-specific field for a base field that has
|
||||
// a type-specific field in the new type
|
||||
sql += "fieldID NOT IN (SELECT fieldID FROM baseFieldMappings "
|
||||
+ "WHERE itemTypeID=?1 AND baseFieldID IN "
|
||||
+ "(SELECT baseFieldID FROM baseFieldMappings WHERE itemTypeID=?3))";
|
||||
}
|
||||
|
||||
return Zotero.DB.columnQuery(sql, [this.itemTypeID, this.id, { int: itemTypeID }]);
|
||||
*/
|
||||
if (!fieldIDs.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fieldIDs;
|
||||
}
|
||||
|
||||
|
@ -753,7 +727,7 @@ Zotero.Item.prototype.setField = function(field, value, loadIn) {
|
|||
throw new Error('"' + field + '" is not a valid itemData field');
|
||||
}
|
||||
|
||||
if (loadIn && this.isNote() && field == 110) { // title
|
||||
if (loadIn && this.isNote() && field == Zotero.ItemFields.getID('title')) {
|
||||
this._noteTitle = value ? value : "";
|
||||
return true;
|
||||
}
|
||||
|
@ -798,9 +772,8 @@ Zotero.Item.prototype.setField = function(field, value, loadIn) {
|
|||
|
||||
if (!loadIn) {
|
||||
// Save date field as multipart date
|
||||
// TEMP - filingDate
|
||||
if (value !== false
|
||||
&& (Zotero.ItemFields.isFieldOfBase(fieldID, 'date') || field == 'filingDate')
|
||||
&& (Zotero.ItemFields.isDate(fieldID))
|
||||
&& !Zotero.Date.isMultipart(value)) {
|
||||
value = Zotero.Date.strToMultipart(value);
|
||||
}
|
||||
|
@ -867,19 +840,29 @@ Zotero.Item.prototype.updateDisplayTitle = function () {
|
|||
var itemTypeID = this.itemTypeID;
|
||||
var itemTypeName = Zotero.ItemTypes.getName(itemTypeID);
|
||||
|
||||
if (title === "" && (itemTypeID == 8 || itemTypeID == 10)) { // 'letter' and 'interview' itemTypeIDs
|
||||
var itemTypeLetter = Zotero.ItemTypes.getID('letter');
|
||||
var itemTypeInterview = Zotero.ItemTypes.getID('interview');
|
||||
var itemTypeCase = Zotero.ItemTypes.getID('case');
|
||||
|
||||
var creatorTypeAuthor = Zotero.CreatorTypes.getID('author');
|
||||
var creatorTypeRecipient = Zotero.CreatorTypes.getID('recipient');
|
||||
var creatorTypeInterviewer = Zotero.CreatorTypes.getID('interviewer');
|
||||
var creatorTypeInterviewee = Zotero.CreatorTypes.getID('interviewee');
|
||||
|
||||
// 'letter' and 'interview'
|
||||
if (title === "" && (itemTypeID == itemTypeLetter || itemTypeID == itemTypeInterview)) {
|
||||
var creatorsData = this.getCreators();
|
||||
var authors = [];
|
||||
var participants = [];
|
||||
for (let i=0; i<creatorsData.length; i++) {
|
||||
let creatorData = creatorsData[i];
|
||||
let creatorTypeID = creatorsData[i].creatorTypeID;
|
||||
if ((itemTypeID == 8 && creatorTypeID == 16) || // 'letter'
|
||||
(itemTypeID == 10 && creatorTypeID == 7)) { // 'interview'
|
||||
if ((itemTypeID == itemTypeLetter && creatorTypeID == creatorTypeRecipient) ||
|
||||
(itemTypeID == itemTypeInterview && creatorTypeID == creatorTypeInterviewer)) {
|
||||
participants.push(creatorData);
|
||||
}
|
||||
else if ((itemTypeID == 8 && creatorTypeID == 1) || // 'letter'/'author'
|
||||
(itemTypeID == 10 && creatorTypeID == 6)) { // 'interview'/'interviewee'
|
||||
else if ((itemTypeID == itemTypeLetter && creatorTypeID == creatorTypeAuthor) ||
|
||||
(itemTypeID == itemTypeInterview && creatorTypeID == creatorTypeInterviewee)) {
|
||||
authors.push(creatorData);
|
||||
}
|
||||
}
|
||||
|
@ -919,7 +902,8 @@ Zotero.Item.prototype.updateDisplayTitle = function () {
|
|||
|
||||
title = '[' + strParts.join('; ') + ']';
|
||||
}
|
||||
else if (itemTypeID == 17) { // 'case' itemTypeID
|
||||
// 'case'
|
||||
else if (itemTypeID == itemTypeCase) {
|
||||
if (title) { // common law cases always have case names
|
||||
var reporter = this.getField('reporter');
|
||||
if (reporter) {
|
||||
|
@ -946,7 +930,7 @@ Zotero.Item.prototype.updateDisplayTitle = function () {
|
|||
}
|
||||
|
||||
var creatorData = this.getCreator(0);
|
||||
if (creatorData && creatorData.creatorTypeID === 1) { // author
|
||||
if (creatorData && creatorData.creatorTypeID === creatorTypeAuthor) {
|
||||
strParts.push(creatorData.lastName);
|
||||
}
|
||||
|
||||
|
@ -1038,8 +1022,10 @@ Zotero.Item.prototype.getCreatorsJSON = function () {
|
|||
* <li>'name' or 'firstName'/'lastName', or 'firstName'/'lastName'/'fieldMode'</li>
|
||||
* <li>'creatorType' (can be name or id) or 'creatorTypeID'</li>
|
||||
* </ul>
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.strict] - Throw on invalid creator type
|
||||
*/
|
||||
Zotero.Item.prototype.setCreator = function (orderIndex, data) {
|
||||
Zotero.Item.prototype.setCreator = function (orderIndex, data, options = {}) {
|
||||
var itemTypeID = this._itemTypeID;
|
||||
if (!itemTypeID) {
|
||||
throw new Error('Item type must be set before setting creators');
|
||||
|
@ -1047,7 +1033,8 @@ Zotero.Item.prototype.setCreator = function (orderIndex, data) {
|
|||
|
||||
this._requireData('creators');
|
||||
|
||||
data = Zotero.Creators.cleanData(data);
|
||||
var origCreatorType = data.creatorType;
|
||||
data = Zotero.Creators.cleanData(data, options);
|
||||
|
||||
if (data.creatorTypeID === undefined) {
|
||||
throw new Error("Creator data must include a valid 'creatorType' or 'creatorTypeID' property");
|
||||
|
@ -1055,9 +1042,14 @@ Zotero.Item.prototype.setCreator = function (orderIndex, data) {
|
|||
|
||||
// If creatorTypeID isn't valid for this type, use the primary type
|
||||
if (!data.creatorTypeID || !Zotero.CreatorTypes.isValidForItemType(data.creatorTypeID, itemTypeID)) {
|
||||
var msg = "Creator type '" + Zotero.CreatorTypes.getName(data.creatorTypeID) + "' "
|
||||
+ "isn't valid for " + Zotero.ItemTypes.getName(itemTypeID)
|
||||
+ " -- changing to primary creator";
|
||||
let itemType = Zotero.ItemTypes.getName(itemTypeID);
|
||||
if (options.strict) {
|
||||
let e = new Error(`Invalid creator type '${origCreatorType}' for type ${itemType}`);
|
||||
e.name = "ZoteroInvalidDataError";
|
||||
throw e;
|
||||
}
|
||||
let msg = `Creator type '${origCreatorType}' isn't valid for ${itemType} -- `
|
||||
+ "changing to primary creator";
|
||||
Zotero.warn(msg);
|
||||
data.creatorTypeID = Zotero.CreatorTypes.getPrimaryIDForType(itemTypeID);
|
||||
}
|
||||
|
@ -1087,7 +1079,7 @@ Zotero.Item.prototype.setCreator = function (orderIndex, data) {
|
|||
/**
|
||||
* @param {Object[]} data - An array of creator data in internal or API JSON format
|
||||
*/
|
||||
Zotero.Item.prototype.setCreators = function (data) {
|
||||
Zotero.Item.prototype.setCreators = function (data, options = {}) {
|
||||
// If empty array, clear all existing creators
|
||||
if (!data.length) {
|
||||
while (this.hasCreatorAt(0)) {
|
||||
|
@ -1097,7 +1089,7 @@ Zotero.Item.prototype.setCreators = function (data) {
|
|||
}
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
this.setCreator(i, data[i]);
|
||||
this.setCreator(i, data[i], options);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2239,7 +2231,7 @@ Zotero.Item.prototype.getFilePath = function () {
|
|||
}
|
||||
|
||||
let file = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
.createInstance(Components.interfaces.nsIFile);
|
||||
try {
|
||||
file.persistentDescriptor = path;
|
||||
}
|
||||
|
@ -2345,7 +2337,7 @@ Zotero.Item.prototype.getFilePathAsync = Zotero.Promise.coroutine(function* () {
|
|||
// the file couldn't be found
|
||||
if (Zotero.isMac && path.startsWith('AAAA')) {
|
||||
let file = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
.createInstance(Components.interfaces.nsIFile);
|
||||
try {
|
||||
file.persistentDescriptor = path;
|
||||
}
|
||||
|
@ -3292,14 +3284,15 @@ Zotero.Item.prototype.getBestAttachments = Zotero.Promise.coroutine(function* ()
|
|||
}
|
||||
|
||||
var url = this.getField('url');
|
||||
var urlFieldID = Zotero.ItemFields.getID('url');
|
||||
|
||||
var sql = "SELECT IA.itemID FROM itemAttachments IA NATURAL JOIN items I "
|
||||
+ "LEFT JOIN itemData ID ON (IA.itemID=ID.itemID AND fieldID=1) "
|
||||
+ `LEFT JOIN itemData ID ON (IA.itemID=ID.itemID AND fieldID=${urlFieldID}) `
|
||||
+ "LEFT JOIN itemDataValues IDV ON (ID.valueID=IDV.valueID) "
|
||||
+ "WHERE parentItemID=? AND linkMode NOT IN (?) "
|
||||
+ `WHERE parentItemID=? AND linkMode NOT IN (${Zotero.Attachments.LINK_MODE_LINKED_URL}) `
|
||||
+ "AND IA.itemID NOT IN (SELECT itemID FROM deletedItems) "
|
||||
+ "ORDER BY contentType='application/pdf' DESC, value=? DESC, dateAdded ASC";
|
||||
var itemIDs = yield Zotero.DB.columnQueryAsync(sql, [this.id, Zotero.Attachments.LINK_MODE_LINKED_URL, url]);
|
||||
var itemIDs = yield Zotero.DB.columnQueryAsync(sql, [this.id, url]);
|
||||
return this.ObjectsClass.get(itemIDs);
|
||||
});
|
||||
|
||||
|
@ -4193,31 +4186,48 @@ Zotero.Item.prototype.isCollection = function() {
|
|||
|
||||
/**
|
||||
* Populate the object's data from an API JSON data object
|
||||
*
|
||||
* @param {Object} json
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.strict = false] - Throw on unknown field or invalid field for type
|
||||
*/
|
||||
Zotero.Item.prototype.fromJSON = function (json) {
|
||||
Zotero.Item.prototype.fromJSON = function (json, options = {}) {
|
||||
var strict = !!options.strict;
|
||||
|
||||
if (!json.itemType && !this._itemTypeID) {
|
||||
throw new Error("itemType property not provided");
|
||||
}
|
||||
|
||||
let itemTypeID = Zotero.ItemTypes.getID(json.itemType);
|
||||
if (!itemTypeID) {
|
||||
let e = new Error(`Invalid item type '${json.itemType}'`);
|
||||
e.name = "ZoteroUnknownTypeError";
|
||||
let e = new Error(`Unknown item type '${json.itemType}'`);
|
||||
e.name = "ZoteroInvalidDataError";
|
||||
throw e;
|
||||
}
|
||||
this.setType(itemTypeID);
|
||||
|
||||
var isValidForType = {};
|
||||
var setFields = {};
|
||||
var setFields = new Set();
|
||||
/*var { fields: extraFields, creators: extraCreators, extra } = Zotero.Utilities.Internal.extractExtraFields(
|
||||
json.extra !== undefined ? json.extra : '',
|
||||
this,
|
||||
Object.keys(json)
|
||||
);*/
|
||||
|
||||
// Transfer valid fields from Extra to regular fields
|
||||
// Currently disabled
|
||||
/*for (let [field, value] of extraFields) {
|
||||
this.setField(field, value);
|
||||
setFields.add(field);
|
||||
extraFields.delete(field);
|
||||
}*/
|
||||
|
||||
// Primary data
|
||||
for (let field in json) {
|
||||
let val = json[field];
|
||||
|
||||
switch (field) {
|
||||
case 'key':
|
||||
case 'version':
|
||||
case 'synced':
|
||||
case 'itemType':
|
||||
case 'note':
|
||||
// Use?
|
||||
|
@ -4228,6 +4238,7 @@ Zotero.Item.prototype.fromJSON = function (json) {
|
|||
case 'parentItem':
|
||||
case 'deleted':
|
||||
case 'inPublications':
|
||||
case 'extra':
|
||||
break;
|
||||
|
||||
case 'accessDate':
|
||||
|
@ -4240,7 +4251,7 @@ Zotero.Item.prototype.fromJSON = function (json) {
|
|||
val = Zotero.Date.dateToSQL(d, true);
|
||||
}
|
||||
this.setField(field, val);
|
||||
setFields[field] = true;
|
||||
setFields.add(field);
|
||||
break;
|
||||
|
||||
case 'dateAdded':
|
||||
|
@ -4257,7 +4268,8 @@ Zotero.Item.prototype.fromJSON = function (json) {
|
|||
break;
|
||||
|
||||
case 'creators':
|
||||
this.setCreators(json.creators);
|
||||
//this.setCreators(json.creators.concat(extraCreators), options);
|
||||
this.setCreators(json.creators, options);
|
||||
break;
|
||||
|
||||
case 'tags':
|
||||
|
@ -4300,8 +4312,20 @@ Zotero.Item.prototype.fromJSON = function (json) {
|
|||
default:
|
||||
let fieldID = Zotero.ItemFields.getID(field);
|
||||
if (!fieldID) {
|
||||
Zotero.logError("Discarding unknown JSON field '" + field + "' for item "
|
||||
+ this.libraryKey);
|
||||
// In strict mode, fail on unknown field
|
||||
if (strict) {
|
||||
let e = new Error(`Unknown field '${field}'`);
|
||||
e.name = "ZoteroInvalidDataError";
|
||||
throw e;
|
||||
}
|
||||
// Otherwise store in Extra
|
||||
// TEMP: Disabled for now, along with tests in itemTest.js
|
||||
/*if (typeof val == 'string') {
|
||||
Zotero.warn(`Storing unknown field '${field}' in Extra for item ${this.libraryKey}`);
|
||||
extraFields.set(field, val);
|
||||
break;
|
||||
}*/
|
||||
Zotero.warn(`Discarding unknown JSON ${typeof val} '${field}' for item ${this.libraryKey}`);
|
||||
continue;
|
||||
}
|
||||
// Convert to base-mapped field if necessary, so that setFields has the base-mapped field
|
||||
|
@ -4314,15 +4338,30 @@ Zotero.Item.prototype.fromJSON = function (json) {
|
|||
}
|
||||
isValidForType[field] = Zotero.ItemFields.isValidForType(fieldID, this.itemTypeID);
|
||||
if (!isValidForType[field]) {
|
||||
Zotero.logError("Discarding invalid field '" + origField + "' for type " + itemTypeID
|
||||
+ " for item " + this.libraryKey);
|
||||
let type = Zotero.ItemTypes.getName(itemTypeID);
|
||||
// In strict mode, fail on invalid field for type
|
||||
if (strict) {
|
||||
let e = new Error(`Invalid field '${origField}' for type ${type}`);
|
||||
e.name = "ZoteroInvalidDataError";
|
||||
throw e;
|
||||
}
|
||||
// Otherwise store in Extra
|
||||
// TEMP: Disabled for now, since imports can assign values to multiple versions of
|
||||
// fields
|
||||
// https://groups.google.com/d/msg/zotero-dev/a1IPUJ2m_3s/hfmdK2P3BwAJ
|
||||
/*Zotero.warn(`Storing invalid field '${origField}' for type ${type} in Extra for `
|
||||
+ `item ${this.libraryKey}`);
|
||||
extraFields.set(field, val);*/
|
||||
continue;
|
||||
}
|
||||
this.setField(field, json[origField]);
|
||||
setFields[field] = true;
|
||||
setFields.add(field);
|
||||
}
|
||||
}
|
||||
|
||||
//this.setField('extra', Zotero.Utilities.Internal.combineExtraFields(extra, extraFields));
|
||||
this.setField('extra', json.extra !== undefined ? json.extra : '');
|
||||
|
||||
if (json.collections || this._collections.length) {
|
||||
this.setCollections(json.collections);
|
||||
}
|
||||
|
@ -4330,7 +4369,7 @@ Zotero.Item.prototype.fromJSON = function (json) {
|
|||
// Clear existing fields not specified
|
||||
var previousFields = this.getUsedFields(true);
|
||||
for (let field of previousFields) {
|
||||
if (!setFields[field] && isValidForType[field] !== false) {
|
||||
if (!setFields.has(field) && isValidForType[field] !== false && field != 'extra') {
|
||||
this.setField(field, false);
|
||||
}
|
||||
}
|
||||
|
@ -4511,6 +4550,45 @@ Zotero.Item.prototype.toResponseJSON = function (options = {}) {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* Migrate valid fields in Extra to real fields
|
||||
*
|
||||
* A separate save is required
|
||||
*/
|
||||
Zotero.Item.prototype.migrateExtraFields = function () {
|
||||
var { itemType, fields, creators, extra } = Zotero.Utilities.Internal.extractExtraFields(
|
||||
this.getField('extra'), this
|
||||
);
|
||||
if (itemType) {
|
||||
this.setType(Zotero.ItemTypes.getID(itemType));
|
||||
}
|
||||
for (let [field, value] of fields) {
|
||||
this.setField(field, value);
|
||||
}
|
||||
if (creators.length) {
|
||||
this.setCreators([...item.getCreators(), ...creators]);
|
||||
}
|
||||
this.setField('extra', extra);
|
||||
if (!this.hasChanged()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Zotero.debug("Migrating Extra fields for item " + this.libraryKey);
|
||||
if (itemType) {
|
||||
Zotero.debug("Item Type: " + itemType);
|
||||
}
|
||||
if (fields.size) {
|
||||
Zotero.debug(Array.from(fields.entries()));
|
||||
}
|
||||
if (creators.length) {
|
||||
Zotero.debug(creators);
|
||||
}
|
||||
Zotero.debug(extra);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Asynchronous load methods
|
||||
|
|
|
@ -42,7 +42,6 @@ Zotero.ItemFields = new function() {
|
|||
// Privileged methods
|
||||
this.getName = getName;
|
||||
this.getID = getID;
|
||||
this.getLocalizedString = getLocalizedString;
|
||||
this.isValidForType = isValidForType;
|
||||
this.isInteger = isInteger;
|
||||
this.getItemTypeFields = getItemTypeFields;
|
||||
|
@ -77,17 +76,29 @@ Zotero.ItemFields = new function() {
|
|||
var baseFields = yield Zotero.DB.columnQueryAsync(sql);
|
||||
|
||||
for (let field of fields) {
|
||||
_fields[field['fieldID']] = {
|
||||
id: field['fieldID'],
|
||||
let isBaseField = baseFields.includes(field.fieldID);
|
||||
let label;
|
||||
try {
|
||||
label = field.label || Zotero.Schema.globalSchemaLocale.fields[field.fieldName];
|
||||
}
|
||||
// Some base fields aren't localized
|
||||
catch (e) {
|
||||
if (!isBaseField) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
_fields[field.fieldID] = {
|
||||
id: field.fieldID,
|
||||
name: field.fieldName,
|
||||
label: field.label,
|
||||
label,
|
||||
custom: !!field.custom,
|
||||
isBaseField: (baseFields.indexOf(field['fieldID']) != -1),
|
||||
formatID: field['fieldFormatID'],
|
||||
itemTypes: fieldItemTypes[field['fieldID']]
|
||||
isBaseField: baseFields.includes(field.fieldID),
|
||||
formatID: field.fieldFormatID,
|
||||
itemTypes: fieldItemTypes[field.fieldID]
|
||||
};
|
||||
// Store by name as well as id
|
||||
_fields[field['fieldName']] = _fields[field['fieldID']];
|
||||
_fields[field.fieldName] = _fields[field.fieldID];
|
||||
_allFields.push({
|
||||
id: field.fieldID,
|
||||
name: field.fieldName
|
||||
|
@ -133,40 +144,29 @@ Zotero.ItemFields = new function() {
|
|||
};
|
||||
|
||||
|
||||
function getLocalizedString(itemType, field) {
|
||||
// unused currently
|
||||
//var typeName = Zotero.ItemTypes.getName(itemType);
|
||||
var fieldName = Zotero.ItemFields.getName(field);
|
||||
this.getLocalizedString = function (field) {
|
||||
if (arguments.length == 2) {
|
||||
Zotero.warn("Zotero.ItemFields.getLocalizedString() no longer takes two arguments "
|
||||
+ "-- update your code");
|
||||
field = arguments[1];
|
||||
}
|
||||
|
||||
var fieldName = this.getName(field);
|
||||
|
||||
// Fields in the items table are special cases
|
||||
switch (field) {
|
||||
case 'dateAdded':
|
||||
case 'dateModified':
|
||||
case 'itemType':
|
||||
return Zotero.getString("itemFields." + field);
|
||||
return Zotero.Schema.globalSchemaLocale.fields[field];
|
||||
}
|
||||
|
||||
// TODO: different labels for different item types
|
||||
|
||||
_fieldCheck(field, 'getLocalizedString');
|
||||
_fieldCheck(field);
|
||||
|
||||
if (_fields[field].label) {
|
||||
return _fields[field].label;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
var loc = Zotero.getString("itemFields." + fieldName);
|
||||
}
|
||||
// If localized string not found, try base field
|
||||
catch (e) {
|
||||
Zotero.debug("Localized string not found for field '" + fieldName + "' -- trying base field");
|
||||
var baseFieldID = this.getBaseIDFromTypeAndField(itemType, field);
|
||||
fieldName = this.getName(baseFieldID);
|
||||
var loc = Zotero.getString("itemFields." + fieldName);
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
}
|
||||
return _fields[field].label;
|
||||
};
|
||||
|
||||
|
||||
function isValidForType(fieldID, itemTypeID) {
|
||||
|
@ -182,15 +182,28 @@ Zotero.ItemFields = new function() {
|
|||
|
||||
|
||||
function isInteger(fieldID) {
|
||||
_fieldCheck(fieldID, 'isInteger');
|
||||
_fieldCheck(fieldID);
|
||||
|
||||
var ffid = _fields[fieldID]['formatID'];
|
||||
return _fieldFormats[ffid] ? _fieldFormats[ffid]['isInteger'] : false;
|
||||
}
|
||||
|
||||
|
||||
this.isDate = function (field) {
|
||||
var fieldID = this.getID(field);
|
||||
var fieldName = this.getName(field);
|
||||
if (Zotero.ItemFields.isFieldOfBase(fieldID, 'date')) {
|
||||
return true;
|
||||
}
|
||||
if (Zotero.Schema.globalSchemaMeta.fields[fieldName]) {
|
||||
return Zotero.Schema.globalSchemaMeta.fields[fieldName].type == 'date'
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
this.isCustom = function (fieldID) {
|
||||
_fieldCheck(fieldID, 'isCustom');
|
||||
_fieldCheck(fieldID);
|
||||
|
||||
return _fields[fieldID].custom;
|
||||
}
|
||||
|
@ -202,7 +215,7 @@ Zotero.ItemFields = new function() {
|
|||
function getItemTypeFields(itemTypeID) {
|
||||
if (!itemTypeID) {
|
||||
let e = new Error("Invalid item type id '" + itemTypeID + "'");
|
||||
e.name = "ZoteroUnknownTypeError";
|
||||
e.name = "ZoteroInvalidDataError";
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
@ -219,14 +232,14 @@ Zotero.ItemFields = new function() {
|
|||
|
||||
|
||||
function isBaseField(field) {
|
||||
_fieldCheck(field, arguments.callee.name);
|
||||
_fieldCheck(field);
|
||||
|
||||
return _fields[field]['isBaseField'];
|
||||
}
|
||||
|
||||
|
||||
function isFieldOfBase(field, baseField) {
|
||||
var fieldID = _fieldCheck(field, 'isFieldOfBase');
|
||||
var fieldID = _fieldCheck(field);
|
||||
|
||||
var baseFieldID = this.getID(baseField);
|
||||
if (!baseFieldID) {
|
||||
|
@ -299,7 +312,7 @@ Zotero.ItemFields = new function() {
|
|||
throw new Error("Invalid item type '" + itemType + "'");
|
||||
}
|
||||
|
||||
_fieldCheck(typeField, 'getBaseIDFromTypeAndField');
|
||||
_fieldCheck(typeField);
|
||||
|
||||
if (!this.isValidForType(typeFieldID, itemTypeID)) {
|
||||
throw new Error("'" + typeField + "' is not a valid field for '" + itemType + "'");
|
||||
|
@ -406,11 +419,11 @@ Zotero.ItemFields = new function() {
|
|||
* Check whether a field is valid, throwing an exception if not
|
||||
* (since it should never actually happen)
|
||||
**/
|
||||
function _fieldCheck(field, func) {
|
||||
function _fieldCheck(field) {
|
||||
var fieldID = Zotero.ItemFields.getID(field);
|
||||
if (!fieldID) {
|
||||
Zotero.debug((new Error).stack, 1);
|
||||
throw new Error("Invalid field '" + field + (func ? "' in ItemFields." + func + "()" : "'"));
|
||||
throw new Error(`Invalid field '${field}`);
|
||||
}
|
||||
return fieldID;
|
||||
}
|
||||
|
@ -508,8 +521,9 @@ Zotero.ItemFields = new function() {
|
|||
var sql = 'SELECT itemTypeID, fieldID FROM itemTypeFieldsCombined ORDER BY orderIndex';
|
||||
var rows = yield Zotero.DB.queryAsync(sql);
|
||||
|
||||
_itemTypeFields = {};
|
||||
_itemTypeFields[1] = []; // notes have no fields
|
||||
_itemTypeFields = {
|
||||
[Zotero.ItemTypes.getID('note')]: [] // Notes have no fields
|
||||
};
|
||||
|
||||
for (let i=0; i<rows.length; i++) {
|
||||
let row = rows[i];
|
||||
|
|
|
@ -36,6 +36,9 @@ Zotero.Items = function() {
|
|||
// but otherwise it can be just a simple property
|
||||
Zotero.defineProperty(this, "_primaryDataSQLParts", {
|
||||
get: function () {
|
||||
var itemTypeAttachment = Zotero.ItemTypes.getID('attachment');
|
||||
var itemTypeNote = Zotero.ItemTypes.getID('note');
|
||||
|
||||
return {
|
||||
itemID: "O.itemID",
|
||||
itemTypeID: "O.itemTypeID",
|
||||
|
@ -52,8 +55,10 @@ Zotero.Items = function() {
|
|||
deleted: "DI.itemID IS NOT NULL AS deleted",
|
||||
inPublications: "PI.itemID IS NOT NULL AS inPublications",
|
||||
|
||||
parentID: "(CASE O.itemTypeID WHEN 14 THEN IAP.itemID WHEN 1 THEN INoP.itemID END) AS parentID",
|
||||
parentKey: "(CASE O.itemTypeID WHEN 14 THEN IAP.key WHEN 1 THEN INoP.key END) AS parentKey",
|
||||
parentID: `(CASE O.itemTypeID WHEN ${itemTypeAttachment} THEN IAP.itemID `
|
||||
+ `WHEN ${itemTypeNote} THEN INoP.itemID END) AS parentID`,
|
||||
parentKey: `(CASE O.itemTypeID WHEN ${itemTypeAttachment} THEN IAP.key `
|
||||
+ `WHEN ${itemTypeNote} THEN INoP.key END) AS parentKey`,
|
||||
|
||||
attachmentCharset: "CS.charset AS attachmentCharset",
|
||||
attachmentLinkMode: "IA.linkMode AS attachmentLinkMode",
|
||||
|
|
|
@ -282,7 +282,7 @@ Zotero.Search.prototype.addCondition = function (condition, operator, value, req
|
|||
|
||||
if (!Zotero.SearchConditions.hasOperator(condition, operator)){
|
||||
let e = new Error("Invalid operator '" + operator + "' for condition " + condition);
|
||||
e.name = "ZoteroUnknownFieldError";
|
||||
e.name = "ZoteroInvalidDataError";
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
@ -425,7 +425,7 @@ Zotero.Search.prototype.updateCondition = function (searchConditionID, condition
|
|||
|
||||
if (!Zotero.SearchConditions.hasOperator(condition, operator)){
|
||||
let e = new Error("Invalid operator '" + operator + "' for condition " + condition);
|
||||
e.name = "ZoteroUnknownFieldError";
|
||||
e.name = "ZoteroInvalidDataError";
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
@ -808,8 +808,29 @@ Zotero.Search.prototype.search = Zotero.Promise.coroutine(function* (asTempTable
|
|||
* Populate the object's data from an API JSON data object
|
||||
*
|
||||
* If this object is identified (has an id or library/key), loadAll() must have been called.
|
||||
*
|
||||
* @param {Object} json
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.strict = false] - Throw on unknown property
|
||||
*/
|
||||
Zotero.Search.prototype.fromJSON = function (json) {
|
||||
Zotero.Search.prototype.fromJSON = function (json, options = {}) {
|
||||
if (options.strict) {
|
||||
for (let prop in json) {
|
||||
switch (prop) {
|
||||
case 'key':
|
||||
case 'version':
|
||||
case 'name':
|
||||
case 'conditions':
|
||||
break;
|
||||
|
||||
default:
|
||||
let e = new Error(`Unknown search property '${prop}'`);
|
||||
e.name = "ZoteroInvalidDataError";
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (json.name) {
|
||||
this.name = json.name;
|
||||
}
|
||||
|
|
|
@ -629,7 +629,7 @@ Zotero.SearchConditions = new function(){
|
|||
|
||||
if (!_conditions[condition]){
|
||||
let e = new Error("Invalid condition '" + condition + "' in hasOperator()");
|
||||
e.name = "ZoteroUnknownFieldError";
|
||||
e.name = "ZoteroInvalidDataError";
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
@ -651,7 +651,7 @@ Zotero.SearchConditions = new function(){
|
|||
return Zotero.getString('searchConditions.' + str)
|
||||
}
|
||||
catch (e) {
|
||||
return Zotero.ItemFields.getLocalizedString(null, str);
|
||||
return Zotero.ItemFields.getLocalizedString(str);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
import FilePicker from 'zotero/filePicker';
|
||||
|
||||
Zotero.DataDirectory = {
|
||||
MIGRATION_MARKER: 'migrate-dir',
|
||||
|
||||
|
@ -98,7 +100,7 @@ Zotero.DataDirectory = {
|
|||
let nsIFile;
|
||||
try {
|
||||
nsIFile = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
.createInstance(Components.interfaces.nsIFile);
|
||||
nsIFile.persistentDescriptor = prefVal;
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -263,7 +265,7 @@ Zotero.DataDirectory = {
|
|||
let nsIFile;
|
||||
try {
|
||||
nsIFile = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
.createInstance(Components.interfaces.nsIFile);
|
||||
nsIFile.persistentDescriptor = prefs['extensions.zotero.dataDir'];
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -439,7 +441,7 @@ Zotero.DataDirectory = {
|
|||
},
|
||||
|
||||
|
||||
choose: Zotero.Promise.coroutine(function* (forceQuitNow, useHomeDir, moreInfoCallback) {
|
||||
choose: async function (forceQuitNow, useHomeDir, moreInfoCallback) {
|
||||
var win = Services.wm.getMostRecentWindow('navigator:browser');
|
||||
var ps = Services.prompt;
|
||||
|
||||
|
@ -450,17 +452,13 @@ Zotero.DataDirectory = {
|
|||
}
|
||||
}
|
||||
else {
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
while (true) {
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(win, Zotero.getString('dataDir.selectDir'), nsIFilePicker.modeGetFolder);
|
||||
fp.displayDirectory = Zotero.File.pathToFile(
|
||||
this._dir ? this._dir : OS.Path.dirname(this.defaultDir)
|
||||
);
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
if (fp.show() == nsIFilePicker.returnOK) {
|
||||
var file = fp.file;
|
||||
let fp = new FilePicker();
|
||||
fp.init(win, Zotero.getString('dataDir.selectDir'), fp.modeGetFolder);
|
||||
fp.displayDirectory = this._dir ? this._dir : OS.Path.dirname(this.defaultDir);
|
||||
fp.appendFilters(fp.filterAll);
|
||||
if (await fp.show() == fp.returnOK) {
|
||||
let file = Zotero.File.pathToFile(fp.file);
|
||||
let dialogText = '';
|
||||
let dialogTitle = '';
|
||||
|
||||
|
@ -547,24 +545,22 @@ Zotero.DataDirectory = {
|
|||
}
|
||||
|
||||
return useHomeDir ? true : file;
|
||||
}),
|
||||
},
|
||||
|
||||
|
||||
forceChange: function (win) {
|
||||
forceChange: async function (win) {
|
||||
if (!win) {
|
||||
win = Services.wm.getMostRecentWindow('navigator:browser');
|
||||
}
|
||||
var ps = Services.prompt;
|
||||
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
while (true) {
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(win, Zotero.getString('dataDir.selectNewDir', Zotero.clientName), nsIFilePicker.modeGetFolder);
|
||||
fp.displayDirectory = Zotero.File.pathToFile(this.dir);
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
if (fp.show() == nsIFilePicker.returnOK) {
|
||||
var file = fp.file;
|
||||
let fp = new FilePicker();
|
||||
fp.init(win, Zotero.getString('dataDir.selectNewDir', Zotero.clientName), fp.modeGetFolder);
|
||||
fp.displayDirectory = this.dir;
|
||||
fp.appendFilters(fp.filterAll);
|
||||
if (await fp.show() == fp.returnOK) {
|
||||
let file = Zotero.File.pathToFile(fp.file);
|
||||
|
||||
if (file.directoryEntries.hasMoreElements()) {
|
||||
ps.alert(null,
|
||||
|
@ -1012,21 +1008,13 @@ Zotero.DataDirectory = {
|
|||
// Focus the first file/folder in the old directory
|
||||
else if (index == 2) {
|
||||
try {
|
||||
let it = new OS.File.DirectoryIterator(oldDir);
|
||||
let entry;
|
||||
try {
|
||||
entry = yield it.next();
|
||||
}
|
||||
catch (e) {
|
||||
if (e != StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
it.close();
|
||||
}
|
||||
if (entry) {
|
||||
yield Zotero.File.reveal(entry.path);
|
||||
let firstEntry;
|
||||
yield Zotero.File.iterateDirectory(oldDir, function (entry, index, iterator) {
|
||||
firstEntry = entry;
|
||||
iterator.close();
|
||||
});
|
||||
if (firstEntry) {
|
||||
yield Zotero.File.reveal(firstEntry.path);
|
||||
}
|
||||
// Focus the database file in the new directory
|
||||
yield Zotero.File.reveal(OS.Path.join(newDir, this.getDatabaseFilename()));
|
||||
|
|
|
@ -586,22 +586,14 @@ Zotero.DBConnection.prototype.queryAsync = Zotero.Promise.coroutine(function* (s
|
|||
}
|
||||
var failed = false;
|
||||
if (options && options.onRow) {
|
||||
// Errors in onRow don't stop the query unless StopIteration is thrown
|
||||
onRow = function (row) {
|
||||
// Errors in onRow don't stop the query unless the 'cancel' function is called
|
||||
onRow = function (row, cancel) {
|
||||
try {
|
||||
options.onRow(row);
|
||||
options.onRow(row, cancel);
|
||||
}
|
||||
catch (e) {
|
||||
// If the onRow throws a StopIteration, stop gracefully
|
||||
if (e instanceof StopIteration) {
|
||||
Zotero.debug("Query cancelled", 3);
|
||||
}
|
||||
// Otherwise, mark the promise as rejected, which Sqlite.jsm doesn't do
|
||||
// on a StopIteration by default
|
||||
else {
|
||||
failed = e;
|
||||
}
|
||||
throw StopIteration;
|
||||
failed = e;
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -659,7 +651,7 @@ Zotero.DBConnection.prototype.queryAsync = Zotero.Promise.coroutine(function* (s
|
|||
}
|
||||
else {
|
||||
// lastInsertRowID is unreliable for async queries, so we don't bother
|
||||
// returning it for SELECT and REPLACE queries
|
||||
// returning it for INSERT and REPLACE queries
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -767,7 +759,7 @@ Zotero.DBConnection.prototype.columnQueryAsync = Zotero.Promise.coroutine(functi
|
|||
Zotero.DBConnection.prototype.logQuery = function (sql, params = [], options) {
|
||||
if (options && options.debug === false) return;
|
||||
var msg = sql;
|
||||
if (params.length) {
|
||||
if (params.length && (!options || options.debugParams !== false)) {
|
||||
msg += " [";
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
let param = params[i];
|
||||
|
|
|
@ -270,6 +270,9 @@ Zotero.Duplicates.prototype._findDuplicates = Zotero.Promise.coroutine(function*
|
|||
yearCache[row.itemID] = row.year;
|
||||
}
|
||||
|
||||
var itemTypeAttachment = Zotero.ItemTypes.getID('attachment');
|
||||
var itemTypeNote = Zotero.ItemTypes.getID('note');
|
||||
|
||||
// Match on normalized title
|
||||
var titleIDs = Zotero.ItemFields.getTypeFieldsFromBase('title');
|
||||
titleIDs.push(Zotero.ItemFields.getID('title'));
|
||||
|
@ -277,7 +280,7 @@ Zotero.Duplicates.prototype._findDuplicates = Zotero.Promise.coroutine(function*
|
|||
+ "JOIN itemDataValues USING (valueID) "
|
||||
+ "WHERE libraryID=? AND fieldID IN "
|
||||
+ "(" + titleIDs.join(', ') + ") "
|
||||
+ "AND itemTypeID NOT IN (1, 14) "
|
||||
+ `AND itemTypeID NOT IN (${itemTypeAttachment}, ${itemTypeNote}) `
|
||||
+ "AND itemID NOT IN (SELECT itemID FROM deletedItems)";
|
||||
var rows = yield Zotero.DB.queryAsync(sql, [this._libraryID]);
|
||||
if (rows.length) {
|
||||
|
@ -299,7 +302,7 @@ Zotero.Duplicates.prototype._findDuplicates = Zotero.Promise.coroutine(function*
|
|||
let sql = "SELECT itemID, lastName, firstName, fieldMode FROM items "
|
||||
+ "JOIN itemCreators USING (itemID) "
|
||||
+ "JOIN creators USING (creatorID) "
|
||||
+ "WHERE libraryID=? AND itemTypeID NOT IN (1, 14) AND "
|
||||
+ `WHERE libraryID=? AND itemTypeID NOT IN (${itemTypeAttachment}, ${itemTypeNote}) AND `
|
||||
+ "itemID NOT IN (SELECT itemID FROM deletedItems)"
|
||||
+ "ORDER BY itemID, orderIndex";
|
||||
let creatorRows = yield Zotero.DB.queryAsync(sql, this._libraryID);
|
||||
|
|
|
@ -333,8 +333,7 @@ Zotero.File = new function(){
|
|||
* Runs synchronously, so should only be run on local (e.g. chrome) URLs
|
||||
*/
|
||||
function getContentsFromURL(url) {
|
||||
var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance();
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.open('GET', url, false);
|
||||
xmlhttp.overrideMimeType("text/plain");
|
||||
xmlhttp.send(null);
|
||||
|
@ -450,7 +449,7 @@ Zotero.File = new function(){
|
|||
|
||||
this.download = Zotero.Promise.coroutine(function* (uri, path) {
|
||||
Zotero.debug("Saving " + (uri.spec ? uri.spec : uri)
|
||||
+ " to " + (path.path ? path.path : path));
|
||||
+ " to " + (path.pathQueryRef ? path.pathQueryRef : path));
|
||||
|
||||
var deferred = Zotero.Promise.defer();
|
||||
NetUtil.asyncFetch(uri, function (is, status, request) {
|
||||
|
@ -563,51 +562,39 @@ Zotero.File = new function(){
|
|||
/**
|
||||
* @return {Promise<Boolean>}
|
||||
*/
|
||||
this.directoryIsEmpty = Zotero.Promise.coroutine(function* (path) {
|
||||
var it = new OS.File.DirectoryIterator(path);
|
||||
this.directoryIsEmpty = async function (path) {
|
||||
var iterator = new OS.File.DirectoryIterator(path);
|
||||
var empty = true;
|
||||
try {
|
||||
let entry = yield it.next();
|
||||
return false;
|
||||
}
|
||||
catch (e) {
|
||||
if (e != StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
await iterator.forEach(() => {
|
||||
iterator.close();
|
||||
empty = false;
|
||||
});
|
||||
}
|
||||
finally {
|
||||
it.close();
|
||||
iterator.close();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return empty;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Run a generator with an OS.File.DirectoryIterator, closing the
|
||||
* iterator when done. Promises yielded by the generator are awaited.
|
||||
* Run a function on each entry in a directory
|
||||
*
|
||||
* The DirectoryIterator is passed as the first parameter to the generator.
|
||||
* 'entry' is an instance of OS.File.DirectoryIterator.Entry:
|
||||
*
|
||||
* Zotero.File.iterateDirectory(path, function* (iterator) {
|
||||
* while (true) {
|
||||
* let entry = yield iterator.next();
|
||||
* let contents = yield Zotero.File.getContentsAsync(entry.path);
|
||||
* [...]
|
||||
* }
|
||||
* })
|
||||
* https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/OSFile.jsm/OS.File.DirectoryIterator.Entry
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
this.iterateDirectory = function (path, generator) {
|
||||
this.iterateDirectory = async function (path, onEntry) {
|
||||
var iterator = new OS.File.DirectoryIterator(path);
|
||||
return Zotero.Promise.coroutine(generator)(iterator)
|
||||
.catch(function (e) {
|
||||
if (e != StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
})
|
||||
.finally(function () {
|
||||
try {
|
||||
await iterator.forEach(onEntry);
|
||||
}
|
||||
finally {
|
||||
iterator.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -682,85 +669,82 @@ Zotero.File = new function(){
|
|||
|
||||
Zotero.debug("Moving files in " + oldDir);
|
||||
|
||||
yield Zotero.File.iterateDirectory(oldDir, function* (iterator) {
|
||||
while (true) {
|
||||
let entry = yield iterator.next();
|
||||
let dest = newDir + entry.path.substr(rootDir.length);
|
||||
|
||||
// entry.isDir can be false for some reason on Travis, causing spurious test failures
|
||||
if (Zotero.automatedTest && !entry.isDir && (yield OS.File.stat(entry.path)).isDir) {
|
||||
Zotero.debug("Overriding isDir for " + entry.path);
|
||||
entry.isDir = true;
|
||||
yield Zotero.File.iterateDirectory(oldDir, async function (entry) {
|
||||
var dest = newDir + entry.path.substr(rootDir.length);
|
||||
|
||||
// entry.isDir can be false for some reason on Travis, causing spurious test failures
|
||||
if (Zotero.automatedTest && !entry.isDir && (await OS.File.stat(entry.path)).isDir) {
|
||||
Zotero.debug("Overriding isDir for " + entry.path);
|
||||
entry.isDir = true;
|
||||
}
|
||||
|
||||
// Move files in directory
|
||||
if (!entry.isDir) {
|
||||
try {
|
||||
await OS.File.move(
|
||||
entry.path,
|
||||
dest,
|
||||
{
|
||||
noOverwrite: options
|
||||
&& options.noOverwrite
|
||||
&& options.noOverwrite(entry.path)
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (e) {
|
||||
checkError(e);
|
||||
Zotero.debug("Error moving " + entry.path);
|
||||
addError(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Move directory with external command if possible and the directory doesn't
|
||||
// already exist in target
|
||||
let moved = false;
|
||||
|
||||
// Move files in directory
|
||||
if (!entry.isDir) {
|
||||
if (useCmd && !(await OS.File.exists(dest))) {
|
||||
Zotero.debug(`Moving ${entry.path} with ${cmd}`);
|
||||
let args = [entry.path, dest];
|
||||
try {
|
||||
yield OS.File.move(
|
||||
entry.path,
|
||||
dest,
|
||||
{
|
||||
noOverwrite: options
|
||||
&& options.noOverwrite
|
||||
&& options.noOverwrite(entry.path)
|
||||
}
|
||||
);
|
||||
await Zotero.Utilities.Internal.exec(cmd, args);
|
||||
moved = true;
|
||||
}
|
||||
catch (e) {
|
||||
checkError(e);
|
||||
Zotero.debug("Error moving " + entry.path);
|
||||
addError(e);
|
||||
Zotero.debug(e, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Move directory with external command if possible and the directory doesn't
|
||||
// already exist in target
|
||||
let moved = false;
|
||||
|
||||
if (useCmd && !(yield OS.File.exists(dest))) {
|
||||
Zotero.debug(`Moving ${entry.path} with ${cmd}`);
|
||||
let args = [entry.path, dest];
|
||||
try {
|
||||
yield Zotero.Utilities.Internal.exec(cmd, args);
|
||||
moved = true;
|
||||
}
|
||||
catch (e) {
|
||||
checkError(e);
|
||||
Zotero.debug(e, 1);
|
||||
}
|
||||
|
||||
|
||||
// If can't use command, try moving with OS.File.move(). Technically this is
|
||||
// unsupported for directories, but it works on all platforms as long as noCopy
|
||||
// is set (and on some platforms regardless)
|
||||
if (!moved && useFunction) {
|
||||
Zotero.debug(`Moving ${entry.path} with OS.File`);
|
||||
try {
|
||||
await OS.File.move(
|
||||
entry.path,
|
||||
dest,
|
||||
{
|
||||
noCopy: true
|
||||
}
|
||||
);
|
||||
moved = true;
|
||||
}
|
||||
|
||||
|
||||
// If can't use command, try moving with OS.File.move(). Technically this is
|
||||
// unsupported for directories, but it works on all platforms as long as noCopy
|
||||
// is set (and on some platforms regardless)
|
||||
if (!moved && useFunction) {
|
||||
Zotero.debug(`Moving ${entry.path} with OS.File`);
|
||||
try {
|
||||
yield OS.File.move(
|
||||
entry.path,
|
||||
dest,
|
||||
{
|
||||
noCopy: true
|
||||
}
|
||||
);
|
||||
moved = true;
|
||||
}
|
||||
catch (e) {
|
||||
checkError(e);
|
||||
Zotero.debug(e, 1);
|
||||
}
|
||||
catch (e) {
|
||||
checkError(e);
|
||||
Zotero.debug(e, 1);
|
||||
}
|
||||
|
||||
// Otherwise, recurse into subdirectories to copy files individually
|
||||
if (!moved) {
|
||||
try {
|
||||
yield moveSubdirs(entry.path, depth - 1);
|
||||
}
|
||||
catch (e) {
|
||||
checkError(e);
|
||||
addError(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, recurse into subdirectories to copy files individually
|
||||
if (!moved) {
|
||||
try {
|
||||
await moveSubdirs(entry.path, depth - 1);
|
||||
}
|
||||
catch (e) {
|
||||
checkError(e);
|
||||
addError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -984,11 +968,8 @@ Zotero.File = new function(){
|
|||
unixMode: 0o755
|
||||
});
|
||||
|
||||
return this.iterateDirectory(source, function* (iterator) {
|
||||
while (true) {
|
||||
let entry = yield iterator.next();
|
||||
yield OS.File.copy(entry.path, OS.Path.join(target, entry.name));
|
||||
}
|
||||
return this.iterateDirectory(source, function (entry) {
|
||||
return OS.File.copy(entry.path, OS.Path.join(target, entry.name));
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -1338,7 +1319,6 @@ Zotero.File = new function(){
|
|||
dialogButtonText: Zotero.getString('file.accessError.showParentDir'),
|
||||
dialogButtonCallback: function () {
|
||||
try {
|
||||
file.parent.QueryInterface(Components.interfaces.nsILocalFile);
|
||||
file.parent.reveal();
|
||||
}
|
||||
// Unsupported on some platforms
|
||||
|
@ -1372,13 +1352,12 @@ Zotero.File = new function(){
|
|||
Zotero.debug("Revealing " + file);
|
||||
|
||||
var nsIFile = this.pathToFile(file);
|
||||
nsIFile.QueryInterface(Components.interfaces.nsILocalFile);
|
||||
try {
|
||||
nsIFile.reveal();
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
// On platforms that don't support nsILocalFile.reveal() (e.g. Linux),
|
||||
// On platforms that don't support nsIFile.reveal() (e.g. Linux),
|
||||
// launch the directory
|
||||
let zp = Zotero.getActiveZoteroPane();
|
||||
if (zp) {
|
||||
|
|
|
@ -226,8 +226,7 @@ Zotero.HTTP = new function() {
|
|||
if (options.username) {
|
||||
options.username = options.username.replace(/%2E/, '.');
|
||||
options.password = url.password || null;
|
||||
url = url.clone();
|
||||
url.userPass = '';
|
||||
url = url.mutate().setUserPass('').finalize();
|
||||
}
|
||||
|
||||
url = url.spec;
|
||||
|
@ -566,8 +565,7 @@ Zotero.HTTP = new function() {
|
|||
return false;
|
||||
}
|
||||
|
||||
var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance();
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
|
||||
// Prevent certificate/authentication dialogs from popping up
|
||||
xmlhttp.mozBackgroundRequest = true;
|
||||
|
@ -640,8 +638,7 @@ Zotero.HTTP = new function() {
|
|||
return false;
|
||||
}
|
||||
|
||||
var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance();
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
// Prevent certificate/authentication dialogs from popping up
|
||||
xmlhttp.mozBackgroundRequest = true;
|
||||
xmlhttp.open('POST', url, true);
|
||||
|
@ -718,8 +715,7 @@ Zotero.HTTP = new function() {
|
|||
|
||||
// Workaround for "Accept third-party cookies" being off in Firefox 3.0.1
|
||||
// https://www.zotero.org/trac/ticket/1070
|
||||
var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance();
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
// Prevent certificate/authentication dialogs from popping up
|
||||
xmlhttp.mozBackgroundRequest = true;
|
||||
xmlhttp.open('HEAD', url, true);
|
||||
|
@ -766,8 +762,7 @@ Zotero.HTTP = new function() {
|
|||
return false;
|
||||
}
|
||||
|
||||
var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance();
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
// Prevent certificate/authentication dialogs from popping up
|
||||
xmlhttp.mozBackgroundRequest = true;
|
||||
xmlhttp.open('OPTIONS', uri.spec, true);
|
||||
|
|
|
@ -27,9 +27,12 @@ Zotero.ID_Tracker = function () {
|
|||
var _tables = [
|
||||
'collections',
|
||||
'creators',
|
||||
'creatorTypes',
|
||||
'customFields',
|
||||
'customItemTypes',
|
||||
'fields',
|
||||
'itemDataValues',
|
||||
'itemTypes',
|
||||
'items',
|
||||
'libraries',
|
||||
'proxies',
|
||||
|
@ -54,7 +57,7 @@ Zotero.ID_Tracker = function () {
|
|||
throw new Error("IDs not loaded for table '" + table + "'");
|
||||
}
|
||||
|
||||
return ++_nextIDs[table];
|
||||
return _nextIDs[table]++;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -83,9 +83,7 @@ Zotero.Integration = new function() {
|
|||
// on OS X, first try /Users/Shared for those who can't put pipes in their home
|
||||
// directories
|
||||
var pipe = null;
|
||||
var sharedDir = Components.classes["@mozilla.org/file/local;1"].
|
||||
createInstance(Components.interfaces.nsILocalFile);
|
||||
sharedDir.initWithPath("/Users/Shared");
|
||||
var sharedDir = Zotero.File.pathToFile('/Users/Shared');
|
||||
|
||||
if(sharedDir.exists() && sharedDir.isDirectory()) {
|
||||
var logname = Components.classes["@mozilla.org/process/environment;1"].
|
||||
|
|
|
@ -229,7 +229,7 @@ Zotero.IPC = new function() {
|
|||
if(pipeDir.exists()) {
|
||||
var dirEntries = pipeDir.directoryEntries;
|
||||
while (dirEntries.hasMoreElements()) {
|
||||
var pipe = dirEntries.getNext().QueryInterface(Ci.nsILocalFile);
|
||||
var pipe = dirEntries.getNext().QueryInterface(Ci.nsIFile);
|
||||
if(pipe.leafName[0] !== "." && (!_instancePipe || !pipe.equals(_instancePipe))) {
|
||||
pipes.push(pipe);
|
||||
}
|
||||
|
@ -461,7 +461,12 @@ Zotero.IPC.Pipe.DeferredOpen.prototype = {
|
|||
|
||||
var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].
|
||||
createInstance(Components.interfaces.nsIInputStreamPump);
|
||||
pump.init(fifoStream, -1, -1, 4096, 1, true);
|
||||
try {
|
||||
pump.init(fifoStream, 0, 0, true);
|
||||
}
|
||||
catch (e) {
|
||||
pump.init(fifoStream, -1, -1, 4096, 1, true);
|
||||
}
|
||||
pump.asyncRead(this, null);
|
||||
|
||||
this._openTime = Date.now();
|
||||
|
|
|
@ -890,11 +890,14 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
|
|||
else if (ids.length <= 5) {
|
||||
var items = Zotero.Items.get(ids);
|
||||
if (items) {
|
||||
let itemTypeAttachment = Zotero.ItemTypes.getID('attachment');
|
||||
let itemTypeNote = Zotero.ItemTypes.getID('note');
|
||||
|
||||
var found = false;
|
||||
for (let item of items) {
|
||||
// Check for note and attachment type, since it's quicker
|
||||
// Check for attachment and note types, since it's quicker
|
||||
// than checking for parent item
|
||||
if (item.itemTypeID == 1 || item.itemTypeID == 14) {
|
||||
if (item.itemTypeID == itemTypeAttachment || item.itemTypeID == itemTypeNote) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2847,7 +2850,7 @@ Zotero.ItemTreeView.fileDragDataProvider.prototype = {
|
|||
var dirPrimitive = {};
|
||||
var dataSize = {};
|
||||
transferable.getTransferData("application/x-moz-file-promise-dir", dirPrimitive, dataSize);
|
||||
var destDir = dirPrimitive.value.QueryInterface(Components.interfaces.nsILocalFile);
|
||||
var destDir = dirPrimitive.value.QueryInterface(Components.interfaces.nsIFile);
|
||||
|
||||
var draggedItems = Zotero.Items.get(this._itemIDs);
|
||||
var items = [];
|
||||
|
@ -2901,7 +2904,7 @@ Zotero.ItemTreeView.fileDragDataProvider.prototype = {
|
|||
var numFiles = 0;
|
||||
while (files.hasMoreElements()) {
|
||||
var f = files.getNext();
|
||||
f.QueryInterface(Components.interfaces.nsILocalFile);
|
||||
f.QueryInterface(Components.interfaces.nsIFile);
|
||||
if (f.leafName.indexOf('.') != 0) {
|
||||
numFiles++;
|
||||
}
|
||||
|
|
|
@ -277,17 +277,14 @@ Zotero.LocateManager = new function() {
|
|||
* @param {Object} [obj] The locate engine, in parsed form, as it was serialized to JSON
|
||||
*/
|
||||
var LocateEngine = function(obj) {
|
||||
this.alias = this.name = "Untitled";
|
||||
this.description = this._urlTemplate = this.icon = null;
|
||||
this.hidden = false;
|
||||
this._alias = this._name = "Untitled";
|
||||
this._description = null;
|
||||
this._icon = null;
|
||||
this._hidden = false;
|
||||
this._urlTemplate = null;
|
||||
this._urlParams = [];
|
||||
|
||||
if(obj) for(var prop in obj) this[prop] = obj[prop];
|
||||
|
||||
// Queue deferred serialization whenever a property is modified
|
||||
for (let prop of ["alias", "name", "description", "icon", "hidden"]) {
|
||||
this.watch(prop, _watchLocateEngineProperties);
|
||||
}
|
||||
}
|
||||
|
||||
LocateEngine.prototype = {
|
||||
|
@ -488,4 +485,19 @@ Zotero.LocateManager = new function() {
|
|||
this.icon = OS.Path.toFileURI(iconFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Queue deferred serialization whenever a property is modified
|
||||
for (let prop of ["alias", "name", "description", "icon", "hidden"]) {
|
||||
let propName = '_' + prop;
|
||||
Object.defineProperty(LocateEngine.prototype, prop, {
|
||||
get: function () {
|
||||
return this[propName];
|
||||
},
|
||||
set: function (val) {
|
||||
var oldVal = this[propName];
|
||||
this[propName] = val;
|
||||
_watchLocateEngineProperties(prop, oldVal, val);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ Zotero.OpenURL = new function() {
|
|||
* Queries OCLC's OpenURL resolver registry and returns an address and version
|
||||
*/
|
||||
function discoverResolvers() {
|
||||
var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", "http://worldcatlibraries.org/registry/lookup?IP=requestor", false);
|
||||
req.send(null);
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
*/
|
||||
Zotero.Prefs = new function(){
|
||||
// Privileged methods
|
||||
this.init = init;
|
||||
this.get = get;
|
||||
this.set = set;
|
||||
|
||||
|
@ -32,11 +31,10 @@ Zotero.Prefs = new function(){
|
|||
this.unregister = unregister;
|
||||
this.observe = observe;
|
||||
|
||||
// Public properties
|
||||
this.prefBranch;
|
||||
this.rootBranch = Services.prefs.getBranch("");
|
||||
|
||||
function init(){
|
||||
this.prefBranch = Services.prefs.getBranch(ZOTERO_CONFIG.PREF_BRANCH);
|
||||
this.init = async function init() {
|
||||
await loadExtensionDefaults();
|
||||
|
||||
// Register observer to handle pref changes
|
||||
this.register();
|
||||
|
@ -87,24 +85,39 @@ Zotero.Prefs = new function(){
|
|||
**/
|
||||
function get(pref, global){
|
||||
try {
|
||||
if (global) {
|
||||
var branch = Services.prefs.getBranch("");
|
||||
}
|
||||
else {
|
||||
var branch = this.prefBranch;
|
||||
}
|
||||
pref = global ? pref : ZOTERO_CONFIG.PREF_BRANCH + pref;
|
||||
let branch = this.rootBranch;
|
||||
|
||||
let value;
|
||||
switch (branch.getPrefType(pref)){
|
||||
case branch.PREF_BOOL:
|
||||
return branch.getBoolPref(pref);
|
||||
value = branch.getBoolPref(pref);
|
||||
break;
|
||||
|
||||
case branch.PREF_STRING:
|
||||
return '' + branch.getComplexValue(pref, Components.interfaces.nsISupportsString);
|
||||
// Pre-Fx59
|
||||
if (!branch.getStringPref) {
|
||||
value = '' + branch.getComplexValue(pref, Components.interfaces.nsISupportsString);
|
||||
}
|
||||
else {
|
||||
value = branch.getStringPref(pref);
|
||||
}
|
||||
break;
|
||||
|
||||
case branch.PREF_INT:
|
||||
return branch.getIntPref(pref);
|
||||
value = branch.getIntPref(pref);
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
catch (e){
|
||||
throw new Error("Invalid preference '" + pref + "'");
|
||||
catch (e) {
|
||||
// If debug system isn't yet initialized, log proper error
|
||||
if (Zotero.Debug.enabled === undefined) {
|
||||
dump(e + "\n\n");
|
||||
}
|
||||
Zotero.logError(e);
|
||||
throw new Error(`Error getting preference '${pref}'`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,21 +127,21 @@ Zotero.Prefs = new function(){
|
|||
**/
|
||||
function set(pref, value, global) {
|
||||
try {
|
||||
if (global) {
|
||||
var branch = Services.prefs.getBranch("");
|
||||
}
|
||||
else {
|
||||
var branch = this.prefBranch;
|
||||
}
|
||||
pref = global ? pref : ZOTERO_CONFIG.PREF_BRANCH + pref;
|
||||
let branch = this.rootBranch;
|
||||
|
||||
switch (branch.getPrefType(pref)) {
|
||||
case branch.PREF_BOOL:
|
||||
return branch.setBoolPref(pref, value);
|
||||
case branch.PREF_STRING:
|
||||
let str = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
str.data = value;
|
||||
return branch.setComplexValue(pref, Ci.nsISupportsString, str);
|
||||
// Pre-Fx59
|
||||
if (!branch.setStringPref) {
|
||||
let str = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
str.data = value;
|
||||
return branch.setComplexValue(pref, Ci.nsISupportsString, str);
|
||||
}
|
||||
return branch.setStringPref(pref, value);
|
||||
case branch.PREF_INT:
|
||||
return branch.setIntPref(pref, value);
|
||||
|
||||
|
@ -140,7 +153,14 @@ Zotero.Prefs = new function(){
|
|||
}
|
||||
if (typeof value == 'string') {
|
||||
Zotero.debug("Creating string pref '" + pref + "'");
|
||||
return branch.setCharPref(pref, value);
|
||||
// Pre-Fx59
|
||||
if (!branch.setStringPref) {
|
||||
let str = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
str.data = value;
|
||||
return branch.setComplexValue(pref, Ci.nsISupportsString, str);
|
||||
}
|
||||
return branch.setStringPref(pref, value);
|
||||
}
|
||||
if (parseInt(value) == value) {
|
||||
Zotero.debug("Creating integer pref '" + pref + "'");
|
||||
|
@ -150,32 +170,36 @@ Zotero.Prefs = new function(){
|
|||
}
|
||||
}
|
||||
catch (e) {
|
||||
// If debug system isn't yet initialized, log proper error
|
||||
if (Zotero.Debug.enabled === undefined) {
|
||||
dump(e + "\n\n");
|
||||
}
|
||||
Zotero.logError(e);
|
||||
throw new Error("Invalid preference '" + pref + "'");
|
||||
throw new Error(`Error setting preference '${pref}'`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.clear = function (pref, global) {
|
||||
if (global) {
|
||||
var branch = Services.prefs.getBranch("");
|
||||
}
|
||||
else {
|
||||
var branch = this.prefBranch;
|
||||
}
|
||||
branch.clearUserPref(pref);
|
||||
pref = global ? pref : ZOTERO_CONFIG.PREF_BRANCH + pref;
|
||||
this.rootBranch.clearUserPref(pref);
|
||||
}
|
||||
|
||||
|
||||
this.resetBranch = function (exclude = []) {
|
||||
var keys = this.prefBranch.getChildList("", {});
|
||||
/**
|
||||
* @param {String[]} [exclude]
|
||||
* @param {String} [branch] - Name of pref branch, ending with a period
|
||||
*/
|
||||
this.resetBranch = function (exclude = [], branch) {
|
||||
var branch = Services.prefs.getBranch(branch || ZOTERO_CONFIG.PREF_BRANCH);
|
||||
var keys = branch.getChildList("", {});
|
||||
for (let key of keys) {
|
||||
if (this.prefBranch.prefHasUserValue(key)) {
|
||||
if (branch.prefHasUserValue(key)) {
|
||||
if (exclude.includes(key)) {
|
||||
continue;
|
||||
}
|
||||
Zotero.debug("Clearing " + key);
|
||||
this.prefBranch.clearUserPref(key);
|
||||
branch.clearUserPref(key);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -236,7 +260,7 @@ Zotero.Prefs = new function(){
|
|||
// Methods to register a preferences observer
|
||||
//
|
||||
function register(){
|
||||
this.prefBranch.addObserver("", this, false);
|
||||
this.rootBranch.addObserver("", this, false);
|
||||
|
||||
// Register pre-set handlers
|
||||
for (var i=0; i<_handlers.length; i++) {
|
||||
|
@ -245,10 +269,10 @@ Zotero.Prefs = new function(){
|
|||
}
|
||||
|
||||
function unregister(){
|
||||
if (!this.prefBranch){
|
||||
if (!this.rootBranch){
|
||||
return;
|
||||
}
|
||||
this.prefBranch.removeObserver("", this);
|
||||
this.rootBranch.removeObserver("", this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -264,7 +288,7 @@ Zotero.Prefs = new function(){
|
|||
var obs = _observers[data];
|
||||
for (var i=0; i<obs.length; i++) {
|
||||
try {
|
||||
obs[i](this.get(data));
|
||||
obs[i](this.get(data, true));
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug("Error while executing preference observer handler for " + data);
|
||||
|
@ -277,11 +301,14 @@ Zotero.Prefs = new function(){
|
|||
var _observersBySymbol = {};
|
||||
|
||||
/**
|
||||
* @param {String} name - Preference name on extensions.zotero branch
|
||||
* @param {String} name - Preference name; if not global, this is on the extensions.zotero branch
|
||||
* @param {Function} handler
|
||||
* @param {Boolean} [global]
|
||||
* @return {Symbol} - Symbol to pass to unregisterObserver()
|
||||
*/
|
||||
this.registerObserver = function (name, handler) {
|
||||
this.registerObserver = function (name, handler, global) {
|
||||
name = global ? name : ZOTERO_CONFIG.PREF_BRANCH + name;
|
||||
|
||||
var symbol = Symbol();
|
||||
_observers[name] = _observers[name] || [];
|
||||
_observers[name].push(handler);
|
||||
|
@ -309,4 +336,108 @@ Zotero.Prefs = new function(){
|
|||
}
|
||||
obs.splice(i, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Firefox 60 no longer loads default preferences for extensions, so do it manually
|
||||
*/
|
||||
async function loadExtensionDefaults() {
|
||||
var defaultBranch = Services.prefs.getDefaultBranch("");
|
||||
|
||||
return new Zotero.Promise(function (resolve) {
|
||||
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
// Lines are in format `pref("[key]", [val]);`, so define a function to be called that
|
||||
// sets the defaults
|
||||
function pref(key, value) {
|
||||
switch (typeof value) {
|
||||
case "boolean":
|
||||
defaultBranch.setBoolPref(key, value);
|
||||
break;
|
||||
case "number":
|
||||
defaultBranch.setIntPref(key, value);
|
||||
break;
|
||||
case "string":
|
||||
defaultBranch.setStringPref(key, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function readDefaults(contents) {
|
||||
let re = /^\s*pref\s*\(\s*['"]([a-zA-Z0-9_\-.]+)['"]\s*,\s*["']?.*["']?\s*\)\s*;\s*$/;
|
||||
let lines = contents.split(/\n/g).filter(line => re.test(line));
|
||||
for (let line of lines) {
|
||||
try {
|
||||
eval(line);
|
||||
}
|
||||
catch (e) {
|
||||
dump(e + "\n\n");
|
||||
Components.utils.reportError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddonManager.getAllAddons(async function(addons) {
|
||||
var reusableStreamInstance = Cc['@mozilla.org/scriptableinputstream;1']
|
||||
.createInstance(Ci.nsIScriptableInputStream);
|
||||
|
||||
for (let addon of addons) {
|
||||
if (!addon.isActive) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
let path = OS.Path.fromFileURI(addon.getResourceURI().spec);
|
||||
|
||||
// Directory
|
||||
if ((await OS.File.stat(path)).isDir) {
|
||||
let dir = OS.Path.join(path, 'defaults', 'preferences');
|
||||
if (await OS.File.exists(dir)) {
|
||||
await Zotero.File.iterateDirectory(dir, async function (entry) {
|
||||
if (!entry.name.endsWith('.js')) return;
|
||||
readDefaults(Zotero.File.getContents(entry.path));
|
||||
});
|
||||
}
|
||||
}
|
||||
// XPI
|
||||
else {
|
||||
let file = Zotero.File.pathToFile(path);
|
||||
let zipReader = Components.classes["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Components.interfaces.nsIZipReader);
|
||||
try {
|
||||
try {
|
||||
zipReader.open(file);
|
||||
zipReader.test(null);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(path + " is not a valid ZIP file");
|
||||
continue;
|
||||
}
|
||||
|
||||
let entries = zipReader.findEntries('defaults/preferences/*.js');
|
||||
while (entries.hasMore()) {
|
||||
let entryName = entries.getNext();
|
||||
let entry = zipReader.getEntry(entryName);
|
||||
|
||||
if (!entry.isDirectory) {
|
||||
let inputStream = zipReader.getInputStream(entryName);
|
||||
reusableStreamInstance.init(inputStream);
|
||||
readDefaults(reusableStreamInstance.read(entry.realSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
zipReader.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -283,17 +283,14 @@ Zotero.Profile = {
|
|||
*/
|
||||
_getProfilesInDir: Zotero.Promise.coroutine(function* (profilesDir) {
|
||||
var dirs = [];
|
||||
yield Zotero.File.iterateDirectory(profilesDir, function* (iterator) {
|
||||
while (true) {
|
||||
let entry = yield iterator.next();
|
||||
// entry.isDir can be false for some reason on Travis, causing spurious test failures
|
||||
if (Zotero.automatedTest && !entry.isDir && (yield OS.File.stat(entry.path)).isDir) {
|
||||
Zotero.debug("Overriding isDir for " + entry.path);
|
||||
entry.isDir = true;
|
||||
}
|
||||
if (entry.isDir && (yield OS.File.exists(OS.Path.join(entry.path, "prefs.js")))) {
|
||||
dirs.push(entry.path);
|
||||
}
|
||||
yield Zotero.File.iterateDirectory(profilesDir, async function (entry) {
|
||||
// entry.isDir can be false for some reason on Travis, causing spurious test failures
|
||||
if (Zotero.automatedTest && !entry.isDir && (await OS.File.stat(entry.path)).isDir) {
|
||||
Zotero.debug("Overriding isDir for " + entry.path);
|
||||
entry.isDir = true;
|
||||
}
|
||||
if (entry.isDir && (await OS.File.exists(OS.Path.join(entry.path, "prefs.js")))) {
|
||||
dirs.push(entry.path);
|
||||
}
|
||||
});
|
||||
return dirs;
|
||||
|
|
|
@ -248,10 +248,6 @@ Zotero.ProgressQueueDialog = function (progressQueue) {
|
|||
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
if (win) {
|
||||
if (win.ZoteroOverlay) {
|
||||
win.ZoteroOverlay.toggleDisplay(true);
|
||||
}
|
||||
|
||||
win.ZoteroPane.selectItem(itemID, false, true);
|
||||
win.focus();
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ Zotero.ProgressWindowSet = new function() {
|
|||
this.add = add;
|
||||
this.tile = tile;
|
||||
this.remove = remove;
|
||||
this.updateTimers = updateTimers;
|
||||
|
||||
var _progressWindows = [];
|
||||
|
||||
|
@ -87,19 +86,6 @@ Zotero.ProgressWindowSet = new function() {
|
|||
}
|
||||
|
||||
|
||||
function updateTimers() {
|
||||
if (!_progressWindows.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i=0; i<_progressWindows.length; i++) {
|
||||
// Pass |requireMouseOver| so that the window only closes
|
||||
// if the mouse was over it at some point
|
||||
_progressWindows[i].instance.startCloseTimer(null, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.closeAll = function () {
|
||||
_progressWindows.forEach(pw => pw.instance.close());
|
||||
}
|
||||
|
|
|
@ -509,11 +509,11 @@ Zotero.Proxy.prototype.toProxy = function(uri) {
|
|||
if(param == "%h") {
|
||||
value = this.dotsToHyphens ? uri.hostPort.replace(/-/g, '.') : uri.hostPort;
|
||||
} else if(param == "%p") {
|
||||
value = uri.path.substr(1);
|
||||
value = uri.pathQueryRef.substr(1);
|
||||
} else if(param == "%d") {
|
||||
value = uri.path.substr(0, uri.path.lastIndexOf("/"));
|
||||
value = uri.pathQueryRef.substr(0, uri.pathQueryRef.lastIndexOf("/"));
|
||||
} else if(param == "%f") {
|
||||
value = uri.path.substr(uri.path.lastIndexOf("/")+1)
|
||||
value = uri.pathQueryRef.substr(uri.pathQueryRef.lastIndexOf("/")+1)
|
||||
}
|
||||
|
||||
proxyURL = proxyURL.substr(0, this.indices[param])+value+proxyURL.substr(this.indices[param]+2);
|
||||
|
|
|
@ -172,7 +172,7 @@ Zotero.QuickCopy = new function() {
|
|||
// Accessing some properties may throw for URIs that do not support those
|
||||
// parts. E.g. hostPort throws NS_ERROR_FAILURE for about:blank
|
||||
var urlHostPort = nsIURI.hostPort;
|
||||
var urlPath = nsIURI.path;
|
||||
var urlPath = nsIURI.pathQueryRef;
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
|
|
|
@ -36,9 +36,9 @@ Zotero.Report.HTML = new function () {
|
|||
+ ' <head>\n'
|
||||
+ ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\n'
|
||||
+ ' <title>' + Zotero.getString('report.title.default') + '</title>\n'
|
||||
+ ' <link rel="stylesheet" type="text/css" href="zotero://report/detail.css"/>\n'
|
||||
+ ' <link rel="stylesheet" type="text/css" media="screen,projection" href="zotero://report/detail_screen.css"/>\n'
|
||||
+ ' <link rel="stylesheet" type="text/css" media="print" href="zotero://report/detail_print.css"/>\n'
|
||||
+ ' <link rel="stylesheet" type="text/css" href="' + _getCSSDataURI('detail') + '"/>\n'
|
||||
+ ' <link rel="stylesheet" type="text/css" media="screen,projection" href="' + _getCSSDataURI('detail_screen') + '"/>\n'
|
||||
+ ' <link rel="stylesheet" type="text/css" media="print" href="' + _getCSSDataURI('detail_print') + '"/>\n'
|
||||
+ ' </head>\n'
|
||||
+ ' <body>\n'
|
||||
+ ' <ul class="report' + (combineChildItems ? ' combineChildItems' : '') + '">';
|
||||
|
@ -130,6 +130,14 @@ Zotero.Report.HTML = new function () {
|
|||
};
|
||||
|
||||
|
||||
function _getCSSDataURI(file) {
|
||||
return 'data:text/css;base64,'
|
||||
+ Zotero.Utilities.Internal.Base64.encode(
|
||||
Zotero.File.getResource(`chrome://zotero/skin/report/${file}.css`)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function _generateMetadataTable(obj) {
|
||||
var table = false;
|
||||
var content = '\t\t\t\t<table>\n';
|
||||
|
@ -200,7 +208,7 @@ Zotero.Report.HTML = new function () {
|
|||
}
|
||||
|
||||
try {
|
||||
var localizedFieldName = Zotero.ItemFields.getLocalizedString(obj.itemType, i);
|
||||
var localizedFieldName = Zotero.ItemFields.getLocalizedString(i);
|
||||
}
|
||||
// Skip fields we don't have a localized string for
|
||||
catch (e) {
|
||||
|
|
|
@ -181,7 +181,7 @@ Zotero.Retractions = {
|
|||
doi = json.DOI;
|
||||
}
|
||||
else if (json.extra) {
|
||||
let fields = Zotero.Utilities.Internal.extractExtraFields(json.extra);
|
||||
let { fields } = Zotero.Utilities.Internal.extractExtraFields(json.extra);
|
||||
let extraField = fields.get('DOI');
|
||||
if (extraField && extraField.value) {
|
||||
doi = extraField.value;
|
||||
|
@ -765,7 +765,7 @@ Zotero.Retractions = {
|
|||
+ "JOIN itemDataValues USING (valueID) WHERE fieldID=?";
|
||||
rows = await Zotero.DB.queryAsync(sql, Zotero.ItemFields.getID('extra'));
|
||||
for (let row of rows) {
|
||||
let fields = Zotero.Utilities.Internal.extractExtraFields(row.value);
|
||||
let { fields } = Zotero.Utilities.Internal.extractExtraFields(row.value);
|
||||
let doi = fields.get('doi');
|
||||
if (!doi || !doi.value) continue;
|
||||
let value = Zotero.Utilities.cleanDOI(doi.value);
|
||||
|
@ -783,7 +783,7 @@ Zotero.Retractions = {
|
|||
var rows = await Zotero.DB.queryAsync(sql, Zotero.ItemFields.getID('extra'));
|
||||
for (let row of rows) {
|
||||
/*
|
||||
let fields = Zotero.Utilities.Internal.extractExtraFields(row.value);
|
||||
let { fields } = Zotero.Utilities.Internal.extractExtraFields(row.value);
|
||||
let pmid = fields.get('pmid') || fields.get('pubmedID');
|
||||
if (!pmid || !pmid.value) continue;
|
||||
this._addItemKeyMapping(this.TYPE_PMID, pmid.value, row.id);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Components.utils.import("resource://zotero/pathparser.js", Zotero);
|
||||
Components.utils.import("resource://zotero/pathparser.jsm", Zotero);
|
||||
Zotero.Router = Zotero.PathParser;
|
||||
delete Zotero.PathParser;
|
||||
|
||||
|
|
|
@ -41,12 +41,12 @@ Zotero.Schema = new function(){
|
|||
|
||||
// If updating from this userdata version or later, don't show "Upgrading database…" and don't make
|
||||
// DB backup first. This should be set to false when breaking compatibility or making major changes.
|
||||
const minorUpdateFrom = 95;
|
||||
const minorUpdateFrom = false;
|
||||
|
||||
var _dbVersions = [];
|
||||
var _schemaVersions = [];
|
||||
// Update when adding _updateCompatibility() line to schema update step
|
||||
var _maxCompatibility = 5;
|
||||
var _maxCompatibility = 6;
|
||||
|
||||
var _repositoryTimerID;
|
||||
var _repositoryNotificationTimerID;
|
||||
|
@ -88,7 +88,7 @@ Zotero.Schema = new function(){
|
|||
/*
|
||||
* Checks if the DB schema exists and is up-to-date, updating if necessary
|
||||
*/
|
||||
this.updateSchema = Zotero.Promise.coroutine(function* (options = {}) {
|
||||
this.updateSchema = async function (options = {}) {
|
||||
// TODO: Check database integrity first with Zotero.DB.integrityCheck()
|
||||
|
||||
// 'userdata' is the last upgrade step run in _migrateUserDataSchema() based on the
|
||||
|
@ -96,7 +96,7 @@ Zotero.Schema = new function(){
|
|||
//
|
||||
// 'compatibility' is incremented manually by upgrade steps in order to break DB
|
||||
// compatibility with older versions.
|
||||
var versions = yield Zotero.Promise.all([
|
||||
var versions = await Zotero.Promise.all([
|
||||
this.getDBVersion('userdata'), this.getDBVersion('compatibility')
|
||||
]);
|
||||
var [userdata, compatibility] = versions;
|
||||
|
@ -129,7 +129,7 @@ Zotero.Schema = new function(){
|
|||
}
|
||||
|
||||
if (compatibility > _maxCompatibility) {
|
||||
let dbClientVersion = yield Zotero.DB.valueQueryAsync(
|
||||
let dbClientVersion = await Zotero.DB.valueQueryAsync(
|
||||
"SELECT value FROM settings "
|
||||
+ "WHERE setting='client' AND key='lastCompatibleVersion'"
|
||||
);
|
||||
|
@ -139,53 +139,81 @@ Zotero.Schema = new function(){
|
|||
}
|
||||
|
||||
// Check if DB is coming from the DB Repair Tool and should be checked
|
||||
var integrityCheck = yield Zotero.DB.valueQueryAsync(
|
||||
var integrityCheck = await Zotero.DB.valueQueryAsync(
|
||||
"SELECT value FROM settings WHERE setting='db' AND key='integrityCheck'"
|
||||
);
|
||||
|
||||
var schemaVersion = yield _getSchemaSQLVersion('userdata');
|
||||
// Check whether bundled global schema file is newer than DB
|
||||
var bundledGlobalSchema = await _readGlobalSchemaFromFile();
|
||||
var bundledGlobalSchemaVersionCompare = await _globalSchemaVersionCompare(
|
||||
bundledGlobalSchema.version
|
||||
);
|
||||
|
||||
// Check whether bundled userdata schema has been updated
|
||||
var userdataVersion = await _getSchemaSQLVersion('userdata');
|
||||
options.minor = minorUpdateFrom && userdata >= minorUpdateFrom;
|
||||
|
||||
// If non-minor userdata upgrade, make backup of database first
|
||||
if (userdata < schemaVersion && !options.minor) {
|
||||
yield Zotero.DB.backupDatabase(userdata, true);
|
||||
if (userdata < userdataVersion && !options.minor) {
|
||||
await Zotero.DB.backupDatabase(userdata, true);
|
||||
}
|
||||
else if (integrityCheck) {
|
||||
yield Zotero.DB.backupDatabase(false, true);
|
||||
// Automatic backup
|
||||
else if (integrityCheck || bundledGlobalSchemaVersionCompare === 1) {
|
||||
await Zotero.DB.backupDatabase(false, true);
|
||||
}
|
||||
|
||||
yield Zotero.DB.queryAsync("PRAGMA foreign_keys = false");
|
||||
await Zotero.DB.queryAsync("PRAGMA foreign_keys = false");
|
||||
try {
|
||||
var updated = yield Zotero.DB.executeTransaction(function* (conn) {
|
||||
var updated = yield _updateSchema('system');
|
||||
// If bundled global schema file is newer than DB, apply it
|
||||
if (bundledGlobalSchemaVersionCompare === 1) {
|
||||
await Zotero.DB.executeTransaction(async function () {
|
||||
await _updateGlobalSchema(bundledGlobalSchema);
|
||||
});
|
||||
}
|
||||
else {
|
||||
let data;
|
||||
// If bundled global schema is up to date, use it
|
||||
if (bundledGlobalSchemaVersionCompare === 0) {
|
||||
data = bundledGlobalSchema;
|
||||
}
|
||||
// If bundled global schema is older than the DB (because of a downgrade), use the
|
||||
// DB version, which will match the mapping tables
|
||||
else if (bundledGlobalSchemaVersionCompare === -1) {
|
||||
data = await _readGlobalSchemaFromDB();
|
||||
}
|
||||
await _loadGlobalSchema(data, bundledGlobalSchema.version);
|
||||
}
|
||||
|
||||
var updated = await Zotero.DB.executeTransaction(async function (conn) {
|
||||
var updated = await _updateSchema('system');
|
||||
|
||||
// Update custom tables if they exist so that changes are in
|
||||
// place before user data migration
|
||||
if (Zotero.DB.tableExists('customItemTypes')) {
|
||||
yield _updateCustomTables(updated);
|
||||
await _updateCustomTables();
|
||||
}
|
||||
|
||||
// Auto-repair databases coming from the DB Repair Tool
|
||||
if (integrityCheck) {
|
||||
yield this.integrityCheck(true);
|
||||
yield Zotero.DB.queryAsync(
|
||||
await this.integrityCheck(true);
|
||||
await Zotero.DB.queryAsync(
|
||||
"DELETE FROM settings WHERE setting='db' AND key='integrityCheck'"
|
||||
);
|
||||
}
|
||||
|
||||
updated = yield _migrateUserDataSchema(userdata, options);
|
||||
yield _updateSchema('triggers');
|
||||
updated = await _migrateUserDataSchema(userdata, options);
|
||||
await _updateSchema('triggers');
|
||||
|
||||
// Populate combined tables for custom types and fields -- this is likely temporary
|
||||
//
|
||||
// We do this again in case custom fields were changed during user data migration
|
||||
yield _updateCustomTables()
|
||||
await _updateCustomTables();
|
||||
|
||||
return updated;
|
||||
}.bind(this));
|
||||
}
|
||||
finally {
|
||||
yield Zotero.DB.queryAsync("PRAGMA foreign_keys = true");
|
||||
await Zotero.DB.queryAsync("PRAGMA foreign_keys = true");
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
|
@ -220,7 +248,7 @@ Zotero.Schema = new function(){
|
|||
}
|
||||
|
||||
// Reset sync queue tries if new version
|
||||
yield _checkClientVersion();
|
||||
await _checkClientVersion();
|
||||
|
||||
// In Standalone, don't load bundled files until after UI is ready. In Firefox, load them as
|
||||
// soon initialization is done so that translation works before the Zotero pane is opened.
|
||||
|
@ -273,7 +301,341 @@ Zotero.Schema = new function(){
|
|||
});
|
||||
|
||||
return updated;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get bundled schema from disk
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
async function _readGlobalSchemaFromFile() {
|
||||
return JSON.parse(
|
||||
await Zotero.File.getResourceAsync('resource://zotero/schema/global/schema.json')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get schema from database
|
||||
*
|
||||
* Doesn't include the .itemTypes property, which was already applied to the mapping tables
|
||||
*/
|
||||
async function _readGlobalSchemaFromDB() {
|
||||
var pako = {};
|
||||
Services.scriptloader.loadSubScript("resource://zotero/pako.js", pako);
|
||||
var data = await Zotero.DB.valueQueryAsync(
|
||||
"SELECT value FROM settings WHERE schema='globalSchema' AND key='data'"
|
||||
);
|
||||
if (data) {
|
||||
try {
|
||||
data = JSON.parse(pako.inflate(data, { to: 'string' }));
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.warn("Unable to extract global schema -- falling back to file: " + e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Zotero.warn("Global schema not found in DB -- falling back to file");
|
||||
}
|
||||
|
||||
// If the data is missing or unreadable in the DB for some reason (e.g., DB corruption),
|
||||
// fall back to the file, though it might be out of date
|
||||
if (!data) {
|
||||
data = await _readGlobalSchemaFromFile();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compares a given version number to the version of the schema in the database
|
||||
*
|
||||
* @return {Number} - 1 if provided version is greater than DB (i.e., DB needs update), 0 if
|
||||
* the same, -1 if DB version is newer
|
||||
*/
|
||||
async function _globalSchemaVersionCompare(version) {
|
||||
if (!version) {
|
||||
throw new Error("version not specified");
|
||||
}
|
||||
|
||||
var dbVersion = await Zotero.Schema.getDBVersion('globalSchema') || null;
|
||||
if (dbVersion > version) {
|
||||
Zotero.debug(`Database has newer global schema (${dbVersion} > ${version}) -- skipping update`);
|
||||
return -1;
|
||||
}
|
||||
else if (dbVersion == version) {
|
||||
Zotero.debug(`Database is up to date with global schema version ${version} -- skipping update`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Zotero.debug(`Global schema needs update from ${dbVersion} to ${version}`);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the item-type/field/creator mapping tables based on the passed schema
|
||||
*/
|
||||
async function _updateGlobalSchema(data) {
|
||||
Zotero.debug("Updating global schema to version " + data.version);
|
||||
|
||||
Zotero.DB.requireTransaction();
|
||||
|
||||
await Zotero.ID.init();
|
||||
|
||||
var preItemTypeRows = await Zotero.DB.queryAsync(
|
||||
"SELECT itemTypeID AS id, typeName AS name FROM itemTypes"
|
||||
);
|
||||
var preFieldRows = await Zotero.DB.queryAsync(
|
||||
"SELECT fieldID AS id, fieldName AS name FROM fields"
|
||||
);
|
||||
var preCreatorTypeRows = await Zotero.DB.queryAsync(
|
||||
"SELECT creatorTypeID AS id, creatorType AS name FROM creatorTypes"
|
||||
);
|
||||
var preFields = new Set(preFieldRows.map(x => x.name));
|
||||
var preCreatorTypes = new Set(preCreatorTypeRows.map(x => x.name));
|
||||
var preItemTypeIDsByName = new Map(preItemTypeRows.map(x => [x.name, x.id]));
|
||||
var preFieldIDsByName = new Map(preFieldRows.map(x => [x.name, x.id]));
|
||||
var preCreatorTypeIDsByName = new Map(preCreatorTypeRows.map(x => [x.name, x.id]));
|
||||
var postFields = new Set();
|
||||
var postCreatorTypes = new Set();
|
||||
var postFieldIDsByName = new Map();
|
||||
var postCreatorTypeIDsByName = new Map();
|
||||
|
||||
// Add new fields and creator types
|
||||
for (let { fields, creatorTypes } of data.itemTypes) {
|
||||
for (let { field, baseField } of fields) {
|
||||
postFields.add(field);
|
||||
if (baseField) {
|
||||
postFields.add(baseField);
|
||||
}
|
||||
}
|
||||
|
||||
for (let { creatorType } of creatorTypes) {
|
||||
postCreatorTypes.add(creatorType);
|
||||
}
|
||||
}
|
||||
var fieldsValueSets = [];
|
||||
var fieldsParams = [];
|
||||
for (let field of postFields) {
|
||||
if (preFields.has(field)) {
|
||||
postFieldIDsByName.set(field, preFieldIDsByName.get(field));
|
||||
}
|
||||
else {
|
||||
let id = Zotero.ID.get('fields');
|
||||
fieldsValueSets.push("(?, ?, NULL)");
|
||||
fieldsParams.push(id, field);
|
||||
postFieldIDsByName.set(field, id);
|
||||
}
|
||||
}
|
||||
if (fieldsValueSets.length) {
|
||||
await Zotero.DB.queryAsync(
|
||||
"INSERT INTO fields VALUES " + fieldsValueSets.join(", "),
|
||||
fieldsParams
|
||||
);
|
||||
}
|
||||
var creatorTypesValueSets = [];
|
||||
var creatorTypesParams = [];
|
||||
for (let type of postCreatorTypes) {
|
||||
if (preCreatorTypes.has(type)) {
|
||||
postCreatorTypeIDsByName.set(type, preCreatorTypeIDsByName.get(type));
|
||||
}
|
||||
else {
|
||||
let id = Zotero.ID.get('creatorTypes');
|
||||
creatorTypesValueSets.push("(?, ?)");
|
||||
creatorTypesParams.push(id, type);
|
||||
postCreatorTypeIDsByName.set(type, id);
|
||||
}
|
||||
}
|
||||
if (creatorTypesValueSets.length) {
|
||||
await Zotero.DB.queryAsync(
|
||||
"INSERT INTO creatorTypes VALUES " + creatorTypesValueSets.join(", "),
|
||||
creatorTypesParams
|
||||
);
|
||||
}
|
||||
|
||||
// Apply changes to DB
|
||||
let itemTypeFieldsValueSets = [];
|
||||
let baseFieldMappingsValueSets = [];
|
||||
let itemTypeCreatorTypesValueSets = [];
|
||||
for (let { itemType, fields, creatorTypes } of data.itemTypes) {
|
||||
let itemTypeID = preItemTypeIDsByName.get(itemType);
|
||||
// let preItemTypeCreatorTypeIDs = [];
|
||||
if (itemTypeID) {
|
||||
// Unused
|
||||
/*preItemTypeCreatorTypeIDs = await Zotero.DB.columnQueryAsync(
|
||||
"SELECT creatorTypeID FROM itemTypeCreatorTypes WHERE itemTypeID=?",
|
||||
itemTypeID
|
||||
);*/
|
||||
}
|
||||
// New item type
|
||||
else {
|
||||
itemTypeID = Zotero.ID.get('itemTypes');
|
||||
await Zotero.DB.queryAsync(
|
||||
"INSERT INTO itemTypes VALUES (?, ?, NULL, 1)",
|
||||
[itemTypeID, itemType]
|
||||
);
|
||||
}
|
||||
|
||||
// Fields
|
||||
let index = 0;
|
||||
let postItemTypeFieldIDs = new Set();
|
||||
for (let { field, baseField } of fields) {
|
||||
let fieldID = postFieldIDsByName.get(field);
|
||||
postItemTypeFieldIDs.add(fieldID);
|
||||
itemTypeFieldsValueSets.push(`(${itemTypeID}, ${fieldID}, 0, ${index++})`);
|
||||
if (baseField) {
|
||||
let baseFieldID = postFieldIDsByName.get(baseField);
|
||||
baseFieldMappingsValueSets.push(`(${itemTypeID}, ${baseFieldID}, ${fieldID})`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: Check for fields removed from this item type
|
||||
// throw new Error(`Field ${id} was removed from ${itemType}`);
|
||||
|
||||
// Creator types
|
||||
for (let { creatorType, primary } of creatorTypes) {
|
||||
let typeID = postCreatorTypeIDsByName.get(creatorType);
|
||||
itemTypeCreatorTypesValueSets.push(`(${itemTypeID}, ${typeID}, ${primary ? 1 : 0})`);
|
||||
}
|
||||
|
||||
// TODO: Check for creator types removed from this item type
|
||||
// throw new Error(`Creator type ${id} was removed from ${itemType}`);
|
||||
|
||||
// TODO: Deal with existing types not in the schema, and their items
|
||||
}
|
||||
|
||||
await Zotero.DB.queryAsync("DELETE FROM itemTypeFields");
|
||||
await Zotero.DB.queryAsync("DELETE FROM baseFieldMappings");
|
||||
await Zotero.DB.queryAsync("DELETE FROM itemTypeCreatorTypes");
|
||||
|
||||
await Zotero.DB.queryAsync("INSERT INTO itemTypeFields VALUES "
|
||||
+ itemTypeFieldsValueSets.join(", "));
|
||||
await Zotero.DB.queryAsync("INSERT INTO baseFieldMappings VALUES "
|
||||
+ baseFieldMappingsValueSets.join(", "));
|
||||
await Zotero.DB.queryAsync("INSERT INTO itemTypeCreatorTypes VALUES "
|
||||
+ itemTypeCreatorTypesValueSets.join(", "));
|
||||
|
||||
// Store data in DB as compressed binary string. This lets us use a schema that matches the
|
||||
// DB tables even if the user downgrades to a version with an earlier bundled schema file.
|
||||
var pako = require('pako');
|
||||
var dbData = { ...data };
|
||||
// Don't include types and fields, which are already in the mapping tables
|
||||
delete dbData.itemTypes;
|
||||
await Zotero.DB.queryAsync(
|
||||
"REPLACE INTO settings VALUES ('globalSchema', 'data', ?)",
|
||||
pako.deflate(JSON.stringify(dbData), { to: 'string' }),
|
||||
{
|
||||
debugParams: false
|
||||
}
|
||||
);
|
||||
await _updateDBVersion('globalSchema', data.version);
|
||||
|
||||
var bundledVersion = (await _readGlobalSchemaFromFile()).version;
|
||||
await _loadGlobalSchema(data, bundledVersion);
|
||||
await _reloadSchema();
|
||||
// Mark that we need to migrate Extra values to any newly available fields in
|
||||
// Zotero.Schema.migrateExtraFields()
|
||||
await Zotero.DB.queryAsync(
|
||||
"REPLACE INTO settings VALUES ('globalSchema', 'migrateExtra', 1)"
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
this._updateGlobalSchemaForTest = async function (schema) {
|
||||
await Zotero.DB.executeTransaction(async function () {
|
||||
await _updateGlobalSchema(schema);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set properties on Zotero.Schema based on the passed data
|
||||
*
|
||||
* @param {Object} data - Global schema data ('version', 'itemTypes', 'locales', etc.)
|
||||
* @param {Number} bundledVersion - Version of the bundled schema.json file
|
||||
*/
|
||||
async function _loadGlobalSchema(data, bundledVersion) {
|
||||
if (!data) {
|
||||
throw new Error("Data not provided");
|
||||
}
|
||||
var locale = data.locales[Zotero.locale];
|
||||
if (!locale) {
|
||||
Zotero.warn(`Locale ${Zotero.locale} not found in global schema locales`);
|
||||
locale = data.locales['en-US'];
|
||||
if (!locale) {
|
||||
throw new Error("en-US locale not found in global schema locales");
|
||||
}
|
||||
}
|
||||
Zotero.Schema.globalSchemaVersion = data.version;
|
||||
Zotero.Schema.globalSchemaLocale = locale;
|
||||
Zotero.Schema.globalSchemaMeta = data.meta;
|
||||
Zotero.Schema.CSL_TYPE_MAPPINGS = {};
|
||||
Zotero.Schema.CSL_TYPE_MAPPINGS_REVERSE = {};
|
||||
for (let cslType in data.csl.types) {
|
||||
for (let zoteroType of data.csl.types[cslType]) {
|
||||
Zotero.Schema.CSL_TYPE_MAPPINGS[zoteroType] = cslType;
|
||||
}
|
||||
Zotero.Schema.CSL_TYPE_MAPPINGS_REVERSE[cslType] = data.csl.types[cslType][0];
|
||||
}
|
||||
Zotero.Schema.CSL_TEXT_MAPPINGS = data.csl.fields.text;
|
||||
Zotero.Schema.CSL_DATE_MAPPINGS = data.csl.fields.date;
|
||||
Zotero.Schema.CSL_NAME_MAPPINGS = data.csl.names;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Migrate values from item Extra fields that can be moved to regular item fields after a global
|
||||
* schema update
|
||||
*
|
||||
* This needs the data object architecture to be initialized, so it's called from zotero.js
|
||||
* rather than in _updateGlobalSchema().
|
||||
*/
|
||||
this.migrateExtraFields = async function () {
|
||||
// Check for a flag set by _updateGlobalSchema()
|
||||
var needsUpdate = await Zotero.DB.valueQueryAsync(
|
||||
"SELECT COUNT(*) FROM settings WHERE setting='globalSchema' AND key='migrateExtra'"
|
||||
);
|
||||
if (!needsUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
var fieldID = Zotero.ItemFields.getID('extra');
|
||||
var sql = "SELECT itemID, value FROM itemData "
|
||||
+ "JOIN itemDataValues USING (valueID) "
|
||||
+ "WHERE fieldID=?";
|
||||
var rows = await Zotero.DB.queryAsync(sql, fieldID);
|
||||
var itemIDs = [];
|
||||
for (let row of rows) {
|
||||
let { itemType, fields, creators } = Zotero.Utilities.Internal.extractExtraFields(
|
||||
row.value
|
||||
);
|
||||
if (itemType || fields.size || creators.length) {
|
||||
itemIDs.push(row.itemID);
|
||||
}
|
||||
}
|
||||
|
||||
var items = await Zotero.Items.getAsync(itemIDs);
|
||||
await Zotero.Items.loadDataTypes(items, ['itemData', 'creator']);
|
||||
for (let item of items) {
|
||||
let changed = item.migrateExtraFields();
|
||||
if (!changed) continue;
|
||||
await item.saveTx({
|
||||
skipDateModifiedUpdate: true,
|
||||
skipSelect: true
|
||||
});
|
||||
}
|
||||
|
||||
await Zotero.DB.queryAsync(
|
||||
"DELETE FROM settings WHERE setting='globalSchema' AND key='migrateExtra'"
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// https://www.zotero.org/support/nsf
|
||||
|
@ -335,15 +697,15 @@ Zotero.Schema = new function(){
|
|||
|
||||
switch (fields[i][0]) {
|
||||
case 'name':
|
||||
var baseFieldID = 110; // title
|
||||
var baseFieldID = Zotero.ItemFields.getID('title');
|
||||
break;
|
||||
|
||||
case 'dateSent':
|
||||
var baseFieldID = 14; // date
|
||||
var baseFieldID = Zotero.ItemFields.getID('date');
|
||||
break;
|
||||
|
||||
case 'homepage':
|
||||
var baseFieldID = 1; // URL
|
||||
var baseFieldID = Zotero.ItemFields.getID('url');
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -415,6 +777,7 @@ Zotero.Schema = new function(){
|
|||
yield _updateCustomTables();
|
||||
yield Zotero.ItemTypes.init();
|
||||
yield Zotero.ItemFields.init();
|
||||
yield Zotero.CreatorTypes.init();
|
||||
yield Zotero.SearchConditions.init();
|
||||
|
||||
// Update item type menus in every open window
|
||||
|
@ -429,58 +792,40 @@ Zotero.Schema = new function(){
|
|||
});
|
||||
|
||||
|
||||
var _updateCustomTables = Zotero.Promise.coroutine(function* (skipDelete, skipSystem) {
|
||||
var _updateCustomTables = async function () {
|
||||
Zotero.debug("Updating custom tables");
|
||||
|
||||
Zotero.DB.requireTransaction();
|
||||
|
||||
if (!skipDelete) {
|
||||
yield Zotero.DB.queryAsync("DELETE FROM itemTypesCombined");
|
||||
yield Zotero.DB.queryAsync("DELETE FROM fieldsCombined WHERE fieldID NOT IN (SELECT fieldID FROM itemData)");
|
||||
yield Zotero.DB.queryAsync("DELETE FROM itemTypeFieldsCombined");
|
||||
yield Zotero.DB.queryAsync("DELETE FROM baseFieldMappingsCombined");
|
||||
}
|
||||
await Zotero.DB.queryAsync("DELETE FROM itemTypesCombined");
|
||||
await Zotero.DB.queryAsync("DELETE FROM fieldsCombined WHERE fieldID NOT IN (SELECT fieldID FROM itemData)");
|
||||
await Zotero.DB.queryAsync("DELETE FROM itemTypeFieldsCombined");
|
||||
await Zotero.DB.queryAsync("DELETE FROM baseFieldMappingsCombined");
|
||||
|
||||
var offset = Zotero.ItemTypes.customIDOffset;
|
||||
yield Zotero.DB.queryAsync(
|
||||
await Zotero.DB.queryAsync(
|
||||
"INSERT INTO itemTypesCombined "
|
||||
+ (
|
||||
skipSystem
|
||||
? ""
|
||||
: "SELECT itemTypeID, typeName, display, 0 AS custom FROM itemTypes UNION "
|
||||
)
|
||||
+ "SELECT itemTypeID, typeName, display, 0 AS custom FROM itemTypes UNION "
|
||||
+ "SELECT customItemTypeID + " + offset + " AS itemTypeID, typeName, display, 1 AS custom FROM customItemTypes"
|
||||
);
|
||||
yield Zotero.DB.queryAsync(
|
||||
await Zotero.DB.queryAsync(
|
||||
"INSERT OR IGNORE INTO fieldsCombined "
|
||||
+ (
|
||||
skipSystem
|
||||
? ""
|
||||
: "SELECT fieldID, fieldName, NULL AS label, fieldFormatID, 0 AS custom FROM fields UNION "
|
||||
)
|
||||
+ "SELECT fieldID, fieldName, NULL AS label, fieldFormatID, 0 AS custom FROM fields UNION "
|
||||
+ "SELECT customFieldID + " + offset + " AS fieldID, fieldName, label, NULL, 1 AS custom FROM customFields"
|
||||
);
|
||||
yield Zotero.DB.queryAsync(
|
||||
await Zotero.DB.queryAsync(
|
||||
"INSERT INTO itemTypeFieldsCombined "
|
||||
+ (
|
||||
skipSystem
|
||||
? ""
|
||||
: "SELECT itemTypeID, fieldID, hide, orderIndex FROM itemTypeFields UNION "
|
||||
)
|
||||
+ "SELECT itemTypeID, fieldID, hide, orderIndex FROM itemTypeFields UNION "
|
||||
+ "SELECT customItemTypeID + " + offset + " AS itemTypeID, "
|
||||
+ "COALESCE(fieldID, customFieldID + " + offset + ") AS fieldID, hide, orderIndex FROM customItemTypeFields"
|
||||
);
|
||||
yield Zotero.DB.queryAsync(
|
||||
await Zotero.DB.queryAsync(
|
||||
"INSERT INTO baseFieldMappingsCombined "
|
||||
+ (
|
||||
skipSystem
|
||||
? ""
|
||||
: "SELECT itemTypeID, baseFieldID, fieldID FROM baseFieldMappings UNION "
|
||||
)
|
||||
+ "SELECT itemTypeID, baseFieldID, fieldID FROM baseFieldMappings UNION "
|
||||
+ "SELECT customItemTypeID + " + offset + " AS itemTypeID, baseFieldID, "
|
||||
+ "customFieldID + " + offset + " AS fieldID FROM customBaseFieldMappings"
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
@ -1335,6 +1680,13 @@ Zotero.Schema = new function(){
|
|||
}
|
||||
}
|
||||
|
||||
var attachmentID = parseInt(yield Zotero.DB.valueQueryAsync(
|
||||
"SELECT itemTypeID FROM itemTypes WHERE typeName='attachment'"
|
||||
));
|
||||
var noteID = parseInt(yield Zotero.DB.valueQueryAsync(
|
||||
"SELECT itemTypeID FROM itemTypes WHERE typeName='note'"
|
||||
));
|
||||
|
||||
|
||||
// Non-foreign key checks
|
||||
//
|
||||
|
@ -1348,29 +1700,29 @@ Zotero.Schema = new function(){
|
|||
"SELECT COUNT(*) > 0 FROM items WHERE itemTypeID IS NULL",
|
||||
"DELETE FROM items WHERE itemTypeID IS NULL",
|
||||
],
|
||||
// Attachments row with itemTypeID != 14
|
||||
// Non-attachment items in attachments table
|
||||
[
|
||||
"SELECT COUNT(*) > 0 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)",
|
||||
`SELECT COUNT(*) > 0 FROM itemAttachments JOIN items USING (itemID) WHERE itemTypeID != ${attachmentID}`,
|
||||
`UPDATE items SET itemTypeID=${attachmentID}, clientDateModified=CURRENT_TIMESTAMP WHERE itemTypeID != ${attachmentID} AND itemID IN (SELECT itemID FROM itemAttachments)`,
|
||||
],
|
||||
// Fields not in type
|
||||
[
|
||||
"SELECT COUNT(*) > 0 FROM itemData WHERE fieldID NOT IN (SELECT fieldID FROM itemTypeFieldsCombined WHERE itemTypeID=(SELECT itemTypeID FROM items WHERE itemID=itemData.itemID))",
|
||||
"DELETE FROM itemData WHERE fieldID NOT IN (SELECT fieldID FROM itemTypeFieldsCombined WHERE itemTypeID=(SELECT itemTypeID FROM items WHERE itemID=itemData.itemID))",
|
||||
],
|
||||
// Missing itemAttachments row
|
||||
// Missing itemAttachments rows
|
||||
[
|
||||
"SELECT COUNT(*) > 0 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)",
|
||||
`SELECT COUNT(*) > 0 FROM items WHERE itemTypeID=${attachmentID} AND itemID NOT IN (SELECT itemID FROM itemAttachments)`,
|
||||
`INSERT INTO itemAttachments (itemID, linkMode) SELECT itemID, 0 FROM items WHERE itemTypeID=${attachmentID} AND itemID NOT IN (SELECT itemID FROM itemAttachments)`,
|
||||
],
|
||||
// Note/child parents
|
||||
[
|
||||
"SELECT COUNT(*) > 0 FROM itemAttachments WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
|
||||
"UPDATE itemAttachments SET parentItemID=NULL WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
|
||||
`SELECT COUNT(*) > 0 FROM itemAttachments WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (${noteID}, ${attachmentID}))`,
|
||||
`UPDATE itemAttachments SET parentItemID=NULL WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (${noteID}, ${attachmentID}))`,
|
||||
],
|
||||
[
|
||||
"SELECT COUNT(*) > 0 FROM itemNotes WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
|
||||
"UPDATE itemNotes SET parentItemID=NULL WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
|
||||
`SELECT COUNT(*) > 0 FROM itemNotes WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (${noteID}, ${attachmentID}))`,
|
||||
`UPDATE itemNotes SET parentItemID=NULL WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (${noteID}, ${attachmentID}))`,
|
||||
],
|
||||
|
||||
// Delete empty creators
|
||||
|
@ -1382,13 +1734,13 @@ Zotero.Schema = new function(){
|
|||
|
||||
// Non-attachment items in the full-text index
|
||||
[
|
||||
"SELECT COUNT(*) > 0 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 COUNT(*) > 0 FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=${attachmentID})`,
|
||||
`DELETE FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=${attachmentID})`
|
||||
],
|
||||
// Full-text items must be attachments
|
||||
[
|
||||
"SELECT COUNT(*) > 0 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)"
|
||||
`SELECT COUNT(*) > 0 FROM fulltextItems WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=${attachmentID})`,
|
||||
`DELETE FROM fulltextItems WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=${attachmentID})`
|
||||
],
|
||||
// Invalid link mode -- set to imported url
|
||||
[
|
||||
|
@ -1532,8 +1884,8 @@ Zotero.Schema = new function(){
|
|||
/*
|
||||
* Create new DB schema
|
||||
*/
|
||||
function _initializeSchema(){
|
||||
return Zotero.DB.executeTransaction(function* (conn) {
|
||||
async function _initializeSchema() {
|
||||
await Zotero.DB.executeTransaction(function* (conn) {
|
||||
var userLibraryID = 1;
|
||||
|
||||
// Enable auto-vacuuming
|
||||
|
@ -1550,7 +1902,9 @@ Zotero.Schema = new function(){
|
|||
yield _getSchemaSQL('triggers').then(function (sql) {
|
||||
return Zotero.DB.executeSQLFile(sql);
|
||||
});
|
||||
yield _updateCustomTables(true);
|
||||
|
||||
var schema = yield _readGlobalSchemaFromFile();
|
||||
yield _updateGlobalSchema(schema);
|
||||
|
||||
yield _getSchemaSQLVersion('system').then(function (version) {
|
||||
return _updateDBVersion('system', version);
|
||||
|
@ -2528,6 +2882,21 @@ Zotero.Schema = new function(){
|
|||
yield Zotero.DB.queryAsync("ALTER TABLE retractedItems ADD COLUMN flag INT DEFAULT 0");
|
||||
}
|
||||
|
||||
else if (i == 106) {
|
||||
yield _updateCompatibility(6);
|
||||
|
||||
yield Zotero.DB.queryAsync("DROP TRIGGER insert_date_field");
|
||||
yield Zotero.DB.queryAsync("DROP TRIGGER update_date_field");
|
||||
yield Zotero.DB.queryAsync("DROP TRIGGER fki_itemAttachments");
|
||||
yield Zotero.DB.queryAsync("DROP TRIGGER fku_itemAttachments");
|
||||
yield Zotero.DB.queryAsync("DROP TRIGGER fki_itemNotes");
|
||||
yield Zotero.DB.queryAsync("DROP TRIGGER fku_itemNotes");
|
||||
|
||||
yield Zotero.DB.queryAsync("DROP TABLE transactionSets");
|
||||
yield Zotero.DB.queryAsync("DROP TABLE transactions");
|
||||
yield Zotero.DB.queryAsync("DROP TABLE transactionLog");
|
||||
}
|
||||
|
||||
// If breaking compatibility or doing anything dangerous, clear minorUpdateFrom
|
||||
}
|
||||
|
||||
|
@ -2593,7 +2962,7 @@ Zotero.Schema = new function(){
|
|||
}
|
||||
else {
|
||||
let file = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
.createInstance(Components.interfaces.nsIFile);
|
||||
try {
|
||||
file.persistentDescriptor = path;
|
||||
}
|
||||
|
|
|
@ -140,7 +140,12 @@ Zotero.Server.SocketListener = new function() {
|
|||
var dataListener = new Zotero.Server.DataListener(iStream, oStream);
|
||||
var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"]
|
||||
.createInstance(Components.interfaces.nsIInputStreamPump);
|
||||
pump.init(iStream, -1, -1, 0, 0, false);
|
||||
try {
|
||||
pump.init(iStream, 0, 0, false);
|
||||
}
|
||||
catch (e) {
|
||||
pump.init(iStream, -1, -1, 0, 0, false);
|
||||
}
|
||||
pump.asyncRead(dataListener, null);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,10 +38,10 @@ Zotero.Sync.Storage.Result.prototype.updateFromResults = function (results) {
|
|||
}
|
||||
|
||||
|
||||
Zotero.Sync.Storage.Result.prototype.toString = function () {
|
||||
/*Zotero.Sync.Storage.Result.prototype.toString = function () {
|
||||
var obj = {};
|
||||
for (let prop of this._props) {
|
||||
obj[prop] = this[prop] || false;
|
||||
}
|
||||
return JSON.stringify(obj, null, " ");
|
||||
}
|
||||
}*/
|
||||
|
|
|
@ -271,6 +271,6 @@ Zotero.Sync.Storage.StreamListener.prototype = {
|
|||
|
||||
_safeSpec: function (uri) {
|
||||
return uri.scheme + '://' + uri.username + ':********@'
|
||||
+ uri.hostPort + uri.path
|
||||
+ uri.hostPort + uri.pathQueryRef
|
||||
},
|
||||
};
|
||||
|
|
|
@ -188,32 +188,23 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
throw new this.VerificationError("NO_URL");
|
||||
}
|
||||
|
||||
url = scheme + '://' + url;
|
||||
var dir = "zotero";
|
||||
var username = this.username;
|
||||
var password = this.password;
|
||||
|
||||
if (!username) {
|
||||
throw new this.VerificationError("NO_USERNAME");
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
throw new this.VerificationError("NO_PASSWORD");
|
||||
}
|
||||
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
var uri = ios.newURI(url, null, null);
|
||||
uri.username = encodeURIComponent(username);
|
||||
uri.password = encodeURIComponent(password);
|
||||
if (!uri.spec.match(/\/$/)) {
|
||||
uri.spec += "/";
|
||||
}
|
||||
this._parentURI = uri;
|
||||
url = scheme + '://'
|
||||
+ encodeURIComponent(username) + ':' + encodeURIComponent(password) + '@'
|
||||
+ url
|
||||
+ (url.endsWith('/') ? '' : '/');
|
||||
|
||||
var uri = uri.clone();
|
||||
uri.spec += "zotero/";
|
||||
this._rootURI = uri;
|
||||
var io = Services.io;
|
||||
this._parentURI = io.newURI(url, null, null);
|
||||
this._rootURI = io.newURI(url + "zotero/", null, null);
|
||||
},
|
||||
|
||||
|
||||
|
@ -656,8 +647,7 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
|
||||
if (req.status == 207) {
|
||||
// Test if missing files return 404s
|
||||
let missingFileURI = uri.clone();
|
||||
missingFileURI.spec += "nonexistent.prop";
|
||||
let missingFileURI = uri.mutate().setSpec(uri.spec + "nonexistent.prop").finalize();
|
||||
try {
|
||||
req = yield Zotero.HTTP.request(
|
||||
"GET",
|
||||
|
@ -681,8 +671,7 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
}
|
||||
|
||||
// Test if Zotero directory is writable
|
||||
let testFileURI = uri.clone();
|
||||
testFileURI.spec += "zotero-test-file.prop";
|
||||
let testFileURI = uri.mutate().setSpec(uri.spec + "zotero-test-file.prop").finalize();
|
||||
req = yield Zotero.HTTP.request("PUT", testFileURI, {
|
||||
body: " ",
|
||||
successCodes: [200, 201, 204],
|
||||
|
@ -765,7 +754,7 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
|
||||
createInstance(Components.interfaces.nsIPromptService);
|
||||
if (err.url) {
|
||||
var spec = err.url.scheme + '://' + err.url.hostPort + err.url.path;
|
||||
var spec = err.url.scheme + '://' + err.url.hostPort + err.url.pathQueryRef;
|
||||
}
|
||||
|
||||
var errorTitle, errorMsg;
|
||||
|
@ -784,7 +773,7 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
|
||||
case 403:
|
||||
errorTitle = Zotero.getString('general.permissionDenied');
|
||||
errorMsg = Zotero.getString('sync.storage.error.webdav.permissionDenied', err.channel.URI.path)
|
||||
errorMsg = Zotero.getString('sync.storage.error.webdav.permissionDenied', err.channel.URI.pathQueryRef)
|
||||
+ "\n\n" + Zotero.getString('sync.storage.error.checkFileSyncSettings');
|
||||
break;
|
||||
|
||||
|
@ -851,7 +840,7 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
if (e.status == 403) {
|
||||
errorTitle = Zotero.getString('general.permissionDenied');
|
||||
let rootURI = this.rootURI;
|
||||
let rootSpec = rootURI.scheme + '://' + rootURI.hostPort + rootURI.path
|
||||
let rootSpec = rootURI.scheme + '://' + rootURI.hostPort + rootURI.pathQueryRef
|
||||
errorMsg = Zotero.getString('sync.storage.error.permissionDeniedAtAddress')
|
||||
+ "\n\n" + rootSpec + "\n\n"
|
||||
+ Zotero.getString('sync.storage.error.checkFileSyncSettings');
|
||||
|
@ -986,7 +975,7 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
Zotero.debug("Purging orphaned storage files");
|
||||
|
||||
var uri = this.rootURI;
|
||||
var path = uri.path;
|
||||
var path = uri.pathQueryRef;
|
||||
|
||||
var contentTypeXML = { "Content-Type": "text/xml; charset=utf-8" };
|
||||
var xmlstr = "<propfind xmlns='DAV:'><prop>"
|
||||
|
@ -1037,7 +1026,7 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
if (href.match(/^https?:\/\//)) {
|
||||
let ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
href = ios.newURI(href, null, null).path;
|
||||
href = ios.newURI(href, null, null).pathQueryRef;
|
||||
}
|
||||
|
||||
let decodedHref = decodeURIComponent(href).normalize();
|
||||
|
@ -1336,9 +1325,7 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
* @return {nsIURI} URI of file on storage server
|
||||
*/
|
||||
_getItemURI: function (item) {
|
||||
var uri = this.rootURI;
|
||||
uri.spec = uri.spec + item.key + '.zip';
|
||||
return uri;
|
||||
return this.rootURI.mutate().setSpec(this.rootURI.spec + item.key + '.zip').finalize();
|
||||
},
|
||||
|
||||
|
||||
|
@ -1350,9 +1337,7 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
* @return {nsIURI} URI of property file on storage server
|
||||
*/
|
||||
_getItemPropertyURI: function (item) {
|
||||
var uri = this.rootURI;
|
||||
uri.spec = uri.spec + item.key + '.prop';
|
||||
return uri;
|
||||
return this.rootURI.mutate().setSpec(this.rootURI.spec + item.key + '.prop').finalize();
|
||||
},
|
||||
|
||||
|
||||
|
@ -1366,11 +1351,7 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
if (!uri.spec.match(/\.zip$/)) {
|
||||
return false;
|
||||
}
|
||||
var propURI = uri.clone();
|
||||
propURI.QueryInterface(Components.interfaces.nsIURL);
|
||||
propURI.fileName = uri.fileName.replace(/\.zip$/, '.prop');
|
||||
propURI.QueryInterface(Components.interfaces.nsIURI);
|
||||
return propURI;
|
||||
return uri.mutate().setFilePath(uri.filePath.replace(/\.zip$/, '.prop')).finalize();
|
||||
},
|
||||
|
||||
|
||||
|
@ -1408,10 +1389,7 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
for (let i = 0 ; i < files.length; i++) {
|
||||
let fileName = files[i];
|
||||
funcs.push(Zotero.Promise.coroutine(function* () {
|
||||
var deleteURI = this.rootURI.clone();
|
||||
deleteURI.QueryInterface(Components.interfaces.nsIURL);
|
||||
deleteURI.fileName = fileName;
|
||||
deleteURI.QueryInterface(Components.interfaces.nsIURI);
|
||||
var deleteURI = this.rootURI.mutate().setSpec(this.rootURI.spec + fileName).finalize();
|
||||
try {
|
||||
var req = yield Zotero.HTTP.request(
|
||||
"DELETE",
|
||||
|
@ -1442,6 +1420,8 @@ Zotero.Sync.Storage.Mode.WebDAV.prototype = {
|
|||
|
||||
// If an item file URI, get the property URI
|
||||
var deletePropURI = this._getPropertyURIFromItemURI(deleteURI);
|
||||
// Only nsIURL has fileName
|
||||
deletePropURI.QueryInterface(Ci.nsIURL);
|
||||
|
||||
// If we already deleted the prop file, skip it
|
||||
if (!deletePropURI || results.deleted.has(deletePropURI.fileName)) {
|
||||
|
|
|
@ -1244,7 +1244,7 @@ Zotero.Sync.Data.Engine.prototype._uploadObjects = Zotero.Promise.coroutine(func
|
|||
// Update local object with saved data if necessary, as long as it hasn't
|
||||
// changed locally since the upload
|
||||
if (!changed) {
|
||||
obj.fromJSON(current.data);
|
||||
obj.fromJSON(current.data, { strict: true });
|
||||
toSave.push(obj);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -381,9 +381,7 @@ Zotero.Sync.Data.Local = {
|
|||
*/
|
||||
_getAPIKeyLoginInfo: function () {
|
||||
try {
|
||||
var loginManager = Components.classes["@mozilla.org/login-manager;1"]
|
||||
.getService(Components.interfaces.nsILoginManager);
|
||||
var logins = loginManager.findLogins(
|
||||
var logins = Services.logins.findLogins(
|
||||
{},
|
||||
this._loginManagerHost,
|
||||
null,
|
||||
|
@ -723,11 +721,10 @@ Zotero.Sync.Data.Local = {
|
|||
var ObjectType = Zotero.Utilities.capitalize(objectType);
|
||||
var libraryName = Zotero.Libraries.get(libraryID).name;
|
||||
|
||||
var knownErrors = [
|
||||
'ZoteroUnknownTypeError',
|
||||
'ZoteroUnknownFieldError',
|
||||
var knownErrors = new Set([
|
||||
'ZoteroInvalidDataError',
|
||||
'ZoteroMissingObjectError'
|
||||
];
|
||||
]);
|
||||
|
||||
Zotero.debug("Processing " + json.length + " downloaded "
|
||||
+ (json.length == 1 ? objectType : objectTypePlural)
|
||||
|
@ -1029,8 +1026,11 @@ Zotero.Sync.Data.Local = {
|
|||
}
|
||||
}
|
||||
catch (e) {
|
||||
// This allows errors handled by syncRunner to know the library in question
|
||||
e.libraryID = libraryID;
|
||||
|
||||
// Display nicer debug line for known errors
|
||||
if (knownErrors.indexOf(e.name) != -1) {
|
||||
if (knownErrors.has(e.name)) {
|
||||
let desc = e.name
|
||||
.replace(/^Zotero/, "")
|
||||
// Convert "MissingObjectError" to "missing object error"
|
||||
|
@ -1409,7 +1409,7 @@ Zotero.Sync.Data.Local = {
|
|||
json = this._checkCacheJSON(json);
|
||||
|
||||
if (!options.skipData) {
|
||||
obj.fromJSON(json.data);
|
||||
obj.fromJSON(json.data, { strict: true });
|
||||
}
|
||||
if (obj.objectType == 'item' && obj.isImportedAttachment()) {
|
||||
yield this._checkAttachmentForDownload(obj, json.data.mtime, options.isNewObject);
|
||||
|
|
|
@ -1263,6 +1263,23 @@ Zotero.Sync.Runner_Module = function (options = {}) {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Show warning for unknown data that couldn't be saved
|
||||
else if (e.name && e.name == 'ZoteroInvalidDataError') {
|
||||
e.message = Zotero.getString(
|
||||
'sync.error.invalidDataError',
|
||||
[
|
||||
Zotero.Libraries.get(e.libraryID).name,
|
||||
Zotero.clientName
|
||||
]
|
||||
)
|
||||
+ "\n\n"
|
||||
+ Zotero.getString('sync.error.invalidDataError.otherData');
|
||||
e.errorType = 'warning';
|
||||
e.dialogButtonText = Zotero.getString('general.checkForUpdates');
|
||||
e.dialogButtonCallback = () => {
|
||||
Zotero.openCheckForUpdatesWindow();
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -313,16 +313,6 @@ Zotero.Translate.Sandbox = {
|
|||
* @inner
|
||||
*/
|
||||
var safeTranslator = {};
|
||||
safeTranslator.__exposedProps__ = {
|
||||
"setSearch":"r",
|
||||
"setDocument":"r",
|
||||
"setHandler":"r",
|
||||
"setString":"r",
|
||||
"setTranslator":"r",
|
||||
"getTranslators":"r",
|
||||
"translate":"r",
|
||||
"getTranslatorObject":"r"
|
||||
};
|
||||
safeTranslator.setSearch = function(arg) {
|
||||
if(!Zotero.isBookmarklet) arg = JSON.parse(JSON.stringify(arg));
|
||||
return translation.setSearch(arg);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue