Closes #359, Ability to store Zotero directory outside of Firefox profile directory

Customizable in the preferences

Also improves handling of Zotero startup errors, adding the ability to customize the tooltiptext of the status bar error icon and to have ZoteroPane.toggleDisplay() run a customizable error function (it no longer opens an empty and broken Zotero pane). For example, a missing Z directory now prompts the user to locate the directory.

Various code parts now check for the Zotero object and Zotero.initialized before trying to do stuff, which should cut down on redundant error lines in the console and generally make things cleaner.


Refs #542, Better icons for preferences window -- need icon for Advanced prefpane
This commit is contained in:
Dan Stillman 2007-02-28 11:33:08 +00:00
parent 4ffaaa9eea
commit f161b1afb8
10 changed files with 347 additions and 25 deletions

View File

@ -82,12 +82,16 @@ var ZoteroItemPane = new function()
function onLoad()
{
if (!Zotero || !Zotero.initialized) {
return;
}
_tabs = document.getElementById('zotero-view-tabs');
// Not in item pane, so skip the introductions
if (!_tabs)
{
return false;
return;
}
_dynamicFields = document.getElementById('zotero-editpane-dynamic-fields');
@ -104,8 +108,6 @@ var ZoteroItemPane = new function()
for(var i = 0; i<itemTypes.length; i++)
if(itemTypes[i]['name'] != 'note' && itemTypes[i]['name'] != 'attachment')
_itemTypeMenu.appendItem(Zotero.getString("itemTypes."+itemTypes[i]['name']),itemTypes[i]['id']);
return true;
}
/*

View File

@ -89,6 +89,10 @@ var ZoteroPane = new function()
*/
function onLoad()
{
if (!Zotero || !Zotero.initialized) {
return;
}
if(Zotero.Prefs.get("zoteroPaneOnTop"))
{
var oldPane = document.getElementById('zotero-pane');
@ -169,6 +173,10 @@ var ZoteroPane = new function()
*/
function onUnload()
{
if (!Zotero || !Zotero.initialized) {
return;
}
var tagSelector = document.getElementById('zotero-tag-selector');
tagSelector.unregister();
@ -185,6 +193,27 @@ var ZoteroPane = new function()
// Visible == target visibility
var visible = document.getElementById('zotero-pane').getAttribute('hidden') == 'true';
// If Zotero not initialized, try to get the error handler
// or load the default error page
if (visible && (!Zotero || !Zotero.initialized)) {
if (Zotero) {
var errFunc = Zotero.startupErrorHandler;
}
if (errFunc) {
errFunc();
}
else {
// TODO: Add a better error page/window here with reporting
// instructions
// window.loadURI('chrome://zotero/content/error.xul');
// TODO: localize if possible
alert("There was an error starting Zotero.");
}
return;
}
document.getElementById('zotero-pane').setAttribute('hidden', !visible);
document.getElementById('zotero-splitter').setAttribute('hidden', !visible);
@ -1591,7 +1620,7 @@ var ZoteroPane = new function()
var index = ps.confirmEx(null,
Zotero.getString('pane.item.attachments.fileNotFound.title'),
Zotero.getString('pane.item.attachments.fileNotFound.text'),
buttonFlags, null, Zotero.getString('pane.item.attachments.locate'),
buttonFlags, null, Zotero.getString('general.locate'),
null, null, {});
if (index == 1) {

View File

@ -321,9 +321,10 @@
</statusbar>
<script>
<![CDATA[
window.addEventListener('load', function(e){
var icon = document.getElementById('zotero-status-bar-icon');
if (Zotero){
if (Zotero && Zotero.initialized){
switch (Zotero.Prefs.get('statusBarIcon')) {
case 2:
icon.setAttribute('hidden', false);
@ -335,13 +336,23 @@
}
}
else {
icon.setAttribute('hidden', false);
if (Zotero) {
var errMsg = Zotero.startupError;
}
// Use defaults if necessary
if (!errMsg) {
var errMsg = 'There was an error starting Zotero.';
}
icon.setAttribute('tooltiptext', errMsg);
icon.setAttribute('error', 'true');
icon.setAttribute('tooltiptext', 'There was an error starting Zotero.');
icon.setAttribute('hidden', false);
}
}, false);
document.getElementById('appcontent').addEventListener('keydown', ZoteroPane.handleKeyDown, true);
]]>
</script>
<menupopup id="menu_ToolsPopup">
@ -350,7 +361,7 @@
oncommand="ZoteroPane.toggleDisplay();" label="Zotero"
key="key_openZotero"/>
</menupopup>
<keyset id="mainKeyset">
<!--
The key can be changed by the pref extensions.zotero.keys.openZotero,

View File

@ -36,6 +36,75 @@ function init()
}
function onDataDirLoad() {
var path = document.getElementById('dataDirPath');
var useDataDir = Zotero.Prefs.get('useDataDir');
path.setAttribute('disabled', !useDataDir);
}
function onDataDirUpdate(event) {
var radiogroup = document.getElementById('dataDir');
var path = document.getElementById('dataDirPath');
var useDataDir = Zotero.Prefs.get('useDataDir');
// If triggered from the Choose button, don't show the dialog, since
// Zotero.chooseZoteroDirectory() shows its own
if (event.originalTarget.tagName == 'button') {
return true;
}
// If directory not set or invalid, prompt for location
if (!getDataDirPath()) {
event.stopPropagation();
var file = Zotero.chooseZoteroDirectory(true);
radiogroup.selectedIndex = file ? 1 : 0;
return !!file;
}
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)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
var index = ps.confirmEx(window,
Zotero.getString('general.restartFirefox.singular'),
'',
buttonFlags,
Zotero.getString('general.restartNow'),
null, null, null, {});
if (index == 0) {
useDataDir = !!radiogroup.selectedIndex;
// quit() is asynchronous, but set this here just in case
Zotero.Prefs.set('useDataDir', useDataDir);
var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
.getService(Components.interfaces.nsIAppStartup);
appStartup.quit(Components.interfaces.nsIAppStartup.eRestart);
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
}
radiogroup.selectedIndex = useDataDir ? 1 : 0;
return useDataDir;
}
function getDataDirPath() {
var desc = Zotero.Prefs.get('dataDir');
if (desc == '') {
return '';
}
var file = Components.classes["@mozilla.org/file/local;1"].
createInstance(Components.interfaces.nsILocalFile);
try {
file.persistentDescriptor = desc;
}
catch (e) {
return '';
}
return file.path;
}
function populateOpenURLResolvers() {
var openURLMenu = document.getElementById('openURLMenu');

View File

@ -243,6 +243,28 @@ To add a new preference:
<label class="statusLine" value="&zotero.preferences.keys.changesTakeEffect;"/>
</prefpane>
<prefpane id="zotero-prefpane-advanced" label="&zotero.preferences.prefpane.advanced;">
<preferences>
<preference id="pref-useDataDir" name="extensions.zotero.useDataDir" type="bool"/>
<preference id="pref-dataDir" name="extensions.zotero.dataDir" type="string"/>
</preferences>
<groupbox>
<caption label="&zotero.preferences.dataDir;"/>
<radiogroup id="dataDir" preference="pref-useDataDir" onsyncfrompreference="onDataDirLoad();" onsynctopreference="return onDataDirUpdate(event);">
<radio label="&zotero.preferences.dataDir.useProfile;" value="false"/>
<hbox>
<radio label="&zotero.preferences.dataDir.custom;" value="true"/>
<textbox id="dataDirPath" preference="pref-dataDir" onsyncfrompreference="return getDataDirPath();" readonly="true" flex="1"/>
<button label="&zotero.preferences.dataDir.choose;" oncommand="var file = Zotero.chooseZoteroDirectory(true); if (!file) { event.stopPropagation(); }"/>
</hbox>
</radiogroup>
</groupbox>
</prefpane>
<!-- These mess up the prefwindow if they come before the prefpanes
https://bugzilla.mozilla.org/show_bug.cgi?id=296418 -->
<script src="include.js"/>

View File

@ -32,12 +32,6 @@ const ZOTERO_CONFIG = {
* Core functions
*/
var Zotero = new function(){
var _initialized = false;
var _debugLogging;
var _debugLevel;
//var _shutdown = false;
var _localizedStringBundle;
// Privileged (public) methods
this.init = init;
//this.shutdown = shutdown;
@ -45,6 +39,7 @@ var Zotero = new function(){
this.getZoteroDirectory = getZoteroDirectory;
this.getStorageDirectory = getStorageDirectory;
this.getZoteroDatabase = getZoteroDatabase;
this.chooseZoteroDirectory = chooseZoteroDirectory;
this.debug = debug;
this.varDump = varDump;
this.safeDebug = safeDebug;
@ -62,17 +57,29 @@ var Zotero = new function(){
this.moveToUnique = moveToUnique;
// Public properties
this.initialized = false;
this.__defineGetter__("startupError", function() { return _startupError; });
this.__defineGetter__("startupErrorHandler", function() { return _startupErrorHandler; });
this.version;
this.platform;
this.locale;
this.isMac;
this.isWin;
var _startupError;
var _startupErrorHandler;
var _zoteroDirectory = false;
var _debugLogging;
var _debugLevel;
//var _shutdown = false;
var _localizedStringBundle;
/*
* Initialize the extension
*/
function init(){
if (_initialized){
if (this.initialized){
return false;
}
@ -114,6 +121,10 @@ var Zotero = new function(){
getService(Components.interfaces.nsILocaleService);
this.locale = localeService.getLocaleComponentForUserAgent();
//var serv = Components.classes["@mozilla.org/network/protocol;1?name=http"].getService(Components.interfaces.nsIHttpProtocolHandler);
//Components.classes["@mozilla.org/network/protocol;1?name=http"].getService(Components.interfaces.nsIHttpProtocolHandler).language
//Components.classes['@mozilla.org/intl/nslocaleservice;1'].getService(Components.interfaces.nsILocaleService).getApplicationLocale().getCategory("NSILOCALE_MESSAGES")
// Load in the localization stringbundle for use by getString(name)
var src = 'chrome://zotero/locale/zotero.properties';
var appLocale = localeService.getApplicationLocale();
@ -123,6 +134,50 @@ var Zotero = new function(){
.getService(Components.interfaces.nsIStringBundleService);
_localizedStringBundle = stringBundleService.createBundle(src, appLocale);
try {
this.getZoteroDirectory();
}
catch (e) {
// Zotero dir not found
if (e.name == 'NS_ERROR_FILE_NOT_FOUND') {
_startupError = Zotero.getString('dataDir.notFound');
_startupErrorHandler = function() {
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow('navigator:browser');
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);
var index = ps.confirmEx(win,
_startupError,
Zotero.getString('dataDir.previousDir') + ' '
+ Zotero.Prefs.get('lastDataDir'),
buttonFlags, null,
Zotero.getString('dataDir.useProfileDir'),
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();
}
}
}
// DEBUG: handle more startup errors
else {
throw (e);
}
return;
}
// Initialize keyboard shortcuts
Zotero.Keys.init();
// Add notifier queue callbacks to the DB layer
@ -140,7 +195,7 @@ var Zotero = new function(){
Zotero.Integration.SOAP.init();
Zotero.Integration.init();
_initialized = true;
this.initialized = true;
return true;
}
@ -164,13 +219,28 @@ var Zotero = new function(){
function getZoteroDirectory(){
var file = Zotero.getProfileDirectory();
file.append('zotero');
// If it doesn't exist, create
if (!file.exists() || !file.isDirectory()){
file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0755);
if (_zoteroDirectory != false) {
// Return a clone of the file pointer so that callers can modify it
return _zoteroDirectory.clone();
}
if (Zotero.Prefs.get('useDataDir')) {
var file = Components.classes["@mozilla.org/file/local;1"].
createInstance(Components.interfaces.nsILocalFile);
file.persistentDescriptor = Zotero.Prefs.get('dataDir');
}
else {
var file = Zotero.getProfileDirectory();
file.append('zotero');
// If it doesn't exist, create
if (!file.exists() || !file.isDirectory()){
file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0755);
}
}
Zotero.debug("Using data directory " + file.path);
_zoteroDirectory = file;
return file;
}
@ -196,6 +266,80 @@ var Zotero = new function(){
}
function chooseZoteroDirectory(forceRestartNow, useProfileDir) {
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow('navigator:browser');
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
if (useProfileDir) {
Zotero.Prefs.set('useDataDir', false);
}
else {
var nsIFilePicker = Components.interfaces.nsIFilePicker;
while (true) {
var fp = Components.classes["@mozilla.org/filepicker;1"]
.createInstance(nsIFilePicker);
fp.init(win, Zotero.getString('dataDir.selectDir'), nsIFilePicker.modeGetFolder);
fp.appendFilters(nsIFilePicker.filterAll);
if (fp.show() == nsIFilePicker.returnOK) {
var file = fp.file;
if (file.directoryEntries.hasMoreElements()) {
var dbfile = file.clone();
dbfile.append('zotero.sqlite');
// Warn if non-empty and no zotero.sqlite
if (!dbfile.exists()) {
var buttonFlags = ps.STD_YES_NO_BUTTONS;
var index = ps.confirmEx(win,
Zotero.getString('dataDir.selectedDirNonEmpty.title'),
Zotero.getString('dataDir.selectedDirNonEmpty.text'),
buttonFlags, null, null, null, null, {});
// Not OK -- return to file picker
if (index == 1) {
continue;
}
}
}
// Set new data directory
Zotero.Prefs.set('dataDir', file.persistentDescriptor);
Zotero.Prefs.set('lastDataDir', file.path);
Zotero.Prefs.set('useDataDir', true);
break;
}
else {
return false;
}
}
}
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING);
if (!forceRestartNow) {
buttonFlags += (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING);
}
var index = ps.confirmEx(win,
Zotero.getString('general.restartFirefox.singular'),
'',
buttonFlags,
Zotero.getString('general.restartNow'),
forceRestartNow ? null : Zotero.getString('general.restartLater'),
null, null, {});
if (index == 0) {
var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
.getService(Components.interfaces.nsIAppStartup);
appStartup.quit(Components.interfaces.nsIAppStartup.eRestart);
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
}
return useProfileDir ? true : file;
}
/*
* Debug logging function
*

View File

@ -1,6 +1,7 @@
<!ENTITY zotero.preferences.title "Zotero Preferences">
<!ENTITY zotero.preferences.prefpane.general "General">
<!ENTITY zotero.preferences.userInterface "User Interface">
<!ENTITY zotero.preferences.position "Display Zotero">
<!ENTITY zotero.preferences.position.above "above">
@ -11,6 +12,7 @@
<!ENTITY zotero.preferences.fontSize.small "Small">
<!ENTITY zotero.preferences.fontSize.medium "Medium">
<!ENTITY zotero.preferences.fontSize.large "Large">
<!ENTITY zotero.preferences.autoUpdate "Automatically check for updated scrapers">
<!ENTITY zotero.preferences.updateNow "Update now">
<!ENTITY zotero.preferences.reportTranslationFailure "Report broken site translators">
@ -18,17 +20,22 @@
<!ENTITY zotero.preferences.automaticSnapshots "Automatically take snapshots when creating items from web pages">
<!ENTITY zotero.preferences.downloadAssociatedFiles "Automatically attach associated PDFs and other files when saving items">
<!ENTITY zotero.preferences.automaticTags "Automatically tag items with keywords and subject headings">
<!ENTITY zotero.preferences.openurl.caption "OpenURL">
<!ENTITY zotero.preferences.openurl.custom "Custom...">
<!ENTITY zotero.preferences.openurl.server "Resolver:">
<!ENTITY zotero.preferences.openurl.version "Version:">
<!ENTITY zotero.preferences.prefpane.export "Export">
<!ENTITY zotero.preferences.quickCopy.caption "Quick Copy">
<!ENTITY zotero.preferences.quickCopy.outputFormat "Output Format:">
<!ENTITY zotero.preferences.quickCopy.macWarning "Note that some formatting may be lost on Mac OS X.">
<!ENTITY zotero.preferences.prefpane.keys "Shortcut Keys">
<!ENTITY zotero.preferences.keys.openZotero "Open/Close Zotero Pane">
<!ENTITY zotero.preferences.keys.toggleFullscreen "Toggle Fullscreen Mode">
<!ENTITY zotero.preferences.keys.library "Library">
@ -38,4 +45,12 @@
<!ENTITY zotero.preferences.keys.toggleTagSelector "Toggle Tag Selector">
<!ENTITY zotero.preferences.keys.copySelectedItemsToClipboard "Copy Selected Items to Clipboard">
<!ENTITY zotero.preferences.keys.overrideGlobal "Try to override conflicting shortcuts">
<!ENTITY zotero.preferences.keys.changesTakeEffect "Changes take effect in new windows only">
<!ENTITY zotero.preferences.keys.changesTakeEffect "Changes take effect in new windows only">
<!ENTITY zotero.preferences.prefpane.advanced "Advanced">
<!ENTITY zotero.preferences.dataDir "Storage Location">
<!ENTITY zotero.preferences.dataDir.useProfile "Use Firefox profile directory">
<!ENTITY zotero.preferences.dataDir.custom "Custom:">
<!ENTITY zotero.preferences.dataDir.choose "Choose...">

View File

@ -1,4 +1,16 @@
general.dontShowWarningAgain = Don't show this warning again.
general.locate = Locate...
general.restartFirefox.singular = Firefox must be restarted for the change to take effect.
general.restartFirefox.plural = Firefox must be restarted for the changes to take effect.
general.restartNow = Restart now
general.restartLater = Restart later
dataDir.notFound = The Zotero data directory could not be found.
dataDir.previousDir = Previous directory:
dataDir.useProfileDir = Use Firefox profile directory
dataDir.selectDir = Select a Zotero data directory
dataDir.selectedDirNonEmpty.title = The directory you selected is not empty and does not appear to be a Zotero data directory.
dataDir.selectedDirNonEmpty.text = Create Zotero files in this directory anyway?
pane.collections.delete = Are you sure you want to delete the selected collection?
pane.collections.deleteSearch = Are you sure you want to delete the selected search?
@ -68,7 +80,6 @@ pane.item.attachments.view.snapshot = View Snapshot
pane.item.attachments.view.file = View File
pane.item.attachments.fileNotFound.title = The attached file could not be found.
pane.item.attachments.fileNotFound.text = It may have been moved or deleted outside of Zotero.
pane.item.attachments.locate = Locate...
pane.item.attachments.delete.confirm = Are you sure you want to delete this attachment?
pane.item.attachments.count.zero = %S attachments:
pane.item.attachments.count.singular = %S attachment:

View File

@ -55,8 +55,24 @@ radio[pane=zotero-prefpane-keys][selected="true"]
}
/* General pane */
/*
* Advanced pane icon
*
* Use the Gear icon until we find a better icon
*/
radio[pane=zotero-prefpane-advanced]
{
-moz-image-region: rect(0px, 224px, 32px, 192px);
}
radio[pane=zotero-prefpane-advanced]:hover,
radio[pane=zotero-prefpane-advanced]:active,
radio[pane=zotero-prefpane-advanced][selected="true"]
{
-moz-image-region: rect(32px, 224px, 64px, 192px);
}
/* General pane */
grid row hbox:first-child
{
-moz-box-pack: end;

View File

@ -1,5 +1,8 @@
// These are DEFAULT prefs for the INSTALL. You will have to reinstall the extension to see differences!
pref("extensions.zotero.useDataDir", false);
pref("extensions.zotero.dataDir", '');
pref("extensions.zotero.lastDataDir", '');
pref("extensions.zotero.debug.log",false);
pref("extensions.zotero.debug.level",5);
pref("extensions.zotero.automaticScraperUpdates",true);