Merge branch 'electron'
This commit is contained in:
commit
c2ca70055c
46 changed files with 1093 additions and 1116 deletions
|
@ -108,9 +108,9 @@
|
|||
|
||||
|
||||
function _setStartupError() {
|
||||
Zotero.startupError = Zotero.localeJoin([
|
||||
Zotero.startupError = [
|
||||
Zotero.getString('upgrade.dbUpdateRequired'), Zotero.getString('general.restartFirefox')
|
||||
]);
|
||||
].join(' ');
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ Zotero.Annotate = new function() {
|
|||
}
|
||||
return colorArray;
|
||||
} catch(e) {
|
||||
throw "Annotate: parseColor passed invalid color";
|
||||
throw new Error("Annotate: parseColor passed invalid color");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,9 +173,9 @@ Zotero.Annotate = new function() {
|
|||
} else if(offset < node.childNodes.length) {
|
||||
node = node.childNodes[offset];
|
||||
} else {
|
||||
throw "Annotate: dereferenceNodeOffset called with invalid offset "+offset;
|
||||
throw new Error("Annotate: dereferenceNodeOffset called with invalid offset "+offset);
|
||||
}
|
||||
if(!node) throw "Annotate: dereferenceNodeOffset resolved to invalid node";
|
||||
if(!node) throw new Error("Annotate: dereferenceNodeOffset resolved to invalid node");
|
||||
}
|
||||
|
||||
return node;
|
||||
|
@ -308,7 +308,7 @@ Zotero.Annotate.Path = function(document, nsResolver, parent, textNode, offset)
|
|||
* @param {Integer} offset The text offset, if the DOM node is a text node
|
||||
*/
|
||||
Zotero.Annotate.Path.prototype.fromNode = function(node, offset) {
|
||||
if(!node) throw "Annotate: Path() called with invalid node";
|
||||
if(!node) throw new Error("Annotate: Path() called with invalid node");
|
||||
Zotero.debug("Annotate: Path() called with node "+node.tagName+" offset "+offset);
|
||||
|
||||
this.parent = "";
|
||||
|
@ -345,7 +345,7 @@ Zotero.Annotate.Path.prototype.fromNode = function(node, offset) {
|
|||
this.offset = 0;
|
||||
}
|
||||
}
|
||||
if(!node) throw "Annotate: Path() handled Zotero <span> inappropriately";
|
||||
if(!node) throw new Error("Annotate: Path() handled Zotero <span> inappropriately");
|
||||
|
||||
lastWasTextNode = lastWasTextNode || node.nodeType == TEXT_TYPE;
|
||||
|
||||
|
@ -387,7 +387,7 @@ Zotero.Annotate.Path.prototype.fromNode = function(node, offset) {
|
|||
|
||||
node = node.parentNode;
|
||||
}
|
||||
if(!node) throw "Annotate: Path() resolved text offset inappropriately";
|
||||
if(!node) throw new Error("Annotate: Path() resolved text offset inappropriately");
|
||||
|
||||
while(node && node !== this._document) {
|
||||
var number = 1;
|
||||
|
@ -928,7 +928,7 @@ Zotero.Annotation.prototype.save = function() {
|
|||
* Displays annotation
|
||||
*/
|
||||
Zotero.Annotation.prototype.display = function() {
|
||||
if(!this.node) throw "Annotation not initialized!";
|
||||
if(!this.node) throw new Error("Annotation not initialized!");
|
||||
|
||||
var x = 0, y = 0;
|
||||
|
||||
|
@ -946,7 +946,7 @@ Zotero.Annotation.prototype.display = function() {
|
|||
* Displays annotation given absolute coordinates for its position
|
||||
*/
|
||||
Zotero.Annotation.prototype.displayWithAbsoluteCoordinates = function(absX, absY, select) {
|
||||
if(!this.node) throw "Annotation not initialized!";
|
||||
if(!this.node) throw new Error("Annotation not initialized!");
|
||||
|
||||
var startScroll = this.window.scrollMaxX;
|
||||
|
||||
|
|
|
@ -431,11 +431,11 @@ Zotero.Attachments = new function(){
|
|||
fileBaseName = this.getFileBaseNameFromItem(parentItem);
|
||||
}
|
||||
if (fileBaseName) {
|
||||
let ext = _getExtensionFromURL(url, contentType);
|
||||
let ext = this._getExtensionFromURL(url, contentType);
|
||||
var filename = fileBaseName + (ext != '' ? '.' + ext : '');
|
||||
}
|
||||
else {
|
||||
var filename = _getFileNameFromURL(url, contentType);
|
||||
var filename = this._getFileNameFromURL(url, contentType);
|
||||
}
|
||||
|
||||
// Create a temporary directory to save to within the storage directory.
|
||||
|
@ -644,7 +644,7 @@ Zotero.Attachments = new function(){
|
|||
// Override MIME type to application/pdf if extension is .pdf --
|
||||
// workaround for sites that respond to the HEAD request with an
|
||||
// invalid MIME type (https://www.zotero.org/trac/ticket/460)
|
||||
var ext = _getExtensionFromURL(url);
|
||||
var ext = this._getExtensionFromURL(url);
|
||||
if (ext == 'pdf') {
|
||||
contentType = 'application/pdf';
|
||||
}
|
||||
|
@ -731,7 +731,7 @@ Zotero.Attachments = new function(){
|
|||
|
||||
var tmpDir = (yield this.createTemporaryStorageDirectory()).path;
|
||||
try {
|
||||
var fileName = Zotero.File.truncateFileName(_getFileNameFromURL(url, contentType), 100);
|
||||
var fileName = Zotero.File.truncateFileName(this._getFileNameFromURL(url, contentType), 100);
|
||||
var tmpFile = OS.Path.join(tmpDir, fileName);
|
||||
|
||||
// If we're using the title from the document, make some adjustments
|
||||
|
@ -742,7 +742,7 @@ Zotero.Attachments = new function(){
|
|||
title = title.replace(/(.+ \([^,]+, [0-9]+x[0-9]+[^\)]+\)) - .+/, "$1" );
|
||||
}
|
||||
// If not native type, strip mime type data in parens
|
||||
else if (!Zotero.MIME.hasNativeHandler(contentType, _getExtensionFromURL(url))) {
|
||||
else if (!Zotero.MIME.hasNativeHandler(contentType, this._getExtensionFromURL(url))) {
|
||||
title = title.replace(/(.+) \([a-z]+\/[^\)]+\)/, "$1" );
|
||||
}
|
||||
}
|
||||
|
@ -1816,7 +1816,7 @@ Zotero.Attachments = new function(){
|
|||
});
|
||||
|
||||
|
||||
function _getFileNameFromURL(url, contentType){
|
||||
this._getFileNameFromURL = function(url, contentType) {
|
||||
var nsIURL = Components.classes["@mozilla.org/network/standard-url;1"]
|
||||
.createInstance(Components.interfaces.nsIURL);
|
||||
nsIURL.spec = url;
|
||||
|
@ -1867,7 +1867,7 @@ Zotero.Attachments = new function(){
|
|||
}
|
||||
|
||||
|
||||
function _getExtensionFromURL(url, contentType) {
|
||||
this._getExtensionFromURL = function(url, contentType) {
|
||||
var nsIURL = Components.classes["@mozilla.org/network/standard-url;1"]
|
||||
.createInstance(Components.interfaces.nsIURL);
|
||||
nsIURL.spec = url;
|
||||
|
|
|
@ -113,7 +113,7 @@ Zotero.Cite = {
|
|||
output.push("}");
|
||||
return output.join("");
|
||||
} else {
|
||||
throw "Unimplemented bibliography format "+format;
|
||||
throw new Error("Unimplemented bibliography format "+format);
|
||||
}
|
||||
} else {
|
||||
if(format == "html") {
|
||||
|
@ -176,9 +176,9 @@ Zotero.Cite = {
|
|||
var secondFieldAlign = bib[0]["second-field-align"];
|
||||
|
||||
// Validate input
|
||||
if(maxOffset == NaN) throw "Invalid maxoffset";
|
||||
if(entrySpacing == NaN) throw "Invalid entryspacing";
|
||||
if(lineSpacing == NaN) throw "Invalid linespacing";
|
||||
if(maxOffset == NaN) throw new Error("Invalid maxoffset");
|
||||
if(entrySpacing == NaN) throw new Error("Invalid entryspacing");
|
||||
if(lineSpacing == NaN) throw new Error("Invalid linespacing");
|
||||
|
||||
var str;
|
||||
var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
|
||||
|
@ -283,7 +283,7 @@ Zotero.Cite = {
|
|||
|
||||
return bib[0].bibstart+preamble+bib[1].join("\\\r\n")+"\\\r\n"+bib[0].bibend;
|
||||
} else {
|
||||
throw "Unimplemented bibliography format "+format;
|
||||
throw new Error("Unimplemented bibliography format "+format);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -850,47 +850,33 @@ Zotero.Server.Connector.SaveSnapshot.prototype = {
|
|||
return item;
|
||||
}
|
||||
|
||||
return new Zotero.Promise((resolve, reject) => {
|
||||
Zotero.Server.Connector.Data[data.url] = "<html>" + data.html + "</html>";
|
||||
Zotero.HTTP.loadDocuments(
|
||||
["zotero://connector/" + encodeURIComponent(data.url)],
|
||||
async function (doc) {
|
||||
delete Zotero.Server.Connector.Data[data.url];
|
||||
|
||||
try {
|
||||
// Create new webpage item
|
||||
let item = new Zotero.Item("webpage");
|
||||
item.libraryID = libraryID;
|
||||
item.setField("title", doc.title);
|
||||
item.setField("url", data.url);
|
||||
item.setField("accessDate", "CURRENT_TIMESTAMP");
|
||||
if (collection) {
|
||||
item.setCollections([collection.id]);
|
||||
}
|
||||
var itemID = await item.saveTx();
|
||||
|
||||
// Save snapshot
|
||||
if (library.filesEditable && !data.skipSnapshot) {
|
||||
await Zotero.Attachments.importFromDocument({
|
||||
document: doc,
|
||||
parentItemID: itemID
|
||||
});
|
||||
}
|
||||
|
||||
resolve(item);
|
||||
}
|
||||
catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
},
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
cookieSandbox
|
||||
);
|
||||
});
|
||||
var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
|
||||
.createInstance(Components.interfaces.nsIDOMParser);
|
||||
var doc = parser.parseFromString(`<html>${data.html}</html>`, 'text/html');
|
||||
doc = Zotero.HTTP.wrapDocument(doc, data.url);
|
||||
|
||||
// Create new webpage item
|
||||
let item = new Zotero.Item("webpage");
|
||||
item.libraryID = libraryID;
|
||||
item.setField("title", doc.title);
|
||||
item.setField("url", data.url);
|
||||
item.setField("accessDate", "CURRENT_TIMESTAMP");
|
||||
if (collection) {
|
||||
item.setCollections([collection.id]);
|
||||
}
|
||||
var itemID = await item.saveTx();
|
||||
|
||||
// Save snapshot
|
||||
if (library.filesEditable && !data.skipSnapshot) {
|
||||
await Zotero.Attachments.importFromDocument({
|
||||
document: doc,
|
||||
parentItemID: itemID
|
||||
});
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle item selection
|
||||
|
|
|
@ -215,7 +215,7 @@ Zotero.FeedItem.prototype.translate = Zotero.Promise.coroutine(function* (librar
|
|||
}
|
||||
|
||||
let deferred = Zotero.Promise.defer();
|
||||
let error = function(e) { Zotero.debug(e, 1); deferred.reject(e); };
|
||||
let error = function(e) { };
|
||||
let translate = new Zotero.Translate.Web();
|
||||
var win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let progressWindow = win.ZoteroPane.progressWindow;
|
||||
|
@ -234,13 +234,12 @@ Zotero.FeedItem.prototype.translate = Zotero.Promise.coroutine(function* (librar
|
|||
}
|
||||
|
||||
// Load document
|
||||
let hiddenBrowser = Zotero.HTTP.loadDocuments(
|
||||
this.getField('url'),
|
||||
doc => deferred.resolve(doc),
|
||||
() => {},
|
||||
error,
|
||||
true
|
||||
);
|
||||
try {
|
||||
yield Zotero.HTTP.processDocuments(this.getField('url'), doc => deferred.resolve(doc));
|
||||
} catch (e) {
|
||||
Zotero.debug(e, 1);
|
||||
deferred.reject(e);
|
||||
}
|
||||
let doc = yield deferred.promise;
|
||||
|
||||
// Set translate document
|
||||
|
@ -266,7 +265,6 @@ Zotero.FeedItem.prototype.translate = Zotero.Promise.coroutine(function* (librar
|
|||
if (libraryID) {
|
||||
let result = yield translate.translate({libraryID, collections: collectionID ? [collectionID] : false})
|
||||
.then(items => items ? items[0] : false);
|
||||
Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
|
||||
if (!result) {
|
||||
let item = yield this.clone(libraryID, collectionID, doc);
|
||||
progressWindow.Translation.itemDoneHandler()(null, null, item);
|
||||
|
@ -285,7 +283,6 @@ Zotero.FeedItem.prototype.translate = Zotero.Promise.coroutine(function* (librar
|
|||
translate.translate({libraryID: false, saveAttachments: false});
|
||||
|
||||
let itemData = yield deferred.promise;
|
||||
Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
|
||||
|
||||
// clean itemData
|
||||
const deleteFields = ['attachments', 'notes', 'id', 'itemID', 'path', 'seeAlso', 'version', 'dateAdded', 'dateModified'];
|
||||
|
|
|
@ -1001,7 +1001,7 @@ Zotero.Items = function() {
|
|||
});
|
||||
}
|
||||
// When no longer idle, cancel timer
|
||||
else if (topic == 'back') {
|
||||
else if (topic === 'active') {
|
||||
if (this._emptyTrashTimeoutID) {
|
||||
clearTimeout(this._emptyTrashTimeoutID);
|
||||
this._emptyTrashTimeoutID = null;
|
||||
|
|
|
@ -1228,5 +1228,27 @@ Zotero.DataDirectory = {
|
|||
ext = ext ? '.' + ext : '';
|
||||
|
||||
return OS.Path.join(this.dir, name + ext);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} name - the name of the subdirectory
|
||||
* @param {Boolean} createIfMissing - ensure that the directory exists
|
||||
* @return {String} the path to the subdirectory
|
||||
*/
|
||||
getSubdirectory: function (name, createIfMissing = false) {
|
||||
let dir = OS.Path.join(this.dir, name);
|
||||
if (createIfMissing) {
|
||||
Zotero.File.createDirectoryIfMissing(dir);
|
||||
}
|
||||
return dir;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} name - the name of the subdirectory
|
||||
* @return {Promise<Boolean>} true if the subdirectory was deleted,
|
||||
* or false if it did not exist
|
||||
*/
|
||||
removeSubdirectory: function (name) {
|
||||
return OS.File.removeDir(OS.Path.join(this.dir, name), {ignoreAbsent: true});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -43,50 +43,45 @@ Zotero.Date = new function(){
|
|||
var _monthsWithEnglish;
|
||||
|
||||
this.init = function () {
|
||||
if (!Zotero.isFx || Zotero.isBookmarklet) {
|
||||
if (!(Zotero.isFx || Zotero.isElectron) || Zotero.isBookmarklet) {
|
||||
throw new Error("Unimplemented");
|
||||
}
|
||||
|
||||
return Zotero.HTTP.request(
|
||||
'GET', 'resource://zotero/schema/dateFormats.json', { responseType: 'json' }
|
||||
).then(function(xmlhttp) {
|
||||
var json = xmlhttp.response;
|
||||
|
||||
var locale = Zotero.locale;
|
||||
var english = locale.startsWith('en');
|
||||
// If no exact match, try first two characters ('de')
|
||||
if (!json[locale]) {
|
||||
locale = locale.substr(0, 2);
|
||||
var json = JSON.parse(Zotero.File.getResource('resource://zotero/schema/dateFormats.json'));
|
||||
var locale = Zotero.locale;
|
||||
var english = locale.startsWith('en');
|
||||
// If no exact match, try first two characters ('de')
|
||||
if (!json[locale]) {
|
||||
locale = locale.substr(0, 2);
|
||||
}
|
||||
// Try first two characters repeated ('de-DE')
|
||||
if (!json[locale]) {
|
||||
locale = locale + "-" + locale.toUpperCase();
|
||||
}
|
||||
// Look for another locale with same first two characters
|
||||
if (!json[locale]) {
|
||||
let sameLang = Object.keys(json).filter(l => l.startsWith(locale.substr(0, 2)));
|
||||
if (sameLang.length) {
|
||||
locale = sameLang[0];
|
||||
}
|
||||
// Try first two characters repeated ('de-DE')
|
||||
if (!json[locale]) {
|
||||
locale = locale + "-" + locale.toUpperCase();
|
||||
}
|
||||
// Look for another locale with same first two characters
|
||||
if (!json[locale]) {
|
||||
let sameLang = Object.keys(json).filter(l => l.startsWith(locale.substr(0, 2)));
|
||||
if (sameLang.length) {
|
||||
locale = sameLang[0];
|
||||
}
|
||||
}
|
||||
// If all else fails, use English
|
||||
if (!json[locale]) {
|
||||
locale = 'en-US';
|
||||
english = true;
|
||||
}
|
||||
_months = json[locale];
|
||||
}
|
||||
// If all else fails, use English
|
||||
if (!json[locale]) {
|
||||
locale = 'en-US';
|
||||
english = true;
|
||||
}
|
||||
_months = json[locale];
|
||||
|
||||
// Add English versions if not already added
|
||||
if (english) {
|
||||
_monthsWithEnglish = _months;
|
||||
// Add English versions if not already added
|
||||
if (english) {
|
||||
_monthsWithEnglish = _months;
|
||||
}
|
||||
else {
|
||||
_monthsWithEnglish = {};
|
||||
for (let key in _months) {
|
||||
_monthsWithEnglish[key] = _months[key].concat(json['en-US'][key]);
|
||||
}
|
||||
else {
|
||||
_monthsWithEnglish = {};
|
||||
for (let key in _months) {
|
||||
_monthsWithEnglish[key] = _months[key].concat(json['en-US'][key]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -126,21 +126,6 @@ Zotero.DBConnection.prototype.test = function () {
|
|||
return this._getConnectionAsync().then(() => {});
|
||||
}
|
||||
|
||||
Zotero.DBConnection.prototype.getAsyncStatement = Zotero.Promise.coroutine(function* (sql) {
|
||||
var conn = yield this._getConnectionAsync();
|
||||
conn = conn._connection;
|
||||
|
||||
try {
|
||||
this._debug(sql, 4);
|
||||
return conn.createAsyncStatement(sql);
|
||||
}
|
||||
catch (e) {
|
||||
var dberr = (conn.lastErrorString != 'not an error')
|
||||
? ' [ERROR: ' + conn.lastErrorString + ']' : '';
|
||||
throw new Error(e + ' [QUERY: ' + sql + ']' + dberr);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Zotero.DBConnection.prototype.parseQueryAndParams = function (sql, params) {
|
||||
// If single scalar value, wrap in an array
|
||||
|
@ -267,44 +252,6 @@ Zotero.DBConnection.prototype.parseQueryAndParams = function (sql, params) {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* Execute an asynchronous statement with previously bound parameters
|
||||
*
|
||||
* Warning: This will freeze if used with a write statement within executeTransaction()!
|
||||
*
|
||||
* @param {mozIStorageAsyncStatement} statement - Statement to run
|
||||
* @param {Function} [progressHandler] - Function to pass each available row to for SELECT queries
|
||||
* @return {Promise} - Resolved on completion, rejected with a reason on error
|
||||
*/
|
||||
Zotero.DBConnection.prototype.executeAsyncStatement = Zotero.Promise.method(function (statement, progressHandler) {
|
||||
var resolve;
|
||||
var reject;
|
||||
statement.executeAsync({
|
||||
handleResult: function (resultSet) {
|
||||
if (progressHandler) {
|
||||
progressHandler(resultSet.getNextRow());
|
||||
}
|
||||
},
|
||||
|
||||
handleError: function (e) {
|
||||
reject(e);
|
||||
},
|
||||
|
||||
handleCompletion: function (reason) {
|
||||
if (reason != Components.interfaces.mozIStorageStatementCallback.REASON_FINISHED) {
|
||||
reject(reason);
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
return new Zotero.Promise(function () {
|
||||
resolve = arguments[0];
|
||||
reject = arguments[1];
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
Zotero.DBConnection.prototype.addCallback = function (type, cb) {
|
||||
switch (type) {
|
||||
case 'begin':
|
||||
|
@ -924,8 +871,7 @@ Zotero.DBConnection.prototype.checkException = function (e) {
|
|||
|
||||
this._dbIsCorrupt = true;
|
||||
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
var ps = Services.prompt;
|
||||
|
||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
||||
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING);
|
||||
|
@ -939,8 +885,7 @@ Zotero.DBConnection.prototype.checkException = function (e) {
|
|||
null, null, {});
|
||||
|
||||
if (index == 0) {
|
||||
var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
|
||||
.getService(Components.interfaces.nsIAppStartup);
|
||||
var appStartup = Services.startup;
|
||||
appStartup.quit(Components.interfaces.nsIAppStartup.eRestart);
|
||||
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
|
||||
}
|
||||
|
@ -975,8 +920,7 @@ Zotero.DBConnection.prototype.backupDatabase = Zotero.Promise.coroutine(function
|
|||
return false;
|
||||
}
|
||||
|
||||
var storageService = Components.classes["@mozilla.org/storage/service;1"]
|
||||
.getService(Components.interfaces.mozIStorageService);
|
||||
var storageService = Services.storage;
|
||||
|
||||
if (!suffix) {
|
||||
var numBackups = Zotero.Prefs.get("backup.numBackups");
|
||||
|
@ -1183,8 +1127,7 @@ Zotero.DBConnection.prototype._getConnectionAsync = async function (options) {
|
|||
Zotero.debug(this._dbPath);
|
||||
|
||||
// Get the storage service
|
||||
var store = Components.classes["@mozilla.org/storage/service;1"].
|
||||
getService(Components.interfaces.mozIStorageService);
|
||||
var store = Services.storage;
|
||||
|
||||
var file = this._dbPath;
|
||||
var backupFile = this._dbPath + '.bak';
|
||||
|
|
|
@ -33,6 +33,7 @@ Zotero.File = new function(){
|
|||
|
||||
this.getExtension = getExtension;
|
||||
this.getContentsFromURL = getContentsFromURL;
|
||||
this.getContentsFromURLAsync = getContentsFromURLAsync;
|
||||
this.putContents = putContents;
|
||||
this.getValidFileName = getValidFileName;
|
||||
this.truncateFileName = truncateFileName;
|
||||
|
@ -58,9 +59,7 @@ Zotero.File = new function(){
|
|||
|
||||
this.pathToFileURI = function (path) {
|
||||
var file = new FileUtils.File(path);
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
return ios.newFileURI(file).spec;
|
||||
return Services.io.newFileURI(file).spec;
|
||||
}
|
||||
|
||||
|
||||
|
@ -107,11 +106,11 @@ Zotero.File = new function(){
|
|||
}
|
||||
|
||||
var dir = OS.Path.dirname(file);
|
||||
while (dir && !await OS.File.exists(dir)) {
|
||||
while (dir && dir != '/' && !await OS.File.exists(dir)) {
|
||||
dir = OS.Path.dirname(dir);
|
||||
}
|
||||
|
||||
return dir || false;
|
||||
return (dir && dir != '/') ? dir : false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -131,6 +130,8 @@ Zotero.File = new function(){
|
|||
* Get contents of a binary file
|
||||
*/
|
||||
this.getBinaryContents = function(file) {
|
||||
Zotero.debug("Zotero.File.getBinaryContents() is deprecated -- "
|
||||
+ "use Zotero.File.getBinaryContentsAsync() when possible", 2);
|
||||
var iStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileInputStream);
|
||||
iStream.init(file, 0x01, 0o664, 0);
|
||||
|
@ -339,12 +340,33 @@ Zotero.File = new function(){
|
|||
xmlhttp.send(null);
|
||||
return xmlhttp.responseText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the contents of resource. Use this for loading
|
||||
* resource/chrome URLs.
|
||||
*
|
||||
* @param {String} url - the resource url
|
||||
* @return {String} the resource contents as a string
|
||||
*/
|
||||
this.getResource = function (url) {
|
||||
return getContentsFromURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a promise for the contents of resource.
|
||||
*
|
||||
* @param {String} url - the resource url
|
||||
* @return {Promise<String>} the resource contents as a string
|
||||
*/
|
||||
this.getResourceAsync = function (url) {
|
||||
return getContentsFromURLAsync(url);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a promise for the contents of a URL as a string
|
||||
*/
|
||||
this.getContentsFromURLAsync = function (url, options={}) {
|
||||
function getContentsFromURLAsync (url, options={}) {
|
||||
return Zotero.HTTP.request("GET", url, Object.assign(options, { responseType: "text" }))
|
||||
.then(function (xmlhttp) {
|
||||
return xmlhttp.response;
|
||||
|
@ -952,6 +974,7 @@ Zotero.File = new function(){
|
|||
|
||||
|
||||
this.createDirectoryIfMissing = function (dir) {
|
||||
dir = this.pathToFile(dir);
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
if (dir.exists() && !dir.isDirectory()) {
|
||||
dir.remove(null);
|
||||
|
|
|
@ -785,8 +785,7 @@ Zotero.HTTP = new function() {
|
|||
* @type Boolean
|
||||
*/
|
||||
this.browserIsOffline = function() {
|
||||
return Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService).offline;
|
||||
return Services.io.offline;
|
||||
}
|
||||
|
||||
|
||||
|
|
252
chrome/content/zotero/xpcom/intl.js
Normal file
252
chrome/content/zotero/xpcom/intl.js
Normal file
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2018 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
Zotero.Intl = new function () {
|
||||
let bundle;
|
||||
let collation;
|
||||
let intlProps;
|
||||
let pluralFormGet;
|
||||
let pluralFormNumForms;
|
||||
|
||||
// Get settings from language pack (extracted by zotero-build/locale/merge_mozilla_files)
|
||||
this.init = function () {
|
||||
Components.utils.import("resource://gre/modules/PluralForm.jsm");
|
||||
|
||||
bundle = Services.strings.createBundle('chrome://zotero/locale/zotero.properties');
|
||||
intlProps = Services.strings.createBundle('chrome://zotero/locale/mozilla/intl.properties');
|
||||
|
||||
[pluralFormGet, pluralFormNumForms] = PluralForm.makeGetter(parseInt(getIntlProp('pluralRule', 1)));
|
||||
setOrClearIntlPref('intl.accept_languages', 'string');
|
||||
|
||||
Zotero.locale = getIntlProp('general.useragent.locale', 'en-US');
|
||||
|
||||
// Also load the brand as appName
|
||||
Zotero.appName = Services.strings
|
||||
.createBundle('chrome://branding/locale/brand.properties')
|
||||
.GetStringFromName('brandShortName');
|
||||
|
||||
// Set the locale direction to Zotero.dir
|
||||
Zotero.dir = Zotero.Locale.defaultScriptDirection(Zotero.locale);
|
||||
Zotero.rtl = (Zotero.dir === 'rtl');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {String} name
|
||||
* @param {String[]} [params=[]] - Strings to substitute for placeholders
|
||||
* @param {Number} [num] - Number (also appearing in `params`) to use when determining which plural
|
||||
* form of the string to use; localized strings should include all forms in the order specified
|
||||
* in https://developer.mozilla.org/en-US/docs/Mozilla/Localization/Localization_and_Plurals,
|
||||
* separated by semicolons
|
||||
*/
|
||||
this.getString = function (name, params, num) {
|
||||
try {
|
||||
var l10n;
|
||||
if (params != undefined) {
|
||||
if (typeof params != 'object'){
|
||||
params = [params];
|
||||
}
|
||||
l10n = bundle.formatStringFromName(name, params, params.length);
|
||||
}
|
||||
else {
|
||||
l10n = bundle.GetStringFromName(name);
|
||||
}
|
||||
if (num !== undefined) {
|
||||
let availableForms = l10n.split(/;/);
|
||||
// If not enough available forms, use last one -- PluralForm.get() uses first by
|
||||
// default, but it's more likely that a localizer will translate the two English
|
||||
// strings with some plural form as the second one, so we might as well use that
|
||||
if (availableForms.length < pluralFormNumForms()) {
|
||||
l10n = availableForms[availableForms.length - 1];
|
||||
}
|
||||
else {
|
||||
l10n = pluralFormGet(num, l10n);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e){
|
||||
if (e.name == 'NS_ERROR_ILLEGAL_VALUE') {
|
||||
Zotero.debug(params, 1);
|
||||
}
|
||||
else if (e.name != 'NS_ERROR_FAILURE') {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
throw new Error('Localized string not available for ' + name);
|
||||
}
|
||||
return l10n;
|
||||
};
|
||||
|
||||
/*
|
||||
* Compares two strings based on the current collator.
|
||||
* @param {String} string1
|
||||
* @param {String} string2
|
||||
* @return {Number} a number indicating how string1 and string2 compare to
|
||||
* each other according to the sort order of this Collator object: a
|
||||
* negative value if string1 comes before string2; a positive value if
|
||||
* string1 comes after string2; 0 if they are considered equal.
|
||||
*/
|
||||
this.compare = function (...args) {
|
||||
return this.collation.compareString(1, ...args);
|
||||
};
|
||||
|
||||
Object.defineProperty(this, 'collation', {
|
||||
get() {
|
||||
if (collation == null) {
|
||||
collation = getLocaleCollation();
|
||||
}
|
||||
return collation;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function getIntlProp(name, fallback = null) {
|
||||
try {
|
||||
return intlProps.GetStringFromName(name);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(`Couldn't load ${name} from intl.properties`);
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
function setOrClearIntlPref(name, type) {
|
||||
var val = getIntlProp(name);
|
||||
if (val !== null) {
|
||||
if (type == 'boolean') {
|
||||
val = val == 'true';
|
||||
}
|
||||
Zotero.Prefs.set(name, val, true);
|
||||
}
|
||||
else {
|
||||
Zotero.Prefs.clear(name, true);
|
||||
}
|
||||
}
|
||||
|
||||
function getLocaleCollation() {
|
||||
try {
|
||||
// DEBUG: Is this necessary, or will Intl.Collator just default to the same locales we're
|
||||
// passing manually?
|
||||
|
||||
let locales;
|
||||
// Fx55+
|
||||
if (Services.locale.getAppLocalesAsBCP47) {
|
||||
locales = Services.locale.getAppLocalesAsBCP47();
|
||||
}
|
||||
else {
|
||||
let locale;
|
||||
// Fx54
|
||||
if (Services.locale.getAppLocale) {
|
||||
locale = Services.locale.getAppLocale();
|
||||
}
|
||||
// Fx <=53
|
||||
else {
|
||||
locale = Services.locale.getApplicationLocale();
|
||||
locale = locale.getCategory('NSILOCALE_COLLATE');
|
||||
}
|
||||
|
||||
// Extract a valid language tag
|
||||
try {
|
||||
locale = locale.match(/^[a-z]{2}(\-[A-Z]{2})?/)[0];
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Error parsing locale ${locale}`);
|
||||
}
|
||||
locales = [locale];
|
||||
}
|
||||
|
||||
var collator = new Intl.Collator(locales, {
|
||||
numeric: true,
|
||||
sensitivity: 'base'
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
|
||||
// Fall back to en-US sorting
|
||||
try {
|
||||
Zotero.logError("Falling back to en-US sorting");
|
||||
collator = new Intl.Collator(['en-US'], {
|
||||
numeric: true,
|
||||
sensitivity: 'base'
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
|
||||
// If there's still an error, just skip sorting
|
||||
collator = {
|
||||
compare: function (a, b) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Grab all ASCII punctuation and space at the begining of string
|
||||
var initPunctuationRE = /^[\x20-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]+/;
|
||||
// Punctuation that should be ignored when sorting
|
||||
var ignoreInitRE = /["'[{(]+$/;
|
||||
|
||||
// Until old code is updated, pretend we're returning an nsICollation
|
||||
return this.collation = {
|
||||
compareString: function (_, a, b) {
|
||||
if (!a && !b) return 0;
|
||||
if (!a || !b) return b ? -1 : 1;
|
||||
|
||||
// Compare initial punctuation
|
||||
var aInitP = initPunctuationRE.exec(a) || '';
|
||||
var bInitP = initPunctuationRE.exec(b) || '';
|
||||
|
||||
var aWordStart = 0, bWordStart = 0;
|
||||
if (aInitP) {
|
||||
aWordStart = aInitP[0].length;
|
||||
aInitP = aInitP[0].replace(ignoreInitRE, '');
|
||||
}
|
||||
if (bInitP) {
|
||||
bWordStart = bInitP.length;
|
||||
bInitP = bInitP[0].replace(ignoreInitRE, '');
|
||||
}
|
||||
|
||||
// If initial punctuation is equivalent, use collator comparison
|
||||
// that ignores all punctuation
|
||||
//
|
||||
// Update: Intl.Collator's ignorePunctuation also ignores whitespace, so we're
|
||||
// no longer using it, meaning we could take out most of the code to handle
|
||||
// initial punctuation separately, unless we think we'll at some point switch to
|
||||
// a collation function that ignores punctuation but not whitespace.
|
||||
if (aInitP == bInitP || !aInitP && !bInitP) return collator.compare(a, b);
|
||||
|
||||
// Otherwise consider "attached" words as well, e.g. the order should be
|
||||
// "__ n", "__z", "_a"
|
||||
// We don't actually care what the attached word is, just whether it's
|
||||
// there, since at this point we're guaranteed to have non-equivalent
|
||||
// initial punctuation
|
||||
if (aWordStart < a.length) aInitP += 'a';
|
||||
if (bWordStart < b.length) bInitP += 'a';
|
||||
|
||||
return aInitP.localeCompare(bInitP);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
|
@ -40,5 +40,16 @@ Zotero.Locale = {
|
|||
'vi-VN': 'Tiếng Việt',
|
||||
'zh-CN': '中文 (简体)',
|
||||
'zh-TW': '正體中文 (繁體)'
|
||||
})
|
||||
}),
|
||||
|
||||
defaultScriptDirection(locale) {
|
||||
switch (locale.split('-')[0]) {
|
||||
case 'ar':
|
||||
case 'fa':
|
||||
case 'he':
|
||||
return 'rtl';
|
||||
default:
|
||||
return 'ltr';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,16 +29,12 @@ Zotero.LocateManager = new function() {
|
|||
|
||||
var _jsonFile;
|
||||
var _locateEngines;
|
||||
var _ios;
|
||||
var _timer;
|
||||
|
||||
/**
|
||||
* Read locateEngines JSON file to initialize locate manager
|
||||
*/
|
||||
this.init = async function() {
|
||||
_ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
|
||||
_jsonFile = _getLocateFile();
|
||||
|
||||
try {
|
||||
|
@ -61,7 +57,7 @@ Zotero.LocateManager = new function() {
|
|||
*/
|
||||
this.addEngine = function(engineURL, dataType, iconURL, confirm) {
|
||||
if(dataType !== Components.interfaces.nsISearchEngine.TYPE_OPENSEARCH) {
|
||||
throw "LocateManager supports only OpenSearch engines";
|
||||
throw new Error("LocateManager supports only OpenSearch engines");
|
||||
}
|
||||
|
||||
Zotero.HTTP.doGet(engineURL, function(xmlhttp) {
|
||||
|
@ -121,7 +117,7 @@ Zotero.LocateManager = new function() {
|
|||
*/
|
||||
this.removeEngine = function(engine) {
|
||||
var oldIndex = _locateEngines.indexOf(engine);
|
||||
if(oldIndex === -1) throw "Engine is not currently listed";
|
||||
if(oldIndex === -1) throw new Error("Engine is not currently listed");
|
||||
_locateEngines.splice(oldIndex, 1);
|
||||
engine._removeIcon();
|
||||
_serializeLocateEngines();
|
||||
|
@ -271,7 +267,7 @@ Zotero.LocateManager = new function() {
|
|||
* Theoretically implements nsISearchSubmission
|
||||
*/
|
||||
var LocateSubmission = function(uri, postData) {
|
||||
this.uri = _ios.newURI(uri, null, null);
|
||||
this.uri = Services.io.newURI(uri, null, null);
|
||||
this.postData = postData;
|
||||
}
|
||||
|
||||
|
@ -316,7 +312,7 @@ Zotero.LocateManager = new function() {
|
|||
xns = {"s":doc.documentElement.namespaceURI,
|
||||
"xmlns":"http://www.w3.org/2000/xmlns"};
|
||||
if(OPENSEARCH_NAMESPACES.indexOf(ns) === -1) {
|
||||
throw "Invalid namespace";
|
||||
throw new Error("Invalid namespace");
|
||||
}
|
||||
|
||||
// get simple attributes
|
||||
|
@ -331,7 +327,7 @@ Zotero.LocateManager = new function() {
|
|||
i = 0;
|
||||
while(urlTags[i].hasAttribute("rel") && urlTags[i].getAttribute("rel") != "results") {
|
||||
i++;
|
||||
if(i == urlTags.length) throw "No Url tag found";
|
||||
if(i == urlTags.length) throw new Error("No Url tag found");
|
||||
}
|
||||
|
||||
// TODO: better error handling
|
||||
|
@ -383,7 +379,7 @@ Zotero.LocateManager = new function() {
|
|||
|
||||
"getItemSubmission":function(item, responseType) {
|
||||
if(responseType && responseType !== "text/html") {
|
||||
throw "LocateManager supports only responseType text/html";
|
||||
throw new Error("LocateManager supports only responseType text/html");
|
||||
}
|
||||
|
||||
if (item.toJSON) {
|
||||
|
@ -447,7 +443,7 @@ Zotero.LocateManager = new function() {
|
|||
|
||||
"_removeIcon":function() {
|
||||
if(!this.icon) return;
|
||||
var uri = _ios.newURI(this.icon, null, null);
|
||||
var uri = Services.io.newURI(this.icon, null, null);
|
||||
var file = uri.QueryInterface(Components.interfaces.nsIFileURL).file;
|
||||
if(file.exists()) file.remove(null);
|
||||
},
|
||||
|
@ -492,4 +488,4 @@ Zotero.LocateManager = new function() {
|
|||
this.icon = OS.Path.toFileURI(iconFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ Zotero.OpenURL = new function() {
|
|||
req.send(null);
|
||||
|
||||
if(!req.responseXML) {
|
||||
throw "Could not access resolver registry";
|
||||
throw new Error("Could not access resolver registry");
|
||||
}
|
||||
|
||||
var resolverArray = new Array();
|
||||
|
|
331
chrome/content/zotero/xpcom/prefs.js
Normal file
331
chrome/content/zotero/xpcom/prefs.js
Normal file
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2018 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
Zotero.Prefs = new function(){
|
||||
// Privileged methods
|
||||
this.init = init;
|
||||
this.get = get;
|
||||
this.set = set;
|
||||
|
||||
this.register = register;
|
||||
this.unregister = unregister;
|
||||
this.observe = observe;
|
||||
|
||||
// Public properties
|
||||
this.prefBranch;
|
||||
|
||||
function init(){
|
||||
this.prefBranch = Services.prefs.getBranch(ZOTERO_CONFIG.PREF_BRANCH);
|
||||
|
||||
// Register observer to handle pref changes
|
||||
this.register();
|
||||
|
||||
// Unregister observer handling pref changes
|
||||
if (Zotero.addShutdownListener) {
|
||||
Zotero.addShutdownListener(this.unregister.bind(this));
|
||||
}
|
||||
|
||||
// Process pref version updates
|
||||
var fromVersion = this.get('prefVersion');
|
||||
if (!fromVersion) {
|
||||
fromVersion = 0;
|
||||
}
|
||||
var toVersion = 2;
|
||||
if (fromVersion < toVersion) {
|
||||
for (var i = fromVersion + 1; i <= toVersion; i++) {
|
||||
switch (i) {
|
||||
case 1:
|
||||
// If a sync username is entered and ZFS is enabled, turn
|
||||
// on-demand downloading off to maintain current behavior
|
||||
if (this.get('sync.server.username')) {
|
||||
if (this.get('sync.storage.enabled')
|
||||
&& this.get('sync.storage.protocol') == 'zotero') {
|
||||
this.set('sync.storage.downloadMode.personal', 'on-sync');
|
||||
}
|
||||
if (this.get('sync.storage.groups.enabled')) {
|
||||
this.set('sync.storage.downloadMode.groups', 'on-sync');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Re-show saveButton guidance panel (and clear old saveIcon pref).
|
||||
// The saveButton guidance panel initially could auto-hide too easily.
|
||||
this.clear('firstRunGuidanceShown.saveIcon');
|
||||
this.clear('firstRunGuidanceShown.saveButton');
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.set('prefVersion', toVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a preference
|
||||
**/
|
||||
function get(pref, global){
|
||||
try {
|
||||
if (global) {
|
||||
var branch = Services.prefs.getBranch("");
|
||||
}
|
||||
else {
|
||||
var branch = this.prefBranch;
|
||||
}
|
||||
|
||||
switch (branch.getPrefType(pref)){
|
||||
case branch.PREF_BOOL:
|
||||
return branch.getBoolPref(pref);
|
||||
case branch.PREF_STRING:
|
||||
return '' + branch.getComplexValue(pref, Components.interfaces.nsISupportsString);
|
||||
case branch.PREF_INT:
|
||||
return branch.getIntPref(pref);
|
||||
}
|
||||
}
|
||||
catch (e){
|
||||
throw new Error("Invalid preference '" + pref + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a preference
|
||||
**/
|
||||
function set(pref, value, global) {
|
||||
try {
|
||||
if (global) {
|
||||
var branch = Services.prefs.getBranch("");
|
||||
}
|
||||
else {
|
||||
var branch = this.prefBranch;
|
||||
}
|
||||
|
||||
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);
|
||||
case branch.PREF_INT:
|
||||
return branch.setIntPref(pref, value);
|
||||
|
||||
// If not an existing pref, create appropriate type automatically
|
||||
case 0:
|
||||
if (typeof value == 'boolean') {
|
||||
Zotero.debug("Creating boolean pref '" + pref + "'");
|
||||
return branch.setBoolPref(pref, value);
|
||||
}
|
||||
if (typeof value == 'string') {
|
||||
Zotero.debug("Creating string pref '" + pref + "'");
|
||||
return branch.setCharPref(pref, value);
|
||||
}
|
||||
if (parseInt(value) == value) {
|
||||
Zotero.debug("Creating integer pref '" + pref + "'");
|
||||
return branch.setIntPref(pref, value);
|
||||
}
|
||||
throw new Error("Invalid preference value '" + value + "' for pref '" + pref + "'");
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
throw new Error("Invalid preference '" + pref + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.clear = function (pref, global) {
|
||||
if (global) {
|
||||
var branch = Services.prefs.getBranch("");
|
||||
}
|
||||
else {
|
||||
var branch = this.prefBranch;
|
||||
}
|
||||
branch.clearUserPref(pref);
|
||||
}
|
||||
|
||||
|
||||
this.resetBranch = function (exclude = []) {
|
||||
var keys = this.prefBranch.getChildList("", {});
|
||||
for (let key of keys) {
|
||||
if (this.prefBranch.prefHasUserValue(key)) {
|
||||
if (exclude.includes(key)) {
|
||||
continue;
|
||||
}
|
||||
Zotero.debug("Clearing " + key);
|
||||
this.prefBranch.clearUserPref(key);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Import settings bundles
|
||||
this.importSettings = function (str, uri) {
|
||||
var ps = Services.prompt;
|
||||
|
||||
if (!uri.match(/https:\/\/([^\.]+\.)?zotero.org\//)) {
|
||||
Zotero.debug("Ignoring settings file not from https://zotero.org");
|
||||
return;
|
||||
}
|
||||
|
||||
str = Zotero.Utilities.trim(str.replace(/<\?xml.*\?>\s*/, ''));
|
||||
Zotero.debug(str);
|
||||
|
||||
var confirm = ps.confirm(
|
||||
null,
|
||||
"",
|
||||
"Apply settings from zotero.org?"
|
||||
);
|
||||
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: parse settings XML
|
||||
}
|
||||
|
||||
// Handlers for some Zotero preferences
|
||||
var _handlers = [
|
||||
[ "automaticScraperUpdates", function(val) {
|
||||
if (val){
|
||||
Zotero.Schema.updateFromRepository(1);
|
||||
}
|
||||
else {
|
||||
Zotero.Schema.stopRepositoryTimer();
|
||||
}
|
||||
}],
|
||||
["fontSize", function (val) {
|
||||
Zotero.setFontSize(
|
||||
Zotero.getActiveZoteroPane().document.getElementById('zotero-pane')
|
||||
);
|
||||
}],
|
||||
[ "layout", function(val) {
|
||||
Zotero.getActiveZoteroPane().updateLayout();
|
||||
}],
|
||||
[ "note.fontSize", function(val) {
|
||||
if (val < 6) {
|
||||
Zotero.Prefs.set('note.fontSize', 11);
|
||||
}
|
||||
}],
|
||||
[ "zoteroDotOrgVersionHeader", function(val) {
|
||||
if (val) {
|
||||
Zotero.VersionHeader.register();
|
||||
}
|
||||
else {
|
||||
Zotero.VersionHeader.unregister();
|
||||
}
|
||||
}],
|
||||
[ "sync.autoSync", function(val) {
|
||||
if (val) {
|
||||
Zotero.Sync.EventListeners.AutoSyncListener.register();
|
||||
Zotero.Sync.EventListeners.IdleListener.register();
|
||||
}
|
||||
else {
|
||||
Zotero.Sync.EventListeners.AutoSyncListener.unregister();
|
||||
Zotero.Sync.EventListeners.IdleListener.unregister();
|
||||
}
|
||||
}],
|
||||
[ "search.quicksearch-mode", function(val) {
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var enumerator = wm.getEnumerator("navigator:browser");
|
||||
while (enumerator.hasMoreElements()) {
|
||||
var win = enumerator.getNext();
|
||||
if (!win.ZoteroPane) continue;
|
||||
Zotero.updateQuickSearchBox(win.ZoteroPane.document);
|
||||
}
|
||||
|
||||
var enumerator = wm.getEnumerator("zotero:item-selector");
|
||||
while (enumerator.hasMoreElements()) {
|
||||
var win = enumerator.getNext();
|
||||
if (!win.Zotero) continue;
|
||||
Zotero.updateQuickSearchBox(win.document);
|
||||
}
|
||||
}]
|
||||
];
|
||||
|
||||
//
|
||||
// Methods to register a preferences observer
|
||||
//
|
||||
function register(){
|
||||
this.prefBranch.addObserver("", this, false);
|
||||
|
||||
// Register pre-set handlers
|
||||
for (var i=0; i<_handlers.length; i++) {
|
||||
this.registerObserver(_handlers[i][0], _handlers[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
function unregister(){
|
||||
if (!this.prefBranch){
|
||||
return;
|
||||
}
|
||||
this.prefBranch.removeObserver("", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {nsIPrefBranch} subject The nsIPrefBranch we're observing (after appropriate QI)
|
||||
* @param {String} topic The string defined by NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
|
||||
* @param {String} data The name of the pref that's been changed (relative to subject)
|
||||
*/
|
||||
function observe(subject, topic, data){
|
||||
if (topic != "nsPref:changed" || !_observers[data] || !_observers[data].length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var obs = _observers[data];
|
||||
for (var i=0; i<obs.length; i++) {
|
||||
try {
|
||||
obs[i](this.get(data));
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug("Error while executing preference observer handler for " + data);
|
||||
Zotero.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _observers = {};
|
||||
this.registerObserver = function(name, handler) {
|
||||
_observers[name] = _observers[name] || [];
|
||||
_observers[name].push(handler);
|
||||
}
|
||||
|
||||
this.unregisterObserver = function(name, handler) {
|
||||
var obs = _observers[name];
|
||||
if (!obs) {
|
||||
Zotero.debug("No preferences observer registered for " + name);
|
||||
return;
|
||||
}
|
||||
|
||||
var i = obs.indexOf(handler);
|
||||
if (i == -1) {
|
||||
Zotero.debug("Handler was not registered for preference " + name);
|
||||
return;
|
||||
}
|
||||
|
||||
obs.splice(i, 1);
|
||||
}
|
||||
}
|
|
@ -387,10 +387,10 @@ Zotero.ProgressWindow = function(options = {}) {
|
|||
this.Translation = {};
|
||||
|
||||
this.Translation.operationInProgress = function() {
|
||||
var desc = Zotero.localeJoin([
|
||||
var desc = [
|
||||
Zotero.getString('general.operationInProgress'),
|
||||
Zotero.getString('general.operationInProgress.waitUntilFinishedAndTryAgain')
|
||||
]);
|
||||
].join(' ');
|
||||
self.Translation._scrapeError(desc);
|
||||
};
|
||||
|
||||
|
|
|
@ -379,7 +379,7 @@ Zotero.Proxy.prototype.validate = function() {
|
|||
Zotero.Proxy.prototype.save = Zotero.Promise.coroutine(function* (transparent) {
|
||||
// ensure this proxy is valid
|
||||
var hasErrors = this.validate();
|
||||
if(hasErrors) throw "Proxy: could not be saved because it is invalid: error "+hasErrors[0];
|
||||
if(hasErrors) throw new Error("Proxy: could not be saved because it is invalid: error "+hasErrors[0]);
|
||||
|
||||
// we never save any changes to non-persisting proxies, so this works
|
||||
var newProxy = !this.proxyID;
|
||||
|
@ -420,7 +420,7 @@ Zotero.Proxy.prototype.save = Zotero.Promise.coroutine(function* (transparent) {
|
|||
Zotero.Proxies.save(this);
|
||||
} else {
|
||||
Zotero.Proxies.refreshHostMap(this);
|
||||
if(!transparent) throw "Proxy: cannot save transparent proxy without transparent param";
|
||||
if(!transparent) throw new Error("Proxy: cannot save transparent proxy without transparent param");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -164,11 +164,9 @@ Zotero.QuickCopy = new function() {
|
|||
return quickCopyPref;
|
||||
}
|
||||
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
var nsIURI;
|
||||
try {
|
||||
nsIURI = ioService.newURI(url, null, null);
|
||||
nsIURI = Services.io.newURI(url, null, null);
|
||||
// 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;
|
||||
|
|
|
@ -253,7 +253,7 @@ We replace the bigger with the smaller.
|
|||
if(typeof val == 'undefined')
|
||||
return undefined;
|
||||
else // @@ add converting of dates and numbers
|
||||
throw "Can't make Term from " + val + " of type " + typeof val;
|
||||
throw new Error("Can't make Term from " + val + " of type " + typeof val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ var $rdf = {
|
|||
return;
|
||||
}
|
||||
}
|
||||
throw "RDFArrayRemove: Array did not contain " + x;
|
||||
throw new Error("RDFArrayRemove: Array did not contain " + x);
|
||||
}
|
||||
},
|
||||
log: {
|
||||
|
|
|
@ -21,7 +21,7 @@ $rdf.N3Parser = function () {
|
|||
|
||||
var pyjslib_Dict = function (listOfPairs) {
|
||||
if(listOfPairs.length > 0)
|
||||
throw "missing.js: oops nnonempty dict not imp";
|
||||
throw new Error("missing.js: oops nnonempty dict not imp");
|
||||
return [];
|
||||
}
|
||||
|
||||
|
@ -57,8 +57,8 @@ $rdf.N3Parser = function () {
|
|||
|
||||
var assertFudge = function (condition, desc) {
|
||||
if(condition) return;
|
||||
if(desc) throw "python Assertion failed: " + desc;
|
||||
throw "(python) Assertion failed.";
|
||||
if(desc) throw new Error("python Assertion failed: " + desc);
|
||||
throw new Error("(python) Assertion failed.");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -192,7 +192,7 @@ $rdf.Serializer = function () {
|
|||
if (obj.termType == 'bnode' && (subjects[sz.toStr(obj)] &&
|
||||
(force || (rootsHash[obj.toNT()] == undefined )))) {// and there are statements
|
||||
if (doneBnodesNT[obj.toNT()]) { // Ah-ha! a loop
|
||||
throw "Serializer: Should be no loops "+obj;
|
||||
throw new Error("Serializer: Should be no loops "+obj);
|
||||
}
|
||||
doneBnodesNT[obj.toNT()] = true;
|
||||
return dummyPropertyTree(obj, subjects, rootsHash);
|
||||
|
@ -258,7 +258,7 @@ $rdf.Serializer = function () {
|
|||
for (var i=0; i<sts.length; i++) {
|
||||
// dump('\t'+sts[i]+'\n');
|
||||
}
|
||||
throw "Isolated node should be a subject" +found;
|
||||
throw new Error("Isolated node should be a subject" +found);
|
||||
}
|
||||
dummySubjectTree(root, subjects, rootsHash); // trace out the ring
|
||||
}
|
||||
|
@ -456,7 +456,7 @@ $rdf.Serializer = function () {
|
|||
return res;
|
||||
|
||||
default:
|
||||
throw "Internal: termToN3 cannot handle " + expr + " of termType+" + expr.termType
|
||||
throw new Error("Internal: termToN3 cannot handle " + expr + " of termType+" + expr.termType);
|
||||
return '' + expr;
|
||||
}
|
||||
}
|
||||
|
@ -767,7 +767,7 @@ $rdf.Serializer = function () {
|
|||
'</' + t + '>']);
|
||||
break;
|
||||
default:
|
||||
throw "Can't serialize object of type " + st.object.termType + " into XML";
|
||||
throw new Error("Can't serialize object of type " + st.object.termType + " into XML");
|
||||
} // switch
|
||||
}
|
||||
}
|
||||
|
@ -830,7 +830,7 @@ $rdf.Serializer = function () {
|
|||
'</' + qname(st.predicate) + '>']);
|
||||
break;
|
||||
default:
|
||||
throw "Can't serialize object of type " + st.object.termType + " into XML";
|
||||
throw new Error("Can't serialize object of type " + st.object.termType + " into XML");
|
||||
|
||||
} // switch
|
||||
}
|
||||
|
|
|
@ -215,7 +215,7 @@ $rdf.Formula.prototype.add = function (subj, pred, obj, why) {
|
|||
// Convenience methods on a formula allow the creation of new RDF terms:
|
||||
$rdf.Formula.prototype.sym = function (uri, name) {
|
||||
if(name != null) {
|
||||
throw "This feature (kb.sym with 2 args) is removed. Do not assume prefix mappings."
|
||||
throw new Error("This feature (kb.sym with 2 args) is removed. Do not assume prefix mappings.");
|
||||
if(!$rdf.ns[uri]) throw 'The prefix "' + uri + '" is not set in the API';
|
||||
uri = $rdf.ns[uri] + name
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ $rdf.Formula.prototype.fromNT = function (str) {
|
|||
if(k < len - 1) {
|
||||
if(str[k + 1] == '@') lang = str.slice(k + 2, len);
|
||||
else if(str.slice(k + 1, k + 3) == '^^') dt = $rdf.fromNT(str.slice(k + 3, len));
|
||||
else throw "Can't convert string from NT: " + str
|
||||
else throw new Error("Can't convert string from NT: " + str);
|
||||
}
|
||||
var str = (str.slice(1, k));
|
||||
str = str.replace(/\\"/g, '"'); // unescape quotes '
|
||||
|
@ -334,7 +334,7 @@ $rdf.Formula.prototype.fromNT = function (str) {
|
|||
var x = new $rdf.Variable(str.slice(1));
|
||||
return x;
|
||||
}
|
||||
throw "Can't convert from NT: " + str;
|
||||
throw new Error("Can't convert from NT: " + str);
|
||||
|
||||
}
|
||||
$rdf.fromNT = $rdf.Formula.prototype.fromNT; // Not for inexpert user
|
||||
|
|
|
@ -101,7 +101,7 @@ Zotero.Schema = new function(){
|
|||
return _initializeSchema()
|
||||
.then(function() {
|
||||
(Zotero.isStandalone ? Zotero.uiReadyPromise : Zotero.initializationPromise)
|
||||
.then(1000)
|
||||
.delay(1000)
|
||||
.then(async function () {
|
||||
await this.updateBundledFiles();
|
||||
if (Zotero.Prefs.get('automaticScraperUpdates')) {
|
||||
|
@ -221,7 +221,7 @@ Zotero.Schema = new function(){
|
|||
// 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.
|
||||
(Zotero.isStandalone ? Zotero.uiReadyPromise : Zotero.initializationPromise)
|
||||
.then(1000)
|
||||
.delay(1000)
|
||||
.then(async function () {
|
||||
await this.updateBundledFiles();
|
||||
if (Zotero.Prefs.get('automaticScraperUpdates')) {
|
||||
|
@ -574,7 +574,7 @@ Zotero.Schema = new function(){
|
|||
var ModeType = Zotero.Utilities.capitalize(modeType);
|
||||
var Mode = Zotero.Utilities.capitalize(mode);
|
||||
|
||||
var repotime = yield Zotero.File.getContentsFromURLAsync("resource://zotero/schema/repotime.txt");
|
||||
var repotime = yield Zotero.File.getResourceAsync("resource://zotero/schema/repotime.txt");
|
||||
var date = Zotero.Date.sqlToDate(repotime.trim(), true);
|
||||
repotime = Zotero.Date.toUnixTimestamp(date);
|
||||
|
||||
|
@ -1454,7 +1454,7 @@ Zotero.Schema = new function(){
|
|||
throw ('Schema type not provided to _getSchemaSQL()');
|
||||
}
|
||||
|
||||
return Zotero.File.getContentsFromURLAsync("resource://zotero/schema/" + schema + ".sql");
|
||||
return Zotero.File.getResourceAsync(`resource://zotero/schema/${schema}.sql`);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ Zotero.Styles = new function() {
|
|||
this.ns = {
|
||||
"csl":"http://purl.org/net/xbiblio/csl"
|
||||
};
|
||||
|
||||
this.CSL_VALIDATOR_URL = "resource://zotero/csl-validator.js";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -101,8 +103,9 @@ Zotero.Styles = new function() {
|
|||
var localeFile = {};
|
||||
var locales = {};
|
||||
var primaryDialects = {};
|
||||
var localesLocation = "chrome://zotero/content/locale/csl/locales.json";
|
||||
localeFile = JSON.parse(yield Zotero.File.getContentsFromURLAsync(localesLocation));
|
||||
localeFile = JSON.parse(
|
||||
yield Zotero.File.getResourceAsync("chrome://zotero/content/locale/csl/locales.json")
|
||||
);
|
||||
|
||||
primaryDialects = localeFile["primary-dialects"];
|
||||
|
||||
|
@ -115,19 +118,10 @@ Zotero.Styles = new function() {
|
|||
this.primaryDialects = primaryDialects;
|
||||
|
||||
// Load renamed styles
|
||||
_renamedStyles = {};
|
||||
var xmlhttp = yield Zotero.HTTP.request(
|
||||
"GET",
|
||||
"resource://zotero/schema/renamed-styles.json",
|
||||
{
|
||||
responseType: 'json'
|
||||
}
|
||||
_renamedStyles = JSON.parse(
|
||||
yield Zotero.File.getResourceAsync("resource://zotero/schema/renamed-styles.json")
|
||||
);
|
||||
// Map some obsolete styles to current ones
|
||||
if (xmlhttp.response) {
|
||||
_renamedStyles = xmlhttp.response;
|
||||
}
|
||||
|
||||
|
||||
_initializationDeferred.resolve();
|
||||
_initialized = true;
|
||||
|
||||
|
@ -252,18 +246,18 @@ Zotero.Styles = new function() {
|
|||
* @return {Promise} A promise representing the style file. This promise is rejected
|
||||
* with the validation error if validation fails, or resolved if it is not.
|
||||
*/
|
||||
this.validate = function(style) {
|
||||
var deferred = Zotero.Promise.defer(),
|
||||
worker = new Worker("resource://zotero/csl-validator.js");
|
||||
worker.onmessage = function(event) {
|
||||
if(event.data) {
|
||||
deferred.reject(event.data);
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}
|
||||
};
|
||||
worker.postMessage(style);
|
||||
return deferred.promise;
|
||||
this.validate = function (style) {
|
||||
return new Zotero.Promise((resolve, reject) => {
|
||||
let worker = new Worker(this.CSL_VALIDATOR_URL);
|
||||
worker.onmessage = function (event) {
|
||||
if (event.data) {
|
||||
reject(event.data);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
worker.postMessage(style);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -493,9 +487,7 @@ Zotero.Styles = new function() {
|
|||
yield Zotero.Styles.reinit();
|
||||
|
||||
// Refresh preferences windows
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
|
||||
getService(Components.interfaces.nsIWindowMediator);
|
||||
var enumerator = wm.getEnumerator("zotero:pref");
|
||||
var enumerator = Services.wm.getEnumerator("zotero:pref");
|
||||
while(enumerator.hasMoreElements()) {
|
||||
var win = enumerator.getNext();
|
||||
if(win.Zotero_Preferences.Cite) {
|
||||
|
@ -682,7 +674,7 @@ Zotero.Style = function (style, path) {
|
|||
'/csl:style/csl:info[1]/csl:link[@rel="source" or @rel="independent-parent"][1]/@href',
|
||||
Zotero.Styles.ns);
|
||||
if(this.source === this.styleID) {
|
||||
throw "Style with ID "+this.styleID+" references itself as source";
|
||||
throw new Error("Style with ID "+this.styleID+" references itself as source");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -224,7 +224,7 @@ Zotero.Sync.EventListeners.IdleListener = {
|
|||
|
||||
_backObserver: {
|
||||
observe: function (subject, topic, data) {
|
||||
if (topic != 'back') {
|
||||
if (topic !== 'active') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2752,7 +2752,7 @@ Zotero.Translate.IO = {
|
|||
}
|
||||
|
||||
if(nodes.getElementsByTagName("parsererror").length) {
|
||||
throw "DOMParser error: loading data into data store failed";
|
||||
throw new Error("DOMParser error: loading data into data store failed");
|
||||
}
|
||||
|
||||
if("normalize" in nodes) nodes.normalize();
|
||||
|
|
|
@ -129,7 +129,7 @@ Zotero.Translate.DOMWrapper = new function() {
|
|||
|
||||
// No double wrapping.
|
||||
if (isWrapper(obj))
|
||||
throw "Trying to double-wrap object!";
|
||||
throw new Error("Trying to double-wrap object!");
|
||||
|
||||
let dummy;
|
||||
if (typeof obj === "function")
|
||||
|
@ -151,7 +151,7 @@ Zotero.Translate.DOMWrapper = new function() {
|
|||
|
||||
// If we have a wrappable type, make sure it's wrapped.
|
||||
if (!isWrapper(x))
|
||||
throw "Trying to unwrap a non-wrapped object!";
|
||||
throw new Error("Trying to unwrap a non-wrapped object!");
|
||||
|
||||
var obj = x.SpecialPowers_wrappedObject;
|
||||
// unwrapped.
|
||||
|
@ -253,7 +253,7 @@ Zotero.Translate.DOMWrapper = new function() {
|
|||
},
|
||||
|
||||
defineProperty(target, prop, descriptor) {
|
||||
throw "Can't call defineProperty on SpecialPowers wrapped object";
|
||||
throw new Error("Can't call defineProperty on SpecialPowers wrapped object");
|
||||
},
|
||||
|
||||
getOwnPropertyDescriptor(target, prop) {
|
||||
|
@ -316,7 +316,7 @@ Zotero.Translate.DOMWrapper = new function() {
|
|||
},
|
||||
|
||||
preventExtensions(target) {
|
||||
throw "Can't call preventExtensions on SpecialPowers wrapped object";
|
||||
throw new Error("Can't call preventExtensions on SpecialPowers wrapped object");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -870,7 +870,7 @@ Zotero.Translate.IO.Read.prototype = {
|
|||
|
||||
"setCharacterSet":function(charset) {
|
||||
if(typeof charset !== "string") {
|
||||
throw "Translate: setCharacterSet: charset must be a string";
|
||||
throw new Error("Translate: setCharacterSet: charset must be a string");
|
||||
}
|
||||
|
||||
// seek back to the beginning
|
||||
|
@ -966,7 +966,7 @@ Zotero.Translate.IO.Write.prototype = {
|
|||
|
||||
"setCharacterSet":function(charset) {
|
||||
if(typeof charset !== "string") {
|
||||
throw "Translate: setCharacterSet: charset must be a string";
|
||||
throw new Error("Translate: setCharacterSet: charset must be a string");
|
||||
}
|
||||
|
||||
if(!this.outputStream) {
|
||||
|
|
|
@ -215,4 +215,7 @@ Zotero.Translator.replaceDeprecatedStatements = function(code) {
|
|||
|
||||
Zotero.Translator.RUN_MODE_IN_BROWSER = 1;
|
||||
Zotero.Translator.RUN_MODE_ZOTERO_STANDALONE = 2;
|
||||
Zotero.Translator.RUN_MODE_ZOTERO_SERVER = 4;
|
||||
Zotero.Translator.RUN_MODE_ZOTERO_SERVER = 4;
|
||||
Zotero.Translator.TRANSLATOR_TYPES = TRANSLATOR_TYPES;
|
||||
Zotero.Translator.TRANSLATOR_OPTIONAL_PROPERTIES = TRANSLATOR_OPTIONAL_PROPERTIES;
|
||||
Zotero.Translator.TRANSLATOR_REQUIRED_PROPERTIES = TRANSLATOR_REQUIRED_PROPERTIES;
|
||||
|
|
|
@ -181,10 +181,10 @@ Zotero.Translators = new function() {
|
|||
|
||||
// add to cache
|
||||
_translators[translator.translatorID] = translator;
|
||||
for (let type in TRANSLATOR_TYPES) {
|
||||
if (translator.translatorType & TRANSLATOR_TYPES[type]) {
|
||||
for (let type in Zotero.Translator.TRANSLATOR_TYPES) {
|
||||
if (translator.translatorType & Zotero.Translator.TRANSLATOR_TYPES[type]) {
|
||||
_cache[type].push(translator);
|
||||
if ((translator.translatorType & TRANSLATOR_TYPES.web) && translator.targetAll) {
|
||||
if ((translator.translatorType & Zotero.Translator.TRANSLATOR_TYPES.web) && translator.targetAll) {
|
||||
_cache.webWithTargetAll.push(translator);
|
||||
}
|
||||
}
|
||||
|
@ -193,8 +193,8 @@ Zotero.Translators = new function() {
|
|||
if (!dbCacheEntry) {
|
||||
yield Zotero.Translators.cacheInDB(
|
||||
fileName,
|
||||
translator.serialize(TRANSLATOR_REQUIRED_PROPERTIES.
|
||||
concat(TRANSLATOR_OPTIONAL_PROPERTIES)),
|
||||
translator.serialize(Zotero.Translator.TRANSLATOR_REQUIRED_PROPERTIES.
|
||||
concat(Zotero.Translator.TRANSLATOR_OPTIONAL_PROPERTIES)),
|
||||
lastModifiedTime
|
||||
);
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ Zotero.Translators = new function() {
|
|||
return Zotero.Translators.load(infoRe.exec(source)[0], path, source);
|
||||
})
|
||||
.catch(function() {
|
||||
throw "Invalid or missing translator metadata JSON object in " + OS.Path.basename(path);
|
||||
throw new Error("Invalid or missing translator metadata JSON object in " + OS.Path.basename(path));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -182,7 +182,7 @@ Zotero.Utilities = {
|
|||
var initialRe = new RegExp('^-?[' + allCaps + ']$');
|
||||
|
||||
if(typeof(author) != "string") {
|
||||
throw "cleanAuthor: author must be a string";
|
||||
throw new Error("cleanAuthor: author must be a string");
|
||||
}
|
||||
|
||||
author = author.replace(/^[\s\u00A0\.\,\/\[\]\:]+/, '')
|
||||
|
@ -246,7 +246,7 @@ Zotero.Utilities = {
|
|||
*/
|
||||
"trim":function(/**String*/ s) {
|
||||
if (typeof(s) != "string") {
|
||||
throw "trim: argument must be a string";
|
||||
throw new Error("trim: argument must be a string");
|
||||
}
|
||||
|
||||
s = s.replace(/^\s+/, "");
|
||||
|
@ -272,7 +272,7 @@ Zotero.Utilities = {
|
|||
*/
|
||||
"superCleanString":function(/**String*/ x) {
|
||||
if(typeof(x) != "string") {
|
||||
throw "superCleanString: argument must be a string";
|
||||
throw new Error("superCleanString: argument must be a string");
|
||||
}
|
||||
|
||||
var x = x.replace(/^[\x00-\x27\x29-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F\s]+/, "");
|
||||
|
@ -289,10 +289,8 @@ Zotero.Utilities = {
|
|||
url = url.trim();
|
||||
if (!url) return false;
|
||||
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
try {
|
||||
return ios.newURI(url, null, null).spec; // Valid URI if succeeds
|
||||
return Services.io.newURI(url, null, null).spec; // Valid URI if succeeds
|
||||
} catch (e) {
|
||||
if (e instanceof Components.Exception
|
||||
&& e.result == Components.results.NS_ERROR_MALFORMED_URI
|
||||
|
@ -300,7 +298,7 @@ Zotero.Utilities = {
|
|||
if (tryHttp && /\w\.\w/.test(url)) {
|
||||
// Assume it's a URL missing "http://" part
|
||||
try {
|
||||
return ios.newURI('http://' + url, null, null).spec;
|
||||
return Services.io.newURI('http://' + url, null, null).spec;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
|
@ -317,7 +315,7 @@ Zotero.Utilities = {
|
|||
*/
|
||||
"cleanTags":function(/**String*/ x) {
|
||||
if(typeof(x) != "string") {
|
||||
throw "cleanTags: argument must be a string";
|
||||
throw new Error("cleanTags: argument must be a string");
|
||||
}
|
||||
|
||||
x = x.replace(/<br[^>]*>/gi, "\n");
|
||||
|
@ -331,7 +329,7 @@ Zotero.Utilities = {
|
|||
*/
|
||||
"cleanDOI":function(/**String**/ x) {
|
||||
if(typeof(x) != "string") {
|
||||
throw "cleanDOI: argument must be a string";
|
||||
throw new Error("cleanDOI: argument must be a string");
|
||||
}
|
||||
|
||||
var doi = x.match(/10(?:\.[0-9]{4,})?\/[^\s]*[^\s\.,]/);
|
||||
|
@ -1245,7 +1243,7 @@ Zotero.Utilities = {
|
|||
*/
|
||||
"quotemeta":function(literal) {
|
||||
if(typeof literal !== "string") {
|
||||
throw "Argument "+literal+" must be a string in Zotero.Utilities.quotemeta()";
|
||||
throw new Error("Argument "+literal+" must be a string in Zotero.Utilities.quotemeta()");
|
||||
}
|
||||
const metaRegexp = /[-[\]{}()*+?.\\^$|,#\s]/g;
|
||||
return literal.replace(metaRegexp, "\\$&");
|
||||
|
@ -1367,6 +1365,7 @@ Zotero.Utilities = {
|
|||
return strings.join(delimiter !== undefined ? delimiter : ", ");
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Generate a random string of length 'len' (defaults to 8)
|
||||
**/
|
||||
|
|
|
@ -1338,6 +1338,150 @@ Zotero.Utilities.Internal = {
|
|||
.join('\n');
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate a function that produces a static output
|
||||
*
|
||||
* Zotero.lazy(fn) returns a function. The first time this function
|
||||
* is called, it calls fn() and returns its output. Subsequent
|
||||
* calls return the same output as the first without calling fn()
|
||||
* again.
|
||||
*/
|
||||
lazy: function (fn) {
|
||||
var x, called = false;
|
||||
return function() {
|
||||
if(!called) {
|
||||
x = fn.apply(this);
|
||||
called = true;
|
||||
}
|
||||
return x;
|
||||
};
|
||||
},
|
||||
|
||||
serial: function (fn) {
|
||||
Components.utils.import("resource://zotero/concurrentCaller.js");
|
||||
var caller = new ConcurrentCaller({
|
||||
numConcurrent: 1,
|
||||
onError: e => Zotero.logError(e)
|
||||
});
|
||||
return function () {
|
||||
var args = arguments;
|
||||
return caller.start(function () {
|
||||
return fn.apply(this, args);
|
||||
}.bind(this));
|
||||
};
|
||||
},
|
||||
|
||||
spawn: function (generator, thisObject) {
|
||||
if (thisObject) {
|
||||
return Zotero.Promise.coroutine(generator.bind(thisObject))();
|
||||
}
|
||||
return Zotero.Promise.coroutine(generator)();
|
||||
},
|
||||
|
||||
/**
|
||||
* Defines property on the object
|
||||
* More compact way to do Object.defineProperty
|
||||
*
|
||||
* @param {Object} obj Target object
|
||||
* @param {String} prop Property to be defined
|
||||
* @param {Object} desc Propery descriptor. If not overriden, "enumerable" is true
|
||||
* @param {Object} opts Options:
|
||||
* lazy {Boolean} If true, the _getter_ is intended for late
|
||||
* initialization of the property. The getter is replaced with a simple
|
||||
* property once initialized.
|
||||
*/
|
||||
defineProperty: function(obj, prop, desc, opts) {
|
||||
if (typeof prop != 'string') throw new Error("Property must be a string");
|
||||
var d = { __proto__: null, enumerable: true, configurable: true }; // Enumerable by default
|
||||
for (let p in desc) {
|
||||
if (!desc.hasOwnProperty(p)) continue;
|
||||
d[p] = desc[p];
|
||||
}
|
||||
|
||||
if (opts) {
|
||||
if (opts.lazy && d.get) {
|
||||
let getter = d.get;
|
||||
d.configurable = true; // Make sure we can change the property later
|
||||
d.get = function() {
|
||||
let val = getter.call(this);
|
||||
|
||||
// Redefine getter on this object as non-writable value
|
||||
delete d.set;
|
||||
delete d.get;
|
||||
d.writable = false;
|
||||
d.value = val;
|
||||
Object.defineProperty(this, prop, d);
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(obj, prop, d);
|
||||
},
|
||||
|
||||
extendClass: function(superClass, newClass) {
|
||||
newClass._super = superClass;
|
||||
newClass.prototype = Object.create(superClass.prototype);
|
||||
newClass.prototype.constructor = newClass;
|
||||
},
|
||||
|
||||
/*
|
||||
* Flattens mixed arrays/values in a passed _arguments_ object and returns
|
||||
* an array of values -- allows for functions to accept both arrays of
|
||||
* values and/or an arbitrary number of individual values
|
||||
*/
|
||||
flattenArguments: function (args){
|
||||
// Put passed scalar values into an array
|
||||
if (args === null || typeof args == 'string' || typeof args.length == 'undefined') {
|
||||
args = [args];
|
||||
}
|
||||
|
||||
var returns = [];
|
||||
for (var i=0; i<args.length; i++){
|
||||
var arg = args[i];
|
||||
if (!arg && arg !== 0) {
|
||||
continue;
|
||||
}
|
||||
if (Array.isArray(arg)) {
|
||||
returns.push(...arg);
|
||||
}
|
||||
else {
|
||||
returns.push(arg);
|
||||
}
|
||||
}
|
||||
return returns;
|
||||
},
|
||||
|
||||
/*
|
||||
* Sets font size based on prefs -- intended for use on root element
|
||||
* (zotero-pane, note window, etc.)
|
||||
*/
|
||||
setFontSize: function (rootElement) {
|
||||
var size = Zotero.Prefs.get('fontSize');
|
||||
rootElement.style.fontSize = size + 'em';
|
||||
if (size <= 1) {
|
||||
size = 'small';
|
||||
}
|
||||
else if (size <= 1.25) {
|
||||
size = 'medium';
|
||||
}
|
||||
else {
|
||||
size = 'large';
|
||||
}
|
||||
// Custom attribute -- allows for additional customizations in zotero.css
|
||||
rootElement.setAttribute('zoteroFontSize', size);
|
||||
},
|
||||
|
||||
getAncestorByTagName: function (elem, tagName){
|
||||
while (elem.parentNode){
|
||||
elem = elem.parentNode;
|
||||
if (elem.localName == tagName) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
quitZotero: function(restart=false) {
|
||||
Zotero.debug("Zotero.Utilities.Internal.quitZotero() is deprecated -- use quit()");
|
||||
|
|
|
@ -28,7 +28,6 @@ Components.utils.import("resource://zotero/config.js");
|
|||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://gre/modules/PluralForm.jsm");
|
||||
Components.classes["@mozilla.org/net/osfileconstantsservice;1"]
|
||||
.getService(Components.interfaces.nsIOSFileConstantsService)
|
||||
.init();
|
||||
|
@ -44,11 +43,9 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
|
|||
this.debug = debug;
|
||||
this.log = log;
|
||||
this.logError = logError;
|
||||
this.localeJoin = localeJoin;
|
||||
this.setFontSize = setFontSize;
|
||||
this.flattenArguments = flattenArguments;
|
||||
this.getAncestorByTagName = getAncestorByTagName;
|
||||
this.randomString = randomString;
|
||||
this.reinit = reinit; // defined in zotero-service.js
|
||||
|
||||
// Public properties
|
||||
|
@ -190,10 +187,8 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
|
|||
|
||||
this.clientName = ZOTERO_CONFIG.CLIENT_NAME;
|
||||
|
||||
var appInfo = Components.classes["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Components.interfaces.nsIXULAppInfo);
|
||||
this.platformVersion = appInfo.platformVersion;
|
||||
this.platformMajorVersion = parseInt(appInfo.platformVersion.match(/^[0-9]+/)[0]);
|
||||
this.platformVersion = Services.appinfo.platformVersion;
|
||||
this.platformMajorVersion = parseInt(this.platformVersion.match(/^[0-9]+/)[0]);
|
||||
this.isFx = true;
|
||||
this.isClient = true;
|
||||
this.isStandalone = Services.appinfo.ID == ZOTERO_CONFIG['GUID'];
|
||||
|
@ -228,59 +223,8 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
|
|||
// Browser
|
||||
Zotero.browser = "g";
|
||||
|
||||
//
|
||||
// Get settings from language pack (extracted by zotero-build/locale/merge_mozilla_files)
|
||||
//
|
||||
function getIntlProp(name, fallback = null) {
|
||||
try {
|
||||
return intlProps.GetStringFromName(name);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(`Couldn't load ${name} from intl.properties`);
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
function setOrClearIntlPref(name, type) {
|
||||
var val = getIntlProp(name);
|
||||
if (val !== null) {
|
||||
if (type == 'boolean') {
|
||||
val = val == 'true';
|
||||
}
|
||||
Zotero.Prefs.set(name, val, 1);
|
||||
}
|
||||
else {
|
||||
Zotero.Prefs.clear(name, 1);
|
||||
}
|
||||
}
|
||||
var intlProps = Services.strings.createBundle("chrome://zotero/locale/mozilla/intl.properties");
|
||||
this.locale = getIntlProp('general.useragent.locale', 'en-US');
|
||||
let [get, numForms] = PluralForm.makeGetter(parseInt(getIntlProp('pluralRule', 1)));
|
||||
this.pluralFormGet = get;
|
||||
this.pluralFormNumForms = numForms;
|
||||
setOrClearIntlPref('intl.accept_languages', 'string');
|
||||
|
||||
// Also load the brand as appName
|
||||
var brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
|
||||
this.appName = brandBundle.GetStringFromName("brandShortName");
|
||||
|
||||
_localizedStringBundle = Services.strings.createBundle("chrome://zotero/locale/zotero.properties");
|
||||
|
||||
// Set the locale direction to Zotero.dir
|
||||
// DEBUG: is there a better way to get the entity from JS?
|
||||
var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance();
|
||||
xmlhttp.open('GET', 'chrome://global/locale/global.dtd', false);
|
||||
xmlhttp.overrideMimeType('text/plain');
|
||||
xmlhttp.send(null);
|
||||
var matches = xmlhttp.responseText.match(/(ltr|rtl)/);
|
||||
if (matches && matches[0] == 'rtl') {
|
||||
Zotero.dir = 'rtl';
|
||||
}
|
||||
else {
|
||||
Zotero.dir = 'ltr';
|
||||
}
|
||||
Zotero.rtl = Zotero.dir == 'rtl';
|
||||
|
||||
Zotero.Intl.init();
|
||||
|
||||
Zotero.Prefs.init();
|
||||
Zotero.Debug.init(options && options.forceDebugLog);
|
||||
|
||||
|
@ -771,9 +715,7 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
|
|||
}
|
||||
// Load More Info page
|
||||
else if (index == 2) {
|
||||
let io = Components.classes['@mozilla.org/network/io-service;1']
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
let uri = io.newURI(kbURL, null, null);
|
||||
let uri = Services.io.newURI(kbURL, null, null);
|
||||
let handler = Components.classes['@mozilla.org/uriloader/external-protocol-service;1']
|
||||
.getService(Components.interfaces.nsIExternalProtocolService)
|
||||
.getProtocolHandlerInfo('http');
|
||||
|
@ -827,7 +769,7 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
|
|||
// Initialize keyboard shortcuts
|
||||
Zotero.Keys.init();
|
||||
|
||||
yield Zotero.Date.init();
|
||||
Zotero.Date.init();
|
||||
Zotero.LocateManager.init();
|
||||
yield Zotero.ID.init();
|
||||
yield Zotero.Collections.init();
|
||||
|
@ -999,7 +941,7 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
|
|||
}
|
||||
|
||||
// remove temp directory
|
||||
Zotero.removeTempDirectory();
|
||||
yield Zotero.removeTempDirectory();
|
||||
|
||||
if (Zotero.DB) {
|
||||
// close DB
|
||||
|
@ -1022,63 +964,34 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
|
|||
return Zotero.File.pathToFile(Zotero.Profile.dir);
|
||||
}
|
||||
|
||||
|
||||
this.getZoteroDirectory = function () {
|
||||
Zotero.warn("Zotero.getZoteroDirectory() is deprecated -- use Zotero.DataDirectory.dir");
|
||||
return Zotero.File.pathToFile(Zotero.DataDirectory.dir);
|
||||
}
|
||||
|
||||
|
||||
function getStorageDirectory(){
|
||||
var file = OS.Path.join(Zotero.DataDirectory.dir, 'storage');
|
||||
file = Zotero.File.pathToFile(file);
|
||||
Zotero.File.createDirectoryIfMissing(file);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
this.getZoteroDatabase = function (name, ext) {
|
||||
Zotero.warn("Zotero.getZoteroDatabase() is deprecated -- use Zotero.DataDirectory.getDatabase()");
|
||||
return Zotero.File.pathToFile(Zotero.DataDirectory.getDatabase(name, ext));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {nsIFile}
|
||||
*/
|
||||
this.getTempDirectory = function () {
|
||||
var tmp = Zotero.File.pathToFile(Zotero.DataDirectory.dir);
|
||||
tmp.append('tmp');
|
||||
Zotero.File.createDirectoryIfMissing(tmp);
|
||||
return tmp;
|
||||
function getStorageDirectory() {
|
||||
return Zotero.File.pathToFile(Zotero.DataDirectory.getSubdirectory('storage', true));
|
||||
}
|
||||
|
||||
|
||||
this.removeTempDirectory = function () {
|
||||
var tmp = Zotero.File.pathToFile(Zotero.DataDirectory.dir);
|
||||
tmp.append('tmp');
|
||||
if (tmp.exists()) {
|
||||
try {
|
||||
tmp.remove(true);
|
||||
}
|
||||
catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
this.getStylesDirectory = function () {
|
||||
var dir = Zotero.File.pathToFile(Zotero.DataDirectory.dir);
|
||||
dir.append('styles');
|
||||
Zotero.File.createDirectoryIfMissing(dir);
|
||||
return dir;
|
||||
return Zotero.File.pathToFile(Zotero.DataDirectory.getSubdirectory('styles', true));
|
||||
}
|
||||
|
||||
|
||||
this.getTranslatorsDirectory = function () {
|
||||
var dir = Zotero.File.pathToFile(Zotero.DataDirectory.dir);
|
||||
dir.append('translators');
|
||||
Zotero.File.createDirectoryIfMissing(dir);
|
||||
return dir;
|
||||
return Zotero.File.pathToFile(Zotero.DataDirectory.getSubdirectory('translators', true));
|
||||
}
|
||||
|
||||
this.getTempDirectory = function () {
|
||||
return Zotero.File.pathToFile(Zotero.DataDirectory.getSubdirectory('tmp', true));
|
||||
}
|
||||
|
||||
this.removeTempDirectory = function () {
|
||||
return Zotero.DataDirectory.removeSubdirectory('tmp');
|
||||
}
|
||||
|
||||
|
||||
|
@ -1170,9 +1083,7 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
|
|||
}
|
||||
|
||||
try {
|
||||
var io = Components.classes['@mozilla.org/network/io-service;1']
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
var uri = io.newURI(url, null, null);
|
||||
var uri = Services.io.newURI(url, null, null);
|
||||
var handler = Components.classes['@mozilla.org/uriloader/external-protocol-service;1']
|
||||
.getService(Components.interfaces.nsIExternalProtocolService)
|
||||
.getProtocolHandlerInfo('http');
|
||||
|
@ -1410,303 +1321,35 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
|
|||
return deferred.promise;
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {String} name
|
||||
* @param {String[]} [params=[]] - Strings to substitute for placeholders
|
||||
* @param {Number} [num] - Number (also appearing in `params`) to use when determining which plural
|
||||
* form of the string to use; localized strings should include all forms in the order specified
|
||||
* in https://developer.mozilla.org/en-US/docs/Mozilla/Localization/Localization_and_Plurals,
|
||||
* separated by semicolons
|
||||
*/
|
||||
this.getString = function (name, params, num) {
|
||||
return this.getStringFromBundle(_localizedStringBundle, ...arguments);
|
||||
return Zotero.Intl.getString(...arguments);
|
||||
}
|
||||
|
||||
|
||||
this.getStringFromBundle = function (bundle, name, params, num) {
|
||||
try {
|
||||
if (params != undefined) {
|
||||
if (typeof params != 'object'){
|
||||
params = [params];
|
||||
}
|
||||
var l10n = bundle.formatStringFromName(name, params, params.length);
|
||||
}
|
||||
else {
|
||||
var l10n = bundle.GetStringFromName(name);
|
||||
}
|
||||
if (num !== undefined) {
|
||||
let availableForms = l10n.split(/;/);
|
||||
// If not enough available forms, use last one -- PluralForm.get() uses first by
|
||||
// default, but it's more likely that a localizer will translate the two English
|
||||
// strings with some plural form as the second one, so we might as well use that
|
||||
if (availableForms.length < this.pluralFormNumForms()) {
|
||||
l10n = availableForms[availableForms.length - 1];
|
||||
}
|
||||
else {
|
||||
l10n = this.pluralFormGet(num, l10n);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e){
|
||||
if (e.name == 'NS_ERROR_ILLEGAL_VALUE') {
|
||||
Zotero.debug(params, 1);
|
||||
}
|
||||
else if (e.name != 'NS_ERROR_FAILURE') {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
throw new Error('Localized string not available for ' + name);
|
||||
}
|
||||
return l10n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines property on the object
|
||||
* More compact way to do Object.defineProperty
|
||||
*
|
||||
* @param {Object} obj Target object
|
||||
* @param {String} prop Property to be defined
|
||||
* @param {Object} desc Propery descriptor. If not overriden, "enumerable" is true
|
||||
* @param {Object} opts Options:
|
||||
* lazy {Boolean} If true, the _getter_ is intended for late
|
||||
* initialization of the property. The getter is replaced with a simple
|
||||
* property once initialized.
|
||||
*/
|
||||
this.defineProperty = function(obj, prop, desc, opts) {
|
||||
if (typeof prop != 'string') throw new Error("Property must be a string");
|
||||
var d = { __proto__: null, enumerable: true, configurable: true }; // Enumerable by default
|
||||
for (let p in desc) {
|
||||
if (!desc.hasOwnProperty(p)) continue;
|
||||
d[p] = desc[p];
|
||||
}
|
||||
|
||||
if (opts) {
|
||||
if (opts.lazy && d.get) {
|
||||
let getter = d.get;
|
||||
d.configurable = true; // Make sure we can change the property later
|
||||
d.get = function() {
|
||||
let val = getter.call(this);
|
||||
|
||||
// Redefine getter on this object as non-writable value
|
||||
delete d.set;
|
||||
delete d.get;
|
||||
d.writable = false;
|
||||
d.value = val;
|
||||
Object.defineProperty(this, prop, d);
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(obj, prop, d);
|
||||
}
|
||||
|
||||
this.extendClass = function(superClass, newClass) {
|
||||
newClass._super = superClass;
|
||||
newClass.prototype = Object.create(superClass.prototype);
|
||||
newClass.prototype.constructor = newClass;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function should be removed
|
||||
*
|
||||
* |separator| defaults to a space (not a comma like Array.join()) if
|
||||
* not specified
|
||||
*
|
||||
* TODO: Substitute localized characters (e.g. Arabic comma and semicolon)
|
||||
*/
|
||||
function localeJoin(arr, separator) {
|
||||
if (typeof separator == 'undefined') {
|
||||
separator = ' ';
|
||||
}
|
||||
return arr.join(separator);
|
||||
}
|
||||
|
||||
|
||||
this.defineProperty = (...args) => Zotero.Utilities.Internal.defineProperty(...args);
|
||||
|
||||
this.extendClass = (...args) => Zotero.Utilities.Internal.extendClass(...args);
|
||||
|
||||
this.getLocaleCollation = function () {
|
||||
if (this.collation) {
|
||||
return this.collation;
|
||||
}
|
||||
|
||||
try {
|
||||
// DEBUG: Is this necessary, or will Intl.Collator just default to the same locales we're
|
||||
// passing manually?
|
||||
|
||||
let locales;
|
||||
// Fx55+
|
||||
if (Services.locale.getAppLocalesAsBCP47) {
|
||||
locales = Services.locale.getAppLocalesAsBCP47();
|
||||
}
|
||||
else {
|
||||
let locale;
|
||||
// Fx54
|
||||
if (Services.locale.getAppLocale) {
|
||||
locale = Services.locale.getAppLocale();
|
||||
}
|
||||
// Fx <=53
|
||||
else {
|
||||
locale = Services.locale.getApplicationLocale();
|
||||
locale = locale.getCategory('NSILOCALE_COLLATE');
|
||||
}
|
||||
|
||||
// Extract a valid language tag
|
||||
try {
|
||||
locale = locale.match(/^[a-z]{2}(\-[A-Z]{2})?/)[0];
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Error parsing locale ${locale}`);
|
||||
}
|
||||
locales = [locale];
|
||||
}
|
||||
|
||||
var collator = new Intl.Collator(locales, {
|
||||
numeric: true,
|
||||
sensitivity: 'base'
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
|
||||
// Fall back to en-US sorting
|
||||
try {
|
||||
Zotero.logError("Falling back to en-US sorting");
|
||||
collator = new Intl.Collator(['en-US'], {
|
||||
numeric: true,
|
||||
sensitivity: 'base'
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
|
||||
// If there's still an error, just skip sorting
|
||||
collator = {
|
||||
compare: function (a, b) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Grab all ASCII punctuation and space at the begining of string
|
||||
var initPunctuationRE = /^[\x20-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]+/;
|
||||
// Punctuation that should be ignored when sorting
|
||||
var ignoreInitRE = /["'[{(]+$/;
|
||||
|
||||
// Until old code is updated, pretend we're returning an nsICollation
|
||||
return this.collation = {
|
||||
compareString: function (_, a, b) {
|
||||
if (!a && !b) return 0;
|
||||
if (!a || !b) return b ? -1 : 1;
|
||||
|
||||
// Compare initial punctuation
|
||||
var aInitP = initPunctuationRE.exec(a) || '';
|
||||
var bInitP = initPunctuationRE.exec(b) || '';
|
||||
|
||||
var aWordStart = 0, bWordStart = 0;
|
||||
if (aInitP) {
|
||||
aWordStart = aInitP[0].length;
|
||||
aInitP = aInitP[0].replace(ignoreInitRE, '');
|
||||
}
|
||||
if (bInitP) {
|
||||
bWordStart = bInitP.length;
|
||||
bInitP = bInitP[0].replace(ignoreInitRE, '');
|
||||
}
|
||||
|
||||
// If initial punctuation is equivalent, use collator comparison
|
||||
// that ignores all punctuation
|
||||
//
|
||||
// Update: Intl.Collator's ignorePunctuation also ignores whitespace, so we're
|
||||
// no longer using it, meaning we could take out most of the code to handle
|
||||
// initial punctuation separately, unless we think we'll at some point switch to
|
||||
// a collation function that ignores punctuation but not whitespace.
|
||||
if (aInitP == bInitP || !aInitP && !bInitP) return collator.compare(a, b);
|
||||
|
||||
// Otherwise consider "attached" words as well, e.g. the order should be
|
||||
// "__ n", "__z", "_a"
|
||||
// We don't actually care what the attached word is, just whether it's
|
||||
// there, since at this point we're guaranteed to have non-equivalent
|
||||
// initial punctuation
|
||||
if (aWordStart < a.length) aInitP += 'a';
|
||||
if (bWordStart < b.length) bInitP += 'a';
|
||||
|
||||
return aInitP.localeCompare(bInitP);
|
||||
}
|
||||
};
|
||||
return Zotero.Intl.collation;
|
||||
}
|
||||
|
||||
this.localeCompare = function (...args) {
|
||||
return Zotero.Intl.compare(...args);
|
||||
}
|
||||
|
||||
this.defineProperty(this, "localeCompare", {
|
||||
get: function() {
|
||||
var collation = this.getLocaleCollation();
|
||||
return collation.compareString.bind(collation, 1);
|
||||
}
|
||||
}, {lazy: true});
|
||||
|
||||
/*
|
||||
* Sets font size based on prefs -- intended for use on root element
|
||||
* (zotero-pane, note window, etc.)
|
||||
*/
|
||||
function setFontSize(rootElement) {
|
||||
var size = Zotero.Prefs.get('fontSize');
|
||||
rootElement.style.fontSize = size + 'em';
|
||||
if (size <= 1) {
|
||||
size = 'small';
|
||||
}
|
||||
else if (size <= 1.25) {
|
||||
size = 'medium';
|
||||
}
|
||||
else {
|
||||
size = 'large';
|
||||
}
|
||||
// Custom attribute -- allows for additional customizations in zotero.css
|
||||
rootElement.setAttribute('zoteroFontSize', size);
|
||||
return Zotero.Utilities.Internal.setFontSize(rootElement);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Flattens mixed arrays/values in a passed _arguments_ object and returns
|
||||
* an array of values -- allows for functions to accept both arrays of
|
||||
* values and/or an arbitrary number of individual values
|
||||
*/
|
||||
function flattenArguments(args){
|
||||
// Put passed scalar values into an array
|
||||
if (args === null || typeof args == 'string' || typeof args.length == 'undefined') {
|
||||
args = [args];
|
||||
}
|
||||
|
||||
var returns = [];
|
||||
for (var i=0; i<args.length; i++){
|
||||
var arg = args[i];
|
||||
if (!arg && arg !== 0) {
|
||||
continue;
|
||||
}
|
||||
if (Array.isArray(arg)) {
|
||||
returns.push(...arg);
|
||||
}
|
||||
else {
|
||||
returns.push(arg);
|
||||
}
|
||||
}
|
||||
return returns;
|
||||
return Zotero.Utilities.Internal.flattenArguments(args);
|
||||
}
|
||||
|
||||
|
||||
function getAncestorByTagName(elem, tagName){
|
||||
while (elem.parentNode){
|
||||
elem = elem.parentNode;
|
||||
if (elem.localName == tagName) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return Zotero.Utilities.Internal.getAncestorByTagName(elem, tagName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a random string of length 'len' (defaults to 8)
|
||||
**/
|
||||
function randomString(len, chars) {
|
||||
this.randomString = function(len, chars) {
|
||||
return Zotero.Utilities.randomString(len, chars);
|
||||
}
|
||||
|
||||
|
@ -1722,47 +1365,16 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
|
|||
return file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a function that produces a static output
|
||||
*
|
||||
* Zotero.lazy(fn) returns a function. The first time this function
|
||||
* is called, it calls fn() and returns its output. Subsequent
|
||||
* calls return the same output as the first without calling fn()
|
||||
* again.
|
||||
*/
|
||||
this.lazy = function(fn) {
|
||||
var x, called = false;
|
||||
return function() {
|
||||
if(!called) {
|
||||
x = fn.apply(this);
|
||||
called = true;
|
||||
}
|
||||
return x;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
this.serial = function (fn) {
|
||||
Components.utils.import("resource://zotero/concurrentCaller.js");
|
||||
var caller = new ConcurrentCaller({
|
||||
numConcurrent: 1,
|
||||
onError: e => Zotero.logError(e)
|
||||
});
|
||||
return function () {
|
||||
var args = arguments;
|
||||
return caller.start(function () {
|
||||
return fn.apply(this, args);
|
||||
}.bind(this));
|
||||
};
|
||||
return Zotero.Utilities.Internal.lazy(fn);
|
||||
}
|
||||
|
||||
this.serial = function (fn) {
|
||||
return Zotero.Utilities.Internal.serial(fn);
|
||||
}
|
||||
|
||||
this.spawn = function (generator, thisObject) {
|
||||
if (thisObject) {
|
||||
return Zotero.Promise.coroutine(generator.bind(thisObject))();
|
||||
}
|
||||
return Zotero.Promise.coroutine(generator)();
|
||||
return Zotero.Utilities.Internal.spawn(generator, thisObject);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2200,315 +1812,6 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
|
|||
};
|
||||
}).call(Zotero);
|
||||
|
||||
Zotero.Prefs = new function(){
|
||||
// Privileged methods
|
||||
this.init = init;
|
||||
this.get = get;
|
||||
this.set = set;
|
||||
|
||||
this.register = register;
|
||||
this.unregister = unregister;
|
||||
this.observe = observe;
|
||||
|
||||
// Public properties
|
||||
this.prefBranch;
|
||||
|
||||
function init(){
|
||||
this.prefBranch = Services.prefs.getBranch(ZOTERO_CONFIG.PREF_BRANCH);
|
||||
|
||||
// Register observer to handle pref changes
|
||||
this.register();
|
||||
|
||||
// Unregister observer handling pref changes
|
||||
if (Zotero.addShutdownListener) {
|
||||
Zotero.addShutdownListener(this.unregister.bind(this));
|
||||
}
|
||||
|
||||
// Process pref version updates
|
||||
var fromVersion = this.get('prefVersion');
|
||||
if (!fromVersion) {
|
||||
fromVersion = 0;
|
||||
}
|
||||
var toVersion = 2;
|
||||
if (fromVersion < toVersion) {
|
||||
for (var i = fromVersion + 1; i <= toVersion; i++) {
|
||||
switch (i) {
|
||||
case 1:
|
||||
// If a sync username is entered and ZFS is enabled, turn
|
||||
// on-demand downloading off to maintain current behavior
|
||||
if (this.get('sync.server.username')) {
|
||||
if (this.get('sync.storage.enabled')
|
||||
&& this.get('sync.storage.protocol') == 'zotero') {
|
||||
this.set('sync.storage.downloadMode.personal', 'on-sync');
|
||||
}
|
||||
if (this.get('sync.storage.groups.enabled')) {
|
||||
this.set('sync.storage.downloadMode.groups', 'on-sync');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Re-show saveButton guidance panel (and clear old saveIcon pref).
|
||||
// The saveButton guidance panel initially could auto-hide too easily.
|
||||
this.clear('firstRunGuidanceShown.saveIcon');
|
||||
this.clear('firstRunGuidanceShown.saveButton');
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.set('prefVersion', toVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a preference
|
||||
**/
|
||||
function get(pref, global){
|
||||
try {
|
||||
if (global) {
|
||||
var branch = Services.prefs.getBranch("");
|
||||
}
|
||||
else {
|
||||
var branch = this.prefBranch;
|
||||
}
|
||||
|
||||
switch (branch.getPrefType(pref)){
|
||||
case branch.PREF_BOOL:
|
||||
return branch.getBoolPref(pref);
|
||||
case branch.PREF_STRING:
|
||||
return '' + branch.getComplexValue(pref, Components.interfaces.nsISupportsString);
|
||||
case branch.PREF_INT:
|
||||
return branch.getIntPref(pref);
|
||||
}
|
||||
}
|
||||
catch (e){
|
||||
throw ("Invalid preference '" + pref + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a preference
|
||||
**/
|
||||
function set(pref, value, global) {
|
||||
try {
|
||||
if (global) {
|
||||
var branch = Services.prefs.getBranch("");
|
||||
}
|
||||
else {
|
||||
var branch = this.prefBranch;
|
||||
}
|
||||
|
||||
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);
|
||||
case branch.PREF_INT:
|
||||
return branch.setIntPref(pref, value);
|
||||
|
||||
// If not an existing pref, create appropriate type automatically
|
||||
case 0:
|
||||
if (typeof value == 'boolean') {
|
||||
Zotero.debug("Creating boolean pref '" + pref + "'");
|
||||
return branch.setBoolPref(pref, value);
|
||||
}
|
||||
if (typeof value == 'string') {
|
||||
Zotero.debug("Creating string pref '" + pref + "'");
|
||||
return branch.setCharPref(pref, value);
|
||||
}
|
||||
if (parseInt(value) == value) {
|
||||
Zotero.debug("Creating integer pref '" + pref + "'");
|
||||
return branch.setIntPref(pref, value);
|
||||
}
|
||||
throw new Error("Invalid preference value '" + value + "' for pref '" + pref + "'");
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
throw new Error("Invalid preference '" + pref + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.clear = function (pref, global) {
|
||||
if (global) {
|
||||
var branch = Services.prefs.getBranch("");
|
||||
}
|
||||
else {
|
||||
var branch = this.prefBranch;
|
||||
}
|
||||
branch.clearUserPref(pref);
|
||||
}
|
||||
|
||||
|
||||
this.resetBranch = function (exclude = []) {
|
||||
var keys = this.prefBranch.getChildList("", {});
|
||||
for (let key of keys) {
|
||||
if (this.prefBranch.prefHasUserValue(key)) {
|
||||
if (exclude.includes(key)) {
|
||||
continue;
|
||||
}
|
||||
Zotero.debug("Clearing " + key);
|
||||
this.prefBranch.clearUserPref(key);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Import settings bundles
|
||||
this.importSettings = function (str, uri) {
|
||||
var ps = Services.prompt;
|
||||
|
||||
if (!uri.match(/https:\/\/([^\.]+\.)?zotero.org\//)) {
|
||||
Zotero.debug("Ignoring settings file not from https://zotero.org");
|
||||
return;
|
||||
}
|
||||
|
||||
str = Zotero.Utilities.trim(str.replace(/<\?xml.*\?>\s*/, ''));
|
||||
Zotero.debug(str);
|
||||
|
||||
var confirm = ps.confirm(
|
||||
null,
|
||||
"",
|
||||
"Apply settings from zotero.org?"
|
||||
);
|
||||
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: parse settings XML
|
||||
}
|
||||
|
||||
// Handlers for some Zotero preferences
|
||||
var _handlers = [
|
||||
[ "automaticScraperUpdates", function(val) {
|
||||
if (val){
|
||||
Zotero.Schema.updateFromRepository(1);
|
||||
}
|
||||
else {
|
||||
Zotero.Schema.stopRepositoryTimer();
|
||||
}
|
||||
}],
|
||||
["fontSize", function (val) {
|
||||
Zotero.setFontSize(
|
||||
Zotero.getActiveZoteroPane().document.getElementById('zotero-pane')
|
||||
);
|
||||
}],
|
||||
[ "layout", function(val) {
|
||||
Zotero.getActiveZoteroPane().updateLayout();
|
||||
}],
|
||||
[ "note.fontSize", function(val) {
|
||||
if (val < 6) {
|
||||
Zotero.Prefs.set('note.fontSize', 11);
|
||||
}
|
||||
}],
|
||||
[ "zoteroDotOrgVersionHeader", function(val) {
|
||||
if (val) {
|
||||
Zotero.VersionHeader.register();
|
||||
}
|
||||
else {
|
||||
Zotero.VersionHeader.unregister();
|
||||
}
|
||||
}],
|
||||
[ "sync.autoSync", function(val) {
|
||||
if (val) {
|
||||
Zotero.Sync.EventListeners.AutoSyncListener.register();
|
||||
Zotero.Sync.EventListeners.IdleListener.register();
|
||||
}
|
||||
else {
|
||||
Zotero.Sync.EventListeners.AutoSyncListener.unregister();
|
||||
Zotero.Sync.EventListeners.IdleListener.unregister();
|
||||
}
|
||||
}],
|
||||
[ "search.quicksearch-mode", function(val) {
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var enumerator = wm.getEnumerator("navigator:browser");
|
||||
while (enumerator.hasMoreElements()) {
|
||||
var win = enumerator.getNext();
|
||||
if (!win.ZoteroPane) continue;
|
||||
Zotero.updateQuickSearchBox(win.ZoteroPane.document);
|
||||
}
|
||||
|
||||
var enumerator = wm.getEnumerator("zotero:item-selector");
|
||||
while (enumerator.hasMoreElements()) {
|
||||
var win = enumerator.getNext();
|
||||
if (!win.Zotero) continue;
|
||||
Zotero.updateQuickSearchBox(win.document);
|
||||
}
|
||||
}]
|
||||
];
|
||||
|
||||
//
|
||||
// Methods to register a preferences observer
|
||||
//
|
||||
function register(){
|
||||
this.prefBranch.QueryInterface(Components.interfaces.nsIPrefBranch2);
|
||||
this.prefBranch.addObserver("", this, false);
|
||||
|
||||
// Register pre-set handlers
|
||||
for (var i=0; i<_handlers.length; i++) {
|
||||
this.registerObserver(_handlers[i][0], _handlers[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
function unregister(){
|
||||
if (!this.prefBranch){
|
||||
return;
|
||||
}
|
||||
this.prefBranch.removeObserver("", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {nsIPrefBranch} subject The nsIPrefBranch we're observing (after appropriate QI)
|
||||
* @param {String} topic The string defined by NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
|
||||
* @param {String} data The name of the pref that's been changed (relative to subject)
|
||||
*/
|
||||
function observe(subject, topic, data){
|
||||
if (topic != "nsPref:changed" || !_observers[data] || !_observers[data].length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var obs = _observers[data];
|
||||
for (var i=0; i<obs.length; i++) {
|
||||
try {
|
||||
obs[i](this.get(data));
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug("Error while executing preference observer handler for " + data);
|
||||
Zotero.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _observers = {};
|
||||
this.registerObserver = function(name, handler) {
|
||||
_observers[name] = _observers[name] || [];
|
||||
_observers[name].push(handler);
|
||||
}
|
||||
|
||||
this.unregisterObserver = function(name, handler) {
|
||||
var obs = _observers[name];
|
||||
if (!obs) {
|
||||
Zotero.debug("No preferences observer registered for " + name);
|
||||
return;
|
||||
}
|
||||
|
||||
var i = obs.indexOf(handler);
|
||||
if (i == -1) {
|
||||
Zotero.debug("Handler was not registered for preference " + name);
|
||||
return;
|
||||
}
|
||||
|
||||
obs.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handles keyboard shortcut initialization from preferences, optionally
|
||||
|
|
|
@ -3898,30 +3898,6 @@ var ZoteroPane = new function()
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Promise<Zotero.Item>|false}
|
||||
*/
|
||||
this.addItemFromPage = Zotero.Promise.method(function (itemType, saveSnapshot, row) {
|
||||
if (row == undefined && this.collectionsView && this.collectionsView.selection) {
|
||||
row = this.collectionsView.selection.currentIndex;
|
||||
}
|
||||
|
||||
if (row !== undefined) {
|
||||
if (!this.canEdit(row)) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
var collectionTreeRow = this.collectionsView.getRow(row);
|
||||
if (collectionTreeRow.isPublications()) {
|
||||
this.displayCannotAddToMyPublicationsMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return this.addItemFromDocument(window.content.document, itemType, saveSnapshot, row);
|
||||
});
|
||||
|
||||
/**
|
||||
* Shows progress dialog for a webpage/snapshot save request
|
||||
*/
|
||||
|
@ -4061,10 +4037,6 @@ var ZoteroPane = new function()
|
|||
* @return {Zotero.Item|false} - The saved item, or false if item can't be saved
|
||||
*/
|
||||
this.addItemFromURL = Zotero.Promise.coroutine(function* (url, itemType, saveSnapshot, row) {
|
||||
if (window.content && url == window.content.document.location.href) {
|
||||
return this.addItemFromPage(itemType, saveSnapshot, row);
|
||||
}
|
||||
|
||||
url = Zotero.Utilities.resolveIntermediateURL(url);
|
||||
|
||||
let [mimeType, hasNativeHandler] = yield Zotero.MIME.getMIMETypeFromURL(url);
|
||||
|
@ -4079,12 +4051,12 @@ var ZoteroPane = new function()
|
|||
deferred.resolve(item)
|
||||
});
|
||||
};
|
||||
var done = function () {}
|
||||
var exception = function (e) {
|
||||
try {
|
||||
yield Zotero.HTTP.processDocuments([url], processor);
|
||||
} catch (e) {
|
||||
Zotero.debug(e, 1);
|
||||
deferred.reject(e);
|
||||
}
|
||||
Zotero.HTTP.loadDocuments([url], processor, done, exception);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
|
|
@ -33,10 +33,14 @@ const Ci = Components.interfaces;
|
|||
/** XPCOM files to be loaded for all modes **/
|
||||
const xpcomFilesAll = [
|
||||
'zotero',
|
||||
'intl',
|
||||
'prefs',
|
||||
'dataDirectory',
|
||||
'date',
|
||||
'debug',
|
||||
'error',
|
||||
'utilities',
|
||||
'utilities_internal',
|
||||
'file',
|
||||
'http',
|
||||
'mimeTypeHandler',
|
||||
|
@ -49,9 +53,7 @@ const xpcomFilesAll = [
|
|||
'translation/translate_firefox',
|
||||
'translation/translator',
|
||||
'translation/tlds',
|
||||
'utilities',
|
||||
'isbn',
|
||||
'utilities_internal',
|
||||
'utilities_translate'
|
||||
];
|
||||
|
||||
|
@ -456,9 +458,7 @@ var _isStandalone = null;
|
|||
*/
|
||||
function isStandalone() {
|
||||
if(_isStandalone === null) {
|
||||
var appInfo = Components.classes["@mozilla.org/xre/app-info;1"].
|
||||
getService(Components.interfaces.nsIXULAppInfo);
|
||||
_isStandalone = appInfo.ID === 'zotero@chnm.gmu.edu';
|
||||
_isStandalone = Services.appinfo.ID === 'zotero@chnm.gmu.edu';
|
||||
}
|
||||
return _isStandalone;
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ pref("extensions.zotero.firstRun2", true);
|
|||
pref("extensions.zotero@chnm.gmu.edu.description", "chrome://zotero/locale/zotero.properties");
|
||||
|
||||
pref("extensions.zotero.saveRelativeAttachmentPath", false);
|
||||
pref("extensions.zotero.baseAttachmentPath", '');
|
||||
pref("extensions.zotero.baseAttachmentPath", "");
|
||||
pref("extensions.zotero.useDataDir", false);
|
||||
pref("extensions.zotero.dataDir", '');
|
||||
pref("extensions.zotero.dataDir", "");
|
||||
pref("extensions.zotero.warnOnUnsafeDataDir", true);
|
||||
pref("extensions.zotero.debug.log",false);
|
||||
pref("extensions.zotero.debug.log.slowTime", 250);
|
||||
|
@ -23,7 +23,7 @@ pref("extensions.zotero.automaticScraperUpdates",true);
|
|||
pref("extensions.zotero.zoteroDotOrgVersionHeader", true);
|
||||
pref("extensions.zotero.triggerProxyAuthentication", true);
|
||||
// Proxy auth URLs should respond successfully to HEAD requests over HTTP and HTTPS (in case of forced HTTPS requests)
|
||||
pref("extensions.zotero.proxyAuthenticationURLs", 'https://www.acm.org,https://www.ebscohost.com,https://www.sciencedirect.com,https://ieeexplore.ieee.org,https://www.jstor.org,http://www.ovid.com,https://link.springer.com,https://www.tandfonline.com');
|
||||
pref("extensions.zotero.proxyAuthenticationURLs", "https://www.acm.org,https://www.ebscohost.com,https://www.sciencedirect.com,https://ieeexplore.ieee.org,https://www.jstor.org,http://www.ovid.com,https://link.springer.com,https://www.tandfonline.com");
|
||||
pref("extensions.zotero.browserContentContextMenu", true);
|
||||
pref("extensions.zotero.openURL.resolver","http://worldcatlibraries.org/registry/gateway");
|
||||
pref("extensions.zotero.openURL.version","1.0");
|
||||
|
@ -39,7 +39,7 @@ pref("extensions.zotero.recursiveCollections", false);
|
|||
pref("extensions.zotero.autoRecognizeFiles", true);
|
||||
pref("extensions.zotero.autoRenameFiles", true);
|
||||
pref("extensions.zotero.autoRenameFiles.fileTypes", "application/pdf");
|
||||
pref("extensions.zotero.attachmentRenameFormatString", '{%c - }{%y - }{%t{50}}');
|
||||
pref("extensions.zotero.attachmentRenameFormatString", "{%c - }{%y - }{%t{50}}");
|
||||
pref("extensions.zotero.capitalizeTitles", false);
|
||||
pref("extensions.zotero.launchNonNativeFiles", false);
|
||||
pref("extensions.zotero.sortNotesChronologically", false);
|
||||
|
@ -69,26 +69,26 @@ pref("extensions.zotero.lastRenameAssociatedFile", false);
|
|||
pref("extensions.zotero.lastLongTagMode", 0);
|
||||
pref("extensions.zotero.lastLongTagDelimiter", ";");
|
||||
|
||||
pref("extensions.zotero.fallbackSort", 'firstCreator,date,title,dateAdded');
|
||||
pref("extensions.zotero.fallbackSort", "firstCreator,date,title,dateAdded");
|
||||
pref("extensions.zotero.sortCreatorAsString", false);
|
||||
|
||||
//Tag Cloud
|
||||
pref("extensions.zotero.tagCloud", false);
|
||||
|
||||
// Keyboard shortcuts
|
||||
pref("extensions.zotero.keys.openZotero", 'Z');
|
||||
pref("extensions.zotero.keys.toggleFullscreen", 'F');
|
||||
pref("extensions.zotero.keys.saveToZotero", 'S');
|
||||
pref("extensions.zotero.keys.newItem", 'N');
|
||||
pref("extensions.zotero.keys.newNote", 'O');
|
||||
pref("extensions.zotero.keys.library", 'L');
|
||||
pref("extensions.zotero.keys.quicksearch", 'K');
|
||||
pref("extensions.zotero.keys.copySelectedItemCitationsToClipboard", 'A');
|
||||
pref("extensions.zotero.keys.copySelectedItemsToClipboard", 'C');
|
||||
pref("extensions.zotero.keys.toggleTagSelector", 'T');
|
||||
pref("extensions.zotero.keys.sync", 'Y');
|
||||
pref("extensions.zotero.keys.toggleAllRead", 'R');
|
||||
pref("extensions.zotero.keys.toggleRead", '`');
|
||||
pref("extensions.zotero.keys.openZotero", "Z");
|
||||
pref("extensions.zotero.keys.toggleFullscreen", "F");
|
||||
pref("extensions.zotero.keys.saveToZotero", "S");
|
||||
pref("extensions.zotero.keys.newItem", "N");
|
||||
pref("extensions.zotero.keys.newNote", "O");
|
||||
pref("extensions.zotero.keys.library", "L");
|
||||
pref("extensions.zotero.keys.quicksearch", "K");
|
||||
pref("extensions.zotero.keys.copySelectedItemCitationsToClipboard", "A");
|
||||
pref("extensions.zotero.keys.copySelectedItemsToClipboard", "C");
|
||||
pref("extensions.zotero.keys.toggleTagSelector", "T");
|
||||
pref("extensions.zotero.keys.sync", "Y");
|
||||
pref("extensions.zotero.keys.toggleAllRead", "R");
|
||||
pref("extensions.zotero.keys.toggleRead", "`");
|
||||
|
||||
pref("extensions.zotero.search.quicksearch-mode", "fields");
|
||||
|
||||
|
@ -107,10 +107,10 @@ pref("extensions.zotero.report.includeAllChildItems", true);
|
|||
pref("extensions.zotero.report.combineChildItems", true);
|
||||
|
||||
// Export and citation settings
|
||||
pref("extensions.zotero.export.lastTranslator", '14763d24-8ba0-45df-8f52-b8d1108e7ac9');
|
||||
pref("extensions.zotero.export.translatorSettings", 'true,false');
|
||||
pref("extensions.zotero.export.lastStyle", 'http://www.zotero.org/styles/chicago-note-bibliography');
|
||||
pref("extensions.zotero.export.bibliographySettings", 'save-as-rtf');
|
||||
pref("extensions.zotero.export.lastTranslator", "14763d24-8ba0-45df-8f52-b8d1108e7ac9");
|
||||
pref("extensions.zotero.export.translatorSettings", "true,false");
|
||||
pref("extensions.zotero.export.lastStyle", "http://www.zotero.org/styles/chicago-note-bibliography");
|
||||
pref("extensions.zotero.export.bibliographySettings", "save-as-rtf");
|
||||
pref("extensions.zotero.export.displayCharsetOption", true);
|
||||
pref("extensions.zotero.export.citePaperJournalArticleURL", false);
|
||||
pref("extensions.zotero.cite.automaticJournalAbbreviations", true);
|
||||
|
@ -119,7 +119,7 @@ pref("extensions.zotero.import.createNewCollection.fromFileOpenHandler", true);
|
|||
pref("extensions.zotero.rtfScan.lastInputFile", "");
|
||||
pref("extensions.zotero.rtfScan.lastOutputFile", "");
|
||||
|
||||
pref("extensions.zotero.export.quickCopy.setting", 'bibliography=http://www.zotero.org/styles/chicago-note-bibliography');
|
||||
pref("extensions.zotero.export.quickCopy.setting", "bibliography=http://www.zotero.org/styles/chicago-note-bibliography");
|
||||
pref("extensions.zotero.export.quickCopy.dragLimit", 50);
|
||||
pref("extensions.zotero.export.quickCopy.quoteBlockquotes.plainText", true);
|
||||
pref("extensions.zotero.export.quickCopy.quoteBlockquotes.richText", true);
|
||||
|
@ -147,14 +147,14 @@ pref("extensions.zotero.streaming.enabled", true);
|
|||
|
||||
// Sync
|
||||
pref("extensions.zotero.sync.autoSync", true);
|
||||
pref("extensions.zotero.sync.server.username", '');
|
||||
pref("extensions.zotero.sync.server.username", "");
|
||||
pref("extensions.zotero.sync.server.compressData", true);
|
||||
pref("extensions.zotero.sync.storage.enabled", true);
|
||||
pref("extensions.zotero.sync.storage.protocol", "zotero");
|
||||
pref("extensions.zotero.sync.storage.verified", false);
|
||||
pref("extensions.zotero.sync.storage.scheme", 'https');
|
||||
pref("extensions.zotero.sync.storage.url", '');
|
||||
pref("extensions.zotero.sync.storage.username", '');
|
||||
pref("extensions.zotero.sync.storage.scheme", "https");
|
||||
pref("extensions.zotero.sync.storage.url", "");
|
||||
pref("extensions.zotero.sync.storage.username", "");
|
||||
pref("extensions.zotero.sync.storage.maxDownloads", 4);
|
||||
pref("extensions.zotero.sync.storage.maxUploads", 2);
|
||||
pref("extensions.zotero.sync.storage.deleteDelayDays", 30);
|
||||
|
@ -177,7 +177,7 @@ pref("extensions.zotero.purge.items", false);
|
|||
pref("extensions.zotero.purge.tags", false);
|
||||
|
||||
// Zotero pane persistent data
|
||||
pref("extensions.zotero.pane.persist", '');
|
||||
pref("extensions.zotero.pane.persist", "");
|
||||
|
||||
// Domains allowed to import, separated by a semicolon
|
||||
pref("extensions.zotero.ingester.allowedSites", "");
|
||||
|
|
|
@ -24,9 +24,13 @@
|
|||
*/
|
||||
|
||||
EXPORTED_SYMBOLS = ["ConcurrentCaller"];
|
||||
Components.utils.import('resource://zotero/require.js');
|
||||
|
||||
var Promise = require('resource://zotero/bluebird.js');
|
||||
if (!(typeof process === 'object' && process + '' === '[object process]')) {
|
||||
Components.utils.import('resource://zotero/require.js');
|
||||
var Promise = require('resource://zotero/bluebird.js');
|
||||
} else {
|
||||
Promise = require('bluebird');
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a fixed number of functions at once, queueing the rest until slots
|
||||
|
@ -272,3 +276,7 @@ ConcurrentCaller.prototype._log = function (msg) {
|
|||
this._logger("[ConcurrentCaller] " + (this._id ? `[${this._id}] ` : "") + msg);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof process === 'object' && process + '' === '[object process]'){
|
||||
module.exports = ConcurrentCaller;
|
||||
}
|
||||
|
|
|
@ -28,4 +28,8 @@ var ZOTERO_CONFIG = {
|
|||
CONNECTORS_URL: "https://www.zotero.org/download/connectors"
|
||||
};
|
||||
|
||||
EXPORTED_SYMBOLS = ["ZOTERO_CONFIG"];
|
||||
if (typeof process === 'object' && process + '' === '[object process]'){
|
||||
module.exports = ZOTERO_CONFIG;
|
||||
} else {
|
||||
EXPORTED_SYMBOLS = ["ZOTERO_CONFIG"];
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ describe("Zotero.Date", function() {
|
|||
beforeEach(function* () {
|
||||
if (Zotero.locale != 'en-US') {
|
||||
Zotero.locale = 'en-US';
|
||||
yield Zotero.Date.init();
|
||||
Zotero.Date.init();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -52,7 +52,7 @@ describe("Zotero.Date", function() {
|
|||
|
||||
it("should resolve to English from unknown locale", function* () {
|
||||
Zotero.locale = 'zz';
|
||||
yield Zotero.Date.init();
|
||||
Zotero.Date.init();
|
||||
let months = Zotero.Date.getMonths().short;
|
||||
assert.lengthOf(months, 12);
|
||||
assert.sameMembers(months, englishShort);
|
||||
|
@ -60,7 +60,7 @@ describe("Zotero.Date", function() {
|
|||
|
||||
it("shouldn't repeat English with unknown locale", function* () {
|
||||
Zotero.locale = 'zz';
|
||||
yield Zotero.Date.init();
|
||||
Zotero.Date.init();
|
||||
let months = Zotero.Date.getMonths(true).short;
|
||||
assert.lengthOf(months, 12);
|
||||
assert.sameMembers(months, englishShort);
|
||||
|
@ -71,7 +71,7 @@ describe("Zotero.Date", function() {
|
|||
beforeEach(function* () {
|
||||
if (Zotero.locale != 'fr-FR') {
|
||||
Zotero.locale = 'fr-FR';
|
||||
yield Zotero.Date.init();
|
||||
Zotero.Date.init();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -101,7 +101,7 @@ describe("Zotero.Date", function() {
|
|||
|
||||
it("should resolve from two-letter locale", function* () {
|
||||
Zotero.locale = 'fr';
|
||||
yield Zotero.Date.init();
|
||||
Zotero.Date.init();
|
||||
let months = Zotero.Date.getMonths().short;
|
||||
assert.lengthOf(months, 12);
|
||||
assert.sameMembers(months, frenchShort);
|
||||
|
@ -109,7 +109,7 @@ describe("Zotero.Date", function() {
|
|||
|
||||
it("should resolve from unknown four-letter locale with common prefix", function* () {
|
||||
Zotero.locale = 'fr-ZZ';
|
||||
yield Zotero.Date.init();
|
||||
Zotero.Date.init();
|
||||
let months = Zotero.Date.getMonths().short;
|
||||
assert.lengthOf(months, 12);
|
||||
assert.sameMembers(months, frenchShort);
|
||||
|
|
|
@ -62,7 +62,7 @@ describe("Zotero.Libraries", function() {
|
|||
});
|
||||
it("should return false for a non-existing ID", function() {
|
||||
assert.isFalse(Zotero.Libraries.exists(-1), "returns boolean false for a negative ID");
|
||||
let badID = Zotero.Libraries.getAll().map(library => library.libraryID).sort().pop() + 1;
|
||||
let badID = Zotero.Libraries.getAll().map(lib => lib.libraryID).reduce((a, b) => (a < b ? b : a)) + 1;
|
||||
assert.isFalse(Zotero.Libraries.exists(badID), "returns boolean false for a non-existent positive ID");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,8 +27,8 @@ describe("Zotero.Styles", function() {
|
|||
|
||||
it("should install the style from url", function* () {
|
||||
var getContentsFromURLAsync = Zotero.File.getContentsFromURLAsync;
|
||||
sinon.stub(Zotero.File, 'getContentsFromURLAsync').callsFake(function(style) {
|
||||
if (style.url == styleID) {
|
||||
sinon.stub(Zotero.File, 'getContentsFromURLAsync').callsFake(function(url) {
|
||||
if (url === styleID) {
|
||||
return Zotero.Promise.resolve(style);
|
||||
} else {
|
||||
return getContentsFromURLAsync.apply(Zotero.File, arguments);
|
||||
|
|
|
@ -67,7 +67,7 @@ describe("Zotero.Utilities.Internal", function () {
|
|||
});
|
||||
|
||||
afterEach(function () {
|
||||
spy.reset();
|
||||
spy.resetHistory();
|
||||
});
|
||||
|
||||
after(function () {
|
||||
|
@ -86,7 +86,7 @@ describe("Zotero.Utilities.Internal", function () {
|
|||
let val = yield gen.next().value;
|
||||
assert.isTrue(val);
|
||||
assert.isTrue(spy.calledWith(i));
|
||||
spy.reset();
|
||||
spy.resetHistory();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -102,7 +102,7 @@ describe("Zotero.Utilities.Internal", function () {
|
|||
let val = yield gen.next().value;
|
||||
assert.isTrue(val);
|
||||
assert.isTrue(spy.calledWith(i));
|
||||
spy.reset();
|
||||
spy.resetHistory();
|
||||
}
|
||||
|
||||
// Another interval would put us over maxTime, so return false immediately
|
||||
|
|
26
test/tests/zoteroIntlTest.js
Normal file
26
test/tests/zoteroIntlTest.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
"use strict";
|
||||
|
||||
describe("Zotero.Intl", function() {
|
||||
describe("#getString()", function () {
|
||||
it("should return the right plural form", function* () {
|
||||
if (Zotero.locale != 'en-US') {
|
||||
this.skip();
|
||||
}
|
||||
var str1 = Zotero.getString('fileInterface.itemsWereImported')
|
||||
.split(/;/)[1]
|
||||
.replace('%1$S', 2);
|
||||
var str2 = Zotero.getString('fileInterface.itemsWereImported', 2, 2);
|
||||
assert.equal(str1, str2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#localeCompare", function () {
|
||||
it("shouldn't ignore whitespace", function () {
|
||||
assert.equal(Zotero.localeCompare("Chang", "Chan H"), 1);
|
||||
});
|
||||
|
||||
it("shouldn't ignore leading punctuation", function () {
|
||||
assert.equal(Zotero.localeCompare("_Abcd", "Abcd"), -1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,33 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
describe("Zotero", function() {
|
||||
describe("#getString()", function () {
|
||||
it("should return the right plural form", function* () {
|
||||
if (Zotero.locale != 'en-US') {
|
||||
this.skip();
|
||||
}
|
||||
Components.utils.import("resource://gre/modules/PluralForm.jsm");
|
||||
var str1 = Zotero.getString('fileInterface.itemsWereImported')
|
||||
.split(/;/)[1]
|
||||
.replace('%1$S', 2);
|
||||
var str2 = Zotero.getString('fileInterface.itemsWereImported', 2, 2);
|
||||
Zotero.debug(str1);
|
||||
Zotero.debug(str2);
|
||||
assert.equal(str1, str2);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("#localeCompare", function () {
|
||||
it("shouldn't ignore whitespace", function () {
|
||||
assert.equal(Zotero.localeCompare("Chang", "Chan H"), 1);
|
||||
});
|
||||
|
||||
it("shouldn't ignore leading punctuation", function () {
|
||||
assert.equal(Zotero.localeCompare("_Abcd", "Abcd"), -1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("VersionHeader", function () {
|
||||
describe("#update()", function () {
|
||||
var majorMinorVersion;
|
||||
|
|
Loading…
Reference in a new issue