2006-10-04 17:16:56 +00:00
|
|
|
/*
|
|
|
|
***** BEGIN LICENSE BLOCK *****
|
|
|
|
|
2009-12-28 09:47:49 +00:00
|
|
|
Copyright © 2009 Center for History and New Media
|
|
|
|
George Mason University, Fairfax, Virginia, USA
|
|
|
|
http://zotero.org
|
2006-10-04 17:16:56 +00:00
|
|
|
|
2009-12-28 09:47:49 +00:00
|
|
|
This file is part of Zotero.
|
2006-10-04 17:16:56 +00:00
|
|
|
|
2009-12-28 09:47:49 +00:00
|
|
|
Zotero is free software: you can redistribute it and/or modify
|
2011-05-18 18:34:22 +00:00
|
|
|
it under the terms of the GNU Affero General Public License as published by
|
2009-12-28 09:47:49 +00:00
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2006-10-04 17:16:56 +00:00
|
|
|
|
2009-12-28 09:47:49 +00:00
|
|
|
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
|
2011-05-18 18:34:22 +00:00
|
|
|
GNU Affero General Public License for more details.
|
2009-12-28 09:47:49 +00:00
|
|
|
|
2011-05-18 18:34:22 +00:00
|
|
|
You should have received a copy of the GNU Affero General Public License
|
2009-12-28 09:47:49 +00:00
|
|
|
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
2006-10-04 17:16:56 +00:00
|
|
|
|
|
|
|
***** END LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
2012-07-17 01:50:14 +00:00
|
|
|
// Commonly used imports accessible anywhere
|
2014-12-09 23:37:43 +00:00
|
|
|
Components.utils.import("resource://zotero/config.js");
|
2012-07-17 01:50:14 +00:00
|
|
|
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
2013-08-17 05:16:58 +00:00
|
|
|
Components.utils.import("resource://gre/modules/osfile.jsm");
|
2012-07-17 01:50:14 +00:00
|
|
|
|
2006-02-21 17:01:06 +00:00
|
|
|
/*
|
|
|
|
* Core functions
|
|
|
|
*/
|
2011-06-14 00:36:21 +00:00
|
|
|
(function(){
|
2006-05-27 00:20:27 +00:00
|
|
|
// Privileged (public) methods
|
2006-03-20 21:47:22 +00:00
|
|
|
this.init = init;
|
2006-07-27 08:45:48 +00:00
|
|
|
this.getProfileDirectory = getProfileDirectory;
|
2006-10-02 23:15:27 +00:00
|
|
|
this.getZoteroDirectory = getZoteroDirectory;
|
2006-07-27 08:45:48 +00:00
|
|
|
this.getStorageDirectory = getStorageDirectory;
|
2006-10-02 23:15:27 +00:00
|
|
|
this.getZoteroDatabase = getZoteroDatabase;
|
2007-10-23 07:11:59 +00:00
|
|
|
this.chooseZoteroDirectory = chooseZoteroDirectory;
|
2006-03-20 21:47:22 +00:00
|
|
|
this.debug = debug;
|
2007-10-23 07:11:59 +00:00
|
|
|
this.log = log;
|
2010-11-02 21:39:54 +00:00
|
|
|
this.logError = logError;
|
2007-10-23 07:11:59 +00:00
|
|
|
this.getErrors = getErrors;
|
|
|
|
this.getSystemInfo = getSystemInfo;
|
2006-05-27 00:20:27 +00:00
|
|
|
this.getString = getString;
|
2007-10-23 07:11:59 +00:00
|
|
|
this.localeJoin = localeJoin;
|
|
|
|
this.setFontSize = setFontSize;
|
2006-03-20 21:47:22 +00:00
|
|
|
this.flattenArguments = flattenArguments;
|
Closes #259, auto-complete of tags
Addresses #260, Add auto-complete to search window
- New XPCOM autocomplete component for Zotero data -- can be used by setting the autocompletesearch attribute of a textbox to 'zotero' and passing a search scope with the autocompletesearchparam attribute. Additional parameters can be passed by appending them to the autocompletesearchparam value with a '/', e.g. 'tag/2732' (to exclude tags that show up in item 2732)
- Tag entry now uses more or less the same interface as metadata -- no more popup window -- note that tab isn't working properly yet, and there's no way to quickly enter multiple tags (though it's now considerably quicker than it was before)
- Autocomplete for tags, excluding any tags already set for the current item
- Standalone note windows now register with the Notifier (since tags needed item modification notifications to work properly), which will help with #282, "Notes opened in separate windows need item notification"
- Tags are now retrieved in alphabetical order
- Scholar.Item.replaceTag(oldTagID, newTag), with a single notify
- Scholar.getAncestorByTagName(elem, tagName) -- walk up the DOM tree from an element until an element with the specified tag name is found (also checks with 'xul:' prefix, for use in XBL), or false if not found -- probably shouldn't be used too widely, since it's doing string comparisons, but better than specifying, say, nine '.parentNode' properties, and makes for more resilient code
A few notes:
- Autocomplete in Minefield seems to self-destruct after using it in the same field a few times, taking down saving of the field with it -- this may or may not be my fault, but it makes Zotero more or less unusable in 3.0 at the moment. Sorry. (I use 3.0 myself for development, so I'll work on it.)
- This would have been much, much easier if having an autocomplete textbox (which uses an XBL-generated popup for the suggestions) within a popup (as it is in the independent note edit panes) didn't introduce all sorts of crazy bugs that had to be defeated with annoying hackery -- one side effect of this is that at the moment you can't close the tags popup with the Escape key
- Independent note windows now need to pull in itemPane.js to function properly, which is a bit messy and not ideal, but less messy and more ideal than duplicating all the dual-state editor and tabindex logic would be
- Hitting tab in a tag field not only doesn't work but also breaks things until the next window refresh.
- There are undoubtedly other bugs.
2006-09-07 08:07:48 +00:00
|
|
|
this.getAncestorByTagName = getAncestorByTagName;
|
2006-06-01 19:46:57 +00:00
|
|
|
this.randomString = randomString;
|
2006-08-01 23:10:31 +00:00
|
|
|
this.moveToUnique = moveToUnique;
|
2015-03-09 18:25:49 +00:00
|
|
|
this.reinit = reinit; // defined in zotero-service.js
|
2006-05-27 00:20:27 +00:00
|
|
|
|
2006-06-15 06:13:02 +00:00
|
|
|
// Public properties
|
2007-10-23 07:11:59 +00:00
|
|
|
this.initialized = false;
|
|
|
|
this.skipLoading = false;
|
2009-12-29 22:21:54 +00:00
|
|
|
this.startupError;
|
2007-10-23 07:11:59 +00:00
|
|
|
this.__defineGetter__("startupErrorHandler", function() { return _startupErrorHandler; });
|
2006-06-15 06:13:02 +00:00
|
|
|
this.version;
|
2006-08-30 19:18:43 +00:00
|
|
|
this.platform;
|
2006-09-06 07:04:02 +00:00
|
|
|
this.locale;
|
2007-10-23 07:11:59 +00:00
|
|
|
this.dir; // locale direction: 'ltr' or 'rtl'
|
2006-08-30 21:56:52 +00:00
|
|
|
this.isMac;
|
2007-10-23 07:11:59 +00:00
|
|
|
this.isWin;
|
|
|
|
this.initialURL; // used by Schema to show the changelog on upgrades
|
|
|
|
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
Components.utils.import("resource://zotero/bluebird.js", this);
|
2.0b3 megacommit
- Support for group libraries
- General support for multiple libraries of different types
- Streamlined sync support
- Using solely libraryID and key rather than itemID, and removed all itemID-changing code
- Combined two requests for increased performance and decreased server load
- Added warning on user account change
- Provide explicit error message on SSL failure
- Removed snapshot and link toolbar buttons and changed browser context menu options and drags to create parent items + snapshots
- Closes #786, Add numPages field
- Fixes #1063, Duplicate item with tags broken in Sync Preview
- Added better purging of deleted tags
- Added local user key before first sync
- Add clientDateModified to all objects for more flexibility in syncing
- Added new triples-based Relation object type, currently used to store links between items copied between local and group libraries
- Updated zotero.org translator for groups
- Additional trigger-based consistency checks
- Fixed broken URL drag in Firefox 3.5
- Disabled zeroconf menu option (no longer functional)
Developer-specific changes:
- Overhauled data layer
- Data object constructors no longer take arguments (return to 1.0-like API)
- Existing objects can be retrieved by setting id or library/key properties
- id/library/key must be set for new objects before other fields
- New methods:
- ZoteroPane.getSelectedLibraryID()
- ZoteroPane.getSelectedGroup(asID)
- ZoteroPane.addItemFromDocument(doc, itemType, saveSnapshot)
- ZoteroPane.addItemFromURL(url, itemType)
- ZoteroPane.canEdit()
- Zotero.CollectionTreeView.selectLibrary(libraryID)
- New Zotero.URI methods
- Changed methods
- Many data object methods now take a libraryID
- ZoteroPane.addAttachmentFromPage(link, itemID)
- Removed saveItem and saveAttachments parameters from Zotero.Translate constructor
- translate() now takes a libraryID, null for local library, or false to not save items (previously on constructor)
- saveAttachments is now a translate() parameter
- Zotero.flattenArguments() better handles passed objects
- Zotero.File.getFileHash() (not currently used)
2009-05-14 18:23:40 +00:00
|
|
|
|
2011-01-31 20:28:42 +00:00
|
|
|
this.getActiveZoteroPane = function() {
|
2013-06-06 06:37:19 +00:00
|
|
|
return Services.wm.getMostRecentWindow("navigator:browser").ZoteroPane;
|
2011-01-31 20:28:42 +00:00
|
|
|
};
|
|
|
|
|
2009-08-08 07:38:34 +00:00
|
|
|
/**
|
|
|
|
* @property {Boolean} locked Whether all Zotero panes are locked
|
|
|
|
* with an overlay
|
|
|
|
*/
|
|
|
|
this.__defineGetter__('locked', function () _locked);
|
2013-08-12 00:51:16 +00:00
|
|
|
this.__defineSetter__('locked', function (lock) {
|
|
|
|
var wasLocked = _locked;
|
|
|
|
_locked = lock;
|
|
|
|
|
|
|
|
if (!wasLocked && lock) {
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
this.unlockDeferred = Zotero.Promise.defer();
|
2013-08-12 00:51:16 +00:00
|
|
|
this.unlockPromise = this.unlockDeferred.promise;
|
|
|
|
}
|
|
|
|
else if (wasLocked && !lock) {
|
|
|
|
Zotero.debug("Running unlock callbacks");
|
|
|
|
this.unlockDeferred.resolve();
|
|
|
|
}
|
|
|
|
});
|
2009-08-08 07:38:34 +00:00
|
|
|
|
2011-07-03 04:15:49 +00:00
|
|
|
/**
|
|
|
|
* @property {Boolean} closing True if the application is closing.
|
|
|
|
*/
|
|
|
|
this.closing = false;
|
|
|
|
|
2013-08-12 00:51:16 +00:00
|
|
|
|
|
|
|
this.initializationDeferred;
|
|
|
|
this.initializationPromise;
|
|
|
|
this.unlockDeferred;
|
|
|
|
this.unlockPromise;
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
var _startupErrorHandler;
|
|
|
|
var _zoteroDirectory = false;
|
|
|
|
var _localizedStringBundle;
|
2009-08-09 19:39:32 +00:00
|
|
|
|
2013-08-12 00:51:16 +00:00
|
|
|
var _locked = false;
|
2011-06-14 00:36:21 +00:00
|
|
|
var _shutdownListeners = [];
|
2009-08-09 19:39:32 +00:00
|
|
|
var _progressMeters;
|
2011-09-21 23:00:20 +00:00
|
|
|
var _progressPopup;
|
2009-08-09 19:39:32 +00:00
|
|
|
var _lastPercentage;
|
2006-06-15 06:13:02 +00:00
|
|
|
|
2011-06-14 00:36:21 +00:00
|
|
|
// whether we are waiting for another Zotero process to release its DB lock
|
|
|
|
var _waitingForDBLock = false;
|
|
|
|
|
2013-06-06 23:31:09 +00:00
|
|
|
/**
|
|
|
|
* Maintains nsITimers to be used when Zotero.wait() completes (to reduce performance penalty
|
|
|
|
* of initializing new objects)
|
|
|
|
*/
|
|
|
|
var _waitTimers = [];
|
|
|
|
|
2012-07-26 01:44:08 +00:00
|
|
|
/**
|
|
|
|
* Maintains nsITimerCallbacks to be used when Zotero.wait() completes
|
|
|
|
*/
|
|
|
|
var _waitTimerCallbacks = [];
|
2011-05-31 19:59:07 +00:00
|
|
|
|
2013-06-06 23:31:09 +00:00
|
|
|
/**
|
|
|
|
* Maintains running nsITimers in global scope, so that they don't disappear randomly
|
|
|
|
*/
|
2016-05-17 15:49:13 +00:00
|
|
|
var _runningTimers = new Map();
|
2013-06-06 23:31:09 +00:00
|
|
|
|
2012-02-14 01:42:32 +00:00
|
|
|
// Errors that were in the console at startup
|
|
|
|
var _startupErrors = [];
|
|
|
|
// Number of errors to maintain in the recent errors buffer
|
|
|
|
const ERROR_BUFFER_SIZE = 25;
|
|
|
|
// A rolling buffer of the last ERROR_BUFFER_SIZE errors
|
|
|
|
var _recentErrors = [];
|
|
|
|
|
2011-06-14 00:36:21 +00:00
|
|
|
/**
|
2006-02-21 17:01:06 +00:00
|
|
|
* Initialize the extension
|
2013-08-12 00:51:16 +00:00
|
|
|
*
|
|
|
|
* @return {Boolean|Promise:Boolean}
|
2006-02-21 17:01:06 +00:00
|
|
|
*/
|
2013-11-30 06:55:48 +00:00
|
|
|
function init(options) {
|
2007-10-23 07:11:59 +00:00
|
|
|
if (this.initialized || this.skipLoading) {
|
2006-05-27 00:20:27 +00:00
|
|
|
return false;
|
2006-03-20 21:47:22 +00:00
|
|
|
}
|
2006-05-27 00:20:27 +00:00
|
|
|
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
this.initializationDeferred = Zotero.Promise.defer();
|
2013-08-12 00:51:16 +00:00
|
|
|
this.initializationPromise = this.initializationDeferred.promise;
|
|
|
|
this.locked = true;
|
|
|
|
|
2015-05-23 07:04:32 +00:00
|
|
|
// Add a function to Zotero.Promise to check whether a value is still defined, and if not
|
|
|
|
// to throw a specific error that's ignored by the unhandled rejection handler in
|
|
|
|
// bluebird.js. This allows for easily cancelling promises when they're no longer
|
2015-05-24 21:39:27 +00:00
|
|
|
// needed, for example after a binding is destroyed.
|
2015-05-23 07:04:32 +00:00
|
|
|
//
|
|
|
|
// Example usage:
|
|
|
|
//
|
2015-05-24 21:39:27 +00:00
|
|
|
// getAsync.tap(() => Zotero.Promise.check(this.mode))
|
2015-05-23 07:04:32 +00:00
|
|
|
//
|
2015-05-24 21:39:27 +00:00
|
|
|
// If the binding is destroyed while getAsync() is being resolved and this.mode no longer
|
|
|
|
// exists, subsequent lines won't be run, and nothing will be logged to the console.
|
2015-05-23 07:04:32 +00:00
|
|
|
this.Promise.check = function (val) {
|
|
|
|
if (!val && val !== 0) {
|
|
|
|
let e = new Error;
|
|
|
|
e.name = "ZoteroPromiseInterrupt";
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2006-06-25 07:31:01 +00:00
|
|
|
// Load in the preferences branch for the extension
|
2006-10-02 23:15:27 +00:00
|
|
|
Zotero.Prefs.init();
|
2013-11-30 06:55:48 +00:00
|
|
|
Zotero.Debug.init(options && options.forceDebugLog);
|
|
|
|
|
|
|
|
if (options) {
|
|
|
|
if (options.openPane) this.openPane = true;
|
2016-06-24 22:28:32 +00:00
|
|
|
if (options.automatedTest) this.automatedTest = true;
|
2015-04-16 21:35:38 +00:00
|
|
|
if (options.skipBundledFiles) this.skipBundledFiles = true;
|
2013-11-30 06:55:48 +00:00
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
|
2013-06-06 06:37:19 +00:00
|
|
|
this.mainThread = Services.tm.mainThread;
|
2009-08-09 10:51:12 +00:00
|
|
|
|
2015-02-23 08:31:52 +00:00
|
|
|
this.clientName = ZOTERO_CONFIG.CLIENT_NAME;
|
|
|
|
|
2013-07-23 00:23:48 +00:00
|
|
|
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]);
|
2010-11-02 21:39:54 +00:00
|
|
|
this.isFx = true;
|
2013-06-06 06:37:19 +00:00
|
|
|
this.isStandalone = Services.appinfo.ID == ZOTERO_CONFIG['GUID'];
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
return Zotero.Promise.try(function () {
|
2013-08-12 07:06:54 +00:00
|
|
|
if(Zotero.isStandalone) {
|
|
|
|
return Services.appinfo.version;
|
|
|
|
} else {
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
var deferred = Zotero.Promise.defer();
|
2013-08-12 07:06:54 +00:00
|
|
|
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
|
|
|
AddonManager.getAddonByID(
|
|
|
|
ZOTERO_CONFIG.GUID,
|
|
|
|
function (addon) {
|
|
|
|
deferred.resolve(addon.version);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
return deferred.promise;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.then(function (version) {
|
|
|
|
Zotero.version = version;
|
2012-01-17 01:39:08 +00:00
|
|
|
|
2013-08-12 07:06:54 +00:00
|
|
|
// OS platform
|
|
|
|
var win = Components.classes["@mozilla.org/appshell/appShellService;1"]
|
|
|
|
.getService(Components.interfaces.nsIAppShellService)
|
|
|
|
.hiddenDOMWindow;
|
|
|
|
this.platform = win.navigator.platform;
|
|
|
|
this.isMac = (this.platform.substr(0, 3) == "Mac");
|
|
|
|
this.isWin = (this.platform.substr(0, 3) == "Win");
|
|
|
|
this.isLinux = (this.platform.substr(0, 5) == "Linux");
|
|
|
|
this.oscpu = win.navigator.oscpu;
|
|
|
|
|
|
|
|
// Browser
|
|
|
|
Zotero.browser = "g";
|
|
|
|
|
|
|
|
// Locale
|
|
|
|
var uaPrefs = Services.prefs.getBranch("general.useragent.");
|
|
|
|
try {
|
|
|
|
this.locale = uaPrefs.getComplexValue("locale", Components.interfaces.nsIPrefLocalizedString);
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
|
|
if(this.locale) {
|
|
|
|
this.locale = this.locale.toString();
|
|
|
|
} else {
|
|
|
|
this.locale = uaPrefs.getCharPref("locale");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.locale.length == 2) {
|
|
|
|
this.locale = this.locale + '-' + this.locale.toUpperCase();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load in the localization stringbundle for use by getString(name)
|
|
|
|
var appLocale = Services.locale.getApplicationLocale();
|
|
|
|
|
|
|
|
_localizedStringBundle = Services.strings.createBundle(
|
|
|
|
"chrome://zotero/locale/zotero.properties", appLocale);
|
|
|
|
|
|
|
|
// Also load the brand as appName
|
|
|
|
var brandBundle = Services.strings.createBundle(
|
|
|
|
"chrome://branding/locale/brand.properties", appLocale);
|
|
|
|
this.appName = brandBundle.GetStringFromName("brandShortName");
|
|
|
|
|
|
|
|
// 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';
|
|
|
|
}
|
2015-03-17 03:40:57 +00:00
|
|
|
Zotero.rtl = Zotero.dir == 'rtl';
|
|
|
|
|
2013-08-12 07:06:54 +00:00
|
|
|
// Make sure that Zotero Standalone is not running as root
|
|
|
|
if(Zotero.isStandalone && !Zotero.isWin) _checkRoot();
|
|
|
|
|
|
|
|
try {
|
|
|
|
var dataDir = Zotero.getZoteroDirectory();
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
// Zotero dir not found
|
|
|
|
if (e.name == 'NS_ERROR_FILE_NOT_FOUND') {
|
|
|
|
Zotero.startupError = Zotero.getString('dataDir.notFound');
|
|
|
|
_startupErrorHandler = function() {
|
|
|
|
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
|
|
|
|
createInstance(Components.interfaces.nsIPromptService);
|
|
|
|
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_OK)
|
|
|
|
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING)
|
|
|
|
+ (ps.BUTTON_POS_2) * (ps.BUTTON_TITLE_IS_STRING);
|
2014-05-08 19:52:31 +00:00
|
|
|
var index = ps.confirmEx(null,
|
2013-08-12 07:06:54 +00:00
|
|
|
Zotero.getString('general.error'),
|
|
|
|
Zotero.startupError + '\n\n' +
|
|
|
|
Zotero.getString('dataDir.previousDir') + ' '
|
|
|
|
+ Zotero.Prefs.get('lastDataDir'),
|
|
|
|
buttonFlags, null,
|
|
|
|
Zotero.getString('dataDir.useProfileDir', Zotero.appName),
|
|
|
|
Zotero.getString('general.locate'),
|
|
|
|
null, {});
|
|
|
|
|
|
|
|
// Revert to profile directory
|
|
|
|
if (index == 1) {
|
|
|
|
Zotero.chooseZoteroDirectory(false, true);
|
|
|
|
}
|
|
|
|
// Locate data directory
|
|
|
|
else if (index == 2) {
|
|
|
|
Zotero.chooseZoteroDirectory();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else if(e.name == "ZOTERO_DIR_MAY_EXIST") {
|
|
|
|
var app = Zotero.isStandalone ? Zotero.getString('app.standalone') : Zotero.getString('app.firefox');
|
|
|
|
var altApp = !Zotero.isStandalone ? Zotero.getString('app.standalone') : Zotero.getString('app.firefox');
|
|
|
|
|
|
|
|
var message = Zotero.getString("dataDir.standaloneMigration.description", [app, altApp]);
|
|
|
|
if(e.multipleProfiles) {
|
|
|
|
message += "\n\n"+Zotero.getString("dataDir.standaloneMigration.multipleProfiles", [app, altApp]);
|
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
|
|
|
|
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
|
|
|
|
createInstance(Components.interfaces.nsIPromptService);
|
2013-08-12 07:06:54 +00:00
|
|
|
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_YES)
|
|
|
|
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_NO)
|
2007-10-23 07:11:59 +00:00
|
|
|
+ (ps.BUTTON_POS_2) * (ps.BUTTON_TITLE_IS_STRING);
|
2013-08-12 07:06:54 +00:00
|
|
|
var index = ps.confirmEx(null, Zotero.getString("dataDir.standaloneMigration.title"), message,
|
|
|
|
buttonFlags, null, null,
|
|
|
|
Zotero.getString('dataDir.standaloneMigration.selectCustom'),
|
2007-10-23 07:11:59 +00:00
|
|
|
null, {});
|
|
|
|
|
2013-08-12 07:06:54 +00:00
|
|
|
// Migrate data directory
|
|
|
|
if (index == 0) {
|
|
|
|
// copy prefs
|
|
|
|
var prefsFile = e.profile.clone();
|
|
|
|
prefsFile.append("prefs.js");
|
|
|
|
if(prefsFile.exists()) {
|
|
|
|
// build sandbox
|
|
|
|
var sandbox = new Components.utils.Sandbox("http://www.example.com/");
|
|
|
|
Components.utils.evalInSandbox(
|
|
|
|
"var prefs = {};"+
|
|
|
|
"function user_pref(key, val) {"+
|
|
|
|
"prefs[key] = val;"+
|
|
|
|
"}"
|
|
|
|
, sandbox);
|
|
|
|
|
|
|
|
// remove comments
|
|
|
|
var prefsJs = Zotero.File.getContents(prefsFile);
|
|
|
|
prefsJs = prefsJs.replace(/^#[^\r\n]*$/mg, "");
|
|
|
|
|
|
|
|
// evaluate
|
|
|
|
Components.utils.evalInSandbox(prefsJs, sandbox);
|
|
|
|
var prefs = sandbox.prefs;
|
|
|
|
for(var key in prefs) {
|
|
|
|
if(key.substr(0, ZOTERO_CONFIG.PREF_BRANCH.length) === ZOTERO_CONFIG.PREF_BRANCH
|
|
|
|
&& key !== "extensions.zotero.firstRun2") {
|
|
|
|
Zotero.Prefs.set(key.substr(ZOTERO_CONFIG.PREF_BRANCH.length), prefs[key]);
|
|
|
|
}
|
2010-09-20 02:24:07 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-12 07:06:54 +00:00
|
|
|
|
|
|
|
// also set data dir if no custom data dir is now defined
|
|
|
|
if(!Zotero.Prefs.get("useDataDir")) {
|
|
|
|
var dir = e.dir.QueryInterface(Components.interfaces.nsILocalFile);
|
|
|
|
Zotero.Prefs.set('dataDir', dir.persistentDescriptor);
|
|
|
|
Zotero.Prefs.set('lastDataDir', dir.path);
|
|
|
|
Zotero.Prefs.set('useDataDir', true);
|
|
|
|
}
|
2010-09-20 02:24:07 +00:00
|
|
|
}
|
2013-08-12 07:06:54 +00:00
|
|
|
// Create new data directory
|
|
|
|
else if (index == 1) {
|
|
|
|
Zotero.File.createDirectoryIfMissing(e.curDir);
|
|
|
|
}
|
|
|
|
// Locate new data directory
|
|
|
|
else if (index == 2) {
|
|
|
|
Zotero.chooseZoteroDirectory(true);
|
2010-09-20 02:24:07 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-12 07:06:54 +00:00
|
|
|
// DEBUG: handle more startup errors
|
|
|
|
else {
|
|
|
|
throw (e);
|
|
|
|
return false;
|
2010-09-20 02:24:07 +00:00
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
2015-11-04 19:30:25 +00:00
|
|
|
if(Zotero.isStandalone) {
|
|
|
|
Zotero.checkForUnsafeDataDirectory(dataDir.path);
|
|
|
|
}
|
2013-08-12 07:06:54 +00:00
|
|
|
// Register shutdown handler to call Zotero.shutdown()
|
|
|
|
var _shutdownObserver = {observe:function() { Zotero.shutdown().done() }};
|
|
|
|
Services.obs.addObserver(_shutdownObserver, "quit-application", false);
|
|
|
|
|
|
|
|
try {
|
|
|
|
Zotero.IPC.init();
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
if (e.name == 'NS_ERROR_FILE_ACCESS_DENIED') {
|
|
|
|
var msg = Zotero.localeJoin([
|
|
|
|
Zotero.getString('startupError.databaseCannotBeOpened'),
|
|
|
|
Zotero.getString('startupError.checkPermissions')
|
|
|
|
]);
|
|
|
|
Zotero.startupError = msg;
|
2013-08-12 07:10:09 +00:00
|
|
|
Zotero.debug(e, 1);
|
2013-08-12 07:06:54 +00:00
|
|
|
Components.utils.reportError(e);
|
|
|
|
return false;
|
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
throw (e);
|
|
|
|
}
|
2013-08-12 07:06:54 +00:00
|
|
|
|
|
|
|
// Get startup errors
|
|
|
|
try {
|
|
|
|
var messages = {};
|
|
|
|
Services.console.getMessageArray(messages, {});
|
2016-01-20 06:23:02 +00:00
|
|
|
_startupErrors = Object.keys(messages.value).map(i => messages[i])
|
|
|
|
.filter(msg => _shouldKeepError(msg));
|
2013-08-12 07:06:54 +00:00
|
|
|
} catch(e) {
|
|
|
|
Zotero.logError(e);
|
2012-02-14 20:20:19 +00:00
|
|
|
}
|
2013-08-12 07:06:54 +00:00
|
|
|
// Register error observer
|
|
|
|
Services.console.registerListener(ConsoleListener);
|
2011-06-30 01:08:30 +00:00
|
|
|
|
2013-08-12 07:06:54 +00:00
|
|
|
// Add shutdown listener to remove quit-application observer and console listener
|
|
|
|
this.addShutdownListener(function() {
|
|
|
|
Services.obs.removeObserver(_shutdownObserver, "quit-application", false);
|
|
|
|
Services.console.unregisterListener(ConsoleListener);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Load additional info for connector or not
|
|
|
|
if(Zotero.isConnector) {
|
|
|
|
Zotero.debug("Loading in connector mode");
|
|
|
|
Zotero.Connector_Types.init();
|
|
|
|
|
2013-11-24 21:08:46 +00:00
|
|
|
// Store a startupError until we get information from Zotero Standalone
|
|
|
|
Zotero.startupError = Zotero.getString("connector.loadInProgress")
|
|
|
|
|
2013-08-12 07:06:54 +00:00
|
|
|
if(!Zotero.isFirstLoadThisSession) {
|
|
|
|
// We want to get a checkInitComplete message before initializing if we switched to
|
|
|
|
// connector mode because Standalone was launched
|
|
|
|
Zotero.IPC.broadcast("checkInitComplete");
|
|
|
|
} else {
|
|
|
|
Zotero.initComplete();
|
|
|
|
}
|
2011-09-20 21:59:28 +00:00
|
|
|
} else {
|
2013-08-12 07:06:54 +00:00
|
|
|
Zotero.debug("Loading in full mode");
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
return Zotero.Promise.try(_initFull)
|
2013-08-12 07:06:54 +00:00
|
|
|
.then(function (success) {
|
|
|
|
if(!success) return false;
|
|
|
|
|
|
|
|
if(Zotero.isStandalone) Zotero.Standalone.init();
|
|
|
|
Zotero.initComplete();
|
|
|
|
});
|
2011-06-30 01:08:30 +00:00
|
|
|
}
|
2013-08-12 07:06:54 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}.bind(this));
|
2011-09-20 21:59:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Triggers events when initialization finishes
|
|
|
|
*/
|
|
|
|
this.initComplete = function() {
|
|
|
|
if(Zotero.initialized) return;
|
2013-08-12 00:51:16 +00:00
|
|
|
|
|
|
|
Zotero.debug("Running initialization callbacks");
|
2013-11-05 20:52:40 +00:00
|
|
|
delete this.startupError;
|
2011-06-14 00:36:21 +00:00
|
|
|
this.initialized = true;
|
2013-08-12 00:51:16 +00:00
|
|
|
this.initializationDeferred.resolve();
|
2011-06-14 00:36:21 +00:00
|
|
|
|
2011-09-20 21:59:28 +00:00
|
|
|
if(Zotero.isConnector) {
|
|
|
|
Zotero.Repo.init();
|
|
|
|
}
|
|
|
|
|
2011-06-14 00:36:21 +00:00
|
|
|
if(!Zotero.isFirstLoadThisSession) {
|
|
|
|
// trigger zotero-reloaded event
|
|
|
|
Zotero.debug('Triggering "zotero-reloaded" event');
|
2013-06-05 21:54:40 +00:00
|
|
|
Services.obs.notifyObservers(Zotero, "zotero-reloaded", null);
|
2011-06-14 00:36:21 +00:00
|
|
|
}
|
|
|
|
|
2011-08-16 18:28:55 +00:00
|
|
|
Zotero.debug('Triggering "zotero-loaded" event');
|
2013-06-05 21:54:40 +00:00
|
|
|
Services.obs.notifyObservers(Zotero, "zotero-loaded", null);
|
2011-06-14 00:36:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialization function to be called only if Zotero is in full mode
|
2013-08-12 00:51:16 +00:00
|
|
|
*
|
|
|
|
* @return {Promise:Boolean}
|
2011-06-14 00:36:21 +00:00
|
|
|
*/
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
var _initFull = Zotero.Promise.coroutine(function* () {
|
2008-09-16 20:11:27 +00:00
|
|
|
Zotero.VersionHeader.init();
|
|
|
|
|
2016-06-27 16:40:38 +00:00
|
|
|
// Check for data reset/restore
|
2013-08-12 00:51:16 +00:00
|
|
|
var dataDir = Zotero.getZoteroDirectory();
|
2016-06-27 16:40:38 +00:00
|
|
|
var restoreFile = OS.Path.join(dataDir.path, 'restore-from-server');
|
|
|
|
var resetDataDirFile = OS.Path.join(dataDir.path, 'reset-data-directory');
|
|
|
|
|
|
|
|
var result = yield Zotero.Promise.all([OS.File.exists(restoreFile), OS.File.exists(resetDataDirFile)]);
|
|
|
|
if (result.some(r => r)) {
|
|
|
|
[Zotero.restoreFromServer, Zotero.resetDataDir] = result;
|
2009-01-02 00:35:09 +00:00
|
|
|
try {
|
|
|
|
// TODO: better error handling
|
|
|
|
|
|
|
|
// TODO: prompt for location
|
|
|
|
// TODO: Back up database
|
|
|
|
|
|
|
|
|
2016-06-27 16:40:38 +00:00
|
|
|
var dbfile = Zotero.getZoteroDatabase().path;
|
|
|
|
yield OS.File.remove(dbfile, {ignoreAbsent: true});
|
|
|
|
|
|
|
|
if (Zotero.restoreFromServer) {
|
|
|
|
yield OS.File.remove(restoreFile);
|
|
|
|
Zotero.restoreFromServer = true;
|
|
|
|
} else if (Zotero.resetDataDir) {
|
|
|
|
Zotero.initAutoSync = true;
|
|
|
|
var storageDir = OS.Path.join(dataDir.path, 'storage');
|
|
|
|
yield Zotero.Promise.all([
|
|
|
|
OS.File.removeDir(storageDir, {ignoreAbsent: true}),
|
|
|
|
OS.File.remove(resetDataDirFile)
|
|
|
|
]);
|
|
|
|
}
|
2009-01-02 00:35:09 +00:00
|
|
|
|
|
|
|
// Recreate database with no quick start guide
|
|
|
|
Zotero.Schema.skipDefaultData = true;
|
2015-03-22 06:06:40 +00:00
|
|
|
yield Zotero.Schema.updateSchema();
|
2009-01-02 00:35:09 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
// Restore from backup?
|
|
|
|
alert(e);
|
|
|
|
}
|
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
|
2014-08-09 22:01:28 +00:00
|
|
|
if(!(yield _initDB())) return false;
|
Merged revisions 1986,1988-1990,1996,1998,2000-2004,2006,2008-2010,2013,2020-2028,2032-2034,2037,2039,2044-2049,2052-2056,2059,2065-2066,2068-2072,2075,2077-2079,2081,2083-2084,2086,2088-2094,2096,2099,2101,2103-2104,2107-2110,2115,2118,2120-2122,2126-2128,2131,2140,2142-2145,2149-2153,2155-2159,2165,2167-2168,2170-2171,2173-2176,2179-2183,2185-2186 via svnmerge from
https://www.zotero.org/svn/extension/branches/1.0
2008-01-30 09:53:19 +00:00
|
|
|
|
2013-05-01 10:29:31 +00:00
|
|
|
Zotero.HTTP.triggerProxyAuth();
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
// Add notifier queue callbacks to the DB layer
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
Zotero.DB.addCallback('begin', function () { return Zotero.Notifier.begin(); });
|
|
|
|
Zotero.DB.addCallback('commit', function () { return Zotero.Notifier.commit(); });
|
|
|
|
Zotero.DB.addCallback('rollback', function () { return Zotero.Notifier.reset(); });
|
2007-10-23 07:11:59 +00:00
|
|
|
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
try {
|
2013-08-12 00:51:16 +00:00
|
|
|
// Require >=2.1b3 database to ensure proper locking
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
if (Zotero.isStandalone) {
|
|
|
|
let dbSystemVersion = yield Zotero.Schema.getDBVersion('system');
|
2013-08-12 00:51:16 +00:00
|
|
|
if (dbSystemVersion > 0 && dbSystemVersion < 31) {
|
|
|
|
var dir = Zotero.getProfileDirectory();
|
|
|
|
dir.append('zotero');
|
|
|
|
|
|
|
|
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
|
|
|
.createInstance(Components.interfaces.nsIPromptService);
|
|
|
|
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
|
|
|
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING)
|
|
|
|
+ (ps.BUTTON_POS_2) * (ps.BUTTON_TITLE_IS_STRING)
|
|
|
|
+ ps.BUTTON_POS_2_DEFAULT;
|
|
|
|
var index = ps.confirmEx(
|
|
|
|
null,
|
|
|
|
Zotero.getString('dataDir.incompatibleDbVersion.title'),
|
|
|
|
Zotero.getString('dataDir.incompatibleDbVersion.text'),
|
|
|
|
buttonFlags,
|
|
|
|
Zotero.getString('general.useDefault'),
|
|
|
|
Zotero.getString('dataDir.standaloneMigration.selectCustom'),
|
|
|
|
Zotero.getString('general.quit'),
|
|
|
|
null,
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
|
|
|
|
var quit = false;
|
|
|
|
|
|
|
|
// Default location
|
|
|
|
if (index == 0) {
|
|
|
|
Zotero.File.createDirectoryIfMissing(dir);
|
|
|
|
|
|
|
|
Zotero.Prefs.set("useDataDir", false)
|
|
|
|
|
|
|
|
Services.startup.quit(
|
|
|
|
Components.interfaces.nsIAppStartup.eAttemptQuit
|
|
|
|
| Components.interfaces.nsIAppStartup.eRestart
|
|
|
|
);
|
|
|
|
}
|
|
|
|
// Select new data directory
|
|
|
|
else if (index == 1) {
|
|
|
|
var dir = Zotero.chooseZoteroDirectory(true);
|
|
|
|
if (!dir) {
|
|
|
|
quit = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
quit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (quit) {
|
|
|
|
Services.startup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
|
|
|
|
}
|
|
|
|
|
|
|
|
throw true;
|
|
|
|
}
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
var updated = yield Zotero.Schema.updateSchema();
|
2011-01-13 23:51:19 +00:00
|
|
|
|
2014-08-09 22:01:28 +00:00
|
|
|
yield Zotero.Users.init();
|
|
|
|
yield Zotero.Libraries.init();
|
|
|
|
|
|
|
|
yield Zotero.ItemTypes.init();
|
|
|
|
yield Zotero.ItemFields.init();
|
|
|
|
yield Zotero.CreatorTypes.init();
|
|
|
|
yield Zotero.FileTypes.init();
|
Relations overhaul (requires new DB upgrade from 4.0)
Relations are now properties of collections and items rather than
first-class objects, stored in separate collectionRelations and
itemRelations tables with ids for subjects, with foreign keys to the
associated data objects.
Related items now use dc:relation relations rather than a separate table
(among other reasons, because API syncing won't necessarily sync both
items at the same time, so they can't be stored by id).
The UI assigns related-item relations bidirectionally, and checks for
related-item and linked-object relations are done unidirectionally by
default.
dc:isReplacedBy is now dc:replaces, so that the subject is an existing
object, and the predicate is now named
Zotero.Attachments.replacedItemPredicate.
Some additional work is still needed, notably around following
replaced-item relations, and migration needs to be tested more fully,
but this seems to mostly work.
2015-06-02 00:09:39 +00:00
|
|
|
yield Zotero.CharacterSets.init();
|
|
|
|
yield Zotero.RelationPredicates.init();
|
2014-08-09 22:01:28 +00:00
|
|
|
|
2015-02-25 03:06:18 +00:00
|
|
|
Zotero.locked = false;
|
|
|
|
|
2013-08-12 00:51:16 +00:00
|
|
|
// Initialize various services
|
|
|
|
Zotero.Integration.init();
|
2011-01-13 23:51:19 +00:00
|
|
|
|
2013-08-12 00:51:16 +00:00
|
|
|
if(Zotero.Prefs.get("httpServer.enabled")) {
|
|
|
|
Zotero.Server.init();
|
2011-01-13 20:52:15 +00:00
|
|
|
}
|
2013-08-12 00:51:16 +00:00
|
|
|
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
yield Zotero.Fulltext.init();
|
2013-08-12 07:10:22 +00:00
|
|
|
|
2016-04-21 20:17:13 +00:00
|
|
|
Zotero.Notifier.registerObserver(Zotero.Tags, 'setting', 'tags');
|
2013-08-12 00:51:16 +00:00
|
|
|
|
2015-07-20 21:27:55 +00:00
|
|
|
yield Zotero.Sync.Data.Local.init();
|
|
|
|
yield Zotero.Sync.Data.Utilities.init();
|
|
|
|
Zotero.Sync.EventListeners.init();
|
2015-10-29 07:41:54 +00:00
|
|
|
Zotero.Sync.Runner = new Zotero.Sync.Runner_Module;
|
2013-08-12 00:51:16 +00:00
|
|
|
|
|
|
|
Zotero.MIMETypeHandler.init();
|
2014-08-09 22:01:28 +00:00
|
|
|
yield Zotero.Proxies.init();
|
2013-08-12 00:51:16 +00:00
|
|
|
|
|
|
|
// Initialize keyboard shortcuts
|
|
|
|
Zotero.Keys.init();
|
|
|
|
|
|
|
|
// Initialize Locate Manager
|
|
|
|
Zotero.LocateManager.init();
|
|
|
|
|
Always start at MAX() + 1 for Zotero.ID.get(), and deasyncify
Instead of getting batches of unused primary key ids, even if they're lower
than other ids, which for some reason seemed like a good idea in 2008, just do
a `MAX()` on the table at startup and return the next available id on each call
to `Zotero.ID.get()`. This is much simpler, and not reusing ids allows them to
be used as a chronological sort field.
While SQLite's `SELECT last_insert_rowid()` could return auto-increment values,
it's unsafe with async DB access, since a second `INSERT` can come in before
the first `last_insert_rowid()` is called. This is true even in a transaction
unless a function that calls it is never called in parallel (e.g., with
`Zotero.Promise.all()`, which can be faster than sequential `yield`s).
Note that the next id is always initialized as MAX() + 1, so if an object is
added and then deleted, after a restart the same id will be given. (This is
equivalent to (though unrelated to) SQLite's `INTEGER PRIMARY KEY` behavior,
as opposed to its `INTEGER PRIMARY KEY AUTOINCREMENT` behavior.)
Closes #993, Feed items out of order
2016-03-30 05:16:41 +00:00
|
|
|
yield Zotero.ID.init();
|
Deasyncification :back: :cry:
While trying to get translation and citing working with asynchronously
generated data, we realized that drag-and-drop support was going to
be...problematic. Firefox only supports synchronous methods for
providing drag data (unlike, it seems, the DataTransferItem interface
supported by Chrome), which means that we'd need to preload all relevant
data on item selection (bounded by export.quickCopy.dragLimit) and keep
the translate/cite methods synchronous (or maintain two separate
versions).
What we're trying instead is doing what I said in #518 we weren't going
to do: loading most object data on startup and leaving many more
functions synchronous. Essentially, this takes the various load*()
methods described in #518, moves them to startup, and makes them operate
on entire libraries rather than individual objects.
The obvious downside here (other than undoing much of the work of the
last many months) is that it increases startup time, potentially quite a
lot for larger libraries. On my laptop, with a 3,000-item library, this
adds about 3 seconds to startup time. I haven't yet tested with larger
libraries. But I'm hoping that we can optimize this further to reduce
that delay. Among other things, this is loading data for all libraries,
when it should be able to load data only for the library being viewed.
But this is also fundamentally just doing some SELECT queries and
storing the results, so it really shouldn't need to be that slow (though
performance may be bounded a bit here by XPCOM overhead).
If we can make this fast enough, it means that third-party plugins
should be able to remain much closer to their current designs. (Some
things, including saving, will still need to be made asynchronous.)
2016-03-07 21:05:51 +00:00
|
|
|
yield Zotero.Collections.init();
|
|
|
|
yield Zotero.Items.init();
|
2015-04-16 21:46:29 +00:00
|
|
|
yield Zotero.Searches.init();
|
2016-04-21 15:07:16 +00:00
|
|
|
yield Zotero.Tags.init();
|
Deasyncification :back: :cry:
While trying to get translation and citing working with asynchronously
generated data, we realized that drag-and-drop support was going to
be...problematic. Firefox only supports synchronous methods for
providing drag data (unlike, it seems, the DataTransferItem interface
supported by Chrome), which means that we'd need to preload all relevant
data on item selection (bounded by export.quickCopy.dragLimit) and keep
the translate/cite methods synchronous (or maintain two separate
versions).
What we're trying instead is doing what I said in #518 we weren't going
to do: loading most object data on startup and leaving many more
functions synchronous. Essentially, this takes the various load*()
methods described in #518, moves them to startup, and makes them operate
on entire libraries rather than individual objects.
The obvious downside here (other than undoing much of the work of the
last many months) is that it increases startup time, potentially quite a
lot for larger libraries. On my laptop, with a 3,000-item library, this
adds about 3 seconds to startup time. I haven't yet tested with larger
libraries. But I'm hoping that we can optimize this further to reduce
that delay. Among other things, this is loading data for all libraries,
when it should be able to load data only for the library being viewed.
But this is also fundamentally just doing some SELECT queries and
storing the results, so it really shouldn't need to be that slow (though
performance may be bounded a bit here by XPCOM overhead).
If we can make this fast enough, it means that third-party plugins
should be able to remain much closer to their current designs. (Some
things, including saving, will still need to be made asynchronous.)
2016-03-07 21:05:51 +00:00
|
|
|
yield Zotero.Creators.init();
|
2015-05-22 08:49:02 +00:00
|
|
|
yield Zotero.Groups.init();
|
2016-02-11 11:02:38 +00:00
|
|
|
yield Zotero.Relations.init();
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
|
2016-04-26 04:00:12 +00:00
|
|
|
// Load all library data except for items, which are loaded when libraries are first
|
|
|
|
// clicked on or if otherwise necessary
|
2016-04-10 22:58:01 +00:00
|
|
|
yield Zotero.Promise.each(
|
|
|
|
Zotero.Libraries.getAll(),
|
|
|
|
library => Zotero.Promise.coroutine(function* () {
|
|
|
|
yield Zotero.SyncedSettings.loadAll(library.libraryID);
|
|
|
|
yield Zotero.Collections.loadAll(library.libraryID);
|
|
|
|
yield Zotero.Searches.loadAll(library.libraryID);
|
|
|
|
})()
|
|
|
|
);
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
}
|
|
|
|
catch (e) {
|
2015-12-30 09:31:57 +00:00
|
|
|
Zotero.logError(e);
|
2013-11-24 21:08:46 +00:00
|
|
|
|
2015-12-30 09:31:57 +00:00
|
|
|
if (e instanceof Zotero.DB.IncompatibleVersionException) {
|
2015-03-30 18:45:53 +00:00
|
|
|
let kbURL = "https://www.zotero.org/support/kb/newer_db_version";
|
2016-02-06 09:59:15 +00:00
|
|
|
let msg = (e.dbClientVersion
|
|
|
|
? Zotero.getString('startupError.incompatibleDBVersion',
|
|
|
|
[Zotero.clientName, e.dbClientVersion])
|
|
|
|
: Zotero.getString('startupError.zoteroVersionIsOlder')) + "\n\n"
|
2015-04-15 20:03:47 +00:00
|
|
|
+ Zotero.getString('startupError.zoteroVersionIsOlder.current', Zotero.version)
|
2015-12-30 09:31:57 +00:00
|
|
|
+ "\n\n"
|
|
|
|
+ Zotero.getString('startupError.zoteroVersionIsOlder.upgrade',
|
|
|
|
ZOTERO_CONFIG.DOMAIN_NAME);
|
2011-06-14 00:36:21 +00:00
|
|
|
Zotero.startupError = msg;
|
2013-11-07 11:33:39 +00:00
|
|
|
_startupErrorHandler = function() {
|
|
|
|
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIPromptService);
|
|
|
|
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
2013-11-13 05:31:45 +00:00
|
|
|
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL)
|
2015-12-30 09:31:57 +00:00
|
|
|
+ (ps.BUTTON_POS_2) * (ps.BUTTON_TITLE_IS_STRING)
|
2013-11-07 11:33:39 +00:00
|
|
|
+ ps.BUTTON_POS_0_DEFAULT;
|
|
|
|
|
2013-11-13 05:31:45 +00:00
|
|
|
var index = ps.confirmEx(
|
|
|
|
null,
|
|
|
|
Zotero.getString('general.error'),
|
|
|
|
Zotero.startupError,
|
|
|
|
buttonFlags,
|
|
|
|
Zotero.getString('general.checkForUpdate'),
|
2015-12-30 09:31:57 +00:00
|
|
|
null,
|
|
|
|
Zotero.getString('general.moreInformation'),
|
|
|
|
null,
|
|
|
|
{}
|
2013-11-13 05:31:45 +00:00
|
|
|
);
|
2013-11-07 11:33:39 +00:00
|
|
|
|
2015-12-30 09:31:57 +00:00
|
|
|
// "Check for Update" button
|
2013-11-07 11:33:39 +00:00
|
|
|
if(index === 0) {
|
|
|
|
if(Zotero.isStandalone) {
|
2013-11-08 02:55:07 +00:00
|
|
|
Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
|
|
|
.getService(Components.interfaces.nsIWindowWatcher)
|
|
|
|
.openWindow(null, 'chrome://mozapps/content/update/updates.xul',
|
|
|
|
'updateChecker', 'chrome,centerscreen', null);
|
2013-11-07 11:33:39 +00:00
|
|
|
} else {
|
|
|
|
// In Firefox, show the add-on manager
|
|
|
|
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
|
|
|
AddonManager.getAddonByID(ZOTERO_CONFIG['GUID'],
|
|
|
|
function (addon) {
|
|
|
|
// Disable auto-update so that the user is presented with the option
|
|
|
|
var initUpdateState = addon.applyBackgroundUpdates;
|
|
|
|
addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE;
|
|
|
|
addon.findUpdates({
|
|
|
|
onNoUpdateAvailable: function() {
|
2013-11-13 05:31:45 +00:00
|
|
|
ps.alert(
|
|
|
|
null,
|
|
|
|
Zotero.getString('general.noUpdatesFound'),
|
|
|
|
Zotero.getString('general.isUpToDate', 'Zotero')
|
|
|
|
);
|
2013-11-07 11:33:39 +00:00
|
|
|
},
|
|
|
|
onUpdateAvailable: function() {
|
|
|
|
// Show available update
|
|
|
|
Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
|
|
|
.getService(Components.interfaces.nsIWindowMediator)
|
|
|
|
.getMostRecentWindow('navigator:browser')
|
|
|
|
.BrowserOpenAddonsMgr('addons://updates/available');
|
|
|
|
},
|
|
|
|
onUpdateFinished: function() {
|
|
|
|
// Restore add-on auto-update state, but don't fire
|
|
|
|
// too quickly or the update will not show in the
|
|
|
|
// add-on manager
|
|
|
|
setTimeout(function() {
|
|
|
|
addon.applyBackgroundUpdates = initUpdateState;
|
|
|
|
}, 1000);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
AddonManager.UPDATE_WHEN_USER_REQUESTED
|
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2015-12-30 09:31:57 +00:00
|
|
|
// 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 handler = Components.classes['@mozilla.org/uriloader/external-protocol-service;1']
|
|
|
|
.getService(Components.interfaces.nsIExternalProtocolService)
|
|
|
|
.getProtocolHandlerInfo('http');
|
|
|
|
handler.preferredAction = Components.interfaces.nsIHandlerInfo.useSystemDefault;
|
|
|
|
handler.launchWithURI(uri, null);
|
|
|
|
}
|
2013-11-07 11:33:39 +00:00
|
|
|
};
|
2015-12-30 09:31:57 +00:00
|
|
|
throw e;
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
2013-11-24 21:08:46 +00:00
|
|
|
|
2013-08-12 00:51:16 +00:00
|
|
|
Zotero.startupError = Zotero.getString('startupError.databaseUpgradeError') + "\n\n" + e;
|
2015-12-30 09:31:57 +00:00
|
|
|
throw e;
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
};
|
|
|
|
|
2016-05-13 05:20:57 +00:00
|
|
|
Zotero.Items.startEmptyTrashTimer();
|
2016-06-23 09:36:38 +00:00
|
|
|
|
|
|
|
yield Zotero.QuickCopy.init();
|
|
|
|
Zotero.addShutdownListener(() => Zotero.QuickCopy.uninit());
|
|
|
|
|
2016-05-13 05:20:57 +00:00
|
|
|
Zotero.Feeds.init();
|
2016-05-17 15:50:26 +00:00
|
|
|
Zotero.addShutdownListener(() => Zotero.Feeds.uninit());
|
2016-05-13 05:20:57 +00:00
|
|
|
|
2013-08-12 00:51:16 +00:00
|
|
|
return true;
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
}
|
|
|
|
catch (e) {
|
2011-06-14 00:36:21 +00:00
|
|
|
Zotero.skipLoading = true;
|
2011-01-13 20:52:15 +00:00
|
|
|
return false;
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
}
|
|
|
|
});
|
2011-06-14 00:36:21 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the DB connection
|
|
|
|
*/
|
2014-08-09 22:01:28 +00:00
|
|
|
var _initDB = Zotero.Promise.coroutine(function* (haveReleasedLock) {
|
2011-06-14 00:36:21 +00:00
|
|
|
try {
|
|
|
|
// Test read access
|
2014-08-09 22:01:28 +00:00
|
|
|
yield Zotero.DB.test();
|
2011-06-14 00:36:21 +00:00
|
|
|
|
|
|
|
var dbfile = Zotero.getZoteroDatabase();
|
2013-12-13 22:19:56 +00:00
|
|
|
|
|
|
|
// Tell any other Zotero instances to release their lock,
|
|
|
|
// in case we lost the lock on the database (how?) and it's
|
|
|
|
// now open in two places at once
|
|
|
|
Zotero.IPC.broadcast("releaseLock "+dbfile.persistentDescriptor);
|
2011-06-14 00:36:21 +00:00
|
|
|
|
|
|
|
// Test write access on Zotero data directory
|
|
|
|
if (!dbfile.parent.isWritable()) {
|
|
|
|
var msg = 'Cannot write to ' + dbfile.parent.path + '/';
|
|
|
|
}
|
|
|
|
// Test write access on Zotero database
|
|
|
|
else if (!dbfile.isWritable()) {
|
|
|
|
var msg = 'Cannot write to ' + dbfile.path;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var msg = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg) {
|
|
|
|
var e = {
|
|
|
|
name: 'NS_ERROR_FILE_ACCESS_DENIED',
|
|
|
|
message: msg,
|
2013-08-12 07:10:09 +00:00
|
|
|
toString: function () this.message
|
2011-06-14 00:36:21 +00:00
|
|
|
};
|
|
|
|
throw (e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
if (e.name == 'NS_ERROR_FILE_ACCESS_DENIED') {
|
|
|
|
var msg = Zotero.localeJoin([
|
|
|
|
Zotero.getString('startupError.databaseCannotBeOpened'),
|
|
|
|
Zotero.getString('startupError.checkPermissions')
|
|
|
|
]);
|
|
|
|
Zotero.startupError = msg;
|
2016-04-04 10:33:15 +00:00
|
|
|
}
|
|
|
|
// Storage busy
|
|
|
|
else if (e.message.endsWith('2153971713')) {
|
2016-05-09 02:38:58 +00:00
|
|
|
// TEMP: Disabled for 5.0 Beta
|
|
|
|
/*
|
2011-06-14 00:36:21 +00:00
|
|
|
if(Zotero.isStandalone) {
|
|
|
|
// Standalone should force Fx to release lock
|
2011-07-03 04:15:49 +00:00
|
|
|
if(!haveReleasedLock && Zotero.IPC.broadcast("releaseLock")) {
|
2011-06-14 00:36:21 +00:00
|
|
|
_waitingForDBLock = true;
|
2011-07-03 04:15:49 +00:00
|
|
|
|
|
|
|
var timeout = Date.now() + 5000; // 5 second timeout
|
|
|
|
while(_waitingForDBLock && !Zotero.closing && Date.now() < timeout) {
|
2011-09-22 07:03:37 +00:00
|
|
|
// AMO Reviewer: This is used by Zotero Standalone, not Zotero for Firefox.
|
2011-07-03 04:15:49 +00:00
|
|
|
Zotero.mainThread.processNextEvent(true);
|
|
|
|
}
|
2011-07-20 03:12:31 +00:00
|
|
|
if(Zotero.closing) return false;
|
2011-07-03 04:15:49 +00:00
|
|
|
|
|
|
|
// Run a second init with haveReleasedLock = true, so that
|
|
|
|
// if we still can't acquire a DB lock, we will give up
|
|
|
|
return _initDB(true);
|
2011-06-14 00:36:21 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Fx should start as connector if Standalone is running
|
|
|
|
var haveStandalone = Zotero.IPC.broadcast("test");
|
|
|
|
if(haveStandalone) {
|
|
|
|
throw "ZOTERO_SHOULD_START_AS_CONNECTOR";
|
|
|
|
}
|
|
|
|
}
|
2016-05-09 02:38:58 +00:00
|
|
|
*/
|
2011-06-14 00:36:21 +00:00
|
|
|
|
|
|
|
var msg = Zotero.localeJoin([
|
|
|
|
Zotero.getString('startupError.databaseInUse'),
|
|
|
|
Zotero.getString(Zotero.isStandalone ? 'startupError.closeFirefox' : 'startupError.closeStandalone')
|
|
|
|
]);
|
|
|
|
Zotero.startupError = msg;
|
2013-11-27 21:08:31 +00:00
|
|
|
} else {
|
|
|
|
Zotero.startupError = Zotero.getString('startupError') + "\n\n" + e;
|
2011-06-14 00:36:21 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 07:10:09 +00:00
|
|
|
Zotero.debug(e.toString(), 1);
|
|
|
|
Components.utils.reportError(e); // DEBUG: doesn't always work
|
2011-06-14 00:36:21 +00:00
|
|
|
Zotero.skipLoading = true;
|
|
|
|
return false;
|
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
|
|
|
|
return true;
|
2014-08-09 22:01:28 +00:00
|
|
|
});
|
2007-10-23 07:11:59 +00:00
|
|
|
|
2011-06-14 00:36:21 +00:00
|
|
|
/**
|
|
|
|
* Called when the DB has been released by another Zotero process to perform necessary
|
|
|
|
* initialization steps
|
|
|
|
*/
|
|
|
|
this.onDBLockReleased = function() {
|
|
|
|
if(Zotero.isConnector) {
|
|
|
|
// if DB lock is released, switch out of connector mode
|
|
|
|
switchConnectorMode(false);
|
|
|
|
} else if(_waitingForDBLock) {
|
|
|
|
// if waiting for DB lock and we get it, continue init
|
|
|
|
_waitingForDBLock = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-17 05:49:26 +00:00
|
|
|
this.shutdown = Zotero.Promise.coroutine(function* () {
|
2008-11-14 13:43:01 +00:00
|
|
|
Zotero.debug("Shutting down Zotero");
|
2011-06-14 00:36:21 +00:00
|
|
|
|
|
|
|
try {
|
2011-07-03 04:15:49 +00:00
|
|
|
// set closing to true
|
|
|
|
Zotero.closing = true;
|
|
|
|
|
2011-06-14 00:36:21 +00:00
|
|
|
// run shutdown listener
|
2016-01-17 05:49:26 +00:00
|
|
|
for (let listener of _shutdownListeners) {
|
2011-08-24 06:29:02 +00:00
|
|
|
try {
|
|
|
|
listener();
|
2011-08-24 06:29:16 +00:00
|
|
|
} catch(e) {
|
|
|
|
Zotero.logError(e);
|
|
|
|
}
|
2011-08-24 06:29:02 +00:00
|
|
|
}
|
2011-06-14 00:36:21 +00:00
|
|
|
|
|
|
|
// remove temp directory
|
|
|
|
Zotero.removeTempDirectory();
|
|
|
|
|
2016-01-17 05:49:26 +00:00
|
|
|
if (Zotero.DB) {
|
2013-12-13 22:19:56 +00:00
|
|
|
// close DB
|
2016-01-17 05:49:26 +00:00
|
|
|
yield Zotero.DB.closeDatabase(true)
|
|
|
|
|
|
|
|
// broadcast that DB lock has been released
|
|
|
|
Zotero.IPC.broadcast("lockReleased");
|
2011-06-14 00:36:21 +00:00
|
|
|
}
|
|
|
|
} catch(e) {
|
2016-01-17 05:49:26 +00:00
|
|
|
Zotero.logError(e);
|
|
|
|
throw e;
|
2011-06-14 00:36:21 +00:00
|
|
|
}
|
2016-01-17 05:49:26 +00:00
|
|
|
});
|
2006-08-01 18:01:56 +00:00
|
|
|
|
|
|
|
|
2006-07-27 08:45:48 +00:00
|
|
|
function getProfileDirectory(){
|
2013-06-06 06:37:19 +00:00
|
|
|
return Services.dirsvc.get("ProfD", Components.interfaces.nsIFile);
|
2006-07-27 08:45:48 +00:00
|
|
|
}
|
|
|
|
|
2010-09-20 02:24:07 +00:00
|
|
|
function getDefaultProfile(prefDir) {
|
|
|
|
// find profiles.ini file
|
|
|
|
var profilesIni = prefDir.clone();
|
|
|
|
profilesIni.append("profiles.ini");
|
|
|
|
if(!profilesIni.exists()) return false;
|
|
|
|
var iniContents = Zotero.File.getContents(profilesIni);
|
|
|
|
|
|
|
|
// cheap and dirty ini parser
|
|
|
|
var curSection = null;
|
|
|
|
var defaultSection = null;
|
|
|
|
var nSections = 0;
|
2016-05-03 21:51:12 +00:00
|
|
|
for (let line of iniContents.split(/(?:\r?\n|\r)/)) {
|
2010-09-20 02:24:07 +00:00
|
|
|
let tline = line.trim();
|
|
|
|
if(tline[0] == "[" && tline[tline.length-1] == "]") {
|
|
|
|
curSection = {};
|
|
|
|
if(tline != "[General]") nSections++;
|
|
|
|
} else if(curSection && tline != "") {
|
|
|
|
let equalsIndex = tline.indexOf("=");
|
|
|
|
let key = tline.substr(0, equalsIndex);
|
|
|
|
let val = tline.substr(equalsIndex+1);
|
|
|
|
curSection[key] = val;
|
|
|
|
if(key == "Default" && val == "1") {
|
|
|
|
defaultSection = curSection;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!defaultSection && curSection) defaultSection = curSection;
|
|
|
|
|
|
|
|
// parse out ini to reveal profile
|
|
|
|
if(!defaultSection || !defaultSection.Path) return false;
|
2010-09-25 16:09:55 +00:00
|
|
|
|
|
|
|
|
2011-08-24 06:07:48 +00:00
|
|
|
if(defaultSection.IsRelative === "1") {
|
2011-08-24 00:54:38 +00:00
|
|
|
var defaultProfile = prefDir.clone().QueryInterface(Components.interfaces.nsILocalFile);
|
2011-08-24 01:15:21 +00:00
|
|
|
try {
|
|
|
|
for each(var dir in defaultSection.Path.split("/")) defaultProfile.append(dir);
|
|
|
|
} catch(e) {
|
|
|
|
Zotero.logError("Could not find profile at "+defaultSection.Path);
|
|
|
|
throw e;
|
|
|
|
}
|
2010-09-20 02:24:07 +00:00
|
|
|
} else {
|
|
|
|
var defaultProfile = Components.classes["@mozilla.org/file/local;1"]
|
|
|
|
.createInstance(Components.interfaces.nsILocalFile);
|
|
|
|
defaultProfile.initWithPath(defaultSection.Path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!defaultProfile.exists()) return false;
|
|
|
|
return [defaultProfile, nSections > 1];
|
|
|
|
}
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
|
2006-10-02 23:15:27 +00:00
|
|
|
function getZoteroDirectory(){
|
2007-10-23 07:11:59 +00:00
|
|
|
if (_zoteroDirectory != false) {
|
|
|
|
// Return a clone of the file pointer so that callers can modify it
|
|
|
|
return _zoteroDirectory.clone();
|
|
|
|
}
|
2006-07-27 08:45:48 +00:00
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
if (Zotero.Prefs.get('useDataDir')) {
|
|
|
|
var file = Components.classes["@mozilla.org/file/local;1"].
|
|
|
|
createInstance(Components.interfaces.nsILocalFile);
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
try {
|
|
|
|
file.persistentDescriptor = Zotero.Prefs.get('dataDir');
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
Zotero.debug("Persistent descriptor in extensions.zotero.dataDir did not resolve", 1);
|
|
|
|
e = { name: "NS_ERROR_FILE_NOT_FOUND" };
|
|
|
|
throw (e);
|
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
if (!file.exists()) {
|
|
|
|
var e = { name: "NS_ERROR_FILE_NOT_FOUND" };
|
|
|
|
throw (e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var file = Zotero.getProfileDirectory();
|
|
|
|
file.append('zotero');
|
2010-09-20 02:24:07 +00:00
|
|
|
|
|
|
|
// if standalone and no directory yet, check Firefox directory
|
|
|
|
// or if in Firefox and no directory yet, check standalone Zotero directory
|
|
|
|
if(!file.exists()) {
|
2013-06-06 06:37:19 +00:00
|
|
|
var prefDir = Services.dirsvc
|
2010-09-25 16:00:31 +00:00
|
|
|
.get("DefProfRt", Components.interfaces.nsILocalFile).parent.parent;
|
|
|
|
|
2010-09-20 02:50:24 +00:00
|
|
|
if(Zotero.isStandalone) {
|
|
|
|
if(Zotero.isWin) {
|
2010-09-25 16:05:15 +00:00
|
|
|
prefDir = prefDir.parent;
|
2010-09-25 16:00:31 +00:00
|
|
|
prefDir.append("Mozilla");
|
|
|
|
prefDir.append("Firefox");
|
2010-09-20 02:50:24 +00:00
|
|
|
} else if(Zotero.isMac) {
|
2010-09-25 16:00:31 +00:00
|
|
|
prefDir.append("Firefox");
|
2010-09-20 02:50:24 +00:00
|
|
|
} else {
|
2010-09-25 16:00:31 +00:00
|
|
|
prefDir.append(".mozilla");
|
|
|
|
prefDir.append("firefox");
|
2010-09-20 02:50:24 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(Zotero.isWin) {
|
2010-09-25 16:00:31 +00:00
|
|
|
prefDir = prefDir.parent;
|
|
|
|
prefDir.append("Zotero");
|
2010-09-25 16:04:18 +00:00
|
|
|
prefDir.append("Zotero");
|
2010-09-20 02:50:24 +00:00
|
|
|
} else if(Zotero.isMac) {
|
2010-09-25 16:00:31 +00:00
|
|
|
prefDir.append("Zotero");
|
2010-09-20 02:50:24 +00:00
|
|
|
} else {
|
2010-09-25 16:00:31 +00:00
|
|
|
prefDir.append(".zotero");
|
2010-09-25 16:05:15 +00:00
|
|
|
prefDir.append("zotero");
|
2010-09-20 02:50:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-25 16:00:31 +00:00
|
|
|
Zotero.debug("Looking for existing profile in "+prefDir.path);
|
2010-09-20 02:24:07 +00:00
|
|
|
|
|
|
|
// get default profile
|
2011-08-24 00:54:38 +00:00
|
|
|
var defProfile;
|
|
|
|
try {
|
|
|
|
defProfile = getDefaultProfile(prefDir);
|
|
|
|
} catch(e) {
|
|
|
|
Zotero.debug("An error occurred locating the Firefox profile; not "+
|
|
|
|
"attempting to migrate from Zotero for Firefox");
|
|
|
|
Zotero.logError(e);
|
|
|
|
}
|
|
|
|
|
2010-09-20 02:24:07 +00:00
|
|
|
if(defProfile) {
|
|
|
|
// get Zotero directory
|
|
|
|
var zoteroDir = defProfile[0].clone();
|
|
|
|
zoteroDir.append("zotero");
|
|
|
|
|
|
|
|
if(zoteroDir.exists()) {
|
|
|
|
// if Zotero directory exists in default profile for alternative app, ask
|
|
|
|
// whether to use
|
|
|
|
var e = { name:"ZOTERO_DIR_MAY_EXIST", curDir:file, profile:defProfile[0], dir:zoteroDir, multipleProfiles:defProfile[1] };
|
|
|
|
throw (e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-11 17:20:09 +00:00
|
|
|
Zotero.File.createDirectoryIfMissing(file);
|
2006-07-27 08:45:48 +00:00
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
Zotero.debug("Using data directory " + file.path);
|
|
|
|
|
|
|
|
_zoteroDirectory = file;
|
2008-09-11 17:20:09 +00:00
|
|
|
return file.clone();
|
2006-07-27 08:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getStorageDirectory(){
|
2006-10-02 23:15:27 +00:00
|
|
|
var file = Zotero.getZoteroDirectory();
|
2006-07-27 08:45:48 +00:00
|
|
|
|
|
|
|
file.append('storage');
|
2008-09-11 17:20:09 +00:00
|
|
|
Zotero.File.createDirectoryIfMissing(file);
|
2006-07-27 08:45:48 +00:00
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
function getZoteroDatabase(name, ext){
|
|
|
|
name = name ? name + '.sqlite' : 'zotero.sqlite';
|
2006-08-01 23:10:31 +00:00
|
|
|
ext = ext ? '.' + ext : '';
|
|
|
|
|
2006-10-02 23:15:27 +00:00
|
|
|
var file = Zotero.getZoteroDirectory();
|
2007-10-23 07:11:59 +00:00
|
|
|
file.append(name + ext);
|
2006-08-01 23:10:31 +00:00
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-31 23:36:01 +00:00
|
|
|
/**
|
|
|
|
* @return {nsIFile}
|
|
|
|
*/
|
2008-11-14 13:43:01 +00:00
|
|
|
this.getTempDirectory = function () {
|
2008-08-31 23:36:01 +00:00
|
|
|
var tmp = this.getZoteroDirectory();
|
|
|
|
tmp.append('tmp');
|
2008-09-11 17:20:09 +00:00
|
|
|
Zotero.File.createDirectoryIfMissing(tmp);
|
2008-08-31 23:36:01 +00:00
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-14 13:43:01 +00:00
|
|
|
this.removeTempDirectory = function () {
|
|
|
|
var tmp = this.getZoteroDirectory();
|
|
|
|
tmp.append('tmp');
|
|
|
|
if (tmp.exists()) {
|
|
|
|
try {
|
|
|
|
tmp.remove(true);
|
|
|
|
}
|
|
|
|
catch (e) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-11 17:20:09 +00:00
|
|
|
this.getStylesDirectory = function () {
|
|
|
|
var dir = this.getZoteroDirectory();
|
|
|
|
dir.append('styles');
|
|
|
|
Zotero.File.createDirectoryIfMissing(dir);
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.getTranslatorsDirectory = function () {
|
|
|
|
var dir = this.getZoteroDirectory();
|
|
|
|
dir.append('translators');
|
|
|
|
Zotero.File.createDirectoryIfMissing(dir);
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-20 18:55:50 +00:00
|
|
|
function chooseZoteroDirectory(forceQuitNow, useProfileDir, moreInfoCallback) {
|
2013-06-06 06:37:19 +00:00
|
|
|
var win = Services.wm.getMostRecentWindow('navigator:browser');
|
|
|
|
var ps = Services.prompt;
|
2006-08-01 23:10:31 +00:00
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
if (useProfileDir) {
|
|
|
|
Zotero.Prefs.set('useDataDir', false);
|
2006-08-01 23:10:31 +00:00
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
else {
|
|
|
|
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
|
|
|
while (true) {
|
|
|
|
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
|
|
|
.createInstance(nsIFilePicker);
|
|
|
|
fp.init(win, Zotero.getString('dataDir.selectDir'), nsIFilePicker.modeGetFolder);
|
2015-11-04 19:30:25 +00:00
|
|
|
fp.displayDirectory = Zotero.getZoteroDirectory();
|
2007-10-23 07:11:59 +00:00
|
|
|
fp.appendFilters(nsIFilePicker.filterAll);
|
|
|
|
if (fp.show() == nsIFilePicker.returnOK) {
|
|
|
|
var file = fp.file;
|
2015-11-04 19:30:25 +00:00
|
|
|
let dialogText = '';
|
|
|
|
let dialogTitle = '';
|
|
|
|
|
|
|
|
// In dropbox folder
|
|
|
|
if (Zotero.File.isDropboxDirectory(file.path)) {
|
|
|
|
dialogTitle = Zotero.getString('general.warning');
|
|
|
|
dialogText = Zotero.getString('dataDir.unsafeLocation.selected.dropbox') + "\n\n"
|
|
|
|
+ Zotero.getString('dataDir.unsafeLocation.selected.useAnyway');
|
|
|
|
}
|
|
|
|
else if (file.directoryEntries.hasMoreElements()) {
|
|
|
|
let dbfile = file.clone();
|
2007-10-23 07:11:59 +00:00
|
|
|
dbfile.append('zotero.sqlite');
|
2009-11-20 20:25:09 +00:00
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
// Warn if non-empty and no zotero.sqlite
|
|
|
|
if (!dbfile.exists()) {
|
2015-11-04 19:30:25 +00:00
|
|
|
dialogTitle = Zotero.getString('dataDir.selectedDirNonEmpty.title');
|
|
|
|
dialogText = Zotero.getString('dataDir.selectedDirNonEmpty.text');
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
}
|
2015-11-04 19:30:25 +00:00
|
|
|
// Directory empty
|
2009-11-20 20:25:09 +00:00
|
|
|
else {
|
2015-11-04 19:30:25 +00:00
|
|
|
dialogTitle = Zotero.getString('dataDir.selectedDirEmpty.title');
|
|
|
|
dialogText = Zotero.getString('dataDir.selectedDirEmpty.text', Zotero.appName) + '\n\n'
|
|
|
|
+ Zotero.getString('dataDir.selectedDirEmpty.useNewDir');
|
|
|
|
}
|
|
|
|
// Warning dialog to be displayed
|
|
|
|
if(dialogText !== '') {
|
|
|
|
let buttonFlags = ps.STD_YES_NO_BUTTONS;
|
2013-03-20 18:55:50 +00:00
|
|
|
if (moreInfoCallback) {
|
|
|
|
buttonFlags += ps.BUTTON_POS_2 * ps.BUTTON_TITLE_IS_STRING;
|
|
|
|
}
|
2015-11-04 19:30:25 +00:00
|
|
|
let index = ps.confirmEx(null,
|
|
|
|
dialogTitle,
|
|
|
|
dialogText,
|
2013-03-20 18:55:50 +00:00
|
|
|
buttonFlags,
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
moreInfoCallback ? Zotero.getString('general.moreInformation') : null,
|
|
|
|
null, {});
|
2015-11-04 19:30:25 +00:00
|
|
|
|
2009-11-20 20:25:09 +00:00
|
|
|
// Not OK -- return to file picker
|
|
|
|
if (index == 1) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-03-20 18:55:50 +00:00
|
|
|
else if (index == 2) {
|
|
|
|
setTimeout(function () {
|
|
|
|
moreInfoCallback();
|
|
|
|
}, 1);
|
|
|
|
return false;
|
|
|
|
}
|
2009-11-20 20:25:09 +00:00
|
|
|
}
|
2015-11-04 19:30:25 +00:00
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
// Set new data directory
|
|
|
|
Zotero.Prefs.set('dataDir', file.persistentDescriptor);
|
|
|
|
Zotero.Prefs.set('lastDataDir', file.path);
|
|
|
|
Zotero.Prefs.set('useDataDir', true);
|
2010-10-02 20:08:16 +00:00
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2006-08-01 23:10:31 +00:00
|
|
|
}
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING);
|
2013-03-20 18:55:50 +00:00
|
|
|
if (!forceQuitNow) {
|
2007-10-23 07:11:59 +00:00
|
|
|
buttonFlags += (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING);
|
2006-08-01 23:10:31 +00:00
|
|
|
}
|
2013-03-20 18:55:50 +00:00
|
|
|
var app = Zotero.appName;
|
2011-01-13 20:52:15 +00:00
|
|
|
var index = ps.confirmEx(null,
|
2007-10-23 07:11:59 +00:00
|
|
|
Zotero.getString('general.restartRequired'),
|
2013-03-20 18:55:50 +00:00
|
|
|
Zotero.getString('general.restartRequiredForChange', app)
|
|
|
|
+ "\n\n" + Zotero.getString('dataDir.moveFilesToNewLocation', app),
|
2007-10-23 07:11:59 +00:00
|
|
|
buttonFlags,
|
2013-03-20 18:55:50 +00:00
|
|
|
Zotero.getString('general.quitApp', app),
|
|
|
|
forceQuitNow ? null : Zotero.getString('general.restartLater'),
|
2007-10-23 07:11:59 +00:00
|
|
|
null, null, {});
|
2006-08-01 23:10:31 +00:00
|
|
|
|
2015-11-04 19:30:25 +00:00
|
|
|
if (forceQuitNow || index == 0) {
|
2013-06-06 06:37:19 +00:00
|
|
|
Services.startup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
2006-08-01 23:10:31 +00:00
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
return useProfileDir ? true : file;
|
2006-08-01 23:10:31 +00:00
|
|
|
}
|
2016-06-27 16:40:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
this.forceNewDataDirectory = function(win) {
|
|
|
|
if (!win) {
|
|
|
|
win = Services.wm.getMostRecentWindow('navigator:browser');
|
|
|
|
}
|
|
|
|
var ps = Services.prompt;
|
|
|
|
|
|
|
|
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
|
|
|
while (true) {
|
|
|
|
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
|
|
|
.createInstance(nsIFilePicker);
|
|
|
|
fp.init(win, Zotero.getString('dataDir.selectNewDir', Zotero.clientName), nsIFilePicker.modeGetFolder);
|
|
|
|
fp.displayDirectory = Zotero.getZoteroDirectory();
|
|
|
|
fp.appendFilters(nsIFilePicker.filterAll);
|
|
|
|
if (fp.show() == nsIFilePicker.returnOK) {
|
|
|
|
var file = fp.file;
|
|
|
|
|
|
|
|
if (file.directoryEntries.hasMoreElements()) {
|
|
|
|
ps.alert(null,
|
|
|
|
Zotero.getString('dataDir.mustSelectEmpty.title'),
|
|
|
|
Zotero.getString('dataDir.mustSelectEmpty.text')
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set new data directory
|
|
|
|
Zotero.Prefs.set('dataDir', file.persistentDescriptor);
|
|
|
|
Zotero.Prefs.set('lastDataDir', file.path);
|
|
|
|
Zotero.Prefs.set('useDataDir', true);
|
|
|
|
return file;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2015-11-04 19:30:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
this.warnOnUnsafeDataDir = true;
|
|
|
|
this.checkForUnsafeDataDirectory = function (path) {
|
|
|
|
if (this.warnOnUnsafeDataDir && Zotero.File.isDropboxDirectory(path)
|
|
|
|
&& Zotero.Prefs.get('warnOnUnsafeDataDir')) {
|
|
|
|
|
|
|
|
this.warnOnUnsafeDataDir = false;
|
|
|
|
let check = {value: false};
|
|
|
|
let index = Services.prompt.confirmEx(
|
|
|
|
null,
|
|
|
|
Zotero.getString('general.warning'),
|
|
|
|
Zotero.getString('dataDir.unsafeLocation.existing.dropbox') + "\n\n"
|
|
|
|
+ Zotero.getString('dataDir.unsafeLocation.existing.chooseDifferent'),
|
|
|
|
Services.prompt.STD_YES_NO_BUTTONS,
|
|
|
|
null, null, null,
|
|
|
|
Zotero.getString('general.dontShowWarningAgain'),
|
|
|
|
check
|
|
|
|
);
|
|
|
|
|
|
|
|
// Yes - display dialog.
|
|
|
|
if (index == 0) {
|
|
|
|
Zotero.chooseZoteroDirectory(true);
|
|
|
|
}
|
|
|
|
if (check.value) {
|
|
|
|
Zotero.Prefs.set('warnOnUnsafeDataDir', false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-08-01 23:10:31 +00:00
|
|
|
|
2006-07-27 08:45:48 +00:00
|
|
|
|
2013-04-11 08:28:38 +00:00
|
|
|
/**
|
|
|
|
* Launch a file, the best way we can
|
|
|
|
*/
|
|
|
|
this.launchFile = function (file) {
|
2016-05-30 13:02:40 +00:00
|
|
|
file = Zotero.File.pathToFile(file);
|
2013-04-11 08:28:38 +00:00
|
|
|
try {
|
|
|
|
file.launch();
|
|
|
|
}
|
|
|
|
catch (e) {
|
2014-08-07 22:29:32 +00:00
|
|
|
Zotero.debug(e, 2);
|
|
|
|
Zotero.debug("launch() not supported -- trying fallback executable", 2);
|
2013-04-11 08:28:38 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
if (Zotero.isWin) {
|
|
|
|
var pref = "fallbackLauncher.windows";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var pref = "fallbackLauncher.unix";
|
|
|
|
}
|
|
|
|
var path = Zotero.Prefs.get(pref);
|
|
|
|
|
|
|
|
var exec = Components.classes["@mozilla.org/file/local;1"]
|
|
|
|
.createInstance(Components.interfaces.nsILocalFile);
|
|
|
|
exec.initWithPath(path);
|
|
|
|
if (!exec.exists()) {
|
|
|
|
throw (path + " does not exist");
|
|
|
|
}
|
|
|
|
|
|
|
|
var proc = Components.classes["@mozilla.org/process/util;1"]
|
|
|
|
.createInstance(Components.interfaces.nsIProcess);
|
|
|
|
proc.init(exec);
|
|
|
|
|
|
|
|
var args = [file.path];
|
|
|
|
proc.runw(true, args, args.length);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
Zotero.debug(e);
|
|
|
|
Zotero.debug("Launching via executable failed -- passing to loadUrl()");
|
|
|
|
|
|
|
|
// If nsILocalFile.launch() isn't available and the fallback
|
|
|
|
// executable doesn't exist, we just let the Firefox external
|
|
|
|
// helper app window handle it
|
|
|
|
var nsIFPH = Components.classes["@mozilla.org/network/protocol;1?name=file"]
|
|
|
|
.getService(Components.interfaces.nsIFileProtocolHandler);
|
|
|
|
var uri = nsIFPH.newFileURI(file);
|
|
|
|
|
|
|
|
var nsIEPS = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"].
|
|
|
|
getService(Components.interfaces.nsIExternalProtocolService);
|
|
|
|
nsIEPS.loadUrl(uri);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-21 17:01:06 +00:00
|
|
|
/*
|
|
|
|
* Debug logging function
|
|
|
|
*
|
2007-10-23 07:11:59 +00:00
|
|
|
* Uses prefs e.z.debug.log and e.z.debug.level (restart required)
|
2006-02-21 17:01:06 +00:00
|
|
|
*
|
2014-08-12 05:17:20 +00:00
|
|
|
* @param {} message
|
|
|
|
* @param {Integer} [level=3]
|
|
|
|
* @param {Boolean|Integer} [stack] Whether to display the calling stack.
|
|
|
|
* If true, stack is displayed starting from the caller. If an integer,
|
|
|
|
* that many stack levels will be omitted starting from the caller.
|
2006-02-21 17:01:06 +00:00
|
|
|
*/
|
2014-08-12 05:17:20 +00:00
|
|
|
function debug(message, level, stack) {
|
|
|
|
// Account for this alias
|
|
|
|
if (stack === true) {
|
|
|
|
stack = 1;
|
|
|
|
} else if (stack >= 0) {
|
|
|
|
stack++;
|
|
|
|
}
|
|
|
|
|
|
|
|
Zotero.Debug.log(message, level, stack);
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Log a message to the Mozilla JS error console
|
|
|
|
*
|
|
|
|
* |type| is a string with one of the flag types in nsIScriptError:
|
|
|
|
* 'error', 'warning', 'exception', 'strict'
|
|
|
|
*/
|
Initial Zotero 1.5 Megacommit
Apologies for the massive (and, due to data_access.js splitting, difficult-to-follow) commit. Please note that external code that accesses the data layer may need to be tweaked for compatibility. Here's a comprehensive-as-possible changelog:
- Added server sync functionality (incomplete)
- Overhaul of data layer
- Split data_access.js into separate files (item.js, items.js, creator.js, etc.)
- Made creators and collections first-class objects, similar to items
- Constructors now take id as first parameter, e.g. new Zotero.Item(1234, 'book'), to allow explicit id setting and id changing
- Made various data layer operations (including attachment fields) require a save() rather than making direct DB changes
- Better handling of unsaved objects
- Item.setCreator() now takes creator objects instead of creator ids, and Item.save() will auto-save unsaved creators
- clone() now works on unsaved objects
- Newly created object instances are now disabled after save() to force refetch of globally accessible instance using Zotero.(Items|Creators|etc.).get()
- Added secondary lookup key to data objects
- Deprecated getID() and getItemType() methods in favor of .id and .itemTypeID properties
- toArray() deprecated in favor of serialize(), which has a somewhat modified format
- Added support for multiple creators with identical data -- currently unimplemented in interface and most of data layer
- Added Item.diff() for comparing item metadata
- Database changes
- Added SQLite triggers to enforce foreign key constraints
- Added Zotero.DB.transactionVacuum flag to run a VACUUM after a transaction
- Added Zotero.DB.transactionDate, .transactionDateTime, and transactionTimestamp to retrieve consistent timestamps for entire transaction
- Properly store 64-bit integers
- Set PRAGMA locking_mode=EXCLUSIVE on database
- Set SQLite page size to 4096 on new databases
- Set SQLite page cache to 8MB
- Do some database cleanup and integrity checking on migration from 1.0 branch
- Removed IF NOT EXISTS from userdata.sql CREATE statements -- userdata.sql is now processed only on DB initialization
- Removed itemNoteTitles table and moved titles into itemNotes
- Abstracted metadata edit box and note box into flexible XBL bindings with various modes, including read-only states
- Massive speed-up of item tree view
- Several fixes from 1.0 branch for Fx3 compatibility
- Added Notifier observer to log delete events for syncing
- Zotero.Utilities changes
- New methods getSQLDataType() and md5()
- Removed onError from Zotero.Utilities.HTTP.doGet()
- Don't display more than 1024 characters in doPost() debug output
- Don't display passwords in doPost() debug output
- Added Zotero.Notifier.untrigger() -- currently unused
- Added Zotero.reloadDataObjects() to reset all in-memory objects
- Added |chars| parameter to Zotero.randomString(len, chars)
- Added Zotero.Date.getUnixTimestamp() and Date.toUnixTimestamp(JSDate)
- Adjusted zotero-service.js to simplify file inclusion
Various things (such as tags) are temporarily broken.
2008-05-04 08:32:48 +00:00
|
|
|
function log(message, type, sourceName, sourceLine, lineNumber, columnNumber) {
|
2007-10-23 07:11:59 +00:00
|
|
|
var scriptError = Components.classes["@mozilla.org/scripterror;1"]
|
|
|
|
.createInstance(Components.interfaces.nsIScriptError);
|
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
type = 'warning';
|
2006-02-21 17:01:06 +00:00
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
var flags = scriptError[type + 'Flag'];
|
|
|
|
|
|
|
|
scriptError.init(
|
|
|
|
message,
|
|
|
|
sourceName ? sourceName : null,
|
|
|
|
sourceLine != undefined ? sourceLine : null,
|
|
|
|
lineNumber != undefined ? lineNumber : null,
|
|
|
|
columnNumber != undefined ? columnNumber : null,
|
|
|
|
flags,
|
2010-08-24 21:08:04 +00:00
|
|
|
'component javascript'
|
2007-10-23 07:11:59 +00:00
|
|
|
);
|
2013-06-06 06:37:19 +00:00
|
|
|
Services.console.logMessage(scriptError);
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
|
2010-11-02 21:39:54 +00:00
|
|
|
/**
|
2015-03-16 19:17:45 +00:00
|
|
|
* Log a JS error to the Mozilla error console and debug output
|
2010-11-02 21:39:54 +00:00
|
|
|
* @param {Exception} err
|
|
|
|
*/
|
|
|
|
function logError(err) {
|
2014-10-03 20:06:01 +00:00
|
|
|
Zotero.debug(err, 1);
|
2010-11-22 19:33:22 +00:00
|
|
|
log(err.message ? err.message : err.toString(), "error",
|
2011-08-11 04:06:45 +00:00
|
|
|
err.fileName ? err.fileName : (err.filename ? err.filename : null), null,
|
2016-04-23 01:09:18 +00:00
|
|
|
err.lineNumber ? err.lineNumber : null, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.warn = function (err) {
|
|
|
|
Zotero.debug(err, 2);
|
|
|
|
log(err.message ? err.message : err.toString(), "warning",
|
|
|
|
err.fileName ? err.fileName : (err.filename ? err.filename : null), null,
|
2010-11-02 21:39:54 +00:00
|
|
|
err.lineNumber ? err.lineNumber : null, null);
|
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
|
2015-04-14 20:09:55 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Display an alert in a given window
|
|
|
|
*
|
|
|
|
* @param {Window}
|
|
|
|
* @param {String} title
|
|
|
|
* @param {String} msg
|
|
|
|
*/
|
|
|
|
this.alert = function (window, title, msg) {
|
|
|
|
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIPromptService);
|
|
|
|
ps.alert(window, title, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
function getErrors(asStrings) {
|
|
|
|
var errors = [];
|
|
|
|
|
2012-02-14 01:42:32 +00:00
|
|
|
for each(var msg in _startupErrors.concat(_recentErrors)) {
|
2008-09-15 09:48:27 +00:00
|
|
|
// Remove password in malformed XML messages
|
|
|
|
if (msg.category == 'malformed-xml') {
|
|
|
|
try {
|
|
|
|
// msg.message is read-only, so store separately
|
|
|
|
var altMessage = msg.message.replace(/(file: "https?:\/\/[^:]+:)([^@]+)(@[^"]+")/, "$1********$3");
|
|
|
|
}
|
|
|
|
catch (e) {}
|
|
|
|
}
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
if (asStrings) {
|
2008-09-15 09:48:27 +00:00
|
|
|
errors.push(altMessage ? altMessage : msg.message)
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
errors.push(msg);
|
|
|
|
}
|
2006-02-21 17:01:06 +00:00
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
return errors;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-02 20:07:50 +00:00
|
|
|
/**
|
|
|
|
* Get versions, platform, etc.
|
|
|
|
*
|
|
|
|
* Can be used synchronously or asynchronously; info on other add-ons
|
|
|
|
* is available only in async mode
|
|
|
|
*/
|
2011-09-20 21:39:48 +00:00
|
|
|
function getSystemInfo(callback) {
|
2011-11-02 20:07:50 +00:00
|
|
|
var info = {
|
|
|
|
version: Zotero.version,
|
|
|
|
platform: Zotero.platform,
|
|
|
|
oscpu: Zotero.oscpu,
|
|
|
|
locale: Zotero.locale,
|
2013-06-06 06:37:19 +00:00
|
|
|
appName: Services.appinfo.name,
|
|
|
|
appVersion: Services.appinfo.version
|
2011-11-02 20:07:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
Zotero.getInstalledExtensions(function(extensions) {
|
|
|
|
info.extensions = extensions.join(', ');
|
|
|
|
|
|
|
|
var str = '';
|
|
|
|
for (var key in info) {
|
|
|
|
str += key + ' => ' + info[key] + ', ';
|
|
|
|
}
|
|
|
|
str = str.substr(0, str.length - 2);
|
|
|
|
callback(str);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
var str = '';
|
|
|
|
for (var key in info) {
|
|
|
|
str += key + ' => ' + info[key] + ', ';
|
|
|
|
}
|
|
|
|
str = str.substr(0, str.length - 2);
|
|
|
|
return str;
|
2006-03-20 21:47:22 +00:00
|
|
|
}
|
Renamed DB to scholar.sqlite, since that seems to be the current fashion
Added some new core functions:
- Scholar.varDump(), after PHP's var_dump()
- Scholar.flattenArguments(), to flatten mixed array/literal argument lists into a single array
- Scholar.join() -- a version of join() that operates externally, for use on, for example, the arguments object (safer than extending Object)
- Scholar.Hash, a slightly smarter associative array -- not perfect, but brings a proper length property and a few convenience methods (and allows for other additions) -- should probably be limited to places where the length property or other additional additions are needed, since its use is a little non-standard (e.g. you have to remember to do _for (i in arr.items)_ rather than just _for (i in arr)_, to use set(), etc.)
2006-03-14 11:45:19 +00:00
|
|
|
|
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
/**
|
|
|
|
* @return {String[]} Array of extension names and versions
|
|
|
|
*/
|
2011-09-20 21:39:48 +00:00
|
|
|
this.getInstalledExtensions = function(callback) {
|
|
|
|
function onHaveInstalledAddons(installed) {
|
2012-11-12 20:39:40 +00:00
|
|
|
installed.sort(function(a, b) {
|
|
|
|
return ((a.appDisabled || a.userDisabled) ? 1 : 0) -
|
|
|
|
((b.appDisabled || b.userDisabled) ? 1 : 0);
|
|
|
|
});
|
2011-09-20 21:39:48 +00:00
|
|
|
var addons = [];
|
|
|
|
for each(var addon in installed) {
|
|
|
|
switch (addon.id) {
|
|
|
|
case "zotero@chnm.gmu.edu":
|
|
|
|
case "{972ce4c6-7e08-4474-a285-3208198ce6fd}": // Default theme
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
addons.push(addon.name + " (" + addon.version
|
2012-11-12 20:39:40 +00:00
|
|
|
+ (addon.type != 2 ? ", " + addon.type : "")
|
|
|
|
+ ((addon.appDisabled || addon.userDisabled) ? ", disabled" : "")
|
|
|
|
+ ")");
|
2010-11-05 05:05:36 +00:00
|
|
|
}
|
2011-09-20 21:39:48 +00:00
|
|
|
callback(addons);
|
|
|
|
}
|
|
|
|
|
2012-02-14 20:20:19 +00:00
|
|
|
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
|
|
|
AddonManager.getAllAddons(onHaveInstalledAddons);
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
}
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
function getString(name, params){
|
2006-06-26 20:41:09 +00:00
|
|
|
try {
|
2007-10-23 07:11:59 +00:00
|
|
|
if (params != undefined){
|
|
|
|
if (typeof params != 'object'){
|
|
|
|
params = [params];
|
|
|
|
}
|
|
|
|
var l10n = _localizedStringBundle.formatStringFromName(name, params, params.length);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var l10n = _localizedStringBundle.GetStringFromName(name);
|
|
|
|
}
|
2006-06-26 20:41:09 +00:00
|
|
|
}
|
|
|
|
catch (e){
|
2014-09-16 19:46:13 +00:00
|
|
|
if (e.name == 'NS_ERROR_ILLEGAL_VALUE') {
|
|
|
|
Zotero.debug(params, 1);
|
|
|
|
}
|
2014-09-19 19:52:53 +00:00
|
|
|
else if (e.name != 'NS_ERROR_FAILURE') {
|
|
|
|
Components.utils.reportError(e);
|
|
|
|
Zotero.debug(e, 1);
|
|
|
|
}
|
2006-06-26 20:41:09 +00:00
|
|
|
throw ('Localized string not available for ' + name);
|
|
|
|
}
|
|
|
|
return l10n;
|
2006-05-27 00:20:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-14 08:06:22 +00:00
|
|
|
/**
|
|
|
|
* 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
|
2014-11-02 19:47:52 +00:00
|
|
|
* @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.
|
2014-11-14 08:06:22 +00:00
|
|
|
*/
|
2014-11-02 19:47:52 +00:00
|
|
|
this.defineProperty = function(obj, prop, desc, opts) {
|
2014-11-14 08:06:22 +00:00
|
|
|
if (typeof prop != 'string') throw new Error("Property must be a string");
|
2014-11-07 04:02:13 +00:00
|
|
|
var d = { __proto__: null, enumerable: true, configurable: true }; // Enumerable by default
|
2014-11-14 08:06:22 +00:00
|
|
|
for (let p in desc) {
|
|
|
|
if (!desc.hasOwnProperty(p)) continue;
|
|
|
|
d[p] = desc[p];
|
|
|
|
}
|
2014-11-02 19:47:52 +00:00
|
|
|
|
|
|
|
if (opts) {
|
|
|
|
if (opts.lazy && d.get) {
|
|
|
|
let getter = d.get;
|
2015-05-13 17:43:05 +00:00
|
|
|
d.configurable = true; // Make sure we can change the property later
|
2014-11-02 19:47:52 +00:00
|
|
|
d.get = function() {
|
2015-05-13 17:43:05 +00:00
|
|
|
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);
|
|
|
|
|
2014-11-02 19:47:52 +00:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-14 08:06:22 +00:00
|
|
|
Object.defineProperty(obj, prop, d);
|
|
|
|
}
|
|
|
|
|
2015-05-13 15:45:45 +00:00
|
|
|
this.extendClass = function(superClass, newClass) {
|
|
|
|
newClass._super = superClass;
|
|
|
|
newClass.prototype = Object.create(superClass.prototype);
|
|
|
|
newClass.prototype.constructor = newClass;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
/*
|
2011-04-16 09:22:43 +00:00
|
|
|
* This function should be removed
|
2007-10-23 07:11:59 +00:00
|
|
|
*
|
|
|
|
* |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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-25 16:14:28 +00:00
|
|
|
this.getLocaleCollation = function () {
|
|
|
|
if (this.collation) {
|
|
|
|
return this.collation;
|
|
|
|
}
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
|
2014-06-25 16:14:28 +00:00
|
|
|
.getService(Components.interfaces.nsILocaleService);
|
|
|
|
var appLocale = localeService.getApplicationLocale();
|
|
|
|
|
2014-06-27 05:12:25 +00:00
|
|
|
// Use nsICollation before Fx30
|
|
|
|
if (Zotero.platformMajorVersion < 30) {
|
2014-06-25 16:14:28 +00:00
|
|
|
var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
|
|
|
|
.getService(Components.interfaces.nsILocaleService);
|
|
|
|
var collationFactory = Components.classes["@mozilla.org/intl/collation-factory;1"]
|
|
|
|
.getService(Components.interfaces.nsICollationFactory);
|
|
|
|
return this.collation = collationFactory.CreateCollation(appLocale);
|
|
|
|
}
|
|
|
|
|
2014-06-27 13:35:07 +00:00
|
|
|
try {
|
|
|
|
var locale = appLocale.getCategory('NSILOCALE_COLLATE');
|
|
|
|
// Extract a valid language tag
|
|
|
|
locale = locale.match(/^[a-z]{2}(\-[A-Z]{2})?/)[0];
|
2014-07-08 13:47:03 +00:00
|
|
|
var collator = new Intl.Collator(locale, {
|
|
|
|
ignorePunctuation: true,
|
2014-07-18 05:03:55 +00:00
|
|
|
numeric: true,
|
|
|
|
sensitivity: 'base'
|
2014-07-08 13:47:03 +00:00
|
|
|
});
|
2014-06-27 13:35:07 +00:00
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
Zotero.debug(e, 1);
|
|
|
|
|
|
|
|
// If there's an error, just skip sorting
|
|
|
|
collator = {
|
|
|
|
compare: function (a, b) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2014-07-18 05:03:55 +00:00
|
|
|
// 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 = /["'[{(]+$/;
|
|
|
|
|
2014-06-25 16:14:28 +00:00
|
|
|
// Until old code is updated, pretend we're returning an nsICollation
|
|
|
|
return this.collation = {
|
|
|
|
compareString: function (_, a, b) {
|
2014-07-18 05:03:55 +00:00
|
|
|
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
|
|
|
|
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);
|
2014-06-25 16:14:28 +00:00
|
|
|
}
|
|
|
|
};
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
|
2014-11-14 08:54:53 +00:00
|
|
|
this.defineProperty(this, "localeCompare", {
|
|
|
|
get: function() {
|
|
|
|
var collation = this.getLocaleCollation();
|
|
|
|
return collation.compareString.bind(collation, 1);
|
|
|
|
}
|
|
|
|
}, {lazy: true});
|
2007-10-23 07:11:59 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Renamed DB to scholar.sqlite, since that seems to be the current fashion
Added some new core functions:
- Scholar.varDump(), after PHP's var_dump()
- Scholar.flattenArguments(), to flatten mixed array/literal argument lists into a single array
- Scholar.join() -- a version of join() that operates externally, for use on, for example, the arguments object (safer than extending Object)
- Scholar.Hash, a slightly smarter associative array -- not perfect, but brings a proper length property and a few convenience methods (and allows for other additions) -- should probably be limited to places where the length property or other additional additions are needed, since its use is a little non-standard (e.g. you have to remember to do _for (i in arr.items)_ rather than just _for (i in arr)_, to use set(), etc.)
2006-03-14 11:45:19 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
2006-03-20 21:47:22 +00:00
|
|
|
function flattenArguments(args){
|
2006-06-02 20:51:34 +00:00
|
|
|
// Put passed scalar values into an array
|
2013-05-01 22:23:09 +00:00
|
|
|
if (args === null || typeof args == 'string' || typeof args.length == 'undefined') {
|
2006-06-02 20:51:34 +00:00
|
|
|
args = [args];
|
|
|
|
}
|
|
|
|
|
2.0b3 megacommit
- Support for group libraries
- General support for multiple libraries of different types
- Streamlined sync support
- Using solely libraryID and key rather than itemID, and removed all itemID-changing code
- Combined two requests for increased performance and decreased server load
- Added warning on user account change
- Provide explicit error message on SSL failure
- Removed snapshot and link toolbar buttons and changed browser context menu options and drags to create parent items + snapshots
- Closes #786, Add numPages field
- Fixes #1063, Duplicate item with tags broken in Sync Preview
- Added better purging of deleted tags
- Added local user key before first sync
- Add clientDateModified to all objects for more flexibility in syncing
- Added new triples-based Relation object type, currently used to store links between items copied between local and group libraries
- Updated zotero.org translator for groups
- Additional trigger-based consistency checks
- Fixed broken URL drag in Firefox 3.5
- Disabled zeroconf menu option (no longer functional)
Developer-specific changes:
- Overhauled data layer
- Data object constructors no longer take arguments (return to 1.0-like API)
- Existing objects can be retrieved by setting id or library/key properties
- id/library/key must be set for new objects before other fields
- New methods:
- ZoteroPane.getSelectedLibraryID()
- ZoteroPane.getSelectedGroup(asID)
- ZoteroPane.addItemFromDocument(doc, itemType, saveSnapshot)
- ZoteroPane.addItemFromURL(url, itemType)
- ZoteroPane.canEdit()
- Zotero.CollectionTreeView.selectLibrary(libraryID)
- New Zotero.URI methods
- Changed methods
- Many data object methods now take a libraryID
- ZoteroPane.addAttachmentFromPage(link, itemID)
- Removed saveItem and saveAttachments parameters from Zotero.Translate constructor
- translate() now takes a libraryID, null for local library, or false to not save items (previously on constructor)
- saveAttachments is now a translate() parameter
- Zotero.flattenArguments() better handles passed objects
- Zotero.File.getFileHash() (not currently used)
2009-05-14 18:23:40 +00:00
|
|
|
var returns = [];
|
Renamed DB to scholar.sqlite, since that seems to be the current fashion
Added some new core functions:
- Scholar.varDump(), after PHP's var_dump()
- Scholar.flattenArguments(), to flatten mixed array/literal argument lists into a single array
- Scholar.join() -- a version of join() that operates externally, for use on, for example, the arguments object (safer than extending Object)
- Scholar.Hash, a slightly smarter associative array -- not perfect, but brings a proper length property and a few convenience methods (and allows for other additions) -- should probably be limited to places where the length property or other additional additions are needed, since its use is a little non-standard (e.g. you have to remember to do _for (i in arr.items)_ rather than just _for (i in arr)_, to use set(), etc.)
2006-03-14 11:45:19 +00:00
|
|
|
for (var i=0; i<args.length; i++){
|
2013-05-01 22:23:09 +00:00
|
|
|
var arg = args[i];
|
|
|
|
if (!arg && arg !== 0) {
|
2.0b3 megacommit
- Support for group libraries
- General support for multiple libraries of different types
- Streamlined sync support
- Using solely libraryID and key rather than itemID, and removed all itemID-changing code
- Combined two requests for increased performance and decreased server load
- Added warning on user account change
- Provide explicit error message on SSL failure
- Removed snapshot and link toolbar buttons and changed browser context menu options and drags to create parent items + snapshots
- Closes #786, Add numPages field
- Fixes #1063, Duplicate item with tags broken in Sync Preview
- Added better purging of deleted tags
- Added local user key before first sync
- Add clientDateModified to all objects for more flexibility in syncing
- Added new triples-based Relation object type, currently used to store links between items copied between local and group libraries
- Updated zotero.org translator for groups
- Additional trigger-based consistency checks
- Fixed broken URL drag in Firefox 3.5
- Disabled zeroconf menu option (no longer functional)
Developer-specific changes:
- Overhauled data layer
- Data object constructors no longer take arguments (return to 1.0-like API)
- Existing objects can be retrieved by setting id or library/key properties
- id/library/key must be set for new objects before other fields
- New methods:
- ZoteroPane.getSelectedLibraryID()
- ZoteroPane.getSelectedGroup(asID)
- ZoteroPane.addItemFromDocument(doc, itemType, saveSnapshot)
- ZoteroPane.addItemFromURL(url, itemType)
- ZoteroPane.canEdit()
- Zotero.CollectionTreeView.selectLibrary(libraryID)
- New Zotero.URI methods
- Changed methods
- Many data object methods now take a libraryID
- ZoteroPane.addAttachmentFromPage(link, itemID)
- Removed saveItem and saveAttachments parameters from Zotero.Translate constructor
- translate() now takes a libraryID, null for local library, or false to not save items (previously on constructor)
- saveAttachments is now a translate() parameter
- Zotero.flattenArguments() better handles passed objects
- Zotero.File.getFileHash() (not currently used)
2009-05-14 18:23:40 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-05-01 22:23:09 +00:00
|
|
|
if (Array.isArray(arg)) {
|
|
|
|
for (var j=0; j<arg.length; j++){
|
|
|
|
returns.push(arg[j]);
|
Renamed DB to scholar.sqlite, since that seems to be the current fashion
Added some new core functions:
- Scholar.varDump(), after PHP's var_dump()
- Scholar.flattenArguments(), to flatten mixed array/literal argument lists into a single array
- Scholar.join() -- a version of join() that operates externally, for use on, for example, the arguments object (safer than extending Object)
- Scholar.Hash, a slightly smarter associative array -- not perfect, but brings a proper length property and a few convenience methods (and allows for other additions) -- should probably be limited to places where the length property or other additional additions are needed, since its use is a little non-standard (e.g. you have to remember to do _for (i in arr.items)_ rather than just _for (i in arr)_, to use set(), etc.)
2006-03-14 11:45:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2013-05-01 22:23:09 +00:00
|
|
|
returns.push(arg);
|
Renamed DB to scholar.sqlite, since that seems to be the current fashion
Added some new core functions:
- Scholar.varDump(), after PHP's var_dump()
- Scholar.flattenArguments(), to flatten mixed array/literal argument lists into a single array
- Scholar.join() -- a version of join() that operates externally, for use on, for example, the arguments object (safer than extending Object)
- Scholar.Hash, a slightly smarter associative array -- not perfect, but brings a proper length property and a few convenience methods (and allows for other additions) -- should probably be limited to places where the length property or other additional additions are needed, since its use is a little non-standard (e.g. you have to remember to do _for (i in arr.items)_ rather than just _for (i in arr)_, to use set(), etc.)
2006-03-14 11:45:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return returns;
|
2006-03-20 21:47:22 +00:00
|
|
|
}
|
Renamed DB to scholar.sqlite, since that seems to be the current fashion
Added some new core functions:
- Scholar.varDump(), after PHP's var_dump()
- Scholar.flattenArguments(), to flatten mixed array/literal argument lists into a single array
- Scholar.join() -- a version of join() that operates externally, for use on, for example, the arguments object (safer than extending Object)
- Scholar.Hash, a slightly smarter associative array -- not perfect, but brings a proper length property and a few convenience methods (and allows for other additions) -- should probably be limited to places where the length property or other additional additions are needed, since its use is a little non-standard (e.g. you have to remember to do _for (i in arr.items)_ rather than just _for (i in arr)_, to use set(), etc.)
2006-03-14 11:45:19 +00:00
|
|
|
|
|
|
|
|
Closes #259, auto-complete of tags
Addresses #260, Add auto-complete to search window
- New XPCOM autocomplete component for Zotero data -- can be used by setting the autocompletesearch attribute of a textbox to 'zotero' and passing a search scope with the autocompletesearchparam attribute. Additional parameters can be passed by appending them to the autocompletesearchparam value with a '/', e.g. 'tag/2732' (to exclude tags that show up in item 2732)
- Tag entry now uses more or less the same interface as metadata -- no more popup window -- note that tab isn't working properly yet, and there's no way to quickly enter multiple tags (though it's now considerably quicker than it was before)
- Autocomplete for tags, excluding any tags already set for the current item
- Standalone note windows now register with the Notifier (since tags needed item modification notifications to work properly), which will help with #282, "Notes opened in separate windows need item notification"
- Tags are now retrieved in alphabetical order
- Scholar.Item.replaceTag(oldTagID, newTag), with a single notify
- Scholar.getAncestorByTagName(elem, tagName) -- walk up the DOM tree from an element until an element with the specified tag name is found (also checks with 'xul:' prefix, for use in XBL), or false if not found -- probably shouldn't be used too widely, since it's doing string comparisons, but better than specifying, say, nine '.parentNode' properties, and makes for more resilient code
A few notes:
- Autocomplete in Minefield seems to self-destruct after using it in the same field a few times, taking down saving of the field with it -- this may or may not be my fault, but it makes Zotero more or less unusable in 3.0 at the moment. Sorry. (I use 3.0 myself for development, so I'll work on it.)
- This would have been much, much easier if having an autocomplete textbox (which uses an XBL-generated popup for the suggestions) within a popup (as it is in the independent note edit panes) didn't introduce all sorts of crazy bugs that had to be defeated with annoying hackery -- one side effect of this is that at the moment you can't close the tags popup with the Escape key
- Independent note windows now need to pull in itemPane.js to function properly, which is a bit messy and not ideal, but less messy and more ideal than duplicating all the dual-state editor and tabindex logic would be
- Hitting tab in a tag field not only doesn't work but also breaks things until the next window refresh.
- There are undoubtedly other bugs.
2006-09-07 08:07:48 +00:00
|
|
|
function getAncestorByTagName(elem, tagName){
|
|
|
|
while (elem.parentNode){
|
|
|
|
elem = elem.parentNode;
|
2008-12-29 09:35:11 +00:00
|
|
|
if (elem.localName == tagName) {
|
Closes #259, auto-complete of tags
Addresses #260, Add auto-complete to search window
- New XPCOM autocomplete component for Zotero data -- can be used by setting the autocompletesearch attribute of a textbox to 'zotero' and passing a search scope with the autocompletesearchparam attribute. Additional parameters can be passed by appending them to the autocompletesearchparam value with a '/', e.g. 'tag/2732' (to exclude tags that show up in item 2732)
- Tag entry now uses more or less the same interface as metadata -- no more popup window -- note that tab isn't working properly yet, and there's no way to quickly enter multiple tags (though it's now considerably quicker than it was before)
- Autocomplete for tags, excluding any tags already set for the current item
- Standalone note windows now register with the Notifier (since tags needed item modification notifications to work properly), which will help with #282, "Notes opened in separate windows need item notification"
- Tags are now retrieved in alphabetical order
- Scholar.Item.replaceTag(oldTagID, newTag), with a single notify
- Scholar.getAncestorByTagName(elem, tagName) -- walk up the DOM tree from an element until an element with the specified tag name is found (also checks with 'xul:' prefix, for use in XBL), or false if not found -- probably shouldn't be used too widely, since it's doing string comparisons, but better than specifying, say, nine '.parentNode' properties, and makes for more resilient code
A few notes:
- Autocomplete in Minefield seems to self-destruct after using it in the same field a few times, taking down saving of the field with it -- this may or may not be my fault, but it makes Zotero more or less unusable in 3.0 at the moment. Sorry. (I use 3.0 myself for development, so I'll work on it.)
- This would have been much, much easier if having an autocomplete textbox (which uses an XBL-generated popup for the suggestions) within a popup (as it is in the independent note edit panes) didn't introduce all sorts of crazy bugs that had to be defeated with annoying hackery -- one side effect of this is that at the moment you can't close the tags popup with the Escape key
- Independent note windows now need to pull in itemPane.js to function properly, which is a bit messy and not ideal, but less messy and more ideal than duplicating all the dual-state editor and tabindex logic would be
- Hitting tab in a tag field not only doesn't work but also breaks things until the next window refresh.
- There are undoubtedly other bugs.
2006-09-07 08:07:48 +00:00
|
|
|
return elem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-06-01 19:46:57 +00:00
|
|
|
/**
|
|
|
|
* Generate a random string of length 'len' (defaults to 8)
|
|
|
|
**/
|
Initial Zotero 1.5 Megacommit
Apologies for the massive (and, due to data_access.js splitting, difficult-to-follow) commit. Please note that external code that accesses the data layer may need to be tweaked for compatibility. Here's a comprehensive-as-possible changelog:
- Added server sync functionality (incomplete)
- Overhaul of data layer
- Split data_access.js into separate files (item.js, items.js, creator.js, etc.)
- Made creators and collections first-class objects, similar to items
- Constructors now take id as first parameter, e.g. new Zotero.Item(1234, 'book'), to allow explicit id setting and id changing
- Made various data layer operations (including attachment fields) require a save() rather than making direct DB changes
- Better handling of unsaved objects
- Item.setCreator() now takes creator objects instead of creator ids, and Item.save() will auto-save unsaved creators
- clone() now works on unsaved objects
- Newly created object instances are now disabled after save() to force refetch of globally accessible instance using Zotero.(Items|Creators|etc.).get()
- Added secondary lookup key to data objects
- Deprecated getID() and getItemType() methods in favor of .id and .itemTypeID properties
- toArray() deprecated in favor of serialize(), which has a somewhat modified format
- Added support for multiple creators with identical data -- currently unimplemented in interface and most of data layer
- Added Item.diff() for comparing item metadata
- Database changes
- Added SQLite triggers to enforce foreign key constraints
- Added Zotero.DB.transactionVacuum flag to run a VACUUM after a transaction
- Added Zotero.DB.transactionDate, .transactionDateTime, and transactionTimestamp to retrieve consistent timestamps for entire transaction
- Properly store 64-bit integers
- Set PRAGMA locking_mode=EXCLUSIVE on database
- Set SQLite page size to 4096 on new databases
- Set SQLite page cache to 8MB
- Do some database cleanup and integrity checking on migration from 1.0 branch
- Removed IF NOT EXISTS from userdata.sql CREATE statements -- userdata.sql is now processed only on DB initialization
- Removed itemNoteTitles table and moved titles into itemNotes
- Abstracted metadata edit box and note box into flexible XBL bindings with various modes, including read-only states
- Massive speed-up of item tree view
- Several fixes from 1.0 branch for Fx3 compatibility
- Added Notifier observer to log delete events for syncing
- Zotero.Utilities changes
- New methods getSQLDataType() and md5()
- Removed onError from Zotero.Utilities.HTTP.doGet()
- Don't display more than 1024 characters in doPost() debug output
- Don't display passwords in doPost() debug output
- Added Zotero.Notifier.untrigger() -- currently unused
- Added Zotero.reloadDataObjects() to reset all in-memory objects
- Added |chars| parameter to Zotero.randomString(len, chars)
- Added Zotero.Date.getUnixTimestamp() and Date.toUnixTimestamp(JSDate)
- Adjusted zotero-service.js to simplify file inclusion
Various things (such as tags) are temporarily broken.
2008-05-04 08:32:48 +00:00
|
|
|
function randomString(len, chars) {
|
2011-07-04 09:08:49 +00:00
|
|
|
return Zotero.Utilities.randomString(len, chars);
|
2006-06-01 19:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-01 23:10:31 +00:00
|
|
|
function moveToUnique(file, newFile){
|
|
|
|
newFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644);
|
|
|
|
var newName = newFile.leafName;
|
|
|
|
newFile.remove(null);
|
|
|
|
|
|
|
|
// Move file to unique name
|
|
|
|
file.moveTo(newFile.parent, newName);
|
|
|
|
return file;
|
|
|
|
}
|
Initial Zotero 1.5 Megacommit
Apologies for the massive (and, due to data_access.js splitting, difficult-to-follow) commit. Please note that external code that accesses the data layer may need to be tweaked for compatibility. Here's a comprehensive-as-possible changelog:
- Added server sync functionality (incomplete)
- Overhaul of data layer
- Split data_access.js into separate files (item.js, items.js, creator.js, etc.)
- Made creators and collections first-class objects, similar to items
- Constructors now take id as first parameter, e.g. new Zotero.Item(1234, 'book'), to allow explicit id setting and id changing
- Made various data layer operations (including attachment fields) require a save() rather than making direct DB changes
- Better handling of unsaved objects
- Item.setCreator() now takes creator objects instead of creator ids, and Item.save() will auto-save unsaved creators
- clone() now works on unsaved objects
- Newly created object instances are now disabled after save() to force refetch of globally accessible instance using Zotero.(Items|Creators|etc.).get()
- Added secondary lookup key to data objects
- Deprecated getID() and getItemType() methods in favor of .id and .itemTypeID properties
- toArray() deprecated in favor of serialize(), which has a somewhat modified format
- Added support for multiple creators with identical data -- currently unimplemented in interface and most of data layer
- Added Item.diff() for comparing item metadata
- Database changes
- Added SQLite triggers to enforce foreign key constraints
- Added Zotero.DB.transactionVacuum flag to run a VACUUM after a transaction
- Added Zotero.DB.transactionDate, .transactionDateTime, and transactionTimestamp to retrieve consistent timestamps for entire transaction
- Properly store 64-bit integers
- Set PRAGMA locking_mode=EXCLUSIVE on database
- Set SQLite page size to 4096 on new databases
- Set SQLite page cache to 8MB
- Do some database cleanup and integrity checking on migration from 1.0 branch
- Removed IF NOT EXISTS from userdata.sql CREATE statements -- userdata.sql is now processed only on DB initialization
- Removed itemNoteTitles table and moved titles into itemNotes
- Abstracted metadata edit box and note box into flexible XBL bindings with various modes, including read-only states
- Massive speed-up of item tree view
- Several fixes from 1.0 branch for Fx3 compatibility
- Added Notifier observer to log delete events for syncing
- Zotero.Utilities changes
- New methods getSQLDataType() and md5()
- Removed onError from Zotero.Utilities.HTTP.doGet()
- Don't display more than 1024 characters in doPost() debug output
- Don't display passwords in doPost() debug output
- Added Zotero.Notifier.untrigger() -- currently unused
- Added Zotero.reloadDataObjects() to reset all in-memory objects
- Added |chars| parameter to Zotero.randomString(len, chars)
- Added Zotero.Date.getUnixTimestamp() and Date.toUnixTimestamp(JSDate)
- Adjusted zotero-service.js to simplify file inclusion
Various things (such as tags) are temporarily broken.
2008-05-04 08:32:48 +00:00
|
|
|
|
|
|
|
|
2013-08-15 01:36:50 +00:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
|
|
|
|
this.serial = function (fn) {
|
2015-10-29 06:49:31 +00:00
|
|
|
Components.utils.import("resource://zotero/concurrentCaller.js");
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
var caller = new ConcurrentCaller(1);
|
|
|
|
caller.setLogger(Zotero.debug);
|
|
|
|
return function () {
|
|
|
|
var args = arguments;
|
|
|
|
return caller.fcall(function () {
|
|
|
|
return fn.apply(this, args);
|
|
|
|
}.bind(this));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.spawn = function (generator, thisObject) {
|
|
|
|
if (thisObject) {
|
|
|
|
return Zotero.Promise.coroutine(generator.bind(thisObject))();
|
|
|
|
}
|
|
|
|
return Zotero.Promise.coroutine(generator)();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-31 19:59:07 +00:00
|
|
|
/**
|
2016-05-17 15:49:13 +00:00
|
|
|
* Emulates the behavior of window.setTimeout
|
2011-05-31 19:59:07 +00:00
|
|
|
*
|
2011-06-14 21:26:48 +00:00
|
|
|
* @param {Function} func The function to be called
|
|
|
|
* @param {Integer} ms The number of milliseconds to wait before calling func
|
2016-05-17 15:49:13 +00:00
|
|
|
* @return {Integer} - ID of timer to be passed to clearTimeout()
|
2011-05-31 19:59:07 +00:00
|
|
|
*/
|
2016-05-17 15:49:13 +00:00
|
|
|
var _lastTimeoutID = 0;
|
|
|
|
this.setTimeout = function (func, ms) {
|
|
|
|
var id = ++_lastTimeoutID;
|
|
|
|
|
|
|
|
var timer = Components.classes["@mozilla.org/timer;1"]
|
|
|
|
.createInstance(Components.interfaces.nsITimer);
|
|
|
|
var timerCallback = {
|
|
|
|
"notify": function () {
|
2011-05-31 19:59:07 +00:00
|
|
|
func();
|
2016-05-17 15:49:13 +00:00
|
|
|
_runningTimers.delete(id);
|
2011-06-14 19:24:39 +00:00
|
|
|
}
|
2016-05-17 15:49:13 +00:00
|
|
|
};
|
2013-06-06 23:31:09 +00:00
|
|
|
timer.initWithCallback(timerCallback, ms, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
2016-05-17 15:49:13 +00:00
|
|
|
_runningTimers.set(id, timer);
|
|
|
|
return id;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
this.clearTimeout = function (id) {
|
|
|
|
var timer = _runningTimers.get(id);
|
|
|
|
if (timer) {
|
|
|
|
timer.cancel();
|
|
|
|
_runningTimers.delete(id);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-08-08 07:38:34 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Show Zotero pane overlay and progress bar in all windows
|
|
|
|
*
|
|
|
|
* @param {String} msg
|
|
|
|
* @param {Boolean} [determinate=false]
|
2009-08-09 19:39:32 +00:00
|
|
|
* @return void
|
2009-08-08 07:38:34 +00:00
|
|
|
*/
|
2011-09-21 23:00:20 +00:00
|
|
|
this.showZoteroPaneProgressMeter = function (msg, determinate, icon) {
|
2013-08-12 00:51:16 +00:00
|
|
|
if (!msg) msg = "";
|
2013-06-06 06:37:19 +00:00
|
|
|
var currentWindow = Services.wm.getMostRecentWindow("navigator:browser");
|
|
|
|
var enumerator = Services.wm.getEnumerator("navigator:browser");
|
2009-08-08 07:38:34 +00:00
|
|
|
var progressMeters = [];
|
|
|
|
while (enumerator.hasMoreElements()) {
|
|
|
|
var win = enumerator.getNext();
|
2011-02-03 07:04:14 +00:00
|
|
|
if(!win.ZoteroPane) continue;
|
2011-09-21 23:00:20 +00:00
|
|
|
if(!win.ZoteroPane.isShowing()) {
|
|
|
|
if (win != currentWindow) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If Zotero is closed in the top-most window, show a popup instead
|
|
|
|
_progressPopup = new Zotero.ProgressWindow();
|
|
|
|
_progressPopup.changeHeadline("Zotero");
|
|
|
|
if (icon) {
|
|
|
|
_progressPopup.addLines([msg], [icon]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
_progressPopup.addDescription(msg);
|
|
|
|
}
|
|
|
|
_progressPopup.show();
|
|
|
|
continue;
|
|
|
|
}
|
2009-08-08 07:38:34 +00:00
|
|
|
|
2013-08-12 00:51:16 +00:00
|
|
|
var label = win.ZoteroPane.document.getElementById('zotero-pane-progress-label');
|
|
|
|
if (msg) {
|
|
|
|
label.hidden = false;
|
|
|
|
label.value = msg;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
label.hidden = true;
|
|
|
|
}
|
2011-02-03 07:04:14 +00:00
|
|
|
var progressMeter = win.ZoteroPane.document.getElementById('zotero-pane-progressmeter')
|
2009-08-08 07:38:34 +00:00
|
|
|
if (determinate) {
|
|
|
|
progressMeter.mode = 'determined';
|
|
|
|
progressMeter.value = 0;
|
2009-08-09 19:39:32 +00:00
|
|
|
progressMeter.max = 1000;
|
2009-08-08 07:38:34 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
progressMeter.mode = 'undetermined';
|
|
|
|
}
|
|
|
|
|
2011-02-03 07:04:14 +00:00
|
|
|
_showWindowZoteroPaneOverlay(win.ZoteroPane.document);
|
|
|
|
win.ZoteroPane.document.getElementById('zotero-pane-overlay-deck').selectedIndex = 0;
|
2009-08-08 07:38:34 +00:00
|
|
|
|
|
|
|
progressMeters.push(progressMeter);
|
|
|
|
}
|
2013-08-12 00:51:16 +00:00
|
|
|
this.locked = true;
|
2009-08-09 19:39:32 +00:00
|
|
|
_progressMeters = progressMeters;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {Number} percentage Percentage complete as integer or float
|
|
|
|
*/
|
|
|
|
this.updateZoteroPaneProgressMeter = function (percentage) {
|
2011-02-03 07:04:14 +00:00
|
|
|
if(percentage !== null) {
|
|
|
|
if (percentage < 0 || percentage > 100) {
|
|
|
|
Zotero.debug("Invalid percentage value '" + percentage + "' in Zotero.updateZoteroPaneProgressMeter()");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
percentage = Math.round(percentage * 10);
|
2009-08-09 19:39:32 +00:00
|
|
|
}
|
2011-02-03 07:04:14 +00:00
|
|
|
if (percentage === _lastPercentage) {
|
2009-08-09 19:39:32 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-05-03 21:51:12 +00:00
|
|
|
for (let pm of _progressMeters) {
|
2011-02-03 07:04:14 +00:00
|
|
|
if (percentage !== null) {
|
|
|
|
if (pm.mode == 'undetermined') {
|
|
|
|
pm.max = 1000;
|
|
|
|
pm.mode = 'determined';
|
|
|
|
}
|
|
|
|
pm.value = percentage;
|
|
|
|
} else if(pm.mode === 'determined') {
|
|
|
|
pm.mode = 'undetermined';
|
2009-08-09 19:39:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_lastPercentage = percentage;
|
2009-08-08 07:38:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hide Zotero pane overlay in all windows
|
|
|
|
*/
|
2013-08-12 00:51:16 +00:00
|
|
|
this.hideZoteroPaneOverlays = function () {
|
|
|
|
this.locked = false;
|
2009-09-14 06:13:04 +00:00
|
|
|
|
2013-06-06 06:37:19 +00:00
|
|
|
var enumerator = Services.wm.getEnumerator("navigator:browser");
|
2009-08-08 07:38:34 +00:00
|
|
|
while (enumerator.hasMoreElements()) {
|
|
|
|
var win = enumerator.getNext();
|
2011-02-03 07:04:14 +00:00
|
|
|
if(win.ZoteroPane && win.ZoteroPane.document) {
|
|
|
|
_hideWindowZoteroPaneOverlay(win.ZoteroPane.document);
|
|
|
|
}
|
2009-08-08 07:38:34 +00:00
|
|
|
}
|
2011-09-21 23:00:20 +00:00
|
|
|
|
|
|
|
if (_progressPopup) {
|
|
|
|
_progressPopup.close();
|
|
|
|
}
|
|
|
|
|
2009-08-09 19:39:32 +00:00
|
|
|
_progressMeters = [];
|
2011-09-21 23:00:20 +00:00
|
|
|
_progressPopup = null;
|
2009-08-09 19:39:32 +00:00
|
|
|
_lastPercentage = null;
|
2009-08-08 07:38:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-14 00:36:21 +00:00
|
|
|
/**
|
|
|
|
* Adds a listener to be called when Zotero shuts down (even if Firefox is not shut down)
|
|
|
|
*/
|
|
|
|
this.addShutdownListener = function(listener) {
|
|
|
|
_shutdownListeners.push(listener);
|
|
|
|
}
|
2009-09-14 06:13:04 +00:00
|
|
|
|
2011-02-03 07:04:14 +00:00
|
|
|
function _showWindowZoteroPaneOverlay(doc) {
|
|
|
|
doc.getElementById('zotero-collections-tree').disabled = true;
|
|
|
|
doc.getElementById('zotero-items-tree').disabled = true;
|
|
|
|
doc.getElementById('zotero-pane-tab-catcher-top').hidden = false;
|
|
|
|
doc.getElementById('zotero-pane-tab-catcher-bottom').hidden = false;
|
|
|
|
doc.getElementById('zotero-pane-overlay').hidden = false;
|
2009-08-08 07:38:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-03 07:04:14 +00:00
|
|
|
function _hideWindowZoteroPaneOverlay(doc) {
|
|
|
|
doc.getElementById('zotero-collections-tree').disabled = false;
|
|
|
|
doc.getElementById('zotero-items-tree').disabled = false;
|
|
|
|
doc.getElementById('zotero-pane-tab-catcher-top').hidden = true;
|
|
|
|
doc.getElementById('zotero-pane-tab-catcher-bottom').hidden = true;
|
|
|
|
doc.getElementById('zotero-pane-overlay').hidden = true;
|
2009-08-08 07:38:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-26 17:43:00 +00:00
|
|
|
this.updateQuickSearchBox = function (document) {
|
2011-10-03 02:27:42 +00:00
|
|
|
var searchBox = document.getElementById('zotero-tb-search');
|
|
|
|
if(!searchBox) return;
|
|
|
|
|
2011-04-26 17:43:00 +00:00
|
|
|
var mode = Zotero.Prefs.get("search.quicksearch-mode");
|
|
|
|
var prefix = 'zotero-tb-search-mode-';
|
|
|
|
var prefixLen = prefix.length;
|
|
|
|
|
|
|
|
var modes = {
|
2011-12-01 19:33:43 +00:00
|
|
|
titleCreatorYear: {
|
2013-02-28 22:31:07 +00:00
|
|
|
label: Zotero.getString('quickSearch.mode.titleCreatorYear')
|
2011-04-26 17:43:00 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
fields: {
|
2013-02-28 22:31:07 +00:00
|
|
|
label: Zotero.getString('quickSearch.mode.fieldsAndTags')
|
2011-04-26 17:43:00 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
everything: {
|
2013-02-28 22:31:07 +00:00
|
|
|
label: Zotero.getString('quickSearch.mode.everything')
|
2011-04-26 17:43:00 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!modes[mode]) {
|
2011-05-02 20:18:26 +00:00
|
|
|
Zotero.Prefs.set("search.quicksearch-mode", "fields");
|
2011-04-26 17:43:00 +00:00
|
|
|
mode = 'fields';
|
|
|
|
}
|
2011-12-01 19:33:43 +00:00
|
|
|
// TEMP -- pre-3.0b3
|
|
|
|
else if (modes[mode] == 'titlesAndCreators') {
|
|
|
|
Zotero.Prefs.set("search.quicksearch-mode", "titleCreatorYear");
|
|
|
|
mode = 'titleCreatorYear'
|
|
|
|
}
|
2011-04-26 17:43:00 +00:00
|
|
|
|
|
|
|
var hbox = document.getAnonymousNodes(searchBox)[0];
|
|
|
|
var input = hbox.getElementsByAttribute('class', 'textbox-input')[0];
|
|
|
|
|
|
|
|
// Already initialized, so just update selection
|
|
|
|
var button = hbox.getElementsByAttribute('id', 'zotero-tb-search-menu-button');
|
|
|
|
if (button.length) {
|
2011-10-03 02:27:42 +00:00
|
|
|
Zotero.debug("already initialized search menu");
|
2011-04-26 17:43:00 +00:00
|
|
|
button = button[0];
|
|
|
|
var menupopup = button.firstChild;
|
|
|
|
for each(var menuitem in menupopup.childNodes) {
|
|
|
|
if (menuitem.id.substr(prefixLen) == mode) {
|
|
|
|
menuitem.setAttribute('checked', true);
|
2012-02-14 20:20:19 +00:00
|
|
|
searchBox.placeholder = modes[mode].label;
|
2011-04-26 17:43:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, build menu
|
|
|
|
button = document.createElement('button');
|
|
|
|
button.id = 'zotero-tb-search-menu-button';
|
|
|
|
button.setAttribute('type', 'menu');
|
|
|
|
|
|
|
|
var menupopup = document.createElement('menupopup');
|
|
|
|
|
|
|
|
for (var i in modes) {
|
|
|
|
var menuitem = document.createElement('menuitem');
|
|
|
|
menuitem.setAttribute('id', prefix + i);
|
|
|
|
menuitem.setAttribute('label', modes[i].label);
|
|
|
|
menuitem.setAttribute('name', 'searchMode');
|
|
|
|
menuitem.setAttribute('type', 'radio');
|
|
|
|
//menuitem.setAttribute("tooltiptext", "");
|
|
|
|
|
|
|
|
menupopup.appendChild(menuitem);
|
|
|
|
|
|
|
|
if (mode == i) {
|
|
|
|
menuitem.setAttribute('checked', true);
|
|
|
|
menupopup.selectedItem = menuitem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-03 02:27:42 +00:00
|
|
|
menupopup.addEventListener("command", function(event) {
|
|
|
|
var mode = event.target.id.substr(22);
|
|
|
|
Zotero.Prefs.set("search.quicksearch-mode", mode);
|
|
|
|
if (document.getElementById("zotero-tb-search").value == "") {
|
|
|
|
event.stopPropagation();
|
|
|
|
}
|
|
|
|
}, false);
|
2011-04-26 17:43:00 +00:00
|
|
|
|
|
|
|
button.appendChild(menupopup);
|
|
|
|
hbox.insertBefore(button, input);
|
|
|
|
|
2012-02-14 20:20:19 +00:00
|
|
|
searchBox.placeholder = modes[mode].label;
|
2011-04-26 19:39:18 +00:00
|
|
|
|
|
|
|
// If Alt-Up/Down, show popup
|
2011-10-03 02:27:42 +00:00
|
|
|
searchBox.addEventListener("keypress", function(event) {
|
|
|
|
if (event.altKey && (event.keyCode == event.DOM_VK_UP || event.keyCode == event.DOM_VK_DOWN)) {
|
|
|
|
document.getElementById('zotero-tb-search-menu-button').open = true;
|
|
|
|
event.stopPropagation();
|
|
|
|
}
|
|
|
|
}, false);
|
2011-04-26 17:43:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-18 03:09:39 +00:00
|
|
|
/*
|
|
|
|
* Clear entries that no longer exist from various tables
|
|
|
|
*/
|
2016-04-10 22:58:01 +00:00
|
|
|
this.purgeDataObjects = Zotero.Promise.coroutine(function* () {
|
2015-05-22 17:38:50 +00:00
|
|
|
yield Zotero.DB.executeTransaction(function* () {
|
|
|
|
return Zotero.Creators.purge();
|
|
|
|
});
|
|
|
|
yield Zotero.DB.executeTransaction(function* () {
|
|
|
|
return Zotero.Tags.purge();
|
|
|
|
});
|
2016-04-10 22:58:01 +00:00
|
|
|
Zotero.Fulltext.purgeUnusedWords();
|
2015-05-22 17:38:50 +00:00
|
|
|
yield Zotero.DB.executeTransaction(function* () {
|
2015-05-22 19:50:27 +00:00
|
|
|
return Zotero.Items.purge();
|
2015-05-22 17:38:50 +00:00
|
|
|
});
|
2010-04-27 08:03:08 +00:00
|
|
|
// DEBUG: this might not need to be permanent
|
2016-04-10 22:58:01 +00:00
|
|
|
//yield Zotero.DB.executeTransaction(function* () {
|
|
|
|
// return Zotero.Relations.purge();
|
|
|
|
//});
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
});
|
2009-02-18 03:09:39 +00:00
|
|
|
|
|
|
|
|
2.0b3 megacommit
- Support for group libraries
- General support for multiple libraries of different types
- Streamlined sync support
- Using solely libraryID and key rather than itemID, and removed all itemID-changing code
- Combined two requests for increased performance and decreased server load
- Added warning on user account change
- Provide explicit error message on SSL failure
- Removed snapshot and link toolbar buttons and changed browser context menu options and drags to create parent items + snapshots
- Closes #786, Add numPages field
- Fixes #1063, Duplicate item with tags broken in Sync Preview
- Added better purging of deleted tags
- Added local user key before first sync
- Add clientDateModified to all objects for more flexibility in syncing
- Added new triples-based Relation object type, currently used to store links between items copied between local and group libraries
- Updated zotero.org translator for groups
- Additional trigger-based consistency checks
- Fixed broken URL drag in Firefox 3.5
- Disabled zeroconf menu option (no longer functional)
Developer-specific changes:
- Overhauled data layer
- Data object constructors no longer take arguments (return to 1.0-like API)
- Existing objects can be retrieved by setting id or library/key properties
- id/library/key must be set for new objects before other fields
- New methods:
- ZoteroPane.getSelectedLibraryID()
- ZoteroPane.getSelectedGroup(asID)
- ZoteroPane.addItemFromDocument(doc, itemType, saveSnapshot)
- ZoteroPane.addItemFromURL(url, itemType)
- ZoteroPane.canEdit()
- Zotero.CollectionTreeView.selectLibrary(libraryID)
- New Zotero.URI methods
- Changed methods
- Many data object methods now take a libraryID
- ZoteroPane.addAttachmentFromPage(link, itemID)
- Removed saveItem and saveAttachments parameters from Zotero.Translate constructor
- translate() now takes a libraryID, null for local library, or false to not save items (previously on constructor)
- saveAttachments is now a translate() parameter
- Zotero.flattenArguments() better handles passed objects
- Zotero.File.getFileHash() (not currently used)
2009-05-14 18:23:40 +00:00
|
|
|
this.reloadDataObjects = function () {
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
return Zotero.Promise.all([
|
|
|
|
Zotero.Collections.reloadAll(),
|
|
|
|
Zotero.Creators.reloadAll(),
|
|
|
|
Zotero.Items.reloadAll()
|
|
|
|
]);
|
Initial Zotero 1.5 Megacommit
Apologies for the massive (and, due to data_access.js splitting, difficult-to-follow) commit. Please note that external code that accesses the data layer may need to be tweaked for compatibility. Here's a comprehensive-as-possible changelog:
- Added server sync functionality (incomplete)
- Overhaul of data layer
- Split data_access.js into separate files (item.js, items.js, creator.js, etc.)
- Made creators and collections first-class objects, similar to items
- Constructors now take id as first parameter, e.g. new Zotero.Item(1234, 'book'), to allow explicit id setting and id changing
- Made various data layer operations (including attachment fields) require a save() rather than making direct DB changes
- Better handling of unsaved objects
- Item.setCreator() now takes creator objects instead of creator ids, and Item.save() will auto-save unsaved creators
- clone() now works on unsaved objects
- Newly created object instances are now disabled after save() to force refetch of globally accessible instance using Zotero.(Items|Creators|etc.).get()
- Added secondary lookup key to data objects
- Deprecated getID() and getItemType() methods in favor of .id and .itemTypeID properties
- toArray() deprecated in favor of serialize(), which has a somewhat modified format
- Added support for multiple creators with identical data -- currently unimplemented in interface and most of data layer
- Added Item.diff() for comparing item metadata
- Database changes
- Added SQLite triggers to enforce foreign key constraints
- Added Zotero.DB.transactionVacuum flag to run a VACUUM after a transaction
- Added Zotero.DB.transactionDate, .transactionDateTime, and transactionTimestamp to retrieve consistent timestamps for entire transaction
- Properly store 64-bit integers
- Set PRAGMA locking_mode=EXCLUSIVE on database
- Set SQLite page size to 4096 on new databases
- Set SQLite page cache to 8MB
- Do some database cleanup and integrity checking on migration from 1.0 branch
- Removed IF NOT EXISTS from userdata.sql CREATE statements -- userdata.sql is now processed only on DB initialization
- Removed itemNoteTitles table and moved titles into itemNotes
- Abstracted metadata edit box and note box into flexible XBL bindings with various modes, including read-only states
- Massive speed-up of item tree view
- Several fixes from 1.0 branch for Fx3 compatibility
- Added Notifier observer to log delete events for syncing
- Zotero.Utilities changes
- New methods getSQLDataType() and md5()
- Removed onError from Zotero.Utilities.HTTP.doGet()
- Don't display more than 1024 characters in doPost() debug output
- Don't display passwords in doPost() debug output
- Added Zotero.Notifier.untrigger() -- currently unused
- Added Zotero.reloadDataObjects() to reset all in-memory objects
- Added |chars| parameter to Zotero.randomString(len, chars)
- Added Zotero.Date.getUnixTimestamp() and Date.toUnixTimestamp(JSDate)
- Adjusted zotero-service.js to simplify file inclusion
Various things (such as tags) are temporarily broken.
2008-05-04 08:32:48 +00:00
|
|
|
}
|
2011-06-14 00:36:21 +00:00
|
|
|
|
2013-04-11 08:28:38 +00:00
|
|
|
|
2011-06-14 00:36:21 +00:00
|
|
|
/**
|
|
|
|
* Brings Zotero Standalone to the foreground
|
|
|
|
*/
|
|
|
|
this.activateStandalone = function() {
|
2013-06-06 06:37:19 +00:00
|
|
|
var uri = Services.io.newURI('zotero://select', null, null);
|
2011-06-14 00:36:21 +00:00
|
|
|
var handler = Components.classes['@mozilla.org/uriloader/external-protocol-service;1']
|
|
|
|
.getService(Components.interfaces.nsIExternalProtocolService)
|
|
|
|
.getProtocolHandlerInfo('zotero');
|
|
|
|
handler.preferredAction = Components.interfaces.nsIHandlerInfo.useSystemDefault;
|
|
|
|
handler.launchWithURI(uri, null);
|
|
|
|
}
|
2012-02-14 01:42:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Determines whether to keep an error message so that it can (potentially) be reported later
|
|
|
|
*/
|
|
|
|
function _shouldKeepError(msg) {
|
|
|
|
const skip = ['CSS Parser', 'content javascript'];
|
|
|
|
|
|
|
|
//Zotero.debug(msg);
|
|
|
|
try {
|
|
|
|
msg.QueryInterface(Components.interfaces.nsIScriptError);
|
|
|
|
//Zotero.debug(msg);
|
|
|
|
if (skip.indexOf(msg.category) != -1 || msg.flags & msg.warningFlag) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (e) { }
|
|
|
|
|
|
|
|
const blacklist = [
|
|
|
|
"No chrome package registered for chrome://communicator",
|
|
|
|
'[JavaScript Error: "Components is not defined" {file: "chrome://nightly/content/talkback/talkback.js',
|
|
|
|
'[JavaScript Error: "document.getElementById("sanitizeItem")',
|
|
|
|
'No chrome package registered for chrome://piggy-bank',
|
|
|
|
'[JavaScript Error: "[Exception... "\'Component is not available\' when calling method: [nsIHandlerService::getTypeFromExtension',
|
|
|
|
'[JavaScript Error: "this._uiElement is null',
|
|
|
|
'Error: a._updateVisibleText is not a function',
|
|
|
|
'[JavaScript Error: "Warning: unrecognized command line flag ',
|
|
|
|
'LibX:',
|
|
|
|
'function skype_',
|
|
|
|
'[JavaScript Error: "uncaught exception: Permission denied to call method Location.toString"]',
|
|
|
|
'CVE-2009-3555',
|
2014-03-14 21:11:26 +00:00
|
|
|
'OpenGL',
|
2013-07-30 19:48:53 +00:00
|
|
|
'trying to re-register CID',
|
2013-11-05 17:39:06 +00:00
|
|
|
'Services.HealthReport',
|
|
|
|
'[JavaScript Error: "this.docShell is null"',
|
|
|
|
'[JavaScript Error: "downloadable font:',
|
2013-11-13 17:57:49 +00:00
|
|
|
'[JavaScript Error: "Image corrupt or truncated:',
|
2014-05-27 00:09:27 +00:00
|
|
|
'[JavaScript Error: "The character encoding of the',
|
|
|
|
'nsLivemarkService.js',
|
|
|
|
'Sync.Engine.Tabs',
|
|
|
|
'content-sessionStore.js',
|
2015-03-29 19:22:07 +00:00
|
|
|
'org.mozilla.appSessions',
|
|
|
|
'bad script XDR magic number'
|
2012-02-14 01:42:32 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
for (var i=0; i<blacklist.length; i++) {
|
|
|
|
if (msg.message.indexOf(blacklist[i]) != -1) {
|
|
|
|
//Zotero.debug("Skipping blacklisted error: " + msg.message);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2013-08-07 22:32:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Warn if Zotero Standalone is running as root and clobber the cache directory if it is
|
|
|
|
*/
|
|
|
|
function _checkRoot() {
|
|
|
|
var env = Components.classes["@mozilla.org/process/environment;1"].
|
|
|
|
getService(Components.interfaces.nsIEnvironment);
|
|
|
|
var user = env.get("USER") || env.get("USERNAME");
|
|
|
|
if(user === "root") {
|
|
|
|
// Show warning
|
|
|
|
if(Services.prompt.confirmEx(null, "", Zotero.getString("standalone.rootWarning"),
|
|
|
|
Services.prompt.BUTTON_POS_0*Services.prompt.BUTTON_TITLE_IS_STRING |
|
|
|
|
Services.prompt.BUTTON_POS_1*Services.prompt.BUTTON_TITLE_IS_STRING,
|
|
|
|
Zotero.getString("standalone.rootWarning.exit"),
|
|
|
|
Zotero.getString("standalone.rootWarning.continue"),
|
|
|
|
null, null, {}) == 0) {
|
|
|
|
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
|
|
|
var exit = Zotero.IPC.getLibc().declare("exit", ctypes.default_abi,
|
|
|
|
ctypes.void_t, ctypes.int);
|
|
|
|
// Zap cache files
|
|
|
|
try {
|
|
|
|
Services.dirsvc.get("ProfLD", Components.interfaces.nsIFile).remove(true);
|
|
|
|
} catch(e) {}
|
|
|
|
// Exit Zotero without giving XULRunner the opportunity to figure out the
|
|
|
|
// cache is missing. Otherwise XULRunner will zap the prefs
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-14 01:42:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Observer for console messages
|
|
|
|
* @namespace
|
|
|
|
*/
|
|
|
|
var ConsoleListener = {
|
|
|
|
"QueryInterface":XPCOMUtils.generateQI([Components.interfaces.nsIConsoleMessage,
|
|
|
|
Components.interfaces.nsISupports]),
|
|
|
|
"observe":function(msg) {
|
|
|
|
if(!_shouldKeepError(msg)) return;
|
2012-02-14 05:40:17 +00:00
|
|
|
if(_recentErrors.length === ERROR_BUFFER_SIZE) _recentErrors.shift();
|
2012-02-14 01:42:32 +00:00
|
|
|
_recentErrors.push(msg);
|
|
|
|
}
|
|
|
|
};
|
2011-06-14 00:36:21 +00:00
|
|
|
}).call(Zotero);
|
2006-06-13 15:14:22 +00:00
|
|
|
|
2006-10-02 23:15:27 +00:00
|
|
|
Zotero.Prefs = new function(){
|
2006-06-25 07:31:01 +00:00
|
|
|
// Privileged methods
|
|
|
|
this.init = init;
|
|
|
|
this.get = get;
|
|
|
|
this.set = set;
|
|
|
|
|
|
|
|
this.register = register;
|
|
|
|
this.unregister = unregister;
|
|
|
|
this.observe = observe;
|
|
|
|
|
|
|
|
// Public properties
|
2007-10-23 07:11:59 +00:00
|
|
|
this.prefBranch;
|
2006-06-25 07:31:01 +00:00
|
|
|
|
|
|
|
function init(){
|
2013-06-06 06:37:19 +00:00
|
|
|
this.prefBranch = Services.prefs.getBranch(ZOTERO_CONFIG.PREF_BRANCH);
|
2006-06-25 07:31:01 +00:00
|
|
|
|
|
|
|
// Register observer to handle pref changes
|
|
|
|
this.register();
|
2012-02-14 20:20:19 +00:00
|
|
|
|
|
|
|
// Process pref version updates
|
|
|
|
var fromVersion = this.get('prefVersion');
|
|
|
|
if (!fromVersion) {
|
|
|
|
fromVersion = 0;
|
|
|
|
}
|
2015-07-06 04:49:35 +00:00
|
|
|
var toVersion = 2;
|
2012-02-14 20:20:19 +00:00
|
|
|
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');
|
|
|
|
}
|
|
|
|
}
|
2015-07-06 04:49:35 +00:00
|
|
|
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;
|
2012-02-14 20:20:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
this.set('prefVersion', toVersion);
|
|
|
|
}
|
2006-06-25 07:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve a preference
|
|
|
|
**/
|
2007-10-23 07:11:59 +00:00
|
|
|
function get(pref, global){
|
2006-06-25 07:31:01 +00:00
|
|
|
try {
|
2007-10-23 07:11:59 +00:00
|
|
|
if (global) {
|
2013-06-06 06:37:19 +00:00
|
|
|
var branch = Services.prefs.getBranch("");
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-01-06 00:05:50 +00:00
|
|
|
var branch = this.prefBranch;
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
|
2012-01-06 00:05:50 +00:00
|
|
|
switch (branch.getPrefType(pref)){
|
|
|
|
case branch.PREF_BOOL:
|
|
|
|
return branch.getBoolPref(pref);
|
|
|
|
case branch.PREF_STRING:
|
2015-01-21 05:28:22 +00:00
|
|
|
return '' + branch.getComplexValue(pref, Components.interfaces.nsISupportsString);
|
2012-01-06 00:05:50 +00:00
|
|
|
case branch.PREF_INT:
|
|
|
|
return branch.getIntPref(pref);
|
2006-06-25 07:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (e){
|
|
|
|
throw ("Invalid preference '" + pref + "'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set a preference
|
|
|
|
**/
|
2010-12-26 19:04:09 +00:00
|
|
|
function set(pref, value) {
|
2006-06-25 07:31:01 +00:00
|
|
|
try {
|
|
|
|
switch (this.prefBranch.getPrefType(pref)){
|
|
|
|
case this.prefBranch.PREF_BOOL:
|
|
|
|
return this.prefBranch.setBoolPref(pref, value);
|
|
|
|
case this.prefBranch.PREF_STRING:
|
2014-03-20 21:01:42 +00:00
|
|
|
let str = Cc["@mozilla.org/supports-string;1"]
|
|
|
|
.createInstance(Ci.nsISupportsString);
|
|
|
|
str.data = value;
|
|
|
|
return this.prefBranch.setComplexValue(pref, Ci.nsISupportsString, str);
|
2006-06-25 07:31:01 +00:00
|
|
|
case this.prefBranch.PREF_INT:
|
|
|
|
return this.prefBranch.setIntPref(pref, value);
|
2010-12-26 19:04:09 +00:00
|
|
|
|
|
|
|
// If not an existing pref, create appropriate type automatically
|
|
|
|
case 0:
|
|
|
|
if (typeof value == 'boolean') {
|
|
|
|
Zotero.debug("Creating boolean pref '" + pref + "'");
|
|
|
|
return this.prefBranch.setBoolPref(pref, value);
|
|
|
|
}
|
|
|
|
if (typeof value == 'string') {
|
|
|
|
Zotero.debug("Creating string pref '" + pref + "'");
|
|
|
|
return this.prefBranch.setCharPref(pref, value);
|
|
|
|
}
|
2011-02-14 04:57:38 +00:00
|
|
|
if (parseInt(value) == value) {
|
|
|
|
Zotero.debug("Creating integer pref '" + pref + "'");
|
|
|
|
return this.prefBranch.setIntPref(pref, value);
|
|
|
|
}
|
2010-12-26 19:04:09 +00:00
|
|
|
throw ("Invalid preference value '" + value + "' for pref '" + pref + "'");
|
2006-06-25 07:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
2014-03-20 21:01:42 +00:00
|
|
|
catch (e) {
|
|
|
|
Components.utils.reportError(e);
|
|
|
|
Zotero.debug(e, 1);
|
2006-06-25 07:31:01 +00:00
|
|
|
throw ("Invalid preference '" + pref + "'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-24 21:07:23 +00:00
|
|
|
this.clear = function (pref) {
|
2015-05-13 14:44:26 +00:00
|
|
|
this.prefBranch.clearUserPref(pref);
|
2010-02-24 21:07:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-29 04:14:05 +00:00
|
|
|
// Import settings bundles
|
|
|
|
this.importSettings = function (str, uri) {
|
2013-06-06 06:37:19 +00:00
|
|
|
var ps = Services.prompt;
|
2010-08-29 04:14:05 +00:00
|
|
|
|
|
|
|
if (!uri.match(/https:\/\/([^\.]+\.)?zotero.org\//)) {
|
|
|
|
Zotero.debug("Ignoring settings file not from https://zotero.org");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
str = Zotero.Utilities.trim(str.replace(/<\?xml.*\?>\s*/, ''));
|
2010-08-29 04:14:05 +00:00
|
|
|
Zotero.debug(str);
|
|
|
|
|
2010-09-20 06:10:06 +00:00
|
|
|
var confirm = ps.confirm(
|
|
|
|
null,
|
2010-08-29 04:14:05 +00:00
|
|
|
"",
|
|
|
|
"Apply settings from zotero.org?"
|
|
|
|
);
|
|
|
|
|
2010-08-30 18:28:52 +00:00
|
|
|
if (!confirm) {
|
|
|
|
return;
|
|
|
|
}
|
2010-08-29 04:14:05 +00:00
|
|
|
|
2013-01-15 08:23:37 +00:00
|
|
|
// TODO: parse settings XML
|
2010-08-29 04:14:05 +00:00
|
|
|
}
|
|
|
|
|
2015-01-21 04:45:28 +00:00
|
|
|
// Handlers for some Zotero preferences
|
|
|
|
var _handlers = [
|
|
|
|
[ "automaticScraperUpdates", function(val) {
|
|
|
|
if (val){
|
|
|
|
Zotero.Schema.updateFromRepository();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Zotero.Schema.stopRepositoryTimer();
|
|
|
|
}
|
|
|
|
}],
|
2016-05-28 00:57:29 +00:00
|
|
|
[ "layout", function(val) {
|
|
|
|
Zotero.getActiveZoteroPane().updateLayout();
|
|
|
|
}],
|
2015-01-21 04:45:28 +00:00
|
|
|
[ "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) {
|
2016-04-01 06:24:50 +00:00
|
|
|
Zotero.Sync.EventListeners.AutoSyncListener.register();
|
|
|
|
Zotero.Sync.EventListeners.IdleListener.register();
|
2015-01-21 04:45:28 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-04-01 06:24:50 +00:00
|
|
|
Zotero.Sync.EventListeners.AutoSyncListener.unregister();
|
|
|
|
Zotero.Sync.EventListeners.IdleListener.unregister();
|
2015-01-21 04:45:28 +00:00
|
|
|
}
|
|
|
|
}],
|
|
|
|
[ "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);
|
|
|
|
}
|
|
|
|
}]
|
|
|
|
];
|
2010-08-29 04:14:05 +00:00
|
|
|
|
2006-06-25 07:31:01 +00:00
|
|
|
//
|
|
|
|
// Methods to register a preferences observer
|
|
|
|
//
|
|
|
|
function register(){
|
|
|
|
this.prefBranch.QueryInterface(Components.interfaces.nsIPrefBranch2);
|
|
|
|
this.prefBranch.addObserver("", this, false);
|
2015-01-21 04:45:28 +00:00
|
|
|
|
|
|
|
// Register pre-set handlers
|
|
|
|
for (var i=0; i<_handlers.length; i++) {
|
|
|
|
this.registerObserver(_handlers[i][0], _handlers[i][1]);
|
|
|
|
}
|
2006-06-25 07:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function unregister(){
|
|
|
|
if (!this.prefBranch){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.prefBranch.removeObserver("", this);
|
|
|
|
}
|
|
|
|
|
2015-01-21 04:45:28 +00:00
|
|
|
/**
|
|
|
|
* @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)
|
|
|
|
*/
|
2006-06-25 07:31:01 +00:00
|
|
|
function observe(subject, topic, data){
|
2015-01-21 04:45:28 +00:00
|
|
|
if (topic != "nsPref:changed" || !_observers[data] || !_observers[data].length) {
|
2006-06-25 07:31:01 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-02-14 20:20:19 +00:00
|
|
|
|
2015-01-21 04:45:28 +00:00
|
|
|
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);
|
|
|
|
}
|
2006-06-25 07:31:01 +00:00
|
|
|
}
|
2015-01-21 04:45:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2012-02-14 20:20:19 +00:00
|
|
|
}
|
2015-01-21 04:45:28 +00:00
|
|
|
|
|
|
|
var i = obs.indexOf(handler);
|
|
|
|
if (i == -1) {
|
|
|
|
Zotero.debug("Handler was not registered for preference " + name);
|
|
|
|
return;
|
2012-02-14 20:20:19 +00:00
|
|
|
}
|
2015-01-21 04:45:28 +00:00
|
|
|
|
|
|
|
obs.splice(i, 1);
|
2006-06-25 07:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
/*
|
|
|
|
* Handles keyboard shortcut initialization from preferences, optionally
|
|
|
|
* overriding existing global shortcuts
|
|
|
|
*
|
|
|
|
* Actions are configured in ZoteroPane.handleKeyPress()
|
|
|
|
*/
|
|
|
|
Zotero.Keys = new function() {
|
|
|
|
this.init = init;
|
|
|
|
this.windowInit = windowInit;
|
|
|
|
this.getCommand = getCommand;
|
|
|
|
|
Merged revisions 2640-2647,2651,2653-2654,2656-2658,2660-2667,2670-2672,2674-2677,2680,2683-2684,2687-2704,2707 to trunk via svnmerge from 1.0 branch
2008-05-16 09:14:11 +00:00
|
|
|
var _keys = {};
|
2007-10-23 07:11:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called by Zotero.init()
|
|
|
|
*/
|
|
|
|
function init() {
|
2014-04-30 19:06:35 +00:00
|
|
|
var cmds = Zotero.Prefs.prefBranch.getChildList('keys', {}, {});
|
2007-10-23 07:11:59 +00:00
|
|
|
|
|
|
|
// Get the key=>command mappings from the prefs
|
2014-04-30 19:06:35 +00:00
|
|
|
for each(var cmd in cmds) {
|
|
|
|
cmd = cmd.substr(5); // strips 'keys.'
|
2013-08-01 03:19:19 +00:00
|
|
|
// Remove old pref
|
2014-04-30 19:06:35 +00:00
|
|
|
if (cmd == 'overrideGlobal') {
|
2013-01-22 23:38:00 +00:00
|
|
|
Zotero.Prefs.clear('keys.overrideGlobal');
|
2007-10-23 07:11:59 +00:00
|
|
|
continue;
|
|
|
|
}
|
2014-04-30 19:06:35 +00:00
|
|
|
_keys[this.getKeyForCommand(cmd)] = cmd;
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called by ZoteroPane.onLoad()
|
|
|
|
*/
|
|
|
|
function windowInit(document) {
|
2013-08-01 03:19:19 +00:00
|
|
|
var globalKeys = [
|
|
|
|
{
|
|
|
|
name: 'openZotero',
|
|
|
|
defaultKey: 'Z'
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'saveToZotero',
|
|
|
|
defaultKey: 'S'
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
2013-08-01 03:19:19 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
globalKeys.forEach(function (x) {
|
|
|
|
let keyElem = document.getElementById('key_' + x.name);
|
|
|
|
if (keyElem) {
|
2014-04-30 19:06:35 +00:00
|
|
|
let prefKey = this.getKeyForCommand(x.name);
|
2013-08-01 03:19:19 +00:00
|
|
|
// Only override the default with the pref if the <key> hasn't
|
|
|
|
// been manually changed and the pref has been
|
|
|
|
if (keyElem.getAttribute('key') == x.defaultKey
|
|
|
|
&& keyElem.getAttribute('modifiers') == 'accel shift'
|
|
|
|
&& prefKey != x.defaultKey) {
|
|
|
|
keyElem.setAttribute('key', prefKey);
|
2011-02-01 06:24:52 +00:00
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
2014-04-30 19:06:35 +00:00
|
|
|
}.bind(this));
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getCommand(key) {
|
2013-07-26 19:34:39 +00:00
|
|
|
key = key.toUpperCase();
|
2007-10-23 07:11:59 +00:00
|
|
|
return _keys[key] ? _keys[key] : false;
|
|
|
|
}
|
2014-04-30 19:06:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
this.getKeyForCommand = function (cmd) {
|
|
|
|
try {
|
|
|
|
var key = Zotero.Prefs.get('keys.' + cmd);
|
|
|
|
}
|
|
|
|
catch (e) {}
|
|
|
|
return key !== undefined ? key.toUpperCase() : false;
|
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
|
2006-06-13 15:14:22 +00:00
|
|
|
|
2008-09-16 20:11:27 +00:00
|
|
|
/**
|
|
|
|
* Add X-Zotero-Version header to HTTP requests to zotero.org
|
|
|
|
*
|
|
|
|
* @namespace
|
|
|
|
*/
|
|
|
|
Zotero.VersionHeader = {
|
|
|
|
init: function () {
|
|
|
|
if (Zotero.Prefs.get("zoteroDotOrgVersionHeader")) {
|
|
|
|
this.register();
|
|
|
|
}
|
2012-02-20 07:26:41 +00:00
|
|
|
Zotero.addShutdownListener(this.unregister);
|
2008-09-16 20:11:27 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
// Called from this.init() and Zotero.Prefs.observe()
|
|
|
|
register: function () {
|
2013-06-05 21:54:40 +00:00
|
|
|
Services.obs.addObserver(this, "http-on-modify-request", false);
|
2008-09-16 20:11:27 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
observe: function (subject, topic, data) {
|
|
|
|
try {
|
|
|
|
var channel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
|
|
|
|
if (channel.URI.host.match(/zotero\.org$/)) {
|
|
|
|
channel.setRequestHeader("X-Zotero-Version", Zotero.version, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
Zotero.debug(e);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
unregister: function () {
|
2013-06-05 21:54:40 +00:00
|
|
|
Services.obs.removeObserver(Zotero.VersionHeader, "http-on-modify-request");
|
2008-09-16 20:11:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-30 20:18:48 +00:00
|
|
|
Zotero.DragDrop = {
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
currentEvent: null,
|
2013-09-05 17:37:09 +00:00
|
|
|
currentOrientation: 0,
|
2008-11-30 20:18:48 +00:00
|
|
|
|
2013-09-05 17:37:09 +00:00
|
|
|
getDataFromDataTransfer: function (dataTransfer, firstOnly) {
|
|
|
|
var dt = dataTransfer;
|
2010-07-09 20:10:43 +00:00
|
|
|
|
2013-08-03 22:08:09 +00:00
|
|
|
var dragData = {
|
|
|
|
dataType: '',
|
|
|
|
data: [],
|
|
|
|
dropEffect: dt.dropEffect
|
|
|
|
};
|
|
|
|
|
2010-07-09 20:10:43 +00:00
|
|
|
var len = firstOnly ? 1 : dt.mozItemCount;
|
|
|
|
|
|
|
|
if (dt.types.contains('zotero/collection')) {
|
|
|
|
dragData.dataType = 'zotero/collection';
|
|
|
|
var ids = dt.getData('zotero/collection').split(",");
|
|
|
|
dragData.data = ids;
|
|
|
|
}
|
|
|
|
else if (dt.types.contains('zotero/item')) {
|
|
|
|
dragData.dataType = 'zotero/item';
|
|
|
|
var ids = dt.getData('zotero/item').split(",");
|
|
|
|
dragData.data = ids;
|
|
|
|
}
|
|
|
|
else if (dt.types.contains('application/x-moz-file')) {
|
|
|
|
dragData.dataType = 'application/x-moz-file';
|
|
|
|
var files = [];
|
|
|
|
for (var i=0; i<len; i++) {
|
|
|
|
var file = dt.mozGetDataAt("application/x-moz-file", i);
|
2016-02-24 09:03:05 +00:00
|
|
|
if (!file) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-07-09 20:10:43 +00:00
|
|
|
file.QueryInterface(Components.interfaces.nsIFile);
|
|
|
|
// Don't allow folder drag
|
|
|
|
if (file.isDirectory()) {
|
|
|
|
continue;
|
2008-11-30 20:18:48 +00:00
|
|
|
}
|
2010-07-09 20:10:43 +00:00
|
|
|
files.push(file);
|
|
|
|
}
|
|
|
|
dragData.data = files;
|
|
|
|
}
|
|
|
|
else if (dt.types.contains('text/x-moz-url')) {
|
|
|
|
dragData.dataType = 'text/x-moz-url';
|
|
|
|
var urls = [];
|
|
|
|
for (var i=0; i<len; i++) {
|
|
|
|
var url = dt.getData("text/x-moz-url").split("\n")[0];
|
|
|
|
urls.push(url);
|
2008-11-30 20:18:48 +00:00
|
|
|
}
|
2010-07-09 20:10:43 +00:00
|
|
|
dragData.data = urls;
|
2008-11-30 20:18:48 +00:00
|
|
|
}
|
2010-07-09 20:10:43 +00:00
|
|
|
|
2008-11-30 20:18:48 +00:00
|
|
|
return dragData;
|
2013-09-05 17:37:09 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
getDragSource: function (dataTransfer) {
|
|
|
|
if (!dataTransfer) {
|
2015-03-06 19:21:33 +00:00
|
|
|
//Zotero.debug("Drag data not available", 2);
|
2013-09-05 17:37:09 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
// For items, the drag source is the CollectionTreeRow of the parent window
|
2013-09-05 17:37:09 +00:00
|
|
|
// of the source tree
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
if (dataTransfer.types.contains("zotero/item")) {
|
|
|
|
var sourceNode = dataTransfer.mozSourceNode;
|
2013-09-05 17:37:09 +00:00
|
|
|
if (!sourceNode || sourceNode.tagName != 'treechildren'
|
|
|
|
|| sourceNode.parentElement.id != 'zotero-items-tree') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
var win = sourceNode.ownerDocument.defaultView;
|
2014-10-10 20:01:09 +00:00
|
|
|
if (win.document.documentElement.getAttribute('windowtype') == 'zotero:search') {
|
2015-03-16 19:17:45 +00:00
|
|
|
return win.ZoteroAdvancedSearch.itemsView.collectionTreeRow;
|
2014-10-10 20:01:09 +00:00
|
|
|
}
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
return win.ZoteroPane.collectionsView.selectedTreeRow;
|
2013-09-05 17:37:09 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
getDragTarget: function (event) {
|
2013-09-05 17:37:09 +00:00
|
|
|
var target = event.target;
|
|
|
|
if (target.tagName == 'treechildren') {
|
|
|
|
var tree = target.parentNode;
|
|
|
|
if (tree.id == 'zotero-collections-tree') {
|
|
|
|
let row = {}, col = {}, obj = {};
|
|
|
|
tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, obj);
|
|
|
|
let win = tree.ownerDocument.defaultView;
|
Async DB megacommit
Promise-based rewrite of most of the codebase, with asynchronous database and file access -- see https://github.com/zotero/zotero/issues/518 for details.
WARNING: This includes backwards-incompatible schema changes.
An incomplete list of other changes:
- Schema overhaul
- Replace main tables with new versions with updated schema
- Enable real foreign key support and remove previous triggers
- Don't use NULLs for local libraryID, which broke the UNIQUE index
preventing object key duplication. All code (Zotero and third-party)
using NULL for the local library will need to be updated to use 0
instead (already done for Zotero code)
- Add 'compatibility' DB version that can be incremented manually to break DB
compatibility with previous versions. 'userdata' upgrades will no longer
automatically break compatibility.
- Demote creators and tags from first-class objects to item properties
- New API syncing properties
- 'synced'/'version' properties to data objects
- 'etag' to groups
- 'version' to libraries
- Create Zotero.DataObject that other objects inherit from
- Consolidate data object loading into Zotero.DataObjects
- Change object reloading so that only the loaded and changed parts of objects are reloaded, instead of reloading all data from the database (with some exceptions, including item primary data)
- Items and collections now have .parentItem and .parentKey properties, replacing item.getSource() and item.getSourceKey()
- New function Zotero.serial(fn), to wrap an async function such that all calls are run serially
- New function Zotero.Utilities.Internal.forEachChunkAsync(arr, chunkSize, func)
- Add tag selector loading message
- Various API and name changes, since everything was breaking anyway
Known broken things:
- Syncing (will be completely rewritten for API syncing)
- Translation architecture (needs promise-based rewrite)
- Duplicates view
- DB integrity check (from schema changes)
- Dragging (may be difficult to fix)
Lots of other big and little things are certainly broken, particularly with the UI, which can be affected by async code in all sorts of subtle ways.
2014-08-06 21:38:05 +00:00
|
|
|
return win.ZoteroPane.collectionsView.getRow(row.value);
|
2013-09-05 17:37:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2008-11-30 20:18:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
/**
|
|
|
|
* Functions for creating and destroying hidden browser objects
|
|
|
|
**/
|
2006-10-02 23:15:27 +00:00
|
|
|
Zotero.Browser = new function() {
|
2012-11-07 22:17:16 +00:00
|
|
|
var nBrowsers = 0;
|
|
|
|
|
2006-07-27 23:01:55 +00:00
|
|
|
this.createHiddenBrowser = createHiddenBrowser;
|
|
|
|
this.deleteHiddenBrowser = deleteHiddenBrowser;
|
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
function createHiddenBrowser(win) {
|
|
|
|
if (!win) {
|
2013-06-06 06:37:19 +00:00
|
|
|
var win = Services.wm.getMostRecentWindow("navigator:browser");
|
2010-09-23 04:57:36 +00:00
|
|
|
if(!win) {
|
2013-06-06 06:37:19 +00:00
|
|
|
var win = Services.ww.activeWindow;
|
2010-09-23 04:57:36 +00:00
|
|
|
}
|
2015-10-29 07:41:54 +00:00
|
|
|
if (!win) {
|
|
|
|
throw new Error("Parent window not available for hidden browser");
|
|
|
|
}
|
2006-07-27 23:01:55 +00:00
|
|
|
}
|
|
|
|
|
Fulltext search support
There are currently two types of fulltext searching: an SQL-based word index and a file scanner. They each have their advantages and drawbacks.
The word index is very fast to search and is currently used for the find-as-you-type quicksearch. However, indexing files takes some time, so we should probably offer a preference to turn it off ("Index attachment content for quicksearch" or something). There's also an issue with Chinese characters (which are indexed by character rather than word, since there are no spaces to go by, so a search for a word with common characters could produce erroneous results). The quicksearch doesn't use a left-bound index (since that would probably upset German speakers searching for "musik" in "nachtmusik," though I don't know for sure how they think of words) but still seems pretty fast.
* Note: There will be a potentially long delay when you start Firefox with this revision as it builds a fulltext word index of your existing items. We obviously need a notification/option for this. *
The file scanner, used in the Attachment Content condition of the search dialog, offers phrase searching as well as regex support (both case-sensitive and not, and defaulting to multiline). It doesn't require an index, though it should probably be optimized to use the word index, if available, for narrowing the results when not in regex mode. (It does only scan files that pass all the other search conditions, which speeds it up considerably for multi-condition searches, and skips non-text files unless instructed otherwise, but it's still relatively slow.)
Both convert HTML to text before searching (with the exception of the binary file scanning mode).
There are some issues with which files get indexed and which don't that we can't do much about and that will probably confuse users immensely. Dan C. suggested some sort of indicator (say, a green dot) to show which files are indexed.
Also added (very ugly) charset detection (anybody want to figure out getCharsetFromString(str)?), a setTimeout() replacement in the XPCOM service, an arrayToHash() method, and a new header to timedtextarea.xml, since it's really not copyright CHNM (it's really just a few lines off from the toolkit timed-textbox binding--I tried to change it to extend timed-textbox and just ignore Return keypress events so that we didn't need to duplicate the Mozilla code, but timed-textbox's reliance on html:input instead of html:textarea made things rather difficult).
To do:
- Pref/buttons to disable/clear/rebuild fulltext index
- Hidden prefs to set maximum file size to index/scan
- Don't index words of fewer than 3 non-Asian characters
- MRU cache for saved searches
- Use word index if available to narrow search scope of fulltext scanner
- Cache attachment info methods
- Show content excerpt in search results (at least in advanced search window, when it exists)
- Notification window (a la scraping) to show when indexing
- Indicator of indexed status
- Context menu option to index
- Indicator that a file scanning search is in progress, if possible
- Find other ways to make it index the NYT front page in under 10 seconds
- Probably fix lots of bugs, which you will likely start telling me about...now.
2006-09-21 00:10:29 +00:00
|
|
|
// Create a hidden browser
|
2007-10-23 07:11:59 +00:00
|
|
|
var hiddenBrowser = win.document.createElement("browser");
|
Merged revisions 2890,2895-2896,2898,2900-2901,2905,2909-2911,2913,2916-2917,2919,2922,2936-2937,2953-2954,2957,2959,2962-2965,2969-2970,2973-2975,2979-2980,2983 via svnmerge from 1.0 branch
2008-07-07 15:18:49 +00:00
|
|
|
hiddenBrowser.setAttribute('type', 'content');
|
Merged revisions 2710-2712,2714-2716,2718-2728,2730-2731,2734,2736-2738,2740-2750,2752-2753,2755,2758-2768,2770-2779,2782,2789-2790,2794,2797-2802,2804,2808-2810,2812,2814-2824,2826-2832,2834-2835 via svnmerge from 1.0 branch
2008-06-11 08:55:59 +00:00
|
|
|
hiddenBrowser.setAttribute('disablehistory', 'true');
|
2007-10-23 07:11:59 +00:00
|
|
|
win.document.documentElement.appendChild(hiddenBrowser);
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
// Disable some features
|
2011-08-12 19:20:35 +00:00
|
|
|
hiddenBrowser.docShell.allowAuth = false;
|
|
|
|
hiddenBrowser.docShell.allowDNSPrefetch = false;
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
hiddenBrowser.docShell.allowImages = false;
|
2012-01-16 16:15:29 +00:00
|
|
|
hiddenBrowser.docShell.allowJavascript = true;
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
hiddenBrowser.docShell.allowMetaRedirects = false;
|
|
|
|
hiddenBrowser.docShell.allowPlugins = false;
|
2012-11-07 22:17:16 +00:00
|
|
|
Zotero.debug("Created hidden browser (" + (nBrowsers++) + ")");
|
2007-10-23 07:11:59 +00:00
|
|
|
return hiddenBrowser;
|
2006-07-27 23:01:55 +00:00
|
|
|
}
|
|
|
|
|
2012-11-06 05:47:49 +00:00
|
|
|
function deleteHiddenBrowser(myBrowsers) {
|
2012-11-07 20:15:56 +00:00
|
|
|
if(!(myBrowsers instanceof Array)) myBrowsers = [myBrowsers];
|
2012-11-06 05:47:49 +00:00
|
|
|
for(var i=0; i<myBrowsers.length; i++) {
|
|
|
|
var myBrowser = myBrowsers[i];
|
|
|
|
myBrowser.stop();
|
|
|
|
myBrowser.destroy();
|
|
|
|
myBrowser.parentNode.removeChild(myBrowser);
|
|
|
|
myBrowser = null;
|
2012-11-07 22:17:16 +00:00
|
|
|
Zotero.debug("Deleted hidden browser (" + (--nBrowsers) + ")");
|
2012-11-06 05:47:49 +00:00
|
|
|
}
|
2006-07-27 23:01:55 +00:00
|
|
|
}
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Implements nsIWebProgressListener
|
|
|
|
*/
|
|
|
|
Zotero.WebProgressFinishListener = function(onFinish) {
|
|
|
|
this.onStateChange = function(wp, req, stateFlags, status) {
|
|
|
|
//Zotero.debug('onStageChange: ' + stateFlags);
|
2015-11-29 00:07:11 +00:00
|
|
|
if (stateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP
|
|
|
|
&& stateFlags & Components.interfaces.nsIWebProgressListener.STATE_IS_NETWORK) {
|
2007-10-23 07:11:59 +00:00
|
|
|
onFinish();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.onProgressChange = function(wp, req, curSelfProgress, maxSelfProgress, curTotalProgress, maxTotalProgress) {
|
|
|
|
//Zotero.debug('onProgressChange');
|
|
|
|
//Zotero.debug('Current: ' + curTotalProgress);
|
|
|
|
//Zotero.debug('Max: ' + maxTotalProgress);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.onLocationChange = function(wp, req, location) {}
|
|
|
|
this.onSecurityChange = function(wp, req, stateFlags, status) {}
|
|
|
|
this.onStatusChange = function(wp, req, status, msg) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-06-05 17:49:04 +00:00
|
|
|
* Saves or loads JSON objects.
|
2007-10-23 07:11:59 +00:00
|
|
|
*/
|
|
|
|
Zotero.JSON = new function() {
|
2010-06-05 17:49:04 +00:00
|
|
|
this.serialize = function(arg) {
|
2011-07-11 22:37:37 +00:00
|
|
|
Zotero.debug("WARNING: Zotero.JSON.serialize() is deprecated; use JSON.stringify()");
|
|
|
|
return JSON.stringify(arg);
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
|
2010-06-05 17:49:04 +00:00
|
|
|
this.unserialize = function(arg) {
|
2011-07-11 22:37:37 +00:00
|
|
|
Zotero.debug("WARNING: Zotero.JSON.unserialize() is deprecated; use JSON.parse()");
|
|
|
|
return JSON.parse(arg);
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
2010-09-25 16:09:55 +00:00
|
|
|
}
|