const SCHOLAR_CONFIG = { GUID: 'zotero@chnm.gmu.edu', DB_FILE: 'zotero.sqlite', DB_REBUILD: false, // erase DB and recreate from schema DEBUG_LOGGING: true, DEBUG_TO_CONSOLE: true, // dump debug messages to console rather than (much slower) Debug Logger REPOSITORY_URL: 'http://chnm.gmu.edu/firefoxscholar/repo', REPOSITORY_CHECK_INTERVAL: 86400, // 24 hours REPOSITORY_RETRY_INTERVAL: 3600 // 1 hour }; /* * Core functions */ var Scholar = new function(){ var _initialized = false; var _shutdown = false; var _localizedStringBundle; // Privileged (public) methods this.init = init; this.shutdown = shutdown; this.getProfileDirectory = getProfileDirectory; this.getScholarDirectory = getScholarDirectory; this.getStorageDirectory = getStorageDirectory; this.getScholarDatabase = getScholarDatabase; this.backupDatabase = backupDatabase; this.debug = debug; this.varDump = varDump; this.getString = getString; this.flattenArguments = flattenArguments; this.join = join; this.inArray = inArray; this.arraySearch = arraySearch; this.randomString = randomString; this.getRandomID = getRandomID; this.moveToUnique = moveToUnique; // Public properties this.version; this.platform; this.isMac; /* * Initialize the extension */ function init(){ if (_initialized){ return false; } // Register shutdown handler to call Scholar.shutdown() var observerService = Components.classes["@mozilla.org/observer-service;1"] .getService(Components.interfaces.nsIObserverService); observerService.addObserver({ observe: function(subject, topic, data){ Scholar.shutdown(subject, topic, data) } }, "xpcom-shutdown", false); // Load in the preferences branch for the extension Scholar.Prefs.init(); // Load in the extension version from the extension manager var nsIUpdateItem = Components.interfaces.nsIUpdateItem; var gExtensionManager = Components.classes["@mozilla.org/extensions/manager;1"] .getService(Components.interfaces.nsIExtensionManager); var itemType = nsIUpdateItem.TYPE_EXTENSION; this.version = gExtensionManager.getItemForID(SCHOLAR_CONFIG['GUID']).version; // 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"); // Load in the localization stringbundle for use by getString(name) var src = 'chrome://scholar/locale/scholar.properties'; var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"] .getService(Components.interfaces.nsILocaleService); var appLocale = localeService.getApplicationLocale(); var stringBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"] .getService(Components.interfaces.nsIStringBundleService); _localizedStringBundle = stringBundleService.createBundle(src, appLocale); // Trigger updating of schema and scrapers Scholar.Schema.updateSchema(); Scholar.Schema.updateScrapersRemote(); // Initialize integration web server Scholar.Integration.SOAP.init(); Scholar.Integration.init(); _initialized = true; return true; } function shutdown(subject, topic, data){ // Called twice otherwise, for some reason if (_shutdown){ return false; } _shutdown = true; Scholar.backupDatabase(); return true; } function getProfileDirectory(){ return Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties) .get("ProfD", Components.interfaces.nsIFile); } function getScholarDirectory(){ var file = Scholar.getProfileDirectory(); file.append('zotero'); // If it doesn't exist, create if (!file.exists() || !file.isDirectory()){ file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0755); } return file; } function getStorageDirectory(){ var file = Scholar.getScholarDirectory(); file.append('storage'); // If it doesn't exist, create if (!file.exists() || !file.isDirectory()){ file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0755); } return file; } function getScholarDatabase(ext){ ext = ext ? '.' + ext : ''; var file = Scholar.getScholarDirectory(); file.append(SCHOLAR_CONFIG['DB_FILE'] + ext); return file; } /* * Back up the main database file * * This could probably create a corrupt file fairly easily if all changes * haven't been flushed to disk -- proceed with caution */ function backupDatabase(){ if (Scholar.DB.transactionInProgress()){ Scholar.debug('Transaction in progress--skipping DB backup', 2); return false; } Scholar.debug('Backing up database'); var file = Scholar.getScholarDatabase(); var backupFile = Scholar.getScholarDatabase('bak'); // Copy via a temporary file so we don't run into disk space issues // after deleting the old backup file var tmpFile = Scholar.getScholarDatabase('tmp'); if (tmpFile.exists()){ tmpFile.remove(null); } try { file.copyTo(file.parent, tmpFile.leafName); } catch (e){ // TODO: deal with low disk space throw (e); } // Remove old backup file if (backupFile.exists()){ backupFile.remove(null); } tmpFile.moveTo(tmpFile.parent, backupFile.leafName); return true; } /* * Debug logging function * * Uses DebugLogger extension available from http://mozmonkey.com/debuglogger/ * if available, otherwise the console (in which case boolean browser.dom.window.dump.enabled * must be created and set to true in about:config) * * Defaults to log level 3 if level not provided */ function debug(message, level) { if (!SCHOLAR_CONFIG['DEBUG_LOGGING']){ return false; } if (typeof message!='string'){ message = Scholar.varDump(message); } if (!level){ level = 3; } if (!SCHOLAR_CONFIG['DEBUG_TO_CONSOLE']){ try { var logManager = Components.classes["@mozmonkey.com/debuglogger/manager;1"] .getService(Components.interfaces.nsIDebugLoggerManager); var logger = logManager.registerLogger("Zotero"); } catch (e){} } if (logger){ logger.log(level, message); } else { dump('zotero(' + level + '): ' + message + "\n\n"); } return true; } /** * PHP var_dump equivalent for JS * * Adapted from http://binnyva.blogspot.com/2005/10/dump-function-javascript-equivalent-of.html */ function varDump(arr,level) { var dumped_text = ""; if (!level){ level = 0; } // The padding given at the beginning of the line. var level_padding = ""; for (var j=0;j function(...){...} \n"; } else { dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n"; } } } } else { // Stings/Chars/Numbers etc. dumped_text = "===>"+arr+"<===("+typeof(arr)+")"; } return dumped_text; } function getString(name){ try { var l10n = _localizedStringBundle.GetStringFromName(name); } catch (e){ throw ('Localized string not available for ' + name); } return l10n; } /* * Flattens mixed arrays/values in a passed _arguments_ object and returns * an array of values -- allows for functions to accept both arrays of * values and/or an arbitrary number of individual values */ function flattenArguments(args){ // Put passed scalar values into an array if (typeof args!='object'){ args = [args]; } var returns = new Array(); for (var i=0; i