commit 9f38337ec7b92aab67db4f053c07109e3282a7b3
Author: Dan Stillman <dstillman@zotero.org>
Date: Tue, 21 Feb 2006 17:01:06 +0000
Initial import of repository structure, basic extension layout, and functions for DB abstraction and schema maintenance
Diffstat:
10 files changed, 452 insertions(+), 0 deletions(-)
diff --git a/chrome.manifest b/chrome.manifest
@@ -0,0 +1,6 @@
+content scholar chrome/chromeFiles/content/scholar/
+locale scholar en-US chrome/chromeFiles/locale/en-US/scholar/
+skin scholar default chrome/chromeFiles/skin/default/scholar/
+
+overlay chrome://browser/content/browser.xul chrome://scholar/content/scholar.xul
+style chrome://browser/content/browser.xul chrome://scholar/skin/scholar.css
diff --git a/chrome/chromeFiles/content/scholar/db.js b/chrome/chromeFiles/content/scholar/db.js
@@ -0,0 +1,257 @@
+var scholarDB = new Scholar_DB();
+
+/*
+ * DB connection and schema management class
+ */
+function Scholar_DB(){
+ // Private members
+ var _connection;
+
+ // Privileged methods
+ this.query = query;
+ this.valueQuery = valueQuery;
+ this.rowQuery = rowQuery;
+ this.statementQuery = statementQuery;
+ this.updateSchema = updateSchema;
+
+
+ /////////////////////////////////////////////////////////////////
+ //
+ // Privileged methods
+ //
+ /////////////////////////////////////////////////////////////////
+
+ /*
+ * Run an SQL query
+ *
+ * Returns:
+ * - mozIStorageStatementWrapper for SELECT's
+ * - lastInsertId for INSERT's
+ * - TRUE for other successful queries
+ * - FALSE on error
+ */
+ function query(sql){
+ var db = _getDBConnection();
+
+ try {
+ // Parse out the SQL command being used
+ var op = sql.match(/^[^a-z]*[^ ]+/i).toString().toLowerCase();
+
+ // If SELECT statement, return result
+ if (op=='select'){
+ var wrapper =
+ Components.classes['@mozilla.org/storage/statement-wrapper;1']
+ .createInstance(Components.interfaces.mozIStorageStatementWrapper);
+
+ wrapper.initialize(db.createStatement(sql));
+ return wrapper;
+ }
+ else {
+ db.executeSimpleSQL(sql);
+
+ if (op=='insert'){
+ return db.lastInsertId;
+ }
+ // DEBUG: Can't get affected rows for UPDATE or DELETE?
+ else {
+ return true;
+ }
+ }
+ }
+ catch(ex){
+ alert(db.lastErrorString);
+ return false;
+ }
+ }
+
+
+ /*
+ * Query a single value and return it
+ */
+ function valueQuery(sql){
+ var db = _getDBConnection();
+ try {
+ var statement = db.createStatement(sql);
+ }
+ catch (e){
+ alert(db.lastErrorString);
+ return false;
+ }
+
+ // No rows
+ if (!statement.executeStep()){
+ return false;
+ }
+ var value = statement.getAsUTF8String(0);
+ statement.reset();
+ return value;
+ }
+
+
+ /*
+ * Run a query and return the first row
+ */
+ function rowQuery(sql){
+ var result = query(sql);
+ if (result && result.step()){
+ return result.row;
+ }
+ }
+
+
+ /*
+ * Run a query, returning a mozIStorageStatement for direct manipulation
+ */
+ function statementQuery(sql){
+ var db = _getDBConnection();
+
+ try {
+ return db.createStatement(sql);
+ }
+ catch (e){
+ return false;
+ }
+ }
+
+
+ /*
+ * Checks if the DB schema exists and is up-to-date, updating if necessary
+ */
+ function updateSchema(){
+ var DBVersion = _getDBVersion();
+
+ if (DBVersion > SCHOLAR_CONFIG['DB_VERSION']){
+ throw("Scholar DB version is newer than config version");
+ }
+ else if (DBVersion < SCHOLAR_CONFIG['DB_VERSION']){
+ if (!DBVersion){
+ dump('Database does not exist -- creating\n');
+ return _initializeSchema();
+ }
+
+ return _migrateSchema(DBVersion);
+ }
+ }
+
+
+
+ /////////////////////////////////////////////////////////////////
+ //
+ // Private methods
+ //
+ /////////////////////////////////////////////////////////////////
+
+ /*
+ * Retrieve a link to the data store
+ */
+ function _getDBConnection(){
+ if (_connection){
+ return _connection;
+ }
+
+ // Get the storage service
+ var store = Components.classes["@mozilla.org/storage/service;1"].
+ getService(Components.interfaces.mozIStorageService);
+
+ // Get the profile directory
+ var file = Components.classes["@mozilla.org/file/directory_service;1"]
+ .getService(Components.interfaces.nsIProperties)
+ .get("ProfD", Components.interfaces.nsILocalFile);
+
+ // This makes file point to PROFILE_DIR/<scholar database file>
+ file.append(SCHOLAR_CONFIG['DB_FILE']);
+
+ _connection = store.openDatabase(file);
+
+ return _connection;
+ }
+
+
+ /*
+ * Retrieve the DB schema version
+ */
+ function _getDBVersion(){
+ if (_getDBConnection().tableExists('version')){
+ return valueQuery("SELECT version FROM version;");
+ }
+ return false;
+ }
+
+
+ /*
+ * Load in SQL schema
+ */
+ function _getSchemaSQL(){
+ // We pull the schema from an external file so we only have to process
+ // it when necessary
+ var req = new XMLHttpRequest();
+ req.open("GET", "chrome://scholar/content/schema.xml", false);
+ req.send(null);
+
+ var schemaVersion =
+ req.responseXML.documentElement.getAttribute('version');
+
+ if (schemaVersion!=SCHOLAR_CONFIG['DB_VERSION']){
+ throw("Scholar config version does not match schema version");
+ }
+
+ return req.responseXML.documentElement.firstChild.data;
+ }
+
+
+ /*
+ * Retrieve the version attribute of the schema SQL XML
+ */
+ function _getSchemaSQLVersion(){
+ var req = new XMLHttpRequest();
+ req.open("GET", "chrome://scholar/content/schema.xml", false);
+ req.send(null);
+ return req.responseXML.documentElement.getAttribute('version');
+ }
+
+
+ /*
+ * Create new DB schema
+ */
+ function _initializeSchema(){
+ query(_getSchemaSQL());
+ query("INSERT INTO version VALUES (" + SCHOLAR_CONFIG['DB_VERSION'] + ")");
+ }
+
+
+ /*
+ * Migrate schema from an older version, preserving data
+ */
+ function _migrateSchema(fromVersion){
+ var toVersion = SCHOLAR_CONFIG['DB_VERSION'];
+ var schemaVersion = _getSchemaSQLVersion();
+
+ if (toVersion!=schemaVersion){
+ throw("Scholar config version does not match schema version");
+ }
+
+ dump('Updating DB from version ' + fromVersion + ' to ' + toVersion + '\n');
+
+ // Step through version changes until we reach the current version
+ //
+ // Each block performs the changes necessary to move from the
+ // previous revision to that one.
+ //
+ // N.B. Be sure to call _updateDBVersion(i) at the end of each block!
+ for (var i=fromVersion+1; i<=toVersion; i++){
+
+ if (i==1){
+ // do stuff
+ // _updateDBVersion(i);
+ }
+ }
+ }
+
+
+ /*
+ * Update the DB schema version tag of an existing database
+ */
+ function _updateDBVersion(version){
+ return query("UPDATE version SET version=" + version);
+ }
+}
diff --git a/chrome/chromeFiles/content/scholar/schema.xml b/chrome/chromeFiles/content/scholar/schema.xml
@@ -0,0 +1,85 @@
+<schema version="1">
+BEGIN;
+ CREATE TABLE version (
+ version INT PRIMARY KEY
+ );
+
+ CREATE TABLE objects (
+ objectID INT PRIMARY KEY,
+ objectTypeID INT,
+ objectTitle TEXT,
+ objectDate DATETIME,
+ objectDateAdded DATETIME DEFAULT CURRENT_TIMESTAMP,
+ objectDateModified DATETIME DEFAULT CURRENT_TIMESTAMP,
+ objectSource TEXT,
+ objectRights TEXT,
+ parentID INT,
+ orderIndex INT
+ );
+ CREATE INDEX parentID ON objects (parentID);
+
+ CREATE TABLE objectTypes (
+ objectTypeID INT PRIMARY KEY,
+ typeName TEXT
+ );
+
+ CREATE TABLE fields (
+ fieldID INT PRIMARY KEY,
+ fieldName TEXT,
+ regex TEXT
+ );
+
+ CREATE TABLE objectTypeFields (
+ objectTypeID,
+ fieldID INT,
+ orderIndex INT,
+ PRIMARY KEY (objectTypeID, fieldID),
+ FOREIGN KEY (objectTypeID) REFERENCES objectTypes(objectTypeID),
+ FOREIGN KEY (fieldID) REFERENCES objectTypes(objectTypeID)
+ );
+
+ CREATE TABLE objectData (
+ objectID INT,
+ fieldID INT,
+ value NONE,
+ PRIMARY KEY (objectID, fieldID),
+ FOREIGN KEY (objectID) REFERENCES objects(objectID),
+ FOREIGN KEY (fieldID) REFERENCES fields(fieldID)
+ );
+ CREATE INDEX value ON objectData (value);
+
+ CREATE TABLE keywords (
+ keywordID INT PRIMARY KEY,
+ keyword TEXT
+ );
+
+ CREATE TABLE objectKeywords (
+ objectID INT,
+ keywordID INT,
+ PRIMARY KEY (objectID, keywordID),
+ FOREIGN KEY (objectID) REFERENCES objects(objectID),
+ FOREIGN KEY (keywordID) REFERENCES keywords(keywordID)
+ );
+
+ CREATE TABLE creators (
+ creatorID INT PRIMARY KEY,
+ firstName TEXT,
+ lastName TEXT
+ );
+
+ CREATE TABLE creatorTypes (
+ creatorTypeID INT PRIMARY KEY,
+ creatorType TEXT
+ );
+
+ CREATE TABLE objectCreators (
+ objectID INT,
+ creatorID INT,
+ creatorTypeID INT,
+ orderIndex INT,
+ PRIMARY KEY (objectID, creatorID),
+ FOREIGN KEY (objectID) REFERENCES objects(objectID),
+ FOREIGN KEY (creatorID) REFERENCES creators(creatorID)
+ );
+COMMIT;
+</schema>
diff --git a/chrome/chromeFiles/content/scholar/scholar.js b/chrome/chromeFiles/content/scholar/scholar.js
@@ -0,0 +1,53 @@
+const SCHOLAR_CONFIG = {
+ DB_FILE : 'scholar.sdb',
+ DB_VERSION : 1,
+ DEBUG_LOGGING : true
+};
+
+/*
+ * Core functions
+ */
+var Scholar = {
+ /*
+ * Initialize the extension
+ */
+ init: function() {
+ scholarDB.updateSchema();
+ },
+
+ /*
+ * Debug logging function
+ *
+ * Uses DebugLogger extension available from http://mozmonkey.com/debuglogger/
+ * if available, otherwise the console
+ *
+ * Defaults to log level 3 if level not provided
+ */
+ debug: function(message, level) {
+ if (!SCHOLAR_CONFIG['DEBUG_LOGGING']){
+ return false;
+ }
+
+ if (!level){
+ level = 3;
+ }
+
+ try {
+ var logManager =
+ Components.classes["@mozmonkey.com/debuglogger/manager;1"]
+ .getService(Components.interfaces.nsIDebugLoggerManager);
+ var logger = logManager.registerLogger("Firefox Scholar");
+ }
+ catch (e){}
+
+ if (logger){
+ logger.log(level, message);
+ }
+ else {
+ dump('scholar(' + level + '): ' + message);
+ }
+ return true;
+ }
+}
+
+window.addEventListener("load", function(e) { Scholar.init(e); }, false);
diff --git a/chrome/chromeFiles/content/scholar/scholar.xul b/chrome/chromeFiles/content/scholar/scholar.xul
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://scholar/skin/scholar.css" type="text/css"?>
+<!DOCTYPE window SYSTEM "chrome://scholar/locale/scholar.dtd">
+
+<overlay id="scholar"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="scholar.js"/>
+ <script src="db.js"/>
+
+ <statusbar id="status-bar">
+ <statusbarpanel id="my-panel" label="&statusbarpanel.helloworld;"/>
+ </statusbar>
+</overlay>
diff --git a/chrome/chromeFiles/content/scholar/test/test.js b/chrome/chromeFiles/content/scholar/test/test.js
@@ -0,0 +1 @@
+alert("Hello, world!");
diff --git a/chrome/chromeFiles/content/scholar/test/test.xul b/chrome/chromeFiles/content/scholar/test/test.xul
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://scholar/skin/scholar.css" type="text/css"?>
+<!DOCTYPE window SYSTEM "chrome://scholar/locale/scholar.dtd">
+
+<window
+ id="test-window"
+ title="Test"
+ orient="horizontal"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ style="padding:2em">
+
+ <script src="../scholar.js"/>
+ <script src="../db.js"/>
+
+ <script src="test.js"/>
+
+ <label>I am a test page.</label>
+</window>
diff --git a/chrome/chromeFiles/locale/en-US/scholar/scholar.dtd b/chrome/chromeFiles/locale/en-US/scholar/scholar.dtd
@@ -0,0 +1 @@
+<!ENTITY statusbarpanel.helloworld "Hello, World">
diff --git a/chrome/chromeFiles/skin/default/scholar/scholar.css b/chrome/chromeFiles/skin/default/scholar/scholar.css
diff --git a/install.rdf b/install.rdf
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<RDF:RDF xmlns:em="http://www.mozilla.org/2004/em-rdf#"
+ xmlns:NC="http://home.netscape.com/NC-rdf#"
+ xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <RDF:Description RDF:about="rdf:#$V4RG2"
+ em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
+ em:minVersion="1.0+"
+ em:maxVersion="1.5.0.*" />
+ <RDF:Description RDF:about="urn:mozilla:install-manifest"
+ em:id="scholar@chnm"
+ em:name="Firefox Scholar"
+ em:version="1.0"
+ em:creator="Center for History and New Media, George Mason University"
+ em:homepageURL="http://chnm.gmu.edu">
+ <em:targetApplication RDF:resource="rdf:#$V4RG2"/>
+ </RDF:Description>
+</RDF:RDF>