Store data in a better format

This commit is contained in:
Neil Brommer 2017-12-27 15:27:08 -08:00
parent bd20c403b3
commit 45f33631e9
5 changed files with 175 additions and 196 deletions

View file

@ -7,7 +7,7 @@ $(document).ready(function () {
for (let group of bookmarkList) { for (let group of bookmarkList) {
if (group != null) if (group != null)
combo.append($("<option>").attr({ "value": group.title }) combo.append($("<option>").attr({ "value": group.groupIndex })
.text(group.title)); .text(group.title));
} }
@ -30,48 +30,30 @@ function addNewBookmark(e) {
if (bkmkGroup == "--") { // create a new group if (bkmkGroup == "--") { // create a new group
var newGroupName = $("#newBookMarkGroupNew").val(); var newGroupName = $("#newBookMarkGroupNew").val();
var newGroup = { var openDBRequest = window.indexedDB.open("bookmarks");
"title": newGroupName,
"bookmarks": [ { "name": bkmkName, "address": bkmkAddress } ]
};
var openDBRequest = window.indexedDB.open("bookmarks", dbVersion + 1);
openDBRequest.onupgradeneeded = function (e) {
var db = e.target.result;
dbVersion++;
if (db.objectStoreNames.contains(newGroup.title)) {
window.alert("The group already exists");
return;
}
var objStore = db.createObjectStore(newGroup.title, { autoIncrement: true });
objStore.createIndex("name", "name", { unique: false });
objStore.createIndex("address", "address", { unique: false });
var bookmarks = newGroup.bookmarks;
for (var i = 0; i < bookmarks.length; i++) {
var bkmk = bookmarks[i];
objStore.add({ "name": bkmk.name, "address": bkmk.address }, i);
}
}
openDBRequest.onsuccess = function (e) { openDBRequest.onsuccess = function (e) {
var db = e.target.result; var db = e.target.result;
var groupsStore = db.transaction("Groups", "readwrite").objectStore("Groups");
var indexStore = db.transaction(["groupIndexes"], "readwrite") groupsStore.getAll().onsuccess = function (evt) {
.objectStore("groupIndexes"); // find the largest index and use that +1
var groups = evt.target.result;
indexStore.getAll().onsuccess = function (evt) { var largest = -1;
var items = evt.target.result; for (var group of groups) {
var largest = 0; if (group.groupIndex > largest)
for (let item of items) { largest = group.groupIndex;
if (item.groupIndex >= largest)
largest = item.groupIndex + 1;
} }
indexStore.add({ "title": newGroup.title, "groupIndex": largest }); var newGroup = {
bookmarkList[largest] = newGroup; groupIndex: largest + 1,
title: newGroupName,
bookmarks: [ { name: bkmkName, address: bkmkAddress } ]
};
groupsStore.add(newGroup);
// don't need to add to bookmarkList because loadBookmarks is
// being called
db.close(); db.close();
loadBookmarks(); loadBookmarks();
@ -84,22 +66,21 @@ function addNewBookmark(e) {
var openDBRequest = window.indexedDB.open("bookmarks"); var openDBRequest = window.indexedDB.open("bookmarks");
openDBRequest.onsuccess = function (e) { openDBRequest.onsuccess = function (e) {
var db = e.target.result; var db = e.target.result;
var newItem = { "name": bkmkName, "address": bkmkAddress };
db.transaction([bkmkGroup], "readwrite") var groupsStore = db.transaction("Groups", "readwrite").objectStore("Groups");
.objectStore(bkmkGroup)
.add(newItem);
for (let group of bookmarkList) { var groupReq = groupsStore.get(parseInt(bkmkGroup));
if (group.title == bkmkGroup) { groupReq.onsuccess = function (evt) {
group.bookmarks.push(newItem); var group = groupReq.result;
break;
} var newItem = { "name": bkmkName, "address": bkmkAddress };
group.bookmarks.push(newItem);
groupsStore.put(group);
db.close();
loadBookmarks();
$(".modal").modal("hide");
} }
db.close();
loadBookmarks();
$(".modal").modal("hide");
} }
openDBRequest.onerror = function (e) { console.log(e); } openDBRequest.onerror = function (e) { console.log(e); }

View file

@ -36,47 +36,59 @@ function toggleEditing (e) {
function deleteBookmark(e) { function deleteBookmark(e) {
var item = $(this); var item = $(this);
var group = item.data("group"); var group = item.data("group");
var key = item.data("key"); var key = item.data("key");
var groupIndex = item.data("group-index");
var bookmarkItem = $("#" + group + "-" + key);
var openDBRequest = window.indexedDB.open("bookmarks"); var openDBRequest = window.indexedDB.open("bookmarks");
openDBRequest.onsuccess = function (e) { openDBRequest.onsuccess = function (e) {
var db = e.target.result; var db = e.target.result;
var deleteRequest = db.transaction(group, "readwrite").objectStore(group).delete(key); var groupsStore = db.transaction("Groups", "readwrite").objectStore("Groups");
deleteRequest.onsuccess = function (evt) {
$("#" + group + "-" + key).remove(); groupsStore.get(groupIndex).onsuccess = function (getEvt) {
var groupData = getEvt.target.result;
// remove the bookmark from the group object
var bookmarkData = {name: bookmarkItem.data("name"), address: bookmarkItem.data("address")};
groupData.bookmarks = groupData.bookmarks.filter(function (item) {
if (item.name != bookmarkData.name && item.address != bookmarkData.address)
return true;
return false;
});
// no need to provide key since keyPath is set
groupsStore.put(groupData);
bookmarkItem.remove();
} }
} }
openDBRequest.onerror = function (evt) { openDBRequest.onerror = function (evt) {
console.log("Error", evt); console.log("Error", evt);
window.alert("There was an error deleting the bookmark");
} }
} }
function deleteGroup(e) { function deleteGroup(e) {
var group = $(this); // the delete group button var group = $(this); // the delete group button
var groupName = group.data("group"); var groupIndex = group.data("group");
var openDBRequest = window.indexedDB.open("bookmarks", dbVersion + 1); var openDBRequest = window.indexedDB.open("bookmarks");
openDBRequest.onupgradeneeded = function (e) { openDBRequest.onsuccess = function (dbe) {
var db = e.target.result; var db = dbe.target.result;
dbVersion++;
var deleteRequest = db.deleteObjectStore(groupName); var groupsStore = db.transaction("Groups", "readwrite").objectStore("Groups");
} var delReq = groupsStore.delete(groupIndex);
delReq.onsuccess = function (dele) {
openDBRequest.onsuccess = function (e) { $("#group-" + groupIndex).remove();
var db = e.target.result; }
var indexStore = db.transaction("groupIndexes", "readwrite").objectStore("groupIndexes");
indexStore.delete(groupName).onsuccess = function (evt) {
$("#group-" + groupName.replace(" ", "-")).parent().remove();
};
} }
openDBRequest.onerror = function (e) { openDBRequest.onerror = function (e) {
console.error(e); console.error(e);
window.alert("There was an error deleting the group");
} }
} }

View file

@ -1,11 +1,5 @@
$(document).ready(function () { $(document).ready(function () {
$("#importExportModal").on("shown.bs.modal", function () { $("#importExportModal").on("shown.bs.modal", showBookmarkData);
var data = JSON.stringify(bookmarkList, null, 4);
if (data != null)
$("#exportText").text(data);
else
$("#exportText").text("[]");
});
$("#btnImportDialog").click(importBookmarks); $("#btnImportDialog").click(importBookmarks);
@ -14,6 +8,22 @@ $(document).ready(function () {
}); });
}); });
function showBookmarkData() {
var openDBRequest = window.indexedDB.open("bookmarks");
openDBRequest.onsuccess = function (e) {
var db = e.target.result;
db.transaction("Groups").objectStore("Groups").getAllKeys().onsuccess = function (evt) {
var data = JSON.stringify(bookmarkList, null, 4);
if (data != null)
$("#exportText").text(data);
else
$("#exportText").text("[]");
}
}
}
function importBookmarks() { function importBookmarks() {
try { try {
var newData = $.parseJSON($("#importText").val()); var newData = $.parseJSON($("#importText").val());
@ -23,10 +33,9 @@ function importBookmarks() {
return; return;
} }
if (verifyBookmarks(newData)) { if (validateBookmarks(newData)) {
$("#btnImportDialog").prop("disabled", true);
setList(newData); setList(newData);
$("#importExportModal").modal("hide");
} else { } else {
window.alert("Invalid Format"); window.alert("Invalid Format");
} }
@ -36,38 +45,32 @@ function setList(data) {
// empty the DB and fill it with the new data // empty the DB and fill it with the new data
bookmarkList = data; bookmarkList = data;
try { var openDBRequest = window.indexedDB.open("bookmarks");
indexedDB.deleteDatabase("bookmarks");
} catch (err) {
// it's OK if the DB doesn't exist
if (err.name != "NotFoundError") {
console.error(err);
return;
}
}
var openDBRequest = window.indexedDB.open("bookmarks", 1);
openDBRequest.onsuccess = function (e) { openDBRequest.onsuccess = function (e) {
dbVersion = db.version; db = e.target.result;
var groupStore = db.transaction("Groups", "readwrite").objectStore("Groups");
groupStore.clear();
// create the object stores
for (group of data) {
groupStore.add(group);
}
$("#importExportModal").modal("hide");
$("#btnImportDialog").prop("disabled", false);
db.close(); db.close();
loadBookmarks(); loadBookmarks();
} }
openDBRequest.onerror = function (err) { console.error(err); } openDBRequest.onerror = function (err) { console.error(err); }
openDBRequest.onupgradeneeded = function (e) {
db = e.target.result;
var groupStore = initDB(db);
// create the object stores
for (var i = 0; i < data.length; i++) {
addGroup(data[i], groupStore, db, i);
}
}
} }
function verifyBookmarks(bookmarks) { function validateBookmarks(bookmarks) {
var indexes = [];
if (!Array.isArray(bookmarks)) if (!Array.isArray(bookmarks))
return false; return false;
@ -80,6 +83,14 @@ function verifyBookmarks(bookmarks) {
if (item.title == null || typeof item.title != "string") if (item.title == null || typeof item.title != "string")
return false; return false;
if (item.groupIndex == null || typeof item.groupIndex != "number")
return false;
if (arrayContains(indexes, item.groupIndex))
return false;
indexes.push(item.groupIndex);
for (var j = 0; j < item.bookmarks.length; j++) { for (var j = 0; j < item.bookmarks.length; j++) {
var bkmk = item.bookmarks[j]; var bkmk = item.bookmarks[j];
@ -96,3 +107,12 @@ function verifyBookmarks(bookmarks) {
return true; return true;
} }
function arrayContains(array, searchFor) {
for (item of array) {
if (item == searchFor)
return true;
}
return false;
}

View file

@ -9,31 +9,30 @@ function loadBookmarks() {
openDBRequest.onsuccess = function (dbEvt) { openDBRequest.onsuccess = function (dbEvt) {
db = dbEvt.target.result; db = dbEvt.target.result;
dbVersion = db.version; dbVersion = db.version;
bookmarkList = [];
db.transaction(["groupIndexes"], "readonly") db.transaction(["Groups"], "readonly").objectStore("Groups").getAll().onsuccess = function (groupsEvt) {
.objectStore("groupIndexes") var groups = groupsEvt.target.result;
.getAll() groups.sort(function (a, b) {
.onsuccess = function (indexEvt) { return a.groupIndex - b.groupIndex;
var indexes = indexEvt.target.result; });
indexes.sort(function (a, b) {
return a.groupIndex - b.groupIndex;
});
// use a placholder because getting the group info is async // use a placholder
// and groups could finish loading in a different order var cardList = $("#cardList");
var cardList = $("#cardList"); for (let groupData of groups) {
for (var i = 0; i < indexes.length; i++) { $("<div>").attr("id", "group-" + groupData.groupIndex)
$("<div>").attr("id", "group-" + indexes[i].groupIndex).appendTo(cardList); .addClass("bookmarkGroupContainer")
} .appendTo(cardList);
for (let item of indexes) {
buildGroup(item, $("#group-" + item.groupIndex));
}
db.close();
} }
;
bookmarkList = [];
for (let groupData of groups) {
buildGroup(groupData, $("#group-" + groupData.groupIndex));
bookmarkList.push(groupData);
}
db.close();
};
} }
openDBRequest.onerror = function (e) { console.log(e); } openDBRequest.onerror = function (e) { console.log(e); }
@ -43,81 +42,55 @@ function loadBookmarks() {
console.log("Creating database"); console.log("Creating database");
db = e.target.result; db = e.target.result;
var data = window.localStorage.getItem("bookmarks"); var groupStore = db.createObjectStore("Groups", {keyPath: "groupIndex"});
if (data != null) { groupStore.createIndex("groupIndex", "groupIndex", {unique: true});
console.log("Importing data from old version"); groupStore.createIndex("title", "title", {unique: false});
data = JSON.parse(data); groupStore.createIndex("bookmarks", "bookmarks", {unique: false});
db.close();
setList(data);
window.localStorage.removeItem("bookmarks");
} else {
var groupStore = initDB(db);
// add example bookmarks var groupData = {
var exBookmarks = db.createObjectStore("Examples", { autoIncrement: true }); groupIndex: 0,
exBookmarks.createIndex("name", "name", { unique: false }); title: "Examples",
exBookmarks.createIndex("address", "address", { unique: false }); bookmarks: [
groupStore.add({ "title": "Examples", "groupIndex": 0 }); {
"name": "Github",
"address": "https://github.com/"
},
{
"name": "This project on Github",
"address": "https://github.com/NeilBrommer/NewTabPage"
}
]
};
exBookmarks.add({ groupStore.add(groupData);
"name": "Github",
"address": "https://github.com/"
});
exBookmarks.add({
"name": "This project on Github",
"address": "https://github.com/NeilBrommer/NewTabPage"
});
exBookmarks.add({
"name": "Hacker News",
"address": "https://news.ycombinator.com/"
});
exBookmarks.add({
"name": "reddit",
"address": "https://www.reddit.com/"
});
$("#aboutModal").modal("show"); $("#aboutModal").modal("show");
}
} }
} }
function buildGroup(groupInfo, placeholder) { function buildGroup(groupInfo, placeholder) {
var groupTransaction = db.transaction([groupInfo.title], "readonly"); buildCard(groupInfo.title, groupInfo.groupIndex, groupInfo.bookmarks).appendTo(placeholder);
var groupStore = groupTransaction.objectStore(groupInfo.title);
var groupRequest = groupStore.getAll();
groupRequest.onsuccess = function (e) {
var bookmarks = e.target.result;
var keyRequest = groupStore.getAllKeys();
keyRequest.onsuccess = function (evt) {
var keys = evt.target.result;
for (var i = 0; i < bookmarks.length; i++) {
bookmarks[i].key = keys[i];
}
bookmarkList[groupInfo.groupIndex] = {
"title": groupInfo.title,
"bookmarks": bookmarks
};
buildCard(groupInfo.title, bookmarks).appendTo(placeholder);
}
}
} }
function buildCard(title, itemList) { function buildCard(title, groupIndex, itemList) {
var card = $("<div>"); var card = $("<div>");
card.attr({ card.attr({
"id": "group-" + title.replace(" ", "-"), "id": "group-" + groupIndex,
"class": "card" "class": "card",
"data-group-name": title,
"data-group-index": groupIndex
}); });
var cardHead = $("<div>"); var cardHead = $("<div>");
cardHead.addClass("card-header"); cardHead.addClass("card-header");
cardHead.text(title); cardHead.text(title);
var btnDrag = $("<span>").addClass("mr-2 start-hidden dragGroupHandle")
.append($("<span>").addClass("fas fa-bars"));
var btnDel = $("<span>") var btnDel = $("<span>")
.attr("data-group", title) .attr("data-group", groupIndex)
.addClass("btnDelGroup far fa-trash-alt float-right mt-1 start-hidden text-danger clickable"); .addClass("btnDelGroup far fa-trash-alt float-right mt-1 start-hidden text-danger clickable");
btnDel.appendTo(cardHead); btnDel.appendTo(cardHead);
btnDrag.prependTo(cardHead);
card.append(cardHead); card.append(cardHead);
var cardList = $("<div>"); var cardList = $("<div>");
@ -126,35 +99,29 @@ function buildCard(title, itemList) {
for (var i = 0; i < itemList.length; i++) { for (var i = 0; i < itemList.length; i++) {
var item = itemList[i]; var item = itemList[i];
// the fa span gets replaced with an svg element, which causes problems
// with using it as a drag handle, so wrap it in the drag element
var handle = $("<span>").addClass("mr-2 start-hidden dragHandle")
.append($("<span>").addClass("fas fa-bars"));
var del = $("<span>") var del = $("<span>")
.attr({"data-group": title, "data-key": item.key}) .attr({"data-group": title, "data-group-index": groupIndex, "data-key": i})
.addClass("btnDel far fa-trash-alt float-right mt-1 start-hidden text-danger"); .addClass("btnDel far fa-trash-alt float-right mt-1 start-hidden text-danger");
del.css("cursor: pointer;"); del.css("cursor: pointer;");
$("<a>") $("<a>")
.attr({ .attr({
"id": title + "-" + item.key, "id": title + "-" + i,
"class": "list-group-item list-group-item-action bookmark", "class": "list-group-item list-group-item-action bookmark",
"href": item.address, "href": item.address,
"data-name": item.name,
"data-address": item.address
}) })
.text(item.name) .text(item.name)
.prepend(handle)
.append(del) .append(del)
.appendTo(cardList); .appendTo(cardList);
} }
return card; return card;
} }
function addGroup(group, groupStore, db, index) {
var objStore = db.createObjectStore(group.title, { autoIncrement: true });
objStore.createIndex("name", "name", { unique: false });
objStore.createIndex("address", "address", { unique: false });
groupStore.add({ "title": group.title, "groupIndex": index });
var bookmarks = group.bookmarks;
for (var i = 0; i < bookmarks.length; i++) {
var bkmk = bookmarks[i];
objStore.add({ "name": bkmk.name, "address": bkmk.address }, i);
}
}

View file

@ -1,6 +1,5 @@
// use this when making changes so that there is no need to parse the page // use this when making changes so that there is no need to parse the page
var bookmarkList; var bookmarkList;
var dbVersion;
var backgroundList = ["img/1.png", "img/2.png", "img/3.png", "img/4.png", var backgroundList = ["img/1.png", "img/2.png", "img/3.png", "img/4.png",
"img/5.png", "img/6.png", "img/7.png", "img/8.png"]; "img/5.png", "img/6.png", "img/7.png", "img/8.png"];