diff --git a/js/common.js b/js/common.js
index edbcff19..ecff5c07 100644
--- a/js/common.js
+++ b/js/common.js
@@ -1,5 +1,5 @@
-define(['jquery', 'reference', 'jquery.ui'],
- function($, reference) {
+define(['jquery', 'reference', 'tagging', 'jquery.ui'],
+ function($, reference, tagging) {
function SortNumeric(x, y) {
return x - y;
}
@@ -296,6 +296,7 @@ define(['jquery', 'reference', 'jquery.ui'],
r += "
";
}
}
+ // TODO(jwall): hover should show tags for the verse.
var t = $("
" + "" + r + " ");
t.find(".hiddenlink").click(function(e) {
@@ -304,6 +305,29 @@ define(['jquery', 'reference', 'jquery.ui'],
t.find(".removeresult").click(function(e) {
Util.RemoveResult(e);
});
+ // TODO(jwall): support longtouch events on mobile.
+ t.find(".resultbody h2").tooltip({
+ items: ".resultbody h2",
+ content: function(tt) {
+ tagging.GetTags(
+ ref.toString(), {
+ success: function(data) {
+ var tags = data ?
+ (data.data ?
+ data.data.tagList : null) : null;
+ var hoverContent =
+ $("Tags:
");
+ hoverContent.append(
+ tags ? tags.join(", ") : "N/A");
+ tt(hoverContent);
+ }});
+ }
+ });
+ t.find(".hiddenlink").tooltip(
+ {
+ items: ".hiddenlink"
+ }
+ );
$("#result").prepend(t);
}
catch (err) {
diff --git a/js/db.js b/js/db.js
index 4a1e314c..209af1fd 100644
--- a/js/db.js
+++ b/js/db.js
@@ -2,15 +2,12 @@
// See http://www.w3.org/TR/IndexedDB/ for more details about the
// IDB* interfaces referenced below.
define(
-'db', {
- // Construct db wrapper.
- // If debug is true then logging will be turned on.
- Init: function(debug) {
- var self = {
+'db', function() {
+ return {
version: 1,
- dbName: "localdata",
- stores: ['settings', 'verselists'],
- debug: false,
+ dbName: "dynamic_bible_db",
+ stores: ['tags'],
+ debug: true,
// Internal method not for external use.
handleError: function(e) {
this.debug && console.log("Error: ", e);
@@ -19,21 +16,25 @@ define(
handleUpdate: function(e) {
var db = e.target.result;
e.target.transaction.onerror = this.handleError;
+ this.debug && console.log("Updating database", this.dbName);
for (i in this.stores) {
- if (db.objectStoreNames.contains(this.stores[i])) {
- // TODO(jwall): handle this more gracefully?
- db.deleteObjectStore(this.stores[i]);
+ if (!db.objectStoreNames.contains(this.stores[i])) {
+ this.debug && console.log("Creating objectStore", this.stores[i]);
+ db.createObjectStore(this.stores[i], {keyPath: "key"});
}
- var store = db.createObjectStore(this.stores[i],
- {keyPath: "key"});
}
},
- // Do operations on an open database.
+ // Turn on debug logging.
+ SetDebug: function() {
+ this.debug = self;
+ },
+ // Session does operations on an open database.
// ops is expected to be a function taking an IDBDatabase object
// as a parameter.
Session: function(ops) {
var self = this;
- var req = indexedDB.open(this.dbname, this.version);
+ self.debug && console.log('Opening session for ', this.dbName, this.version);
+ var req = indexedDB.open(this.dbName, this.version);
// HandleUpgrades
req.onupgradeneeded = function(e) {
self.handleUpdate(e);
@@ -42,7 +43,8 @@ define(
ops(e.target.result);
};
},
- // Do operations on an open transaction scoped to the list of stores.
+ // Transaction does operations on an open transaction scoped to
+ // the list of stores.
// ops is expected to be a function taking an IDBTransation object
// as a parameter.
// type is an optional transaction type. values should be one of the
@@ -61,72 +63,92 @@ define(
});
},
// Get a key from the the object store.
- // success is expected to be a function taking an IDBRequest object
- // as a parameter.
- // error is optional and expected to be a function taking an IDBRequest
- // object as a parameter.
- Get: function(storeName, key, success, error) {
+ // callbacks is a dict with two fields.
+ // callbacks.success is expected to be a function taking an
+ // IDBRequest object as a parameter.
+ // callbacks.error is optional and expected to be a function
+ // taking an IDBRequest object as a parameter.
+ // trans is optional and is expected to be a a function taking
+ // an IDBTransaction object. If none is provided
+ // one will be started for you.
+ Get: function(storeName, key, callbacks, trans) {
var self = this;
- self.Transaction(
- [storeName], function(trans) {
- var store = trans.objectStore(storeName);
- var req = store.get(key);
- req.onsuccess = success;
- req.onerror = error || self.handleError;
- });
+ var op = function(trans) {
+ var store = trans.objectStore(storeName);
+ var req = store.get(key);
+ req.onsuccess = callbacks.success;
+ req.onerror = callbacks.error || self.handleError;
+ };
+ if (trans) {
+ ops(trans);
+ } else {
+ self.Transaction([storeName], op);
+ }
},
// Store or update a key with data in an object store.
- // success is expected to be a function taking an IDBRequest object
- // as a parameter.
- // error is optional and expected to be a function taking an IDBRequest
- // object as a parameter.
- Update: function(storeName, key, data, success, error) {
+ // callbacks is a dict with up to two fields.
+ // success is expected to be a function taking an IDBRequest
+ // object as a parameter.
+ // error is also optional and expected to be a function taking an
+ // IDBRequest object as a parameter.
+ // The trans argument is optional and is expected to be a a
+ // function taking an IDBTransaction object. If none is provided
+ // one will be started for you.
+ Update: function(storeName, key, data, callbacks, trans) {
var self = this;
- self.Transaction(
- [storeName], function(trans) {
- var store = trans.objectStore(storeName);
- var req = store.put({"key": key, "data": data});
- req.onsuccess = success;
- req.onerror = error || self.handleError;
- }, "readwrite");
+ var op = function(trans) {
+ var store = trans.objectStore(storeName);
+ var req = store.put(
+ {"key": key, "data": data, ts: new Date().getTime()});
+ req.onsuccess = callbacks.success;
+ req.onerror = callbacks.error || self.handleError;
+ };
+ if (trans) {
+ op(trans);
+ } else {
+ self.Transaction(
+ [storeName], op, "readwrite");
+ }
},
// Delete a key from an object store.
- // success is expected to be a function taking an IDBRequest object
- // as a parameter.
- // error is optional and expected to be a function taking an IDBRequest
- // object as a parameter.
- Delete: function(storeName, key, success, error) {
+ // callbacks is a dict with up to two fields.
+ // callbacks.success is expected to be a function taking an
+ // IDBRequest object as a parameter.
+ // callbacks.error is optional and expected to be a function
+ // taking an IDBRequest object as a parameter.
+ Delete: function(storeName, key, callbacks) {
var self = this;
self.Transaction(
[storeName], function(trans) {
var store = trans.objectStore(storeName);
var req = store.delete(key);
- req.onsuccess = success;
- req.onerror = error || self.handleError;
+ req.onsuccess = callbacks.success;
+ req.onerror = callbacks.error || self.handleError;
}, "readwrite");
},
// Query a range of values from an object store.
// range is expected to be an IDBKeyRange.
- // success is expected to be a function taking an IDBRequest object
- // as a parameter.
- // error is optional and expected to be a function taking an IDBRequest
- // object as a parameter.
- Query: function(storeName, range, success, error) {
+ // callbacks is a dict with up to two fields.
+ // callbacks.success is expected to be a function taking an
+ // IDBRequest object as a parameter.
+ // callbacks.error is optional and expected to be a function
+ // taking an IDBRequest object as a parameter.
+ // The trans argument is optional and is expected to be a a
+ // function taking an IDBTransaction object. If none is provided
+ // one will be started for you.
+ Query: function(storeName, range, callbacks, trans) {
var self = this;
- self.Transaction(
- [storeName], function(trans) {
- var store = trans.objectStore(storeName);
- var req = store.openCursor(range);
- req.onsuccess = success;
- req.onerror = error || self.handleError;
- });
+ var op = function(trans) {
+ var store = trans.objectStore(storeName);
+ var req = store.openCursor(range);
+ req.onsuccess = callbacks.success;
+ req.onerror = callbacks.error || self.handleError;
+ };
+ if (trans) {
+ op(trans);
+ } else {
+ self.Transaction([storeName], op);
+ }
}
};
- self.debug = debug;
- self.Session(
- function(e) {
- self.debug && console.log("Database Init complete");
- });
- return self;
- }
});
diff --git a/js/main.js b/js/main.js
index 0a73e9c1..1489fea8 100644
--- a/js/main.js
+++ b/js/main.js
@@ -1,5 +1,5 @@
-require(["jquery", "db", "common", "reference", "jquery.cookie", "jquery.ui"],
- function($, db, common, ref) {
+require(["jquery", "db", "common", "jquery.cookie", "jquery.ui"],
+ function($, db, common) {
$(document).ready(function()
{
$("#searchform").submit(function()
@@ -66,4 +66,4 @@ require(["jquery", "db", "common", "reference", "jquery.cookie", "jquery.ui"],
});
});
-
\ No newline at end of file
+
diff --git a/js/reference.js b/js/reference.js
index 9be9742c..17aa94ff 100644
--- a/js/reference.js
+++ b/js/reference.js
@@ -658,6 +658,16 @@ define("reference",
return ref.concat("-").concat(this.endchapter)
.concat(":").concat(this.endverse);
};
+ Reference.prototype.toDict = function() {
+ return {
+ startBook: this.bookname,
+ startChapter: this.startchapter,
+ startVerse: this.startverse,
+ endBook: this.bookname,
+ endChapter: this.startchapter,
+ endVerse: this.endverse
+ };
+ };
return {
Parse: function(ref) {return new Reference(ref);},
bookName: bookName
diff --git a/js/tagging.js b/js/tagging.js
new file mode 100644
index 00000000..518bdd92
--- /dev/null
+++ b/js/tagging.js
@@ -0,0 +1,50 @@
+(function() {
+var tagStore = 'tags';
+define(
+['db', 'reference'], function(db, reference) {
+ return {
+ // UpdateTags updates a given references tags asynchronously.
+ // ref should be a Reference object.
+ // tags should be a list of strings representing the tags for this
+ // reference.
+ // callbacks.success is expected to be a function that takes
+ // an IDBRequest as an argument.
+ // callbacks.error is expected to be a function that takes
+ // an IDBRequest as an argument.
+ UpdateTags: function(ref, tags, callbacks) {
+ db.Transaction(
+ [tagStore], function(trans) {
+ db.Update(
+ 'tags', ref.toString(),
+ {tagList: tags, Ref: ref.toDict()},
+ callbacks, trans);
+ }, 'readwrite');
+ },
+ // GetTags retrieves a given references tags asynchronously.
+ // ref should be a Reference object.
+ // callbacks.success is expected to be a function that takes
+ // the list of tags as an argument.
+ // callbacks.error is expected to be a function that takes
+ // an IDBRequest as an argument.
+ GetTags: function(ref, callbacks) {
+ db.Get(tagStore, ref.toString(),
+ {success: function(req) {
+ var data = req.target.result;
+ // TODO suppport book and chapter indexes for
+ // range lookups.
+ callbacks.success(data);
+ }});
+ },
+ GetVersesForTag: function() {
+ console.log('TODO(jwall): Implement GetVersesForTag');
+ },
+ // Sync retrieves a given references tags asynchronously.
+ // url should be a valid http URL to the service to sync the tags
+ // to.
+ // callbacks
+ Sync: function(url, callbacks) {
+ console.log('TODO(jwall): Implement Sync');
+ }
+ };
+});
+})();