mirror of
https://gitlab.com/walljm/dynamicbible.git
synced 2025-07-25 16:29:49 -04:00
Add a Tagging module.
* It uses an indexedb datastore. * Fix the api of the indexeddb wrapper now that I have some real world usage examples. * Implemented API Calls: * UpdateTags * GetTags * Exposed but unimplemented API Calls: * GetVersesForTag * Sync * Add a tooltip that shows the tags for a reference to the reference link.
This commit is contained in:
parent
0857a03e47
commit
dcd08a2dd1
28
js/common.js
28
js/common.js
@ -1,5 +1,5 @@
|
|||||||
define(['jquery', 'reference', 'jquery.ui'],
|
define(['jquery', 'reference', 'tagging', 'jquery.ui'],
|
||||||
function($, reference) {
|
function($, reference, tagging) {
|
||||||
function SortNumeric(x, y) {
|
function SortNumeric(x, y) {
|
||||||
return x - y;
|
return x - y;
|
||||||
}
|
}
|
||||||
@ -296,6 +296,7 @@ define(['jquery', 'reference', 'jquery.ui'],
|
|||||||
r += "<br />";
|
r += "<br />";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO(jwall): hover should show tags for the verse.
|
||||||
var t = $("<div class='passage result'><a href='javascript:void();' class='removeresult' style='border: 0;'><img style='border: 0px;' src='images/delete.png' width='48' height='48' /></a><span class='resultbody'>" + "<h2><a href='http://www.dynamicbible.com/?r="+ ref.toString() + "'>" + ref.toString() + "</a></h2>" + r + "</span><br clear='all' /></div>");
|
var t = $("<div class='passage result'><a href='javascript:void();' class='removeresult' style='border: 0;'><img style='border: 0px;' src='images/delete.png' width='48' height='48' /></a><span class='resultbody'>" + "<h2><a href='http://www.dynamicbible.com/?r="+ ref.toString() + "'>" + ref.toString() + "</a></h2>" + r + "</span><br clear='all' /></div>");
|
||||||
|
|
||||||
t.find(".hiddenlink").click(function(e) {
|
t.find(".hiddenlink").click(function(e) {
|
||||||
@ -304,6 +305,29 @@ define(['jquery', 'reference', 'jquery.ui'],
|
|||||||
t.find(".removeresult").click(function(e) {
|
t.find(".removeresult").click(function(e) {
|
||||||
Util.RemoveResult(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 =
|
||||||
|
$("<div>Tags: </div>");
|
||||||
|
hoverContent.append(
|
||||||
|
tags ? tags.join(", ") : "N/A");
|
||||||
|
tt(hoverContent);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
t.find(".hiddenlink").tooltip(
|
||||||
|
{
|
||||||
|
items: ".hiddenlink"
|
||||||
|
}
|
||||||
|
);
|
||||||
$("#result").prepend(t);
|
$("#result").prepend(t);
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
|
154
js/db.js
154
js/db.js
@ -2,15 +2,12 @@
|
|||||||
// See http://www.w3.org/TR/IndexedDB/ for more details about the
|
// See http://www.w3.org/TR/IndexedDB/ for more details about the
|
||||||
// IDB* interfaces referenced below.
|
// IDB* interfaces referenced below.
|
||||||
define(
|
define(
|
||||||
'db', {
|
'db', function() {
|
||||||
// Construct db wrapper.
|
return {
|
||||||
// If debug is true then logging will be turned on.
|
|
||||||
Init: function(debug) {
|
|
||||||
var self = {
|
|
||||||
version: 1,
|
version: 1,
|
||||||
dbName: "localdata",
|
dbName: "dynamic_bible_db",
|
||||||
stores: ['settings', 'verselists'],
|
stores: ['tags'],
|
||||||
debug: false,
|
debug: true,
|
||||||
// Internal method not for external use.
|
// Internal method not for external use.
|
||||||
handleError: function(e) {
|
handleError: function(e) {
|
||||||
this.debug && console.log("Error: ", e);
|
this.debug && console.log("Error: ", e);
|
||||||
@ -19,21 +16,25 @@ define(
|
|||||||
handleUpdate: function(e) {
|
handleUpdate: function(e) {
|
||||||
var db = e.target.result;
|
var db = e.target.result;
|
||||||
e.target.transaction.onerror = this.handleError;
|
e.target.transaction.onerror = this.handleError;
|
||||||
|
this.debug && console.log("Updating database", this.dbName);
|
||||||
for (i in this.stores) {
|
for (i in this.stores) {
|
||||||
if (db.objectStoreNames.contains(this.stores[i])) {
|
if (!db.objectStoreNames.contains(this.stores[i])) {
|
||||||
// TODO(jwall): handle this more gracefully?
|
this.debug && console.log("Creating objectStore", this.stores[i]);
|
||||||
db.deleteObjectStore(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
|
// ops is expected to be a function taking an IDBDatabase object
|
||||||
// as a parameter.
|
// as a parameter.
|
||||||
Session: function(ops) {
|
Session: function(ops) {
|
||||||
var self = this;
|
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
|
// HandleUpgrades
|
||||||
req.onupgradeneeded = function(e) {
|
req.onupgradeneeded = function(e) {
|
||||||
self.handleUpdate(e);
|
self.handleUpdate(e);
|
||||||
@ -42,7 +43,8 @@ define(
|
|||||||
ops(e.target.result);
|
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
|
// ops is expected to be a function taking an IDBTransation object
|
||||||
// as a parameter.
|
// as a parameter.
|
||||||
// type is an optional transaction type. values should be one of the
|
// 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.
|
// Get a key from the the object store.
|
||||||
// success is expected to be a function taking an IDBRequest object
|
// callbacks is a dict with two fields.
|
||||||
// as a parameter.
|
// callbacks.success is expected to be a function taking an
|
||||||
// error is optional and expected to be a function taking an IDBRequest
|
// IDBRequest object as a parameter.
|
||||||
// object as a parameter.
|
// callbacks.error is optional and expected to be a function
|
||||||
Get: function(storeName, key, success, error) {
|
// 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;
|
var self = this;
|
||||||
self.Transaction(
|
var op = function(trans) {
|
||||||
[storeName], function(trans) {
|
var store = trans.objectStore(storeName);
|
||||||
var store = trans.objectStore(storeName);
|
var req = store.get(key);
|
||||||
var req = store.get(key);
|
req.onsuccess = callbacks.success;
|
||||||
req.onsuccess = success;
|
req.onerror = callbacks.error || self.handleError;
|
||||||
req.onerror = error || self.handleError;
|
};
|
||||||
});
|
if (trans) {
|
||||||
|
ops(trans);
|
||||||
|
} else {
|
||||||
|
self.Transaction([storeName], op);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// Store or update a key with data in an object store.
|
// Store or update a key with data in an object store.
|
||||||
// success is expected to be a function taking an IDBRequest object
|
// callbacks is a dict with up to two fields.
|
||||||
// as a parameter.
|
// success is expected to be a function taking an IDBRequest
|
||||||
// error is optional and expected to be a function taking an IDBRequest
|
// object as a parameter.
|
||||||
// object as a parameter.
|
// error is also optional and expected to be a function taking an
|
||||||
Update: function(storeName, key, data, success, error) {
|
// 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;
|
var self = this;
|
||||||
self.Transaction(
|
var op = function(trans) {
|
||||||
[storeName], function(trans) {
|
var store = trans.objectStore(storeName);
|
||||||
var store = trans.objectStore(storeName);
|
var req = store.put(
|
||||||
var req = store.put({"key": key, "data": data});
|
{"key": key, "data": data, ts: new Date().getTime()});
|
||||||
req.onsuccess = success;
|
req.onsuccess = callbacks.success;
|
||||||
req.onerror = error || self.handleError;
|
req.onerror = callbacks.error || self.handleError;
|
||||||
}, "readwrite");
|
};
|
||||||
|
if (trans) {
|
||||||
|
op(trans);
|
||||||
|
} else {
|
||||||
|
self.Transaction(
|
||||||
|
[storeName], op, "readwrite");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// Delete a key from an object store.
|
// Delete a key from an object store.
|
||||||
// success is expected to be a function taking an IDBRequest object
|
// callbacks is a dict with up to two fields.
|
||||||
// as a parameter.
|
// callbacks.success is expected to be a function taking an
|
||||||
// error is optional and expected to be a function taking an IDBRequest
|
// IDBRequest object as a parameter.
|
||||||
// object as a parameter.
|
// callbacks.error is optional and expected to be a function
|
||||||
Delete: function(storeName, key, success, error) {
|
// taking an IDBRequest object as a parameter.
|
||||||
|
Delete: function(storeName, key, callbacks) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.Transaction(
|
self.Transaction(
|
||||||
[storeName], function(trans) {
|
[storeName], function(trans) {
|
||||||
var store = trans.objectStore(storeName);
|
var store = trans.objectStore(storeName);
|
||||||
var req = store.delete(key);
|
var req = store.delete(key);
|
||||||
req.onsuccess = success;
|
req.onsuccess = callbacks.success;
|
||||||
req.onerror = error || self.handleError;
|
req.onerror = callbacks.error || self.handleError;
|
||||||
}, "readwrite");
|
}, "readwrite");
|
||||||
},
|
},
|
||||||
// Query a range of values from an object store.
|
// Query a range of values from an object store.
|
||||||
// range is expected to be an IDBKeyRange.
|
// range is expected to be an IDBKeyRange.
|
||||||
// success is expected to be a function taking an IDBRequest object
|
// callbacks is a dict with up to two fields.
|
||||||
// as a parameter.
|
// callbacks.success is expected to be a function taking an
|
||||||
// error is optional and expected to be a function taking an IDBRequest
|
// IDBRequest object as a parameter.
|
||||||
// object as a parameter.
|
// callbacks.error is optional and expected to be a function
|
||||||
Query: function(storeName, range, success, error) {
|
// 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;
|
var self = this;
|
||||||
self.Transaction(
|
var op = function(trans) {
|
||||||
[storeName], function(trans) {
|
var store = trans.objectStore(storeName);
|
||||||
var store = trans.objectStore(storeName);
|
var req = store.openCursor(range);
|
||||||
var req = store.openCursor(range);
|
req.onsuccess = callbacks.success;
|
||||||
req.onsuccess = success;
|
req.onerror = callbacks.error || self.handleError;
|
||||||
req.onerror = 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;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
require(["jquery", "db", "common", "reference", "jquery.cookie", "jquery.ui"],
|
require(["jquery", "db", "common", "jquery.cookie", "jquery.ui"],
|
||||||
function($, db, common, ref) {
|
function($, db, common) {
|
||||||
$(document).ready(function()
|
$(document).ready(function()
|
||||||
{
|
{
|
||||||
$("#searchform").submit(function()
|
$("#searchform").submit(function()
|
||||||
@ -66,4 +66,4 @@ require(["jquery", "db", "common", "reference", "jquery.cookie", "jquery.ui"],
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -658,6 +658,16 @@ define("reference",
|
|||||||
return ref.concat("-").concat(this.endchapter)
|
return ref.concat("-").concat(this.endchapter)
|
||||||
.concat(":").concat(this.endverse);
|
.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 {
|
return {
|
||||||
Parse: function(ref) {return new Reference(ref);},
|
Parse: function(ref) {return new Reference(ref);},
|
||||||
bookName: bookName
|
bookName: bookName
|
||||||
|
50
js/tagging.js
Normal file
50
js/tagging.js
Normal file
@ -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');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
})();
|
Loading…
x
Reference in New Issue
Block a user