Merge branch 'electron'

This commit is contained in:
Dan Stillman 2018-08-16 19:16:46 -04:00
commit c2ca70055c
46 changed files with 1093 additions and 1116 deletions

View file

@ -108,9 +108,9 @@
function _setStartupError() {
Zotero.startupError = Zotero.localeJoin([
Zotero.startupError = [
Zotero.getString('upgrade.dbUpdateRequired'), Zotero.getString('general.restartFirefox')
]);
].join(' ');
}

View file

@ -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;

View file

@ -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;

View file

@ -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);
}
},

View file

@ -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

View file

@ -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'];

View file

@ -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;

View file

@ -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});
}
};

View file

@ -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]);
}
}
});
}
};

View file

@ -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';

View file

@ -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);

View file

@ -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;
}

View 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);
}
};
}
};

View file

@ -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';
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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();

View 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);
}
}

View file

@ -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);
};

View file

@ -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");
}
});

View file

@ -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;

View file

@ -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;
}

View file

@ -14,7 +14,7 @@ var $rdf = {
return;
}
}
throw "RDFArrayRemove: Array did not contain " + x;
throw new Error("RDFArrayRemove: Array did not contain " + x);
}
},
log: {

View file

@ -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.");
}

View file

@ -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
}

View file

@ -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

View file

@ -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`);
}

View file

@ -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");
}
}

View file

@ -224,7 +224,7 @@ Zotero.Sync.EventListeners.IdleListener = {
_backObserver: {
observe: function (subject, topic, data) {
if (topic != 'back') {
if (topic !== 'active') {
return;
}

View file

@ -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();

View file

@ -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) {

View file

@ -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;

View file

@ -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));
});
}

View file

@ -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)
**/

View file

@ -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()");

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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", "");

View file

@ -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;
}

View file

@ -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"];
}

View file

@ -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);

View file

@ -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");
});
});

View file

@ -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);

View file

@ -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

View 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);
});
});
});

View file

@ -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;