www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit 3b0f20c4930bf397504a39cb20c14826972d891a
parent d26eed03dc0a48630320b11c9139d02a717d52ea
Author: Dan Stillman <dstillman@zotero.org>
Date:   Fri,  2 Jan 2009 00:35:09 +0000

Add initial implementations of "Restore to Server" and "Restore from Server" to the Sync pref pane


Diffstat:
Mchrome/content/zotero/overlay.js | 34+++++++++++++++++++++++++++++++---
Mchrome/content/zotero/preferences/preferences.js | 142++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mchrome/content/zotero/preferences/preferences.xul | 264++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mchrome/content/zotero/xpcom/db.js | 12+++++++-----
Mchrome/content/zotero/xpcom/schema.js | 52+++++++++++++++++++++++++++-------------------------
Mchrome/content/zotero/xpcom/sync.js | 70+++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mchrome/content/zotero/xpcom/zotero.js | 34+++++++++++++++++++++++++++++++---
Mchrome/skin/default/zotero/preferences.css | 46++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 489 insertions(+), 165 deletions(-)

diff --git a/chrome/content/zotero/overlay.js b/chrome/content/zotero/overlay.js @@ -179,12 +179,40 @@ var ZoteroPane = new function() // If the database was initialized and Zotero hasn't been run before // in this profile, display the Quick Start Guide -- this way the guide - // won't be displayed they sync their DB to another profile or if + // won't be displayed when they sync their DB to another profile or if // they the DB is initialized erroneously (e.g. while switching data // directory locations) - if (Zotero.Schema.dbInitialized && Zotero.Prefs.get('firstRun')) { + if (Zotero.restoreFromServer) { + Zotero.restoreFromServer = false; + + setTimeout(function () { + var pr = Components.classes["@mozilla.org/network/default-prompt;1"] + .getService(Components.interfaces.nsIPrompt); + var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING) + + (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL); + var index = pr.confirmEx( + "Zotero Restore", + "The local Zotero database has been cleared." + + " " + + "Would you like to restore from the Zotero server now?", + buttonFlags, + "Sync Now", + null, null, null, {} + ); + + if (index == 0) { + Zotero.Sync.Server.sync(function () { + pr.alert( + "Restore Completed", + "The local Zotero database has been successfully restored." + ); + }); + } + }, 1000); + } + else if (Zotero.Schema.dbInitialized && Zotero.Prefs.get('firstRun')) { setTimeout(function () { - gBrowser.selectedTab = gBrowser.addTab('http://www.zotero.org/documentation/quick_start_guide'); + gBrowser.selectedTab = gBrowser.addTab(ZOTERO_CONFIG.FIRST_RUN_URL); }, 400); Zotero.Prefs.set('firstRun', false); } diff --git a/chrome/content/zotero/preferences/preferences.js b/chrome/content/zotero/preferences/preferences.js @@ -148,6 +148,24 @@ function populateOpenURLResolvers() { // // Sync // +/* +function updateSyncStatus() { + var disabled = !Zotero.Sync.Server.enabled; + + var radioGroup = document.getElementById('zotero-reset').firstChild; + radioGroup.disabled = disabled; + var labels = radioGroup.getElementsByTagName('label'); + for each(var label in labels) { + label.disabled = disabled; + } + var labels = radioGroup.getElementsByTagName('description'); + for each(var label in labels) { + label.disabled = disabled; + } + document.getElementById('zotero-reset-button').disabled = disabled; +} +*/ + function updateStorageSettings(value) { if (!value) { value = document.getElementById('pref-storage-protocol').value; @@ -223,6 +241,130 @@ function verifyStorageServer() { } } +function handleSyncResetSelect(obj) { + var index = obj.selectedIndex; + var rows = obj.getElementsByTagName('row'); + + for (var i=0; i<rows.length; i++) { + if (i == index) { + rows[i].setAttribute('selected', 'true'); + } + else { + rows[i].removeAttribute('selected'); + } + } +} + +function handleSyncReset(action) { + var pr = Components.classes["@mozilla.org/network/default-prompt;1"] + .getService(Components.interfaces.nsIPrompt); + + if (!Zotero.Sync.Server.enabled) { + pr.alert( + Zotero.getString('general.error'), + // TODO: localize + "You must enter a username and password in the " + + document.getElementById('zotero-prefpane-sync') + .getElementsByTagName('tab')[0].label + + " tab before using the reset options." + ); + return; + } + + var account = Zotero.Sync.Server.username; + + switch (action) { + case 'restore-from-server': + var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING) + + (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL) + + pr.BUTTON_POS_1_DEFAULT; + var index = pr.confirmEx( + // TODO: localize + Zotero.getString('general.warning'), + "All data in this copy of Zotero will be erased and replaced with " + + "data belonging to user '" + account + "' on the Zotero server.", + buttonFlags, + "Replace Zotero Data", + null, null, null, {} + ); + + switch (index) { + case 0: + // TODO: better error handling + + // Verify username and password + Zotero.Sync.Server.login(function () { + Zotero.Schema.stopRepositoryTimer(); + Zotero.Sync.Runner.clearSyncTimeout(); + + Zotero.DB.skipBackup = true; + + var file = Zotero.getZoteroDirectory(); + file.append('restore-from-server'); + Zotero.File.putContents(file, ''); + + var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING); + var index = pr.confirmEx( + Zotero.getString('general.restartRequired'), + // TODO: localize + "Firefox must be restarted to complete the restore process.", + buttonFlags, + Zotero.getString('general.restartNow'), + null, null, null, {} + ); + + 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); + }); + break; + + // Cancel + case 1: + return; + } + break; + + case 'restore-to-server': + var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING) + + (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL) + + pr.BUTTON_POS_1_DEFAULT; + var index = pr.confirmEx( + // TODO: localize + Zotero.getString('general.warning'), + "All item data belonging to user '" + account + "' on the Zotero server " + + "will be erased and replaced with data from this copy of Zotero.", + buttonFlags, + "Replace Server Data", + null, null, null, {} + ); + + switch (index) { + case 0: + // TODO: better error handling + Zotero.Sync.Server.clear(function () { + Zotero.Sync.Server.sync(function () { + pr.alert( + "Restore Completed", + "Item data on the Zotero server has been " + + "successfully restored." + ); + }); + }); + break; + + // Cancel + case 1: + return; + } + + break; + + default: + throw ("Invalid action '" + action + "' in handleSyncReset()"); + } +} /* diff --git a/chrome/content/zotero/preferences/preferences.xul b/chrome/content/zotero/preferences/preferences.xul @@ -171,120 +171,164 @@ To add a new preference: <preference id="pref-storage-username" name="extensions.zotero.sync.storage.username" type="string" instantApply="true"/> </preferences> - <groupbox> - <caption label="Zotero Sync Server"/> - - <grid> - <columns> - <column/> - <column/> - </columns> - - <rows> - <row> - <label value="Username:"/> - <textbox preference="pref-sync-username" - onchange="Zotero.Prefs.set('sync.server.username', this.value); var pass = document.getElementById('sync-password'); if (pass.value) { Zotero.Sync.Server.password = pass.value; }"/> - </row> - <row> - <label value="Password:"/> - <textbox id="sync-password" type="password" - onchange="Zotero.Sync.Server.password = this.value"/> - </row> - <!-- - <row> - <box/> - <hbox> - <button label="Verify login" - oncommand="alert('Unimplemented')"/> - </hbox> - </row> - --> - </rows> - </grid> - - <separator class="thin"/> - - <hbox> - <checkbox label="Sync automatically" preference="pref-sync-autosync"/> - </hbox> - </groupbox> - - - <groupbox> - <caption label="Storage Server"/> - - <hbox> - <checkbox label="Enable file syncing" preference="pref-storage-enabled"/> - </hbox> - - <separator class="thin"/> - - <grid id="storage-settings"> - <columns> - <column/> - <column flex="1"/> - </columns> - - <rows> - <row> - <label value="Protocol:"/> + <tabbox> + <tabs> + <tab label="Settings"/> + <tab label="Reset"/> + </tabs> + + <tabpanels> + <tabpanel orient="vertical"> + <groupbox> + <caption label="Zotero Sync Server"/> + + <grid> + <columns> + <column/> + <column/> + </columns> + + <rows> + <row> + <label value="Username:"/> + <textbox preference="pref-sync-username" + onchange="Zotero.Prefs.set('sync.server.username', this.value); var pass = document.getElementById('sync-password'); if (pass.value) { Zotero.Sync.Server.password = pass.value; }"/> + </row> + <row> + <label value="Password:"/> + <textbox id="sync-password" type="password" + onchange="Zotero.Sync.Server.password = this.value"/> + </row> + <!-- + <row> + <box/> + <hbox> + <button label="Verify login" + oncommand="alert('Unimplemented')"/> + </hbox> + </row> + --> + </rows> + </grid> + + <separator class="thin"/> + <hbox> - <menulist id="storage-url-protocol" - preference="pref-storage-protocol" - onsynctopreference="updateStorageSettings(this.value)"> - <menupopup> - <menuitem label="WebDAV" value="webdav"/> - <!-- TODO: localize --> - <menuitem label="WebDAV (Secure)" value="webdavs"/> - </menupopup> - </menulist> - </hbox> - </row> - <row> - <label value="URL:"/> - <hbox> - <label id="storage-url-prefix"/> - <textbox id="storage-url" flex="1" - preference="pref-storage-url" - onkeypress="if (Zotero.isMac &amp;&amp; event.keyCode == 13) { this.blur(); verifyStorageServer(); }" - onsynctopreference="unverifyStorageServer();" - onchange="this.value = this.value.replace(/(^https?:\/\/|\/zotero\/?$|\/$)/g, '')"/> - <label value="/zotero/"/> + <checkbox label="Sync automatically" preference="pref-sync-autosync"/> </hbox> - </row> - <row> - <label value="Username:"/> - <hbox> - <textbox id="storage-username" - preference="pref-storage-username" - onkeypress="if (Zotero.isMac &amp;&amp; event.keyCode == 13) { this.blur(); setTimeout('verifyStorageServer();', 1); }" - onsynctopreference="unverifyStorageServer();" - onchange="var pass = document.getElementById('storage-password'); if (pass.value) { Zotero.Sync.Storage.password = pass.value; }"/> - </hbox> - </row> - <row> - <label value="Password:"/> - <hbox> - <textbox id="storage-password" flex="0" type="password" - onkeypress="if (Zotero.isMac &amp;&amp; event.keyCode == 13) { this.blur(); setTimeout('verifyStorageServer();', 1); }" - oninput="unverifyStorageServer()" - onchange="Zotero.Sync.Storage.password = this.value"/> - </hbox> - </row> - <row> - <box/> + </groupbox> + + + <groupbox> + <caption label="Storage Server"/> + <hbox> - <button id="storage-verify" label="Verify Server" - oncommand="verifyStorageServer()"/> - <button id="storage-abort" label="Stop" hidden="true"/> - <progressmeter id="storage-progress" hidden="true" - mode="undetermined"/> + <checkbox label="Enable file syncing" preference="pref-storage-enabled"/> </hbox> - </row> - </rows> - </grid> - </groupbox> + + <separator class="thin"/> + + <grid id="storage-settings"> + <columns> + <column/> + <column flex="1"/> + </columns> + + <rows> + <row> + <label value="Protocol:"/> + <hbox> + <menulist id="storage-url-protocol" + preference="pref-storage-protocol" + onsynctopreference="updateStorageSettings(this.value)"> + <menupopup> + <menuitem label="WebDAV" value="webdav"/> + <!-- TODO: localize --> + <menuitem label="WebDAV (Secure)" value="webdavs"/> + </menupopup> + </menulist> + </hbox> + </row> + <row> + <label value="URL:"/> + <hbox> + <label id="storage-url-prefix"/> + <textbox id="storage-url" flex="1" + preference="pref-storage-url" + onkeypress="if (Zotero.isMac &amp;&amp; event.keyCode == 13) { this.blur(); verifyStorageServer(); }" + onsynctopreference="unverifyStorageServer();" + onchange="this.value = this.value.replace(/(^https?:\/\/|\/zotero\/?$|\/$)/g, '')"/> + <label value="/zotero/"/> + </hbox> + </row> + <row> + <label value="Username:"/> + <hbox> + <textbox id="storage-username" + preference="pref-storage-username" + onkeypress="if (Zotero.isMac &amp;&amp; event.keyCode == 13) { this.blur(); setTimeout('verifyStorageServer();', 1); }" + onsynctopreference="unverifyStorageServer();" + onchange="var pass = document.getElementById('storage-password'); if (pass.value) { Zotero.Sync.Storage.password = pass.value; }"/> + </hbox> + </row> + <row> + <label value="Password:"/> + <hbox> + <textbox id="storage-password" flex="0" type="password" + onkeypress="if (Zotero.isMac &amp;&amp; event.keyCode == 13) { this.blur(); setTimeout('verifyStorageServer();', 1); }" + oninput="unverifyStorageServer()" + onchange="Zotero.Sync.Storage.password = this.value"/> + </hbox> + </row> + <row> + <box/> + <hbox> + <button id="storage-verify" label="Verify Server" + oncommand="verifyStorageServer()"/> + <button id="storage-abort" label="Stop" hidden="true"/> + <progressmeter id="storage-progress" hidden="true" + mode="undetermined"/> + </hbox> + </row> + </rows> + </grid> + </groupbox> + </tabpanel> + + <tabpanel id="zotero-reset" orient="vertical"> + <radiogroup oncommand="handleSyncResetSelect(this);"> + <grid> + <columns> + <column/> + <column align="start" pack="start" flex="1"/> + </columns> + + <rows> + <row id="zotero-restore-from-server" selected="true"> + <radio/> + <vbox onclick="this.previousSibling.click()"> + <label value="Restore from server"/> + <description>Erase all local Zotero data and restore from the sync server.</description> + </vbox> + </row> + + <row id="zotero-restore-to-server"> + <radio/> + <vbox onclick="this.previousSibling.click()"> + <label value="Restore to server"/> + <description>Erase all server data and overwrite with local Zotero data.</description> + </vbox> + </row> + </rows> + </grid> + </radiogroup> + + <hbox> + <button id="zotero-reset-button" label="Reset..." oncommand="handleSyncReset(document.getElementById('zotero-reset').firstChild.selectedItem.parentNode.id.substr(7))"/> + </hbox> + </tabpanel> + </tabpanels> + </tabbox> </prefpane> diff --git a/chrome/content/zotero/xpcom/db.js b/chrome/content/zotero/xpcom/db.js @@ -658,11 +658,7 @@ Zotero.DBConnection.prototype.checkException = function (e) { if (e.name && e.name == 'NS_ERROR_FILE_CORRUPTED') { // Write corrupt marker to data directory var file = Zotero.getZoteroDatabase(this._dbName, 'is.corrupt'); - var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"] - .createInstance(Components.interfaces.nsIFileOutputStream); - foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate - foStream.write('', 0); - foStream.close(); + Zotero.File.putContents(file, ''); this._dbIsCorrupt = true; @@ -694,6 +690,12 @@ Zotero.DBConnection.prototype.checkException = function (e) { } +Zotero.DBConnection.prototype.closeDatabase = function () { + var db = this._getDBConnection(); + db.close(); +} + + Zotero.DBConnection.prototype.backupDatabase = function (suffix) { if (this.transactionInProgress()) { this._debug("Transaction in progress--skipping backup of DB '" + this._dbName + "'", 2); diff --git a/chrome/content/zotero/xpcom/schema.js b/chrome/content/zotero/xpcom/schema.js @@ -26,8 +26,8 @@ Zotero.Schema = new function(){ this.updateSchema = updateSchema; this.stopRepositoryTimer = stopRepositoryTimer; + this.skipDefaultData = false; this.dbInitialized = false; - this.upgradeFinished = false; this.goToChangeLog = false; var _dbVersions = []; @@ -685,30 +685,32 @@ Zotero.Schema = new function(){ _updateDBVersion('userdata', _getSchemaSQLVersion('userdata')); _updateDBVersion('triggers', _getSchemaSQLVersion('triggers')); - /* - TODO: uncomment for release - var sql = "INSERT INTO items VALUES(1, 14, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'AJ4PT6IT')"; - Zotero.DB.query(sql); - var sql = "INSERT INTO itemAttachments VALUES (1, NULL, 3, 'text/html', 25, NULL, NULL)"; - Zotero.DB.query(sql); - var sql = "INSERT INTO itemDataValues VALUES (?, ?)"; - Zotero.DB.query(sql, [1, "Zotero - " + Zotero.getString('install.quickStartGuide')]); - var sql = "INSERT INTO itemData VALUES (1, 110, 1)"; - Zotero.DB.query(sql); - var sql = "INSERT INTO itemDataValues VALUES (2, 'http://www.zotero.org/documentation/quick_start_guide')"; - Zotero.DB.query(sql); - var sql = "INSERT INTO itemData VALUES (1, 1, 2)"; - Zotero.DB.query(sql); - var sql = "INSERT INTO itemDataValues VALUES (3, CURRENT_TIMESTAMP)"; - Zotero.DB.query(sql); - var sql = "INSERT INTO itemData VALUES (1, 27, 3)"; - Zotero.DB.query(sql); - var sql = "INSERT INTO itemNotes (itemID, sourceItemID, note) VALUES (1, NULL, ?)"; - var msg = Zotero.getString('install.quickStartGuide.message.welcome') - + " " + Zotero.getString('install.quickStartGuide.message.clickViewPage') - + "\n\n" + Zotero.getString('install.quickStartGuide.message.thanks'); - Zotero.DB.query(sql, msg); - */ + if (!Zotero.Schema.skipDefaultData) { + /* + TODO: uncomment for release + var sql = "INSERT INTO items VALUES(1, 14, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'AJ4PT6IT')"; + Zotero.DB.query(sql); + var sql = "INSERT INTO itemAttachments VALUES (1, NULL, 3, 'text/html', 25, NULL, NULL)"; + Zotero.DB.query(sql); + var sql = "INSERT INTO itemDataValues VALUES (?, ?)"; + Zotero.DB.query(sql, [1, "Zotero - " + Zotero.getString('install.quickStartGuide')]); + var sql = "INSERT INTO itemData VALUES (1, 110, 1)"; + Zotero.DB.query(sql); + var sql = "INSERT INTO itemDataValues VALUES (2, 'http://www.zotero.org/documentation/quick_start_guide')"; + Zotero.DB.query(sql); + var sql = "INSERT INTO itemData VALUES (1, 1, 2)"; + Zotero.DB.query(sql); + var sql = "INSERT INTO itemDataValues VALUES (3, CURRENT_TIMESTAMP)"; + Zotero.DB.query(sql); + var sql = "INSERT INTO itemData VALUES (1, 27, 3)"; + Zotero.DB.query(sql); + var sql = "INSERT INTO itemNotes (itemID, sourceItemID, note) VALUES (1, NULL, ?)"; + var msg = Zotero.getString('install.quickStartGuide.message.welcome') + + " " + Zotero.getString('install.quickStartGuide.message.clickViewPage') + + "\n\n" + Zotero.getString('install.quickStartGuide.message.thanks'); + Zotero.DB.query(sql, msg); + */ + } Zotero.DB.commitTransaction(); self.dbInitialized = true; diff --git a/chrome/content/zotero/xpcom/sync.js b/chrome/content/zotero/xpcom/sync.js @@ -408,6 +408,7 @@ Zotero.Sync.Runner = new function () { if (_running) { throw ("Sync already running in Zotero.Sync.Runner.sync()"); } + _queue = [ Zotero.Sync.Server.sync, Zotero.Sync.Storage.sync, @@ -423,6 +424,12 @@ Zotero.Sync.Runner = new function () { this.next = function () { + if (!_running) { + var msg = "Sync not running in Zotero.Sync.Runner.next()"; + this.setError(msg); + throw (msg); + } + if (!_queue.length) { this.setSyncIcon(); _running = false; @@ -538,7 +545,6 @@ Zotero.Sync.Runner.EventListener = { } - /** * Methods for syncing with the Zotero Server */ @@ -666,7 +672,7 @@ Zotero.Sync.Server = new function () { var _sessionLock; - function login(callback) { + function login(callback, callbackCallback) { var url = _serverURL + "login"; var username = Zotero.Sync.Server.username; @@ -714,13 +720,13 @@ Zotero.Sync.Server = new function () { //Zotero.debug('Got session ID ' + _sessionID + ' from server'); if (callback) { - callback(); + callback(callbackCallback); } }); } - function sync() { + function sync(callback) { Zotero.Sync.Runner.setSyncIcon('animate'); if (_attempts < 0) { @@ -729,12 +735,12 @@ Zotero.Sync.Server = new function () { if (!_sessionID) { Zotero.debug("Session ID not available -- logging in"); - Zotero.Sync.Server.login(Zotero.Sync.Server.sync); + Zotero.Sync.Server.login(Zotero.Sync.Server.sync, callback); return; } if (!_sessionLock) { - Zotero.Sync.Server.lock(Zotero.Sync.Server.sync); + Zotero.Sync.Server.lock(Zotero.Sync.Server.sync, callback); return; } @@ -764,7 +770,7 @@ Zotero.Sync.Server = new function () { Zotero.debug("Invalid session ID -- logging in"); _sessionID = false; _syncInProgress = false; - Zotero.Sync.Server.login(Zotero.Sync.Server.sync); + Zotero.Sync.Server.login(Zotero.Sync.Server.sync, callback); return; } @@ -828,8 +834,14 @@ Zotero.Sync.Server = new function () { Zotero.debug("Sync cancelled"); Zotero.DB.rollbackTransaction(); Zotero.Sync.Server.unlock(function () { - Zotero.Sync.Runner.reset(); - Zotero.Sync.Runner.next(); + if (callback) { + Zotero.Sync.Runner.setSyncIcon(); + callback(); + } + else { + Zotero.Sync.Runner.reset(); + Zotero.Sync.Runner.next(); + } }); Zotero.reloadDataObjects(); _syncInProgress = false; @@ -849,7 +861,13 @@ Zotero.Sync.Server = new function () { Zotero.DB.commitTransaction(); Zotero.Sync.Server.unlock(function () { _syncInProgress = false; - Zotero.Sync.Runner.next(); + if (callback) { + Zotero.Sync.Runner.setSyncIcon(); + callback(); + } + else { + Zotero.Sync.Runner.next(); + } }); return; } @@ -890,7 +908,13 @@ Zotero.Sync.Server = new function () { Zotero.DB.commitTransaction(); Zotero.Sync.Server.unlock(function () { _syncInProgress = false; - Zotero.Sync.Runner.next(); + if (callback) { + Zotero.Sync.Runner.setSyncIcon(); + callback(); + } + else { + Zotero.Sync.Runner.next(); + } }); } @@ -975,7 +999,7 @@ Zotero.Sync.Server = new function () { } - function lock(callback) { + function lock(callback, callbackCallback) { Zotero.debug("Getting session lock"); if (_attempts < 0) { @@ -1019,7 +1043,7 @@ Zotero.Sync.Server = new function () { _sessionLock = true; if (callback) { - callback(); + callback(callbackCallback); } }); } @@ -1066,14 +1090,14 @@ Zotero.Sync.Server = new function () { } - function clear() { + function clear(callback) { if (_attempts < 0) { _error('Too many attempts in Zotero.Sync.Server.clear()'); } if (!_sessionID) { Zotero.debug("Session ID not available -- logging in"); - Zotero.Sync.Server.login(Zotero.Sync.Server.clear); + Zotero.Sync.Server.login(Zotero.Sync.Server.clear, callback); return; } @@ -1085,7 +1109,7 @@ Zotero.Sync.Server = new function () { if (_invalidSession(xmlhttp)) { Zotero.debug("Invalid session ID -- logging in"); _sessionID = false; - Zotero.Sync.Server.login(Zotero.Sync.Server.clear); + Zotero.Sync.Server.login(Zotero.Sync.Server.clear, callback); return; } @@ -1102,6 +1126,10 @@ Zotero.Sync.Server = new function () { } Zotero.Sync.Server.resetClient(); + + if (callback) { + callback(); + } }); _resetAttempts(); @@ -1111,14 +1139,14 @@ Zotero.Sync.Server = new function () { /** * Clear session lock on server */ - function resetServer() { + function resetServer(callback) { if (_attempts < 0) { _error('Too many attempts in Zotero.Sync.Server.resetServer()'); } if (!_sessionID) { Zotero.debug("Session ID not available -- logging in"); - Zotero.Sync.Server.login(Zotero.Sync.Server.resetServer); + Zotero.Sync.Server.login(Zotero.Sync.Server.resetServer, callback); return; } @@ -1130,7 +1158,7 @@ Zotero.Sync.Server = new function () { if (_invalidSession(xmlhttp)) { Zotero.debug("Invalid session ID -- logging in"); _sessionID = false; - Zotero.Sync.Server.login(Zotero.Sync.Server.reset); + Zotero.Sync.Server.login(Zotero.Sync.Server.reset, callback); return; } @@ -1149,6 +1177,10 @@ Zotero.Sync.Server = new function () { } _syncInProgress = false; + + if (callback) { + callback(); + } }); _resetAttempts(); diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js @@ -26,6 +26,7 @@ const ZOTERO_CONFIG = { REPOSITORY_URL: 'http://www.zotero.org/repo', REPOSITORY_CHECK_INTERVAL: 86400, // 24 hours REPOSITORY_RETRY_INTERVAL: 3600, // 1 hour + FIRST_RUN_URL: 'http://www.zotero.org/support/quick_start_guide', SYNC_URL: 'https://sync.zotero.org/' }; @@ -173,7 +174,7 @@ var Zotero = new function(){ } try { - this.getZoteroDirectory(); + var dataDir = this.getZoteroDirectory(); } catch (e) { // Zotero dir not found @@ -218,8 +219,32 @@ var Zotero = new function(){ Zotero.VersionHeader.init(); - // Initialize keyboard shortcuts - Zotero.Keys.init(); + // Check for DB restore + var restoreFile = dataDir.clone(); + restoreFile.append('restore-from-server'); + if (restoreFile.exists()) { + try { + // TODO: better error handling + + // TODO: prompt for location + // TODO: Back up database + + restoreFile.remove(false); + + var dbfile = Zotero.getZoteroDatabase(); + dbfile.remove(false); + + // Recreate database with no quick start guide + Zotero.Schema.skipDefaultData = true; + Zotero.Schema.updateSchema(); + + this.restoreFromServer = true; + } + catch (e) { + // Restore from backup? + alert(e); + } + } try { Zotero.DB.test(); @@ -280,6 +305,9 @@ var Zotero = new function(){ Zotero.MIMETypeHandler.init(); Zotero.Proxies.init(); + // Initialize keyboard shortcuts + Zotero.Keys.init(); + this.initialized = true; Zotero.debug("Initialized in "+((new Date()).getTime() - start)+" ms"); diff --git a/chrome/skin/default/zotero/preferences.css b/chrome/skin/default/zotero/preferences.css @@ -72,6 +72,8 @@ grid row hbox:first-child /* * Sync pane */ + +/* Settings tab */ #zotero-prefpane-sync row, #zotero-prefpane-sync row hbox { -moz-box-align: center; @@ -113,6 +115,50 @@ grid row hbox:first-child min-width: 8em; } +/* Reset tab */ +#zotero-reset row +{ + margin: 0; + padding: 15px; +} + +#zotero-reset row:not(:last-child) +{ + border-bottom: 1px #999 solid; +} + +#zotero-reset row vbox +{ + -moz-box-align: start; +} + +#zotero-reset row[selected="true"] +{ +} + + +#zotero-reset row vbox label +{ + margin-left: 3px; + font-weight: bold; + font-size: 14px; +} + +#zotero-reset description +{ + margin-left: 3px; + margin-top: 1px; + font-size: 12px; +} + +/* Reset button */ +#zotero-reset > hbox +{ + margin-top: 5px; + -moz-box-pack: center; +} + + /* * Search pane