Initial import of repository structure, basic extension layout, and functions for DB abstraction and schema maintenance
This commit is contained in:
commit
9f38337ec7
10 changed files with 452 additions and 0 deletions
6
chrome.manifest
Normal file
6
chrome.manifest
Normal file
|
@ -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
|
257
chrome/chromeFiles/content/scholar/db.js
Normal file
257
chrome/chromeFiles/content/scholar/db.js
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
85
chrome/chromeFiles/content/scholar/schema.xml
Normal file
85
chrome/chromeFiles/content/scholar/schema.xml
Normal file
|
@ -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>
|
53
chrome/chromeFiles/content/scholar/scholar.js
Normal file
53
chrome/chromeFiles/content/scholar/scholar.js
Normal file
|
@ -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);
|
14
chrome/chromeFiles/content/scholar/scholar.xul
Normal file
14
chrome/chromeFiles/content/scholar/scholar.xul
Normal file
|
@ -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>
|
1
chrome/chromeFiles/content/scholar/test/test.js
Normal file
1
chrome/chromeFiles/content/scholar/test/test.js
Normal file
|
@ -0,0 +1 @@
|
|||
alert("Hello, world!");
|
18
chrome/chromeFiles/content/scholar/test/test.xul
Normal file
18
chrome/chromeFiles/content/scholar/test/test.xul
Normal file
|
@ -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>
|
1
chrome/chromeFiles/locale/en-US/scholar/scholar.dtd
Normal file
1
chrome/chromeFiles/locale/en-US/scholar/scholar.dtd
Normal file
|
@ -0,0 +1 @@
|
|||
<!ENTITY statusbarpanel.helloworld "Hello, World">
|
0
chrome/chromeFiles/skin/default/scholar/scholar.css
Normal file
0
chrome/chromeFiles/skin/default/scholar/scholar.css
Normal file
17
install.rdf
Normal file
17
install.rdf
Normal file
|
@ -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>
|
Loading…
Add table
Reference in a new issue