initial checkin from subversion
This commit is contained in:
1671
IndexedDBShim.js
Normal file
1671
IndexedDBShim.js
Normal file
File diff suppressed because it is too large
Load Diff
3
IndexedDBShim.min.js
vendored
Normal file
3
IndexedDBShim.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
27
_cache.manifest
Normal file
27
_cache.manifest
Normal file
@@ -0,0 +1,27 @@
|
||||
CACHE MANIFEST
|
||||
#REV $Revision: 19 $
|
||||
|
||||
CACHE:
|
||||
index.html
|
||||
database.js
|
||||
datahandler.js
|
||||
globals.js
|
||||
helpers.js
|
||||
IndexedDBShim.min.js
|
||||
IndexedDBShim.js
|
||||
transfer.js
|
||||
uicontroler.js
|
||||
jquery-1.10.2.min.js
|
||||
IndexedDBShim.min.js
|
||||
jquery.indexeddb.js
|
||||
jquery.mobile-1.3.2.min.js
|
||||
jquery.mobile.structure-1.3.2.min.css
|
||||
jquery.mobile.theme-1.3.2.css
|
||||
images/ajax-loader.gif
|
||||
images/icons-18-black.png
|
||||
images/icons-18-white.png
|
||||
images/icons-36-black.png
|
||||
images/icons-36-white.png
|
||||
|
||||
NETWORK:
|
||||
shoppinglist.php
|
||||
66
database.js
Normal file
66
database.js
Normal file
@@ -0,0 +1,66 @@
|
||||
var DataBaseJSRevision="$Revision: 58 $".split(' ')[1]
|
||||
|
||||
function openOrCreateDatabase(){
|
||||
db=$.indexedDB("ShoppingList", {
|
||||
"schema" : {
|
||||
"1": function(transaction){
|
||||
/* maxModified */
|
||||
var maxModi=transaction.createObjectStore("maxModified", {
|
||||
"autoIncrement": false,
|
||||
"keyPath":"objectId"
|
||||
});
|
||||
|
||||
/* Entry */
|
||||
var entry=transaction.createObjectStore("Entry", {
|
||||
"autoIncrement": true
|
||||
});
|
||||
entry.createIndex("Description",{unique:false,multiEntry:false},"Description");
|
||||
|
||||
/* Config */
|
||||
var config=transaction.createObjectStore("Config", {
|
||||
"autoIncrement": false,
|
||||
"keyPath": "Id"
|
||||
});
|
||||
|
||||
/* TransferQ*/
|
||||
var transferQ=transaction.createObjectStore("TransferQ", {
|
||||
"autoIncrement": true
|
||||
});
|
||||
transferQ.createIndex("type",{unique:false,multiEntry:false},"type");
|
||||
|
||||
/* Shop */
|
||||
var shop=transaction.createObjectStore("Shop", {
|
||||
"autoIncrement": false,
|
||||
"keyPath": "GlobalId"
|
||||
})
|
||||
},
|
||||
"2": function(transaction){
|
||||
transaction.objectStore("Shop").createIndex("Description",{unique:false,multiEntry:false},"Description");
|
||||
}
|
||||
}
|
||||
}).progress(function(db,event) {
|
||||
console.log("Progress creating DB",db,event);
|
||||
}).done(function(db,event){
|
||||
console.log("Success creating DB",db,event);
|
||||
}).fail(function(error,event){
|
||||
console.log("ERROR on DB Creation",error,event);
|
||||
|
||||
var errCode = "N/A";
|
||||
|
||||
try {
|
||||
errCode=error.debug[1].code;
|
||||
} catch (err) {}
|
||||
|
||||
if (5==errCode) {
|
||||
console.log("Known timing issue with polyfill ...");
|
||||
} else {
|
||||
|
||||
if (confirm('A problem with the local DB found ("' + error.message + '") deleting the DB might help - proceed?')) {
|
||||
$.indexedDB("ShoppingList").deleteDatabase("Shoppinglist").done(function(){
|
||||
window.location.reload()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
298
datahandler.js
Normal file
298
datahandler.js
Normal file
@@ -0,0 +1,298 @@
|
||||
var DataHandlerJSRevision="$Revision: 70 $".split(' ')[1]
|
||||
|
||||
function changedEntryDataHandler(response) {
|
||||
var allEntries=response.Entries;
|
||||
var maxModified=0;
|
||||
|
||||
if (allEntries != null) {
|
||||
db.transaction(["Entry"]).then( // transaction has three callbacks in the .then function:
|
||||
function(){ // Transaction Complete
|
||||
if (maxModified > 0) {
|
||||
db.objectStore("maxModified").put({objectId:"Entry",value:maxModified});
|
||||
}
|
||||
$("#lstEntries").listview("refresh");
|
||||
|
||||
console.log("Transaction complete [ changedEntryDataHandler ]" );
|
||||
check4Changes();
|
||||
},
|
||||
function(){ // Transaction Aborted
|
||||
$("#lstEntries").listview("refresh");
|
||||
console.log("Transaction aborted! [ changedEntryDataHandler ]" );
|
||||
},
|
||||
function(t){ // Transaction in Progress
|
||||
for (i=0;i<allEntries.length;i++){
|
||||
var theEntry=allEntries[i];
|
||||
|
||||
// this has to be it's own function so that theEntry resolves to the right value also in the callback events!
|
||||
function singleEntryInsert(theEntry){
|
||||
t.objectStore("Entry").index("Description").getKey(theEntry.Description).done( function (result,event) {
|
||||
if (null==result) {
|
||||
if (theEntry.Status != "d") {// if item doesn't exist then add it.
|
||||
t.objectStore("Entry").add({"Description":theEntry.Description, "shopGlobalId":theEntry.shopGlobalId }).done( function(result,event){
|
||||
if (getActiveShopGlobalId()==theEntry.shopGlobalId) {
|
||||
addEntryToUi(result,theEntry.Description);
|
||||
}
|
||||
if (Number(theEntry.Modified) > Number(maxModified)) {
|
||||
maxModified=theEntry.Modified;
|
||||
}
|
||||
console.log("[ changedEntryDataHandler ] Added Entry from Server : " , theEntry);
|
||||
}).fail( function (result, event){
|
||||
console.log("Failed Inserting List Item: " , result , event )
|
||||
});
|
||||
} else {
|
||||
console.log("[ changedEntryDataHandler ] Entry from Server : " , theEntry, " didn't exist on the client, therefore doing nothing");
|
||||
|
||||
if (Number(theEntry.Modified) > Number(maxModified)) {
|
||||
maxModified=theEntry.Modified;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (theEntry.Status=="d") {
|
||||
t.objectStore("Entry").delete(result).done(function (result,event){
|
||||
if (Number(theEntry.Modified) > Number(maxModified)) {
|
||||
maxModified=theEntry.Modified;
|
||||
}
|
||||
});
|
||||
deleteEntryFromUi(result);
|
||||
console.log("Deleted Entry:" , theEntry.Description , " Key:" , result)
|
||||
} else {
|
||||
// shop updated
|
||||
t.objectStore("Entry").put({"Description":theEntry.Description, "shopGlobalId":theEntry.ShopGlobalId }).done( function(result,event){
|
||||
|
||||
if (Number(theEntry.Modified) > Number(maxModified)) {
|
||||
maxModified=theEntry.Modified;
|
||||
}
|
||||
console.log("[ changedEntryDataHandler ] changed Entry from Server : " , theEntry );
|
||||
}).fail( function (result, event){
|
||||
console.log("Failed changing Entry List Item: " , result , event )
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
singleEntryInsert(theEntry);
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
deleteQitem(response);
|
||||
console.log("[ changedEntryDataHandler ] - No New Entries." );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function brandBrowser(sShoppingListName) {
|
||||
sGShoppingListName=sShoppingListName;
|
||||
sGBrowserId=generateUUID();
|
||||
addToQ("BrandBrowser",sGShoppingListName);
|
||||
db.objectStore("Config").add({Id:"ShoppingListName",value:sGShoppingListName});
|
||||
db.objectStore("Config").add({Id:"BrowserId",value:sGBrowserId});
|
||||
|
||||
db.objectStore("maxModified").add({objectId:"Entry",value:0});
|
||||
db.objectStore("maxModified").add({objectId:"Shop",value:0});
|
||||
|
||||
// Actually - that's not it: it's only for new shopping lists and not if a member is added...
|
||||
//db.objectStore("Shop").add({ShopName:"ShopName(Click to change)"});
|
||||
|
||||
$("#pnlBranding").hide();
|
||||
setMode("Entries");
|
||||
loadAndShowShops();
|
||||
|
||||
window.setTimeout(check4Changes,1000);
|
||||
}
|
||||
|
||||
function unbrandBrowser() {
|
||||
db.deleteDatabase("Shoppinglist").done(function(){
|
||||
window.location.reload()
|
||||
});
|
||||
}
|
||||
|
||||
function addNewEntry(sEntry){
|
||||
var shopGlobalId=getActiveShopGlobalId();
|
||||
if (shopGlobalId== null) {
|
||||
shopGlobalId=generateUUID();
|
||||
shopChangeHandler(shopGlobalId,"Default");
|
||||
}
|
||||
|
||||
db.objectStore("Entry").add({"Description":sEntry,"shopGlobalId":shopGlobalId }).done( function(result,event){
|
||||
addToQ("SendEntry",result);
|
||||
addEntryToUi(result,sEntry);
|
||||
$("#lstEntries").listview("refresh");
|
||||
|
||||
}).fail( function (result, event){
|
||||
console.log("Failed Inserting List Item: " , result, event )
|
||||
});
|
||||
}
|
||||
|
||||
function deleteEntry(sKey) {
|
||||
db.objectStore("Entry").get(Number(sKey)).done( function(result,event){
|
||||
addToQ("DeleteEntry",result);
|
||||
db.objectStore("Entry").delete(Number(sKey)).done( function(result,event){
|
||||
deleteEntryFromUi(sKey)
|
||||
}).fail( function (result, event){
|
||||
console.log("[deleteEntry] Failed deleting List Item: " , result , event )
|
||||
});
|
||||
}).fail( function (result, event){
|
||||
console.log("[deleteEntry] Failed retrieving List Item Details: " , result , event )
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function shopDeletion(shopGlobalId){
|
||||
db.objectStore("Shop").delete(shopGlobalId)
|
||||
.done(function(){
|
||||
addToQ("ShopDeletion",shopGlobalId);
|
||||
|
||||
$("#pnlShops>ul>li>a.ui-btn-active").remove();
|
||||
loadAndShowShops(null).done(function(){
|
||||
setMode("Entries");
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function shopChangeHandler(shopGlobalId,shopName){
|
||||
db.objectStore("Shop").put({"GlobalId":shopGlobalId, "Description":shopName})
|
||||
.done(function(result){
|
||||
console.log("[shopChangeHandler] - created new Shop with UUID " , shopGlobalId , " and Description " , shopName , " resulting in key " , result );
|
||||
addToQ("SendShop",shopGlobalId);
|
||||
|
||||
loadAndShowShops(shopGlobalId).done(function(){
|
||||
setMode("Entries");
|
||||
});
|
||||
})
|
||||
.fail(function (result,event){
|
||||
console.log("[shopChangeHandler] - error creating new Shop: " , result , event )
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function check4Changes(){
|
||||
var ojAllModi=new Object();
|
||||
ojAllModi.maxModified=new Object();
|
||||
|
||||
db.transaction(["maxModified"]).then( // transaction has three callbacks in the .then function:
|
||||
function() { // transaction complete
|
||||
callServerFunction("SendChangedData",ojAllModi,changedDataTypeDispatcher,
|
||||
function(){
|
||||
// on error wait 5 sec.
|
||||
window.setTimeout(check4Changes,5000);
|
||||
}
|
||||
);
|
||||
},
|
||||
function(){ // Transaction Aborted
|
||||
console.log("Transaction aborted! [ check4Changes ]" );
|
||||
},
|
||||
function(t){ // Transaction in Progress
|
||||
t.objectStore("maxModified").each(function(result){
|
||||
if (result != null) {
|
||||
console.log("[Check4Changes] - maxModified " , result);
|
||||
ojAllModi.maxModified[result.key]=result.value.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function changedDataTypeDispatcher(response){
|
||||
console.log("[changedDataTypeDispatcher] Detected type: " , response.ChangeType);
|
||||
|
||||
if (response.ChangeType=="Entry") {
|
||||
changedEntryDataHandler(response)
|
||||
}
|
||||
if (response.ChangeType=="Shop") {
|
||||
changedShopDataHandler(response)
|
||||
}
|
||||
if (response.ChangeType=="None"){
|
||||
check4Changes();
|
||||
}
|
||||
}
|
||||
|
||||
function changedShopDataHandler(response){
|
||||
var allShops=response.Shops;
|
||||
var maxModified=0;
|
||||
|
||||
if (allShops != null) {
|
||||
db.transaction(["Shop"]).then( // transaction has three callbacks in the .then function:
|
||||
function(){ // Transaction Complete
|
||||
if (maxModified > 0) {
|
||||
db.objectStore("maxModified").put({objectId:"Shop",value:maxModified})
|
||||
.done(function(result){
|
||||
console.log("updated modified to " + maxModified + " [ changedShopDataHandler ]" );
|
||||
})
|
||||
.fail(function(result,event){
|
||||
console.log("[changeShopDataHandler] Failed to update modified: " , result ,event );
|
||||
});
|
||||
}
|
||||
|
||||
loadAndShowShops();
|
||||
|
||||
console.log("[changeShopDataHandler] Transaction complete" );
|
||||
check4Changes();
|
||||
},
|
||||
function(){ // Transaction Aborted
|
||||
console.log("Transaction aborted! [ changedShopDataHandler ]" );
|
||||
},
|
||||
function(t){ // Transaction in Progress
|
||||
for (i=0;i<allShops.length;i++){
|
||||
var theShop=allShops[i];
|
||||
|
||||
// this has to be it's own function so that theShop resolves to the right value also in the callback events!
|
||||
function singleShopInsert(theShop){
|
||||
t.objectStore("Shop").get(theShop.GlobalId).done( function (result,event) {
|
||||
if (null==result) {
|
||||
if (theShop.Status != "d") {// if item doesn't exist then add it.
|
||||
t.objectStore("Shop").add({"Description":theShop.Description, "GlobalId":theShop.GlobalId}).done( function(result,event){
|
||||
|
||||
if (Number(theShop.Modified) > Number(maxModified)) {
|
||||
maxModified=theShop.Modified;
|
||||
}
|
||||
console.log("[ changedShopDataHandler ] Added Shop from Server : " . theShop);
|
||||
}).fail( function (result, event){
|
||||
console.log("Failed Inserting List Item: " , result , event )
|
||||
});
|
||||
} else {
|
||||
// yes, looks a bit doubled but has to be as the other 2 are transaction success dependant...
|
||||
if (Number(theShop.Modified) > Number(maxModified)) {
|
||||
maxModified=theShop.Modified;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (theShop.Status=="d") {
|
||||
t.objectStore("Shop").delete(result.GlobalId).done(function (result,event){
|
||||
if (Number(theShop.Modified) > Number(maxModified)) {
|
||||
maxModified=theShop.Modified;
|
||||
}
|
||||
});
|
||||
|
||||
console.log("Deleted Shop:" , theShop )
|
||||
} else {
|
||||
// shop updated
|
||||
t.objectStore("Shop").put({"Description":theShop.Description, "GlobalId":theShop.GlobalId }).done( function(result,event){
|
||||
|
||||
if (Number(theShop.Modified) > Number(maxModified)) {
|
||||
maxModified=theShop.Modified;
|
||||
}
|
||||
console.log("[ changedShopDataHandler ] changed Shop from Server : " , theShop );
|
||||
}).fail( function (result, event){
|
||||
console.log("[ changedShopDataHandler ] Failed changing Shop Item: " , result,event );
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
singleShopInsert(theShop);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
deleteQitem(response);
|
||||
console.log("[ changedShopDataHandler ] - No New Shops." );
|
||||
}
|
||||
|
||||
}
|
||||
42
dbcreateScript.sql
Normal file
42
dbcreateScript.sql
Normal file
@@ -0,0 +1,42 @@
|
||||
/* $Revision: 14 $*/
|
||||
|
||||
CREATE TABLE entry (key integer primary key autoincrement, shoppinglistKey integer, productKey integer, BrowserId, status varchar(1), modified bigint, Description, shopKey bigint);
|
||||
CREATE TABLE modified (objectId,maxmodi bigint);
|
||||
CREATE TABLE "shop" (key integer primary key autoincrement, shoppinglistKey integer, globalId , Description, status varchar(1), modified bigint, browserId);
|
||||
CREATE TABLE shoppinglist (key integer primary key autoincrement,name);
|
||||
CREATE TRIGGER entry_insert_modified after insert on entry for each row
|
||||
Begin
|
||||
update modified set maxmodi=maxmodi + 1 where objectId='Entry';
|
||||
select case WHEN changes() = 0
|
||||
THEN raise (ABORT,'No entry in modified table for Entry, run statement
|
||||
insert into modified (objectId,maxmodi) values (''Entry'',0)')
|
||||
END;
|
||||
update entry set modified = (select maxmodi from modified where objectId='Entry') where rowid = new.rowid;
|
||||
End;
|
||||
CREATE TRIGGER entry_update_modified after update on entry for each row
|
||||
BEGIN
|
||||
update modified set maxmodi=maxmodi + 1 where objectId='Entry';
|
||||
select case WHEN changes() = 0
|
||||
THEN raise (ABORT,'No entry in modified table for Entry, run statement
|
||||
insert into modified (objectId,maxmodi) values (''Entry'',0)')
|
||||
END;
|
||||
update entry set modified = (select maxmodi from modified where objectId='Entry') where rowid = new.rowid;
|
||||
End;
|
||||
CREATE TRIGGER shop_insert_modified after insert on shop for each row
|
||||
Begin
|
||||
update modified set maxmodi=maxmodi + 1 where objectId='Shop';
|
||||
select case WHEN changes() = 0
|
||||
THEN raise (ABORT,'No entry in modified table for Shop, run statement
|
||||
insert into modified (objectId,maxmodi) values (''Shop'',0)')
|
||||
END;
|
||||
update shop set modified = (select maxmodi from modified where objectId='Shop') where rowid = new.rowid;
|
||||
End;
|
||||
CREATE TRIGGER shop_update_modified after update on shop for each row
|
||||
Begin
|
||||
update modified set maxmodi=maxmodi + 1 where objectId='Shop';
|
||||
select case WHEN changes() = 0
|
||||
THEN raise (ABORT,'No entry in modified table for Shop, run statement
|
||||
insert into modified (objectId,maxmodi) values (''Shop'',0)')
|
||||
END;
|
||||
update shop set modified = (select maxmodi from modified where objectId='Shop') where rowid = new.rowid;
|
||||
End;
|
||||
77
globals.js
Normal file
77
globals.js
Normal file
@@ -0,0 +1,77 @@
|
||||
var GlobalsJSRevision="$Revision: 58 $".split(' ')[1]
|
||||
|
||||
var sGShoppingListName="";
|
||||
var sGBrowserId="";
|
||||
var isBlocked=false;
|
||||
var revision="$Revision: 58 $".split(" ")[1];
|
||||
var db=null;
|
||||
|
||||
function initSession(){
|
||||
openOrCreateDatabase();
|
||||
|
||||
db.objectStore("Config").get("ShoppingListName").done(function(result, event){
|
||||
if (result != null) {
|
||||
sGShoppingListName=result.value
|
||||
db.objectStore("Config").get("BrowserId").done(function(result, event){
|
||||
if (result != null) {
|
||||
sGBrowserId=result.value;
|
||||
db.objectStore("Config").get("ActiveShopId").done(function(result, event){
|
||||
if (result != null) {
|
||||
console.log("Found Shop in Config",result.value);
|
||||
loadAndShowShops(result.value);
|
||||
} else {
|
||||
console.log("No Shop in Config. ");
|
||||
loadAndShowShops();
|
||||
}
|
||||
}).fail(function (error,event){
|
||||
console.log("Error loading Shop from Config");
|
||||
loadAndShowShops();
|
||||
});
|
||||
// on start check for item changes
|
||||
check4Changes();
|
||||
updateTransferQCounter();
|
||||
setMode("Entries");
|
||||
} else {
|
||||
setMode("Branding");
|
||||
}
|
||||
})
|
||||
} else {
|
||||
setMode("Branding");
|
||||
}
|
||||
}).fail(function (error,event){
|
||||
console.log("Error when reading the initial config information",error,event);
|
||||
var errCode = "N/A";
|
||||
try {
|
||||
errCode=error.debug[1].code;
|
||||
} catch (err) {}
|
||||
|
||||
if (5==errCode) {
|
||||
console.log("Known timing issue with polyfill ..., re-triggering DB-creation..");
|
||||
// re-trigger DB-creation... by the time the user is finished with the branding we should be fine...
|
||||
openOrCreateDatabase();
|
||||
setMode("Branding");
|
||||
} else {
|
||||
alert("Error while reading initial config information: " + error + ":" + event)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Check if a new cache is available on page load. || TODO: the Server could notify for new versions, then the check would be done closer to time.
|
||||
window.addEventListener('load', function(e) {
|
||||
window.applicationCache.addEventListener('updateready', function(e) {
|
||||
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
|
||||
// Intentially not calling swapcache here, it's quite useless because it will only use the new verstion for newly loaded files anyway...
|
||||
if (confirm('A new version of this site is available. Load it?')) {
|
||||
window.location.reload();
|
||||
}
|
||||
} else {
|
||||
// Manifest didn't changed. Nothing new to server.
|
||||
}
|
||||
}, false);
|
||||
}, false);
|
||||
|
||||
var indexHtmlRevision = $("#lbRevision").text().split(" ")[1];
|
||||
$("#lbRevision").text("Index.html " + indexHtmlRevision + " | dataHandler " + DataHandlerJSRevision + " | transfer " + TransferJSRevision + " | helpers " + HelpersJSRevision + " | uictrl " + UiControlerJSRevision + " | database " + DataBaseJSRevision)
|
||||
|
||||
}
|
||||
32
helpers.js
Normal file
32
helpers.js
Normal file
@@ -0,0 +1,32 @@
|
||||
var HelpersJSRevision="$Revision: 59 $".split(' ')[1]
|
||||
|
||||
function generateUUID() {
|
||||
var delim = "-";
|
||||
|
||||
function S4() {
|
||||
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
||||
}
|
||||
|
||||
return (S4() + S4() + delim + S4() + delim + S4() + delim + S4() + delim + S4() + S4() + S4());
|
||||
};
|
||||
|
||||
function getURLParameter(name) {
|
||||
return decodeURI(
|
||||
(RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
|
||||
);
|
||||
}
|
||||
|
||||
function myConsoleLog() {
|
||||
var outputLine="";
|
||||
for (var i=0; i<arguments.length; i++) {
|
||||
var theArgVal="";
|
||||
try {
|
||||
theArgVal=JSON.stringify(arguments[i]);
|
||||
} catch (err) {
|
||||
theArgVal=arguments[i];
|
||||
}
|
||||
outputLine+=theArgVal + " "
|
||||
|
||||
}
|
||||
$("#txtDebugConsole").text(outputLine + "\r\n" + $("#txtDebugConsole").text());
|
||||
}
|
||||
BIN
images/ajax-loader.gif
Normal file
BIN
images/ajax-loader.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
BIN
images/icons-18-black.png
Normal file
BIN
images/icons-18-black.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
images/icons-18-white.png
Normal file
BIN
images/icons-18-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
images/icons-36-black.png
Normal file
BIN
images/icons-36-black.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
BIN
images/icons-36-white.png
Normal file
BIN
images/icons-36-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
179
index.html
Normal file
179
index.html
Normal file
@@ -0,0 +1,179 @@
|
||||
<!doctype html>
|
||||
|
||||
<html lang="en" manifest="cache.manifest">
|
||||
<head>
|
||||
<!-- meta name="apple-mobile-web-app-capable" content="yes" / TODO: prevents from cache refreshing! -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>Shopping List</title>
|
||||
<style type="text/css">
|
||||
@import "jquery.mobile.theme-1.3.2.css";
|
||||
@import "jquery.mobile.structure-1.3.2.min.css";
|
||||
legend { font-weight:bold;text-decoration:underline}
|
||||
</style>
|
||||
|
||||
<script src="jquery-1.10.2.min.js"></script>
|
||||
<script src="jquery.mobile-1.3.2.min.js"></script>
|
||||
<script src="IndexedDBShim.js"></script>
|
||||
<script src="jquery.indexeddb.js"></script>
|
||||
<script src="globals.js"></script>
|
||||
<script src="database.js"></script>
|
||||
<script src="transfer.js"></script>
|
||||
<script src="datahandler.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<script src="uicontroler.js"></script>
|
||||
|
||||
<script language='JavaScript'>
|
||||
|
||||
$(document).bind('pageinit',function() {
|
||||
defineDisplayStatus();
|
||||
if (applicationCache.status==applicationCache.IDLE) { applicationCache.update(); }
|
||||
|
||||
$("#lbHeading").text("Shopping List");
|
||||
$("#pnlHeading").show();
|
||||
|
||||
// get rid of the Searchbox of the Entries ListView
|
||||
$("#lstEntries").prev().children(".ui-input-search").hide();
|
||||
|
||||
initSession();
|
||||
|
||||
// Enter key submits input fields
|
||||
$("#tbCode,#tbShoppingListName,#tbNewEntry,#tbShopName").keyup( function(e) {
|
||||
if (e.keyCode == 13) {
|
||||
e.currentTarget.onsubmit();
|
||||
}
|
||||
});
|
||||
|
||||
// Setup recurring transfer poll
|
||||
window.setInterval(transferQDispatcher,10000);
|
||||
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id='pnlHeading' data-role="header">
|
||||
<a id="btnHeadingLeft" data-role="button" data-icon="arrow-l">TESTL</a>
|
||||
<h1 id='lbHeading'>TESTMID</h1>
|
||||
<a id="btnHeadingRight" data-role="button" data-icon="gear">TESTR</a>
|
||||
|
||||
<div id='pnlShops'>
|
||||
</div>
|
||||
|
||||
<div id='pnlSettingsNav' style='display:none'>
|
||||
<div data-role="navbar">
|
||||
<ul>
|
||||
<li><a onClick='showTransferQ();' class="ui-btn-active ui-state-persist">TransferQ</a></li>
|
||||
<li><a onClick='setMode("SettingsSettings")'>Settings</a></li>
|
||||
<li><a onClick='setMode("About")'>About</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='pnlBranding' style='display:none'>
|
||||
<div id='pnlDisclaimer'>
|
||||
<fieldset><legend>Terms of Use+Disclaimer</legend>
|
||||
By using this service you agree to the following terms of use:
|
||||
<ul>
|
||||
<li>There is no guarantee of this service to be available and working at any point in time</li>
|
||||
<li>There is no data security whatsoever, data might be lost or shared</li>
|
||||
<li>This service does not offer any form of data protection or privacy</li>
|
||||
<li>No claims can be made for any demage due to using this service</li>
|
||||
<li>Data entered into this system immediately becomes ownership of the system operator</li>
|
||||
<li>Even though there are no access restrictions this system isn't available for public use</li>
|
||||
<ul>
|
||||
<br>
|
||||
<a data-role="button" data-icon="check" data-iconpos="right" onclick='$("#pnlDisclaimer").slideUp();$("#pnlDisclaimerAccepted").slideDown();' >Agree</a>
|
||||
<a data-role="button" data-icon="delete" data-iconpos="right" href='http://www.google.com' >Decline</a>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div id='pnlDisclaimerAccepted' style='display:none'>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Shopping List Name:</td>
|
||||
<td><input type='text' onsubmit='$("#btnSubmitBranding").click();' style='width:200px' id='tbShoppingListName' value=''></input></td>
|
||||
</tr><tr>
|
||||
<td colspan='2'> <a data-role="button" data-icon="arrow-r" data-iconpos="right" id='btnSubmitBranding' onclick='JavaScript:brandBrowser($("#tbShoppingListName").val());' >Brand</a> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<hr />
|
||||
<br />
|
||||
<fieldset><legend>INFO</legend>
|
||||
In order to access a shopping list form multiple computers there must be an identifier that is unique for each shopping list.
|
||||
Everybody who knows this identifier can access this shopping list!
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id='pnlEntries' style='display:none'>
|
||||
<table width='100%' border='0'>
|
||||
<tr>
|
||||
<td style='width:80%'>
|
||||
<input type="text" x-webkit-speech name="name" onsubmit="$('#btnSubmitNewEntry').click();" id="tbNewEntry" data-clear-btn="true" value="" data-mini="true" onchange="this.onkeyup()" onkeyup='$("#lstEntries").prev().children(".ui-input-search").children("input").val(this.value).change();'/>
|
||||
</td> <td>
|
||||
<input id="btnSubmitNewEntry" onclick="addNewEntry($('#tbNewEntry').val());$('#tbNewEntry').val('').change();" type="submit" data-mini="true" data-theme="b" value="Add" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr>
|
||||
<ul data-role="listview" id='lstEntries' data-filter="true"> <!-- filtering when entering value in add box... -->
|
||||
</ul>
|
||||
<div data-role="footer" data-id="foo1" data-position="fixed">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='pnlShopDetails' style='display:none'>
|
||||
<div data-role='fieldcontain'>
|
||||
<label for="tbShopName">Shop-Name:</label>
|
||||
<input type="text" id="tbShopName" onsubmit="$('#btnShopAddEdit').click();" placeholder="Name of the Shop" value="" />
|
||||
</div>
|
||||
<a id="btnShopAddEdit" data-role="button" data-icon="arrow-r" data-iconpos="right" onclick="shopChangeHandler($('#tbShopName').attr('globalid') || generateUUID(),$('#tbShopName').val())" type="submit" data-theme="b">Done</a>
|
||||
<a id="btnShopDelete" data-role="button" data-icon="delete" data-iconpos="right" onclick="shopDeletion($('#tbShopName').attr('globalid'))" type="submit" data-theme="c">Delete Shop</a>
|
||||
</div>
|
||||
|
||||
<div id='pnlTransferQ' style='display:none'>
|
||||
<a data-role="button" data-icon="refresh" onclick='refreshTransferQDisplay()'>Refresh</a>
|
||||
<ul data-role="listview" id='lstTransferQItems' data-filter="false">
|
||||
</ul>
|
||||
<hr/ >
|
||||
<h3>Data:</h3>
|
||||
<textarea style='background-colour:yellow' id='txtTransferQDetails'>
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<div id='pnlSettings' style='display:none'>
|
||||
<a id="btnUnbrand" data-role="button" data-icon="delete" data-iconpos="right" onclick="unbrandBrowser();" type="submit">Unbrand</a>
|
||||
<a id="btnShowDebugConsole" data-role="button" data-icon="check" data-iconpos="right" onclick="window.console.log=myConsoleLog;$('#pnlDebugConsole').slideToggle(2000)" type="submit">Show Debug Console</a>
|
||||
</div>
|
||||
|
||||
<div id='pnlAbout' style='display:none'>
|
||||
Offline, Synchronizing ShoppingList<br />
|
||||
Implemented and operated by Joe Tretter (j.tretter at gmail dot com)<br />
|
||||
</div>
|
||||
|
||||
<div id='pnlDebugConsole' style='display:none'>
|
||||
<div data-role="fieldcontain">
|
||||
<label for="tbCode">Code</label>
|
||||
<input onsubmit='$("#txtDebugOutput").text(eval($("#tbCode").val()))' id='tbCode'></input>
|
||||
</div>
|
||||
<div data-role="fieldcontain">
|
||||
<label for="txtDebugOutput">Result Output</label>
|
||||
<textarea cols="40" rows="8" id="txtDebugOutput"></textarea>
|
||||
</div>
|
||||
<div data-role="fieldcontain">
|
||||
<label for="txtDebugConsole">Debug Console</label>
|
||||
<textarea cols="40" rows="8" id="txtDebugConsole"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<span id='lbRevision' style='font-size:xx-small' >$Revision: 74 $</span>
|
||||
</body>
|
||||
</html>
|
||||
6
jquery-1.10.2.min.js
vendored
Normal file
6
jquery-1.10.2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
522
jquery.indexeddb.js
Normal file
522
jquery.indexeddb.js
Normal file
@@ -0,0 +1,522 @@
|
||||
(function($, undefined) {
|
||||
'use strict';
|
||||
var indexedDB = idbModules.shimIndexedDB || window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
|
||||
var IDBKeyRange = idbModules.IDBKeyRange || window.IDBKeyRange || window.webkitIDBKeyRange;
|
||||
var IDBCursor = idbModules.IDBCursor || window.IDBCursor || window.webkitIDBCursor || {};
|
||||
if (typeof IDBCursor.PREV === "undefined") {
|
||||
IDBCursor.PREV = "prev";
|
||||
}
|
||||
if (typeof IDBCursor.NEXT === "undefined") {
|
||||
IDBCursor.NEXT = "next";
|
||||
}
|
||||
|
||||
/**
|
||||
* Best to use the constant IDBTransaction since older version support numeric types while the latest spec
|
||||
* supports strings
|
||||
*/
|
||||
var IDBTransaction = idbModules.IDBTransaction || window.IDBTransaction || window.webkitIDBTransaction;
|
||||
|
||||
function getDefaultTransaction(mode) {
|
||||
var result = null;
|
||||
switch (mode) {
|
||||
case 0:
|
||||
case 1:
|
||||
case "readwrite":
|
||||
case "readonly":
|
||||
result = mode;
|
||||
break;
|
||||
default:
|
||||
result = IDBTransaction.READ_WRITE || "readwrite";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
$.extend({
|
||||
/**
|
||||
* The IndexedDB object used to open databases
|
||||
* @param {Object} dbName - name of the database
|
||||
* @param {Object} config - version, onupgradeneeded, onversionchange, schema
|
||||
*/
|
||||
"indexedDB": function(dbName, config) {
|
||||
if (config) {
|
||||
// Parse the config argument
|
||||
if (typeof config === "number") config = {
|
||||
"version": config
|
||||
};
|
||||
|
||||
var version = config.version;
|
||||
if (config.schema && !version) {
|
||||
var max = -1;
|
||||
for (var key in config.schema) {
|
||||
max = max > key ? max : key;
|
||||
}
|
||||
version = config.version || max;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var wrap = {
|
||||
"request": function(req, args) {
|
||||
return $.Deferred(function(dfd) {
|
||||
try {
|
||||
var idbRequest = typeof req === "function" ? req(args) : req;
|
||||
idbRequest.onsuccess = function(e) {
|
||||
|
||||
dfd.resolveWith(idbRequest, [idbRequest.result, e]);
|
||||
};
|
||||
idbRequest.onerror = function(e) {
|
||||
|
||||
dfd.rejectWith(idbRequest, [idbRequest.error, e]);
|
||||
};
|
||||
if (typeof idbRequest.onblocked !== "undefined" && idbRequest.onblocked === null) {
|
||||
idbRequest.onblocked = function(e) {
|
||||
|
||||
var res;
|
||||
try {
|
||||
res = idbRequest.result;
|
||||
} catch (e) {
|
||||
res = null; // Required for Older Chrome versions, accessing result causes error
|
||||
}
|
||||
dfd.notifyWith(idbRequest, [res, e]);
|
||||
};
|
||||
}
|
||||
if (typeof idbRequest.onupgradeneeded !== "undefined" && idbRequest.onupgradeneeded === null) {
|
||||
idbRequest.onupgradeneeded = function(e) {
|
||||
|
||||
dfd.notifyWith(idbRequest, [idbRequest.result, e]);
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
e.name = "exception";
|
||||
dfd.rejectWith(idbRequest, ["exception", e]);
|
||||
}
|
||||
});
|
||||
},
|
||||
// Wraps the IDBTransaction to return promises, and other dependent methods
|
||||
"transaction": function(idbTransaction) {
|
||||
return {
|
||||
"objectStore": function(storeName) {
|
||||
try {
|
||||
return wrap.objectStore(idbTransaction.objectStore(storeName));
|
||||
} catch (e) {
|
||||
idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
|
||||
return wrap.objectStore(null);
|
||||
}
|
||||
},
|
||||
"createObjectStore": function(storeName, storeParams) {
|
||||
try {
|
||||
return wrap.objectStore(idbTransaction.db.createObjectStore(storeName, storeParams));
|
||||
} catch (e) {
|
||||
idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
|
||||
}
|
||||
},
|
||||
"deleteObjectStore": function(storeName) {
|
||||
try {
|
||||
idbTransaction.db.deleteObjectStore(storeName);
|
||||
} catch (e) {
|
||||
idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
|
||||
}
|
||||
},
|
||||
"abort": function() {
|
||||
idbTransaction.abort();
|
||||
}
|
||||
};
|
||||
},
|
||||
"objectStore": function(idbObjectStore) {
|
||||
var result = {};
|
||||
// Define CRUD operations
|
||||
var crudOps = ["add", "put", "get", "delete", "clear", "count"];
|
||||
for (var i = 0; i < crudOps.length; i++) {
|
||||
result[crudOps[i]] = (function(op) {
|
||||
return function() {
|
||||
return wrap.request(function(args) {
|
||||
return idbObjectStore[op].apply(idbObjectStore, args);
|
||||
}, arguments);
|
||||
};
|
||||
})(crudOps[i]);
|
||||
}
|
||||
|
||||
result.each = function(callback, range, direction) {
|
||||
return wrap.cursor(function() {
|
||||
if (direction) {
|
||||
return idbObjectStore.openCursor(wrap.range(range), direction);
|
||||
} else {
|
||||
return idbObjectStore.openCursor(wrap.range(range));
|
||||
}
|
||||
}, callback);
|
||||
};
|
||||
|
||||
result.index = function(name) {
|
||||
return wrap.index(function() {
|
||||
return idbObjectStore.index(name);
|
||||
});
|
||||
};
|
||||
|
||||
result.createIndex = function(prop, options, indexName) {
|
||||
if (arguments.length === 2 && typeof options === "string") {
|
||||
indexName = arguments[1];
|
||||
options = null;
|
||||
}
|
||||
if (!indexName) {
|
||||
indexName = prop;
|
||||
}
|
||||
return wrap.index(function() {
|
||||
return idbObjectStore.createIndex(indexName, prop, options);
|
||||
});
|
||||
};
|
||||
|
||||
result.deleteIndex = function(indexName) {
|
||||
return idbObjectStore.deleteIndex(indexName);
|
||||
};
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
"range": function(r) {
|
||||
if ($.isArray(r)) {
|
||||
if (r.length === 1) {
|
||||
return IDBKeyRange.only(r[0]);
|
||||
} else {
|
||||
return IDBKeyRange.bound(r[0], r[1], (typeof r[2] === 'undefined') ? false : r[2], (typeof r[3] === 'undefined') ? false : r[3]);
|
||||
}
|
||||
} else if (typeof r === "undefined") {
|
||||
return null;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
},
|
||||
|
||||
"cursor": function(idbCursor, callback) {
|
||||
return $.Deferred(function(dfd) {
|
||||
try {
|
||||
|
||||
var cursorReq = typeof idbCursor === "function" ? idbCursor() : idbCursor;
|
||||
cursorReq.onsuccess = function(e) {
|
||||
|
||||
if (!cursorReq.result) {
|
||||
dfd.resolveWith(cursorReq, [null, e]);
|
||||
return;
|
||||
}
|
||||
var elem = {
|
||||
// Delete, update do not move
|
||||
"delete": function() {
|
||||
return wrap.request(function() {
|
||||
return cursorReq.result["delete"]();
|
||||
});
|
||||
},
|
||||
"update": function(data) {
|
||||
return wrap.request(function() {
|
||||
return cursorReq.result["update"](data);
|
||||
});
|
||||
},
|
||||
"next": function(key) {
|
||||
this.data = key;
|
||||
},
|
||||
"key": cursorReq.result.key,
|
||||
"value": cursorReq.result.value
|
||||
};
|
||||
|
||||
dfd.notifyWith(cursorReq, [elem, e]);
|
||||
var result = callback.apply(cursorReq, [elem]);
|
||||
|
||||
try {
|
||||
if (result === false) {
|
||||
dfd.resolveWith(cursorReq, [null, e]);
|
||||
} else if (typeof result === "number") {
|
||||
cursorReq.result["advance"].apply(cursorReq.result, [result]);
|
||||
} else {
|
||||
if (elem.data) cursorReq.result["continue"].apply(cursorReq.result, [elem.data]);
|
||||
else cursorReq.result["continue"]();
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
dfd.rejectWith(cursorReq, [cursorReq.result, e]);
|
||||
}
|
||||
};
|
||||
cursorReq.onerror = function(e) {
|
||||
|
||||
dfd.rejectWith(cursorReq, [cursorReq.result, e]);
|
||||
};
|
||||
} catch (e) {
|
||||
|
||||
e.type = "exception";
|
||||
dfd.rejectWith(cursorReq, [null, e]);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
"index": function(index) {
|
||||
try {
|
||||
var idbIndex = (typeof index === "function" ? index() : index);
|
||||
} catch (e) {
|
||||
idbIndex = null;
|
||||
}
|
||||
|
||||
return {
|
||||
"each": function(callback, range, direction) {
|
||||
return wrap.cursor(function() {
|
||||
if (direction) {
|
||||
return idbIndex.openCursor(wrap.range(range), direction);
|
||||
} else {
|
||||
return idbIndex.openCursor(wrap.range(range));
|
||||
}
|
||||
|
||||
}, callback);
|
||||
},
|
||||
"eachKey": function(callback, range, direction) {
|
||||
return wrap.cursor(function() {
|
||||
if (direction) {
|
||||
return idbIndex.openKeyCursor(wrap.range(range), direction);
|
||||
} else {
|
||||
return idbIndex.openKeyCursor(wrap.range(range));
|
||||
}
|
||||
}, callback);
|
||||
},
|
||||
"get": function(key) {
|
||||
if (typeof idbIndex.get === "function") {
|
||||
return wrap.request(idbIndex.get(key));
|
||||
} else {
|
||||
return idbIndex.openCursor(wrap.range(key));
|
||||
}
|
||||
},
|
||||
"count": function() {
|
||||
if (typeof idbIndex.count === "function") {
|
||||
return wrap.request(idbIndex.count());
|
||||
} else {
|
||||
throw "Count not implemented for cursors";
|
||||
}
|
||||
},
|
||||
"getKey": function(key) {
|
||||
if (typeof idbIndex.getKey === "function") {
|
||||
return wrap.request(idbIndex.getKey(key));
|
||||
} else {
|
||||
return idbIndex.openKeyCursor(wrap.range(key));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Start with opening the database
|
||||
var dbPromise = wrap.request(function() {
|
||||
|
||||
return version ? indexedDB.open(dbName, parseInt(version)) : indexedDB.open(dbName);
|
||||
});
|
||||
dbPromise.then(function(db, e) {
|
||||
|
||||
db.onversionchange = function() {
|
||||
// Try to automatically close the database if there is a version change request
|
||||
if (!(config && config.onversionchange && config.onversionchange() !== false)) {
|
||||
db.close();
|
||||
}
|
||||
};
|
||||
}, function(error, e) {
|
||||
|
||||
// Nothing much to do if an error occurs
|
||||
}, function(db, e) {
|
||||
if (e && e.type === "upgradeneeded") {
|
||||
if (config && config.schema) {
|
||||
// Assuming that version is always an integer
|
||||
|
||||
for (var i = e.oldVersion + 1; i <= e.newVersion; i++) {
|
||||
typeof config.schema[i] === "function" && config.schema[i].call(this, wrap.transaction(this.transaction));
|
||||
}
|
||||
}
|
||||
if (config && typeof config.upgrade === "function") {
|
||||
config.upgrade.call(this, wrap.transaction(this.transaction));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return $.extend(dbPromise, {
|
||||
"cmp": function(key1, key2) {
|
||||
return indexedDB.cmp(key1, key2);
|
||||
},
|
||||
"deleteDatabase": function() {
|
||||
// Kinda looks ugly coz DB is opened before it needs to be deleted.
|
||||
// Blame it on the API
|
||||
return $.Deferred(function(dfd) {
|
||||
dbPromise.then(function(db, e) {
|
||||
db.close();
|
||||
wrap.request(function() {
|
||||
return indexedDB.deleteDatabase(dbName);
|
||||
}).then(function(result, e) {
|
||||
dfd.resolveWith(this, [result, e]);
|
||||
}, function(error, e) {
|
||||
dfd.rejectWith(this, [error, e]);
|
||||
}, function(db, e) {
|
||||
dfd.notifyWith(this, [db, e]);
|
||||
});
|
||||
}, function(error, e) {
|
||||
dfd.rejectWith(this, [error, e]);
|
||||
}, function(db, e) {
|
||||
dfd.notifyWith(this, [db, e]);
|
||||
});
|
||||
});
|
||||
},
|
||||
"transaction": function(storeNames, mode) {
|
||||
!$.isArray(storeNames) && (storeNames = [storeNames]);
|
||||
mode = getDefaultTransaction(mode);
|
||||
return $.Deferred(function(dfd) {
|
||||
dbPromise.then(function(db, e) {
|
||||
var idbTransaction;
|
||||
try {
|
||||
|
||||
idbTransaction = db.transaction(storeNames, mode);
|
||||
|
||||
idbTransaction.onabort = idbTransaction.onerror = function(e) {
|
||||
dfd.rejectWith(idbTransaction, [e]);
|
||||
};
|
||||
idbTransaction.oncomplete = function(e) {
|
||||
dfd.resolveWith(idbTransaction, [e]);
|
||||
};
|
||||
} catch (e) {
|
||||
|
||||
e.type = "exception";
|
||||
dfd.rejectWith(this, [e]);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
dfd.notifyWith(idbTransaction, [wrap.transaction(idbTransaction)]);
|
||||
} catch (e) {
|
||||
e.type = "exception";
|
||||
dfd.rejectWith(this, [e]);
|
||||
}
|
||||
}, function(err, e) {
|
||||
dfd.rejectWith(this, [e, err]);
|
||||
}, function(res, e) {
|
||||
|
||||
//dfd.notifyWith(this, ["", e]);
|
||||
});
|
||||
|
||||
});
|
||||
},
|
||||
"objectStore": function(storeName, mode) {
|
||||
var me = this,
|
||||
result = {};
|
||||
|
||||
function op(callback) {
|
||||
return $.Deferred(function(dfd) {
|
||||
function onTransactionProgress(trans, callback) {
|
||||
try {
|
||||
|
||||
callback(trans.objectStore(storeName)).then(function(result, e) {
|
||||
dfd.resolveWith(this, [result, e]);
|
||||
}, function(err, e) {
|
||||
dfd.rejectWith(this, [err, e]);
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
e.name = "exception";
|
||||
dfd.rejectWith(trans, [e, e]);
|
||||
}
|
||||
}
|
||||
me.transaction(storeName, getDefaultTransaction(mode)).then(function() {
|
||||
|
||||
// Nothing to do when transaction is complete
|
||||
}, function(err, e) {
|
||||
// If transaction fails, CrudOp fails
|
||||
if (err.code === err.NOT_FOUND_ERR && (mode === true || typeof mode === "object")) {
|
||||
|
||||
var db = this.result;
|
||||
db.close();
|
||||
dbPromise = wrap.request(function() {
|
||||
|
||||
return indexedDB.open(dbName, (parseInt(db.version, 10) || 1) + 1);
|
||||
});
|
||||
dbPromise.then(function(db, e) {
|
||||
|
||||
db.onversionchange = function() {
|
||||
// Try to automatically close the database if there is a version change request
|
||||
if (!(config && config.onversionchange && config.onversionchange() !== false)) {
|
||||
db.close();
|
||||
}
|
||||
};
|
||||
me.transaction(storeName, getDefaultTransaction(mode)).then(function() {
|
||||
|
||||
// Nothing much to do
|
||||
}, function(err, e) {
|
||||
dfd.rejectWith(this, [err, e]);
|
||||
}, function(trans, e) {
|
||||
|
||||
onTransactionProgress(trans, callback);
|
||||
});
|
||||
}, function(err, e) {
|
||||
dfd.rejectWith(this, [err, e]);
|
||||
}, function(db, e) {
|
||||
if (e.type === "upgradeneeded") {
|
||||
try {
|
||||
|
||||
db.createObjectStore(storeName, mode === true ? {
|
||||
"autoIncrement": true
|
||||
} : mode);
|
||||
|
||||
} catch (ex) {
|
||||
|
||||
dfd.rejectWith(this, [ex, e]);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dfd.rejectWith(this, [err, e]);
|
||||
}
|
||||
}, function(trans) {
|
||||
|
||||
onTransactionProgress(trans, callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function crudOp(opName, args) {
|
||||
return op(function(wrappedObjectStore) {
|
||||
return wrappedObjectStore[opName].apply(wrappedObjectStore, args);
|
||||
});
|
||||
}
|
||||
|
||||
function indexOp(opName, indexName, args) {
|
||||
return op(function(wrappedObjectStore) {
|
||||
var index = wrappedObjectStore.index(indexName);
|
||||
return index[opName].apply(index[opName], args);
|
||||
});
|
||||
}
|
||||
|
||||
var crud = ["add", "delete", "get", "put", "clear", "count", "each"];
|
||||
for (var i = 0; i < crud.length; i++) {
|
||||
result[crud[i]] = (function(op) {
|
||||
return function() {
|
||||
return crudOp(op, arguments);
|
||||
};
|
||||
})(crud[i]);
|
||||
}
|
||||
|
||||
result.index = function(indexName) {
|
||||
return {
|
||||
"each": function(callback, range, direction) {
|
||||
return indexOp("each", indexName, [callback, range, direction]);
|
||||
},
|
||||
"eachKey": function(callback, range, direction) {
|
||||
return indexOp("eachKey", indexName, [callback, range, direction]);
|
||||
},
|
||||
"get": function(key) {
|
||||
return indexOp("get", indexName, [key]);
|
||||
},
|
||||
"count": function() {
|
||||
return indexOp("count", indexName, []);
|
||||
},
|
||||
"getKey": function(key) {
|
||||
return indexOp("getKey", indexName, [key]);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.indexedDB.IDBCursor = IDBCursor;
|
||||
$.indexedDB.IDBTransaction = IDBTransaction;
|
||||
$.idb = $.indexedDB;
|
||||
})(jQuery);
|
||||
9
jquery.mobile-1.3.2.min.js
vendored
Normal file
9
jquery.mobile-1.3.2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
12
jquery.mobile.structure-1.3.2.min.css
vendored
Normal file
12
jquery.mobile.structure-1.3.2.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1068
jquery.mobile.theme-1.3.2.css
Normal file
1068
jquery.mobile.theme-1.3.2.css
Normal file
File diff suppressed because it is too large
Load Diff
BIN
shoppinglist.db
Normal file
BIN
shoppinglist.db
Normal file
Binary file not shown.
228
shoppinglist.php
Normal file
228
shoppinglist.php
Normal file
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
/* $Revision: 58 $ */
|
||||
|
||||
error_reporting(-1);
|
||||
ini_set('display_errors', 'On');
|
||||
|
||||
$db = new SQLite3('/var/lib/sqlite/shoppinglist.db');
|
||||
try {
|
||||
$db->busyTimeout(300000); // 5 min. is a lot but who knows how busy we are; apart from that people don't notice as things run in background :)
|
||||
} catch (Exception $ex) {
|
||||
// if not supported then can't set it but it's not a break of the leg ;)
|
||||
}
|
||||
$ShoppingListKey = null;
|
||||
$BrowserId = null;
|
||||
|
||||
function readGlobalVars() {
|
||||
global $db, $ShoppingListKey, $BrowserId;
|
||||
$BrowserId=$_POST['BrowserId'];
|
||||
$ShoppingListName=$_POST['ShoppingListName'];
|
||||
$ShoppingListKey = $db->querySingle("SELECT key FROM shoppinglist where name='" . SQLite3::escapeString($ShoppingListName) . "'");
|
||||
return($ShoppingListKey);
|
||||
}
|
||||
|
||||
function BrandBrowser() {
|
||||
global $db, $ShoppingListKey, $BrowserId;
|
||||
|
||||
$ShoppingListName=$_POST['ShoppingListName'];
|
||||
|
||||
$res=true;
|
||||
$ShoppingListKey = readGlobalVars();
|
||||
if (null == $ShoppingListKey ) {
|
||||
$res=$db->exec("insert into shoppinglist (name) values ('" . SQLite3::escapeString($ShoppingListName) . "')");
|
||||
$ShoppingListKey = $db->lastInsertRowID();
|
||||
}
|
||||
echo "{ \"Result\":\"" . ($res==true?"True":"False") . "\", \"TransferQKey\":\"" . $_POST['TransferQKey'] . "\" }";
|
||||
|
||||
}
|
||||
|
||||
function DeleteShop(){
|
||||
global $db, $ShoppingListKey, $BrowserId;
|
||||
|
||||
$shopGlobalId = $_POST['GlobalId'];
|
||||
|
||||
$sql="update entry set BrowserId = '" . SQLite3::escapeString($BrowserId) . "', status='d' where shoppingListKey=$ShoppingListKey and shopKey in (select key from Shop where globalId='" . SQLite3::escapeString($shopGlobalId) . "') ";
|
||||
$res=$db->exec($sql);
|
||||
|
||||
if ($res == true) {
|
||||
$res=$db->exec("update shop set BrowserId = '" . SQLite3::escapeString($BrowserId) . "', status='d' where shoppingListKey=" . $ShoppingListKey . " and globalId='" . SQLite3::escapeString($shopGlobalId) . "' ");
|
||||
}
|
||||
|
||||
echo "{ \"Result\":\"" . ($res==true?"True":"False") . "\", \"TransferQKey\":\"" . $_POST['TransferQKey'] . "\" }";
|
||||
}
|
||||
|
||||
function ReceiveShop() {
|
||||
global $db, $ShoppingListKey, $BrowserId;
|
||||
$description = $_POST['Description'];
|
||||
$shopGlobalId = $_POST['GlobalId'];
|
||||
$status = isset($_POST['value']) ? $_POST['value'] : "a";
|
||||
|
||||
if ($status != "d") {
|
||||
$status = "a";
|
||||
}
|
||||
|
||||
$res=true;
|
||||
$shopKey = $db->querySingle("Select key from shop where globalId='" . SQLite3::escapeString($shopGlobalId) . "'");
|
||||
if (null == $shopKey) {
|
||||
$res=$db->exec("insert into Shop (status,shoppinglistKey,BrowserId,globalId,Description) values ('a'," . $ShoppingListKey . ", '" . $BrowserId . "','" . SQLite3::escapeString($shopGlobalId) . "','" . SQLite3::escapeString($description) . "')");
|
||||
$shopKey = $db->lastInsertRowID();
|
||||
} else {
|
||||
$res=$db->exec("update Shop set status='" . SQLite3::escapeString($status) . "', BrowserId='" . $BrowserId . "', Description = '" . SQLite3::escapeString($description) . "' where key=" . $shopKey);
|
||||
}
|
||||
|
||||
echo "{ \"Result\":\"" . ($res==true?"True":"False") . "\", \"TransferQKey\":\"" . $_POST['TransferQKey'] . "\", \"ShopKey\":\"$shopKey\" }";
|
||||
}
|
||||
|
||||
function ReceiveEntry() {
|
||||
global $db, $ShoppingListKey, $BrowserId;
|
||||
$description = $_POST['Description'];
|
||||
$shopGlobalId = $_POST['shopGlobalId'];
|
||||
|
||||
$res = true;
|
||||
$shopKey = $db->querySingle("Select key from shop where shoppinglistkey=" . $ShoppingListKey . " and globalId='" . SQLite3::escapeString($shopGlobalId) . "'");
|
||||
if (null == $shopKey) {
|
||||
// normally the shop should arrive first, but it's not guaranteed.... if it doesn't the create a dummy shop...
|
||||
$res=$db->exec("insert into Shop (status,shoppinglistkey,BrowserId,globalId,Description) values ('a'," . $ShoppingListKey . ", '" . SQLite3::escapeString($BrowserId) . "','" . SQLite3::escapeString($shopGlobalId) . "','Default')");
|
||||
$shopKey = $db->lastInsertRowID();
|
||||
}
|
||||
|
||||
if ($res==true) {
|
||||
$EntryKey = $db->querySingle("SELECT key FROM Entry where Description='" . SQLite3::escapeString($description) . "' and ShoppingListKey=" . $ShoppingListKey . " and shopKey=" . $shopKey);
|
||||
if (null == $EntryKey) {
|
||||
$res=$db->exec("insert into Entry (Status,ShoppingListKey,BrowserId,shopKey,Description) values ('a'," . $ShoppingListKey . ",'" . SQLite3::escapeString($BrowserId) . "'," . $shopKey . ",'" . SQLite3::escapeString($description) . "')");
|
||||
$EntryKey = $db->lastInsertRowID();
|
||||
} else {
|
||||
$res=$db->exec("update Entry set status='a', BrowserId='" . $BrowserId . "', Description = '" . SQLite3::escapeString($description) . "' where key=" . $EntryKey);
|
||||
}
|
||||
}
|
||||
|
||||
echo "{ \"Result\":\"" . ($res==true?"True":"False") . "\", \"TransferQKey\":\"" . $_POST['TransferQKey'] . "\", \"EntryKey\":\"$EntryKey\" }";
|
||||
}
|
||||
|
||||
function SendChangedData() {
|
||||
global $db, $ShoppingListKey, $BrowserId;
|
||||
|
||||
$maxModified = $_POST['maxModified'];
|
||||
|
||||
$sleepTimer=5; // sleep 5 seconds per Iteration
|
||||
$numIterations=0;
|
||||
|
||||
$Data=null;
|
||||
|
||||
while ($Data == null && ($numIterations++ * $sleepTimer)<100){ // do a roundtrip all 100 seconds.
|
||||
|
||||
$Data=getModifiedShopData($maxModified["Shop"]);
|
||||
if ($Data==null) { $Data=getModifiedEntryData($maxModified["Entry"] ); }
|
||||
|
||||
if ($Data != null) {
|
||||
echo $Data;
|
||||
} else {
|
||||
sleep($sleepTimer);
|
||||
}
|
||||
}
|
||||
|
||||
if (null == $Data) {
|
||||
echo "{ \"ChangeType\":\"None\", \"Result\":\"True\" }";
|
||||
}
|
||||
}
|
||||
|
||||
function getModifiedShopData($maxModified) {
|
||||
global $db, $ShoppingListKey, $BrowserId;
|
||||
|
||||
$sAddCond="";
|
||||
|
||||
// For initial downloads do not send deleted records.
|
||||
if ($maxModified == 0) {
|
||||
$sAddCond=" and Shop.status != 'd' ";
|
||||
}
|
||||
|
||||
$allShops = null;
|
||||
$retVal = null;
|
||||
$ojShops=null;
|
||||
|
||||
$sql="SELECT shop.status, shop.modified, shop.key, shop.globalId, shop.Description FROM shop where shop.shoppinglistKey=" . $ShoppingListKey . " and shop.browserId != '" . SQLite3::escapeString($BrowserId) . "' and shop.modified>" . SQLite3::escapeString($maxModified) . "" . $sAddCond . " Order by shop.modified";
|
||||
|
||||
$allShops = $db->query($sql);
|
||||
|
||||
while ($theShop = $allShops->fetchArray()) {
|
||||
|
||||
if (null==$ojShops) { $ojShops=", \"Shops\":["; }
|
||||
$ojShops .= "{ \"ShopKey\":\"" . $theShop["key"] . "\", \"Modified\":\"" . $theShop["modified"] . "\", \"Status\":\"" . $theShop["status"] . "\", \"GlobalId\":" . json_encode($theShop["globalId"]) . ", \"Description\":" . json_encode($theShop["Description"]) . " },";
|
||||
}
|
||||
if (null!=$ojShops) { $ojShops = rtrim($ojShops,",") . "]"; } else { $ojShops=""; }
|
||||
|
||||
if ($ojShops!=null) {
|
||||
$retVal= "{ \"ChangeType\":\"Shop\", \"Result\":\"" . ($allShops==true?"True":"False") . "\" " . $ojShops . " }";
|
||||
}
|
||||
|
||||
return($retVal);
|
||||
}
|
||||
|
||||
|
||||
function getModifiedEntryData($maxModified) {
|
||||
global $db, $ShoppingListKey, $BrowserId;
|
||||
|
||||
$sAddCond="";
|
||||
|
||||
// For initial downloads do not send deleted records.
|
||||
if ($maxModified == 0) {
|
||||
$sAddCond=" and Entry.status != 'd' ";
|
||||
}
|
||||
|
||||
$allEntries = null;
|
||||
$retVal = null;
|
||||
$ojEntries=null;
|
||||
|
||||
$allEntries = $db->query("SELECT entry.status, entry.modified, entry.key, entry.Description, shop.globalId FROM entry,shop where entry.shoppingListKey=" . $ShoppingListKey . " and shop.key=entry.shopKey and entry.BrowserId != '" . SQLite3::escapeString($BrowserId) . "' and entry.modified>" . SQLite3::escapeString($maxModified) . "" . $sAddCond . " Order by entry.modified");
|
||||
|
||||
while ($theEntry = $allEntries->fetchArray()) {
|
||||
|
||||
if (null==$ojEntries) { $ojEntries=", \"Entries\":["; }
|
||||
$ojEntries .= "{ \"EntryKey\":\"" . $theEntry["key"] . "\", \"Modified\":\"" . $theEntry["modified"] . "\", \"Status\":\"" . $theEntry["status"] . "\", \"Description\":" . json_encode($theEntry["Description"]) . ", \"shopGlobalId\":" . json_encode($theEntry["globalId"]) . " },";
|
||||
}
|
||||
if (null!=$ojEntries) { $ojEntries = rtrim($ojEntries,",") . "]"; } else { $ojEntries=""; }
|
||||
|
||||
if ($ojEntries!=null) {
|
||||
$retVal= "{ \"ChangeType\":\"Entry\", \"Result\":\"" . ($allEntries==true?"True":"False") . "\" " . $ojEntries . " }";
|
||||
}
|
||||
|
||||
return($retVal);
|
||||
}
|
||||
|
||||
function DeleteEntry(){
|
||||
global $db, $ShoppingListKey, $BrowserId;
|
||||
|
||||
$Description = $_POST['Description'];
|
||||
$shopGlobalId = null;
|
||||
if (!empty($_POST['shopGlobalId'])) {
|
||||
$shopGlobalId = $_POST['shopGlobalId'];
|
||||
}
|
||||
|
||||
$res = true;
|
||||
|
||||
if ($res==true) {
|
||||
$sql="update entry set BrowserId = '" . SQLite3::escapeString($BrowserId) . "', status='d' where shoppingListKey=$ShoppingListKey and Description='" . SQLite3::escapeString($Description) . "'";
|
||||
if (null != $shopGlobalId) { $sql = $sql . " and shopKey = (select key from shop where globalId='" . SQLite3::escapeString($shopGlobalId) . "')"; }
|
||||
|
||||
$res=$db->exec($sql);
|
||||
}
|
||||
|
||||
echo "{ \"Result\":\"" . ($res==true?"True":"False") . "\", \"TransferQKey\":\"" . $_POST['TransferQKey'] . "\" }";
|
||||
}
|
||||
|
||||
readGlobalVars();
|
||||
|
||||
if(isset($_POST['action']) && !empty($_POST['action'])) {
|
||||
$action = $_POST['action'];
|
||||
switch($action) {
|
||||
case 'BrandBrowser' : BrandBrowser() ; break;
|
||||
case 'ReceiveEntry' : ReceiveEntry() ; break;
|
||||
case 'ReceiveShop' : ReceiveShop() ; break;
|
||||
case 'SendChangedData' : SendChangedData() ; break;
|
||||
case 'DeleteEntry' : DeleteEntry() ; break;
|
||||
case 'DeleteShop' : DeleteShop() ; break;
|
||||
}
|
||||
}
|
||||
|
||||
$db->close();
|
||||
?>
|
||||
110
test.html
Normal file
110
test.html
Normal file
@@ -0,0 +1,110 @@
|
||||
<!doctype html>
|
||||
|
||||
<html lang="en" >
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>IndexDB problem</title>
|
||||
|
||||
<script src="jquery-1.10.2.min.js"></script>
|
||||
<script src="IndexedDBShim.js"></script>
|
||||
<script src="jquery.indexeddb.js"></script>
|
||||
|
||||
<script language='JavaScript'>
|
||||
var oneKJunk="gjdfsa;klgjepqrioutypv iywhklcrhlkjdhfnlckjhrweqlkjchglkjwrhlgkhwelrkhglkehwrrlkgchowkehmlgghdf;kjghsljkdfhglkjsdhglkjshdglkjhsdflkjghsdflkjhgsljkdfhgkljsdhfglkjshdfglkjvwhflkjvhw;lkjerhlgkjhsdfpiuhvpsifdhpvsdnfivnwpehgphdf;hvnpinunwrtgj;khqr.g,jhl;qnvpkerjghnda.kfj,hgnvpeo;kjhn;cokerhgdkfjgshdfuvjhwcierijcghkajdhgiloeruihgdf;kjhafkl;jsfdh~gsdkfjhgsdfghiwe768ydfoiusghdfoig6uysdfogisdhglksdhflgkhnlkgq.wjnrlgkvjhlwkerjhglkdfjhglksdjhfglskdhglskdfhgpdhgowierhgoihqlughqroeringfhgeqroigheowighodrghodisfhgoihfgiadshgoiwehrgqoeriyhgoipqhwdflgvsdkfhvlkvhbilewruhgiperurghnweoirghsldkjfghkljdhgerlihgwipoeughoweilhgiourehytliehrgpidhadgwwgteriuyiptuewyptiwueryt09pyp9fhpeiguhdsl;fkjhgwfe9i5tuypdsilghsldkjhgwoireugyhpwg4ourhlkjh5gpoiugh9pyito78ygf0ws87odygvfpwieyrgiplehrvclkjfdhlkjghosiduygpewiurytpieqruhgpeighwpieutyp39qy4tqpiuhrpiuqrehytpiwuethwpeituhwertl;ihwertieuhrtpwiertywpeiruhtpweruithw4oyi8twer;ihjgswuilwhepihywperhgweirpluthwepirtuhywept9hfwpeihtpwieutwpietywepiruytwpuyfpiwehpyeyrwp3igptwiegyuttweoiruhytouiwerh";
|
||||
|
||||
var db=$.indexedDB("Test1", {
|
||||
"schema": {
|
||||
"1": function(versionTransaction){
|
||||
/* maxModified */
|
||||
var test1=versionTransaction.createObjectStore("Test1", {
|
||||
"autoIncrement": true
|
||||
});
|
||||
|
||||
test1.createIndex("type",{unique:false,multiEntry:false},"type");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function execDBInsert(){
|
||||
db.objectStore("Test1").add({"type":"abc"+Math.floor(Math.random()*5), "data":Math.floor(Math.random()*1000), "junk":oneKJunk }).done(function(key){
|
||||
console.log("OK",key);
|
||||
myLog("OK " + key + ".");
|
||||
}).fail(function(a,b){
|
||||
console.log("FAIL",a,b);
|
||||
myLog("Fail:" + a + ":" + b);
|
||||
})
|
||||
}
|
||||
|
||||
function execDBUpdate(){
|
||||
db.objectStore("Test1").each(function (item) {
|
||||
item.value.type="UA"+Math.floor(Math.random()*5);
|
||||
item.update(item.value);
|
||||
}).done(function(key){
|
||||
console.log("OK",key);
|
||||
}).fail(function(a,b){
|
||||
console.log("FAIL",a,b);
|
||||
})
|
||||
}
|
||||
|
||||
function execDBUpdateSingle(){
|
||||
var stopper=false;
|
||||
db.objectStore("Test1").each(function (item) {
|
||||
if (!stopper) {
|
||||
console.log("Updating",item);
|
||||
item.value.type="US"+Math.floor(Math.random()*5);
|
||||
item.update(item.value);
|
||||
|
||||
}
|
||||
stopper = true;
|
||||
}).done(function(key){
|
||||
console.log("OK",key);
|
||||
myLog("OK " + key);
|
||||
}).fail(function(a,b){
|
||||
console.log("FAIL",a,b);
|
||||
myLog("Fail:" + a + ":" + b);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function execDBPut(){
|
||||
db.objectStore("Test1").each(function (item) {
|
||||
item.value.type="PUT"+Math.floor(Math.random()*5);
|
||||
db.objectStore("Test1").put(item.value,item.key);
|
||||
}).done(function(key){
|
||||
console.log("OK",key);
|
||||
}).fail(function(a,b){
|
||||
console.log("FAIL",a,b);
|
||||
})
|
||||
}
|
||||
|
||||
function StressInsert(){
|
||||
$("#log").text("");
|
||||
for (i=0;i<1024;i++) {
|
||||
window.setTimeout(execDBInsert,1+Math.floor(Math.random()*1000));
|
||||
}
|
||||
}
|
||||
|
||||
function myLog(text){
|
||||
$("#log").text( text + "\n" + $("#log").text());
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<button onclick='execDBInsert();'>GO-Insert</button>
|
||||
<button onclick='StressInsert();'>StressInsert</button>
|
||||
<button onclick='execDBUpdate();'>GO-Update (all)</button>
|
||||
<button onclick='execDBUpdateSingle();'>GO-Update (Single)</button>
|
||||
<button onclick='execDBPut();'>GO-PUT</button>
|
||||
<hr>
|
||||
<button onclick='$.indexedDB("Test1").deleteDatabase("Test1").done(function(){ myLog("Done Delete DB");}).fail(function(){ myLog("FAILED Delete DB");});'>Delete DB</button>
|
||||
<hr>
|
||||
<input id='code'></input><button onclick='$("#output").text(eval($("#code").val()))'>GO</button>
|
||||
<textarea id='output'>
|
||||
</textarea>
|
||||
<div id='log'>
|
||||
log
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
117
transfer.js
Normal file
117
transfer.js
Normal file
@@ -0,0 +1,117 @@
|
||||
var TransferJSRevision="$Revision: 58 $".split(' ')[1]
|
||||
|
||||
function callServerFunction(sFunctionName, ojData, cbSuccess, cbError) {
|
||||
ojData.action=sFunctionName;
|
||||
ojData.ShoppingListName=sGShoppingListName;
|
||||
ojData.BrowserId=sGBrowserId;
|
||||
|
||||
$.ajax
|
||||
({
|
||||
type: "POST",
|
||||
timeout: 120000,
|
||||
url: './shoppinglist.php',
|
||||
dataType: 'json',
|
||||
async: true,
|
||||
//json object to sent to the authentication url
|
||||
data: ojData}).done(cbSuccess).fail(cbError);
|
||||
}
|
||||
|
||||
|
||||
function OnError_callback(response,textstatus)
|
||||
{
|
||||
console.log('[OnError_callback] Error:', response, textstatus);
|
||||
}
|
||||
|
||||
function transferQDispatcher() {
|
||||
updateTransferQCounter();
|
||||
|
||||
db.objectStore("TransferQ").each(function(Qitem){
|
||||
if (Qitem.value.type=="SendEntry") {
|
||||
var EntryId=Qitem.value.data;
|
||||
var TransferQKey=Qitem.key;
|
||||
db.objectStore("Entry").get(Number(EntryId)).done(function(result,event){
|
||||
if (null != result) {
|
||||
var theEntry={"EntryId":EntryId, "TransferQKey":TransferQKey, "Description":result.Description, "shopGlobalId":result.shopGlobalId};
|
||||
callServerFunction("ReceiveEntry",theEntry,deleteQitem,OnError_callback)
|
||||
} else {
|
||||
// this entry no longer exists, maybe the user deleted it before it could be transferred
|
||||
deleteQitem({"TransferQKey":TransferQKey, "Result":"True"});
|
||||
console.log("[transferQDispatcher] Failed to find Q-record from Data :" , Qitem);
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (Qitem.value.type=="SendShop") {
|
||||
var ShopKey=Qitem.value.data;
|
||||
var TransferQKey=Qitem.key;
|
||||
db.objectStore("Shop").get(ShopKey).done(function(result,event){
|
||||
if (null != result) {
|
||||
var theShop={"GlobalId":result.GlobalId, "TransferQKey":TransferQKey, "Description":result.Description};
|
||||
callServerFunction("ReceiveShop",theShop,deleteQitem,OnError_callback)
|
||||
} else {
|
||||
// this entry no longer exists, maybe the user deleted it before it could be transferred
|
||||
deleteQitem({"TransferQKey":TransferQKey, "Result":"True"});
|
||||
console.log("[transferQDispatcher] Failed to find Q-record from Data :" , Qitem);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (Qitem.value.type=="ShopDeletion") {
|
||||
var GlobalId=Qitem.value.data;
|
||||
var TransferQKey=Qitem.key;
|
||||
|
||||
var oData={"TransferQKey":TransferQKey, "GlobalId":GlobalId};
|
||||
callServerFunction("DeleteShop",oData,deleteQitem,OnError_callback)
|
||||
}
|
||||
|
||||
if (Qitem.value.type=="BrandBrowser") {
|
||||
var TransferQKey=Qitem.key;
|
||||
var oData={ "ShoppingListName":Qitem.value.data, "TransferQKey":TransferQKey };
|
||||
callServerFunction("BrandBrowser",oData,deleteQitem,OnError_callback)
|
||||
}
|
||||
|
||||
if (Qitem.value.type=="DeleteEntry") {
|
||||
var TransferQKey=Qitem.key;
|
||||
var oData={"TransferQKey":TransferQKey, "Description":Qitem.value.data.Description, "shopGlobalId":Qitem.value.data.shopGlobalId};
|
||||
callServerFunction("DeleteEntry",oData,deleteQitem,OnError_callback)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function deleteQitem(response){
|
||||
if (response.Result == "True") {
|
||||
db.objectStore("TransferQ").delete(Number(response.TransferQKey)).done(function(){
|
||||
updateTransferQCounter();
|
||||
console.log("[deleteQitem] Done SendEntry (" + response.TransferQKey + "): ", response)
|
||||
}).fail(function(result,event){
|
||||
console.log("[deleteQitem] failed deleteQitem (" , response , "): ", response,event)
|
||||
});
|
||||
} else {
|
||||
console.log("[deleteQitem] Failed SendEntry (" + response.TransferQKey + "): " , response);
|
||||
}
|
||||
}
|
||||
|
||||
function addToQ(type,data,unique) {
|
||||
var isUnique=false || unique;
|
||||
var theItem = new Object();
|
||||
theItem.type=type;
|
||||
theItem.data=data;
|
||||
|
||||
if (isUnique) {
|
||||
db.objectStore("TransferQ").index("type").get("GetServerEntries").done(function(result){
|
||||
if (result==null) {
|
||||
db.objectStore("TransferQ").add(theItem).done(function (result){ transferQDispatcher(); });
|
||||
console.log("[addToQ] uniqueAdd added: " , theItem );
|
||||
} else {
|
||||
console.log("[addToQ] uniqueAdd item not added because such typed item already exists: " , theItem);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
db.objectStore("TransferQ").add(theItem).done(function (result){ transferQDispatcher(); });
|
||||
console.log("[addToQ] non-unique Add added: " , theItem);
|
||||
}
|
||||
}
|
||||
|
||||
304
uicontroler.js
Normal file
304
uicontroler.js
Normal file
@@ -0,0 +1,304 @@
|
||||
var UiControlerJSRevision="$Revision: 72 $".split(' ')[1]
|
||||
|
||||
function changeButtonText(sBtnId,sNewText) {
|
||||
$("#" + sBtnId + " .ui-btn-text").text(sNewText);
|
||||
}
|
||||
|
||||
function defineDisplayStatus(){
|
||||
$("#pnlHeading").hide();
|
||||
$("#pnlShopDetails").hide();
|
||||
$("#pnlEntries").hide();
|
||||
$("#lbHeading").text("???");
|
||||
$("#btnHeadingLeft").hide();
|
||||
$("#btnHeadingLeft").unbind();
|
||||
changeButtonText("btnHeadingLeft"," ");
|
||||
$("#btnHeadingRight").hide();
|
||||
$("#btnHeadingRight").unbind();
|
||||
changeButtonText("btnHeadingRight","...");
|
||||
$("#pnlShops").hide();
|
||||
$("#pnlTransferQ").hide();
|
||||
$("#pnlAbout").hide();
|
||||
$("#pnlSettings").hide();
|
||||
$("#pnlSettingsNav").hide();
|
||||
}
|
||||
|
||||
/* ---- FRW ------------ */
|
||||
function deleteData(sType,sKey){
|
||||
console.log("Delete data called",sType,sKey)
|
||||
}
|
||||
|
||||
function addEntryToUi(sKey,sEntry){
|
||||
if ($("#entry_" + sKey).length == 0) { // Avoid adding duplicated especially after branding
|
||||
$("#lstEntries").append("<li data-icon=\"delete\" key='" + sKey + "' id='entry_" + sKey + "'><a>" + sEntry + "</a><a data-role='button' onclick='deleteEntry(\"" + sKey + "\")'></a></li>");
|
||||
// $("#lstEntries").listview("refresh");
|
||||
}
|
||||
}
|
||||
|
||||
function showQItemDetail(Qkey,Type,data){
|
||||
$("#txtTransferQDetails").text("Sorry, Unavailable for this object");
|
||||
|
||||
if ((Type=="DeleteEntry") || (Type=="ShopDeletion")) {
|
||||
$("#txtTransferQDetails").text("Deleted " + Type + ": " + data + " no more information available as item was deleted.");
|
||||
}
|
||||
|
||||
if ((Type=="SendShop")||(Type=="SendEntry")) {
|
||||
if (Type=="SendEntry") { data=Number(data); }
|
||||
db.objectStore("Entry").get(data).done(function(result){
|
||||
$("#txtTransferQDetails").text(JSON.stringify(result));
|
||||
}).fail(function(result,event){
|
||||
$("#txtTransferQDetails").text("Error loading Item.");
|
||||
console.log("[showQItemDetail] Error loading Entry Item: ",result,event);
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function addTransferQItemToUi(item){
|
||||
if ($("#Qitem_" + item.key).length == 0) { // Avoid adding duplicated especially after branding
|
||||
$("#lstTransferQItems").append("<li onclick='showQItemDetail(\"" + item.key + "\",\"" + item.value.type + "\", \"" + item.value.data + "\");' data-icon=\"arrow_r\" id='Qitem_" + item.key + "'><a>" + item.key + " -- "+ item.value.type + "</a></li>");
|
||||
$("#lstTransferQItems").listview("refresh");
|
||||
}
|
||||
}
|
||||
|
||||
function deleteEntryFromUi(sKey){
|
||||
$("#entry_" + sKey).remove();
|
||||
$("#lstEntries").listview("refresh");
|
||||
}
|
||||
|
||||
|
||||
function showSettings(){
|
||||
setMode("Settings");
|
||||
}
|
||||
|
||||
function showTransferQ(){
|
||||
setMode("TransferQ");
|
||||
refreshTransferQDisplay();
|
||||
}
|
||||
|
||||
function refreshTransferQDisplay(){
|
||||
$("#lstTransferQItems").empty();
|
||||
|
||||
db.objectStore("TransferQ").each(function(item){
|
||||
if (null != item) {
|
||||
addTransferQItemToUi(item);
|
||||
}
|
||||
}).done(function (result, event){
|
||||
console.log("[refreshTransferQDisplay] Success, filtered by shop " , shopGlobalId);
|
||||
}).fail( function (result, event){
|
||||
console.log("[refreshTransferQDisplay] Failed: " , result , event )
|
||||
});
|
||||
}
|
||||
|
||||
function loadAndShowEntries(shopGlobalId){
|
||||
$("#lstEntries").empty();
|
||||
$("#lstEntries").hide();
|
||||
$.mobile.showPageLoadingMsg();
|
||||
|
||||
db.objectStore("Entry").each(function(item){
|
||||
if (null != item) {
|
||||
if (item.value.shopGlobalId==shopGlobalId) {
|
||||
addEntryToUi(item.key,item.value.Description);
|
||||
}
|
||||
}
|
||||
}).done(function (result, event){
|
||||
$("#lstEntries").listview("refresh");
|
||||
console.log("[loadAndShowEntries] Success, filtered by shop " , shopGlobalId);
|
||||
$("#lstEntries").show();
|
||||
$.mobile.hidePageLoadingMsg();
|
||||
}).fail( function (result, event){
|
||||
console.log("[loadAndShowEntries] Failed: " , result , event )
|
||||
$("#lstEntries").show();
|
||||
$.mobile.hidePageLoadingMsg();
|
||||
});
|
||||
}
|
||||
|
||||
function getActiveShopGlobalId() {
|
||||
shopGlobalId=$("#pnlShops>ul>li>a.ui-btn-active").parent().attr("id");
|
||||
|
||||
if (null!=shopGlobalId) {
|
||||
shopGlobalId=shopGlobalId.split("_")[1];
|
||||
} else {
|
||||
shopGlobalId=null;
|
||||
}
|
||||
|
||||
return(shopGlobalId)
|
||||
}
|
||||
|
||||
function changeShop(newShop){
|
||||
var newShopId=null;
|
||||
if (null != newShop) {
|
||||
newShopId=$(newShop).parent().attr('id').split("_")[1];
|
||||
}
|
||||
console.log("[changeShop] switching to newShopId " , newShopId);
|
||||
db.objectStore("Config").put({Id:"ActiveShopId",value:newShopId});
|
||||
loadAndShowEntries(newShopId);
|
||||
}
|
||||
|
||||
function addShop(){
|
||||
$('#tbShopName').removeAttr('globalid')
|
||||
$("#tbShopName").val("");
|
||||
setMode("AddShop");
|
||||
}
|
||||
|
||||
function editShop(theShop){
|
||||
var theShopGlobalId=$(theShop).attr('id').split("_")[1];
|
||||
db.objectStore("Shop").get(theShopGlobalId).done(function(result){
|
||||
$("#tbShopName").val(result.Description);
|
||||
$("#tbShopName").attr("globalid",theShopGlobalId);
|
||||
})
|
||||
setMode("EditShop");
|
||||
}
|
||||
|
||||
|
||||
function loadAndShowShops(shopGlobalId){
|
||||
var activeNav=shopGlobalId || getActiveShopGlobalId();
|
||||
|
||||
var parent=$("#pnlShops").parent();
|
||||
$("#pnlShops").remove();
|
||||
$(parent).append("<div id='pnlShops' style='display:none'>");
|
||||
$("#pnlShops").hide(); // shouldn't be needed but I can still see the shops build up...
|
||||
|
||||
var numItems=0;
|
||||
|
||||
var navBarNum=1;
|
||||
$("#pnlShops").append("<ul id='lstShops" + navBarNum + "'></ul>");
|
||||
var myPromise = db.objectStore("Shop").index("Description").each(function(item){
|
||||
if (activeNav==null){
|
||||
// if no Shop was selected yet then activate the first one
|
||||
activeNav=item.value.GlobalId;
|
||||
}
|
||||
$("#lstShops" + navBarNum).append("<li id='shop_" + item.value.GlobalId + "'><a onclick='changeShop(this);'>" + item.value.Description + "</a></li>");
|
||||
$("#shop_"+item.value.GlobalId).bind("taphold",function(e){ editShop(this);});
|
||||
|
||||
numItems++;
|
||||
if ((numItems % 5) == 0) { // more than 5 buttons in the navbar look ugly, in that case we create a new line...
|
||||
navBarNum++;
|
||||
$("#pnlShops").append("<ul id='lstShops" + navBarNum + "'></ul>");
|
||||
}
|
||||
});
|
||||
myPromise.done(function (result, event){
|
||||
$("#lstShops" + navBarNum).append("<li id='btnAddShop' data-iconpos='right' data-icon='plus'><a onclick='addShop();'>Add Shop</a></li>");
|
||||
$("#pnlShops").navbar();
|
||||
|
||||
$("#pnlShops").show();
|
||||
|
||||
// Mark the previously active button as active.
|
||||
$($("#shop_" + activeNav).children()[0]).addClass("ui-btn-active")
|
||||
|
||||
loadAndShowEntries(getActiveShopGlobalId());
|
||||
|
||||
console.log("Success loadAndShowShops");
|
||||
});
|
||||
myPromise.fail( function (result, event){
|
||||
console.log("Failed loadAndShowShops: " , result , event )
|
||||
});
|
||||
return(myPromise);
|
||||
}
|
||||
|
||||
|
||||
function setMode(sMode){
|
||||
defineDisplayStatus();
|
||||
console.log("Setting Mode " , sMode)
|
||||
|
||||
if ("Branding" == sMode) {
|
||||
$("#lbHeading").text("Branding");
|
||||
$("#pnlHeading").show();
|
||||
|
||||
$("#pnlBranding").show();
|
||||
}
|
||||
|
||||
if ("Entries" == sMode) {
|
||||
|
||||
$("#lbHeading").text("Entries [" + sGShoppingListName + "]");
|
||||
$("#pnlHeading").show();
|
||||
$("#pnlShops").show();
|
||||
|
||||
$("#btnHeadingRight").show();
|
||||
$("#btnHeadingRight").bind("click", showSettings);
|
||||
|
||||
$("#pnlEntries").show();
|
||||
}
|
||||
|
||||
if ("AddShop" == sMode) {
|
||||
$("#lbHeading").text("Add Shop");
|
||||
$("#pnlHeading").show();
|
||||
$("#pnlShops").hide();
|
||||
$("#btnShopDelete").hide();
|
||||
|
||||
changeButtonText("btnShopAddEdit","Add");
|
||||
$("#pnlShopDetails").show();
|
||||
|
||||
changeButtonText("btnHeadingLeft","Back");
|
||||
$("#btnHeadingLeft").bind("click", function(){ setMode("Entries"); });
|
||||
$("#btnHeadingLeft").show();
|
||||
}
|
||||
|
||||
if ("EditShop" == sMode) {
|
||||
$("#lbHeading").text("Edit Shop");
|
||||
$("#pnlHeading").show();
|
||||
$("#pnlShops").hide();
|
||||
$("#btnShopDelete").show();
|
||||
|
||||
changeButtonText("btnShopAddEdit","Change");
|
||||
$("#pnlShopDetails").show();
|
||||
|
||||
changeButtonText("btnHeadingLeft","Back");
|
||||
$("#btnHeadingLeft").bind("click", function(){ setMode("Entries"); });
|
||||
$("#btnHeadingLeft").show();
|
||||
}
|
||||
|
||||
if ("Settings" == sMode) {
|
||||
$("#lbHeading").text("...");
|
||||
$("#pnlHeading").show();
|
||||
if ($("#pnlSettingsNav>div>ul>li>a.ui-btn-active").length == 1) {
|
||||
$("#pnlSettingsNav>div>ul>li>a.ui-btn-active").click();
|
||||
} else {
|
||||
showTransferQ();
|
||||
}
|
||||
|
||||
$("#pnlSettingsNav").show();
|
||||
|
||||
changeButtonText("btnHeadingLeft","Back");
|
||||
$("#btnHeadingLeft").bind("click", function(){ setMode("Entries"); });
|
||||
$("#btnHeadingLeft").show();
|
||||
}
|
||||
|
||||
if ("About" == sMode) {
|
||||
$("#lbHeading").text("About");
|
||||
$("#pnlHeading").show();
|
||||
$("#pnlSettingsNav").show();
|
||||
$("#pnlAbout").show();
|
||||
|
||||
changeButtonText("btnHeadingLeft","Back");
|
||||
$("#btnHeadingLeft").bind("click", function(){ setMode("Entries"); });
|
||||
$("#btnHeadingLeft").show();
|
||||
}
|
||||
|
||||
if ("SettingsSettings" == sMode) {
|
||||
$("#lbHeading").text("Settings");
|
||||
$("#pnlHeading").show();
|
||||
$("#pnlSettingsNav").show();
|
||||
$("#pnlSettings").show();
|
||||
|
||||
changeButtonText("btnHeadingLeft","Back");
|
||||
$("#btnHeadingLeft").bind("click", function(){ setMode("Entries"); });
|
||||
$("#btnHeadingLeft").show();
|
||||
}
|
||||
|
||||
|
||||
if ("TransferQ" == sMode){
|
||||
$("#lbHeading").text("Transfer Queue Display");
|
||||
$("#pnlHeading").show();
|
||||
$("#pnlSettingsNav").show();
|
||||
$("#pnlTransferQ").show();
|
||||
|
||||
changeButtonText("btnHeadingLeft","Back");
|
||||
$("#btnHeadingLeft").bind("click", function(){ setMode("Entries"); });
|
||||
$("#btnHeadingLeft").show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function updateTransferQCounter(){
|
||||
db.objectStore("TransferQ").count().done(function (result) { changeButtonText("btnHeadingRight",result); });
|
||||
}
|
||||
3
updateSQL.sql
Normal file
3
updateSQL.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
2013-11-07 - delete orphaned entries:
|
||||
|
||||
update entry set status='d' where entry.status != 'd' and shopkey not in (select key from shop where status != 'd');
|
||||
Reference in New Issue
Block a user