diff --git a/main.js b/main.js
index 51174d8..0741dfb 100644
--- a/main.js
+++ b/main.js
@@ -51,12 +51,188 @@ function systemMsg (message,level=0) { // abstraction?
// but later we will also have it push an error toast in the ui.
}
+function initDatabase (e) {
+ var db = e.target.result;
+ var objectStore = db.createObjectStore("pecs", {keyPath: "word"});
+ objectStore.createIndex("word", "word", {unique: true});
+ objectStore.createIndex("locate", "locate");
+}
+
+function saveApp () {
+ var idbHandle = window.indexedDB.open("masterLibrary");
+ idbHandle.onerror = (e) => {
+ systemMsg("Error loading database",2);
+ };
+ idbHandle.onupgradeneeded = initDatabase;
+ idbHandle.onsuccess = (e) => {
+ var masterLibrary = idbHandle.result;
+ var saving = masterLibrary.transaction("pecs","readwrite",{durability:"strict"});
+ var pecStore = saving.objectStore("pecs");
+ library.forEach(pecItem=>{
+ var action = pecStore.get(pecItem.word);
+ action.onsuccess = (e)=>{
+ var record = action.result;
+ if (record == undefined) {
+ record = {
+ word: pecItem.word,
+ image: pecItem.image,
+ locate: "library"
+ };
+ } else {
+ record.locate = "library";
+ }
+ pecStore.put(record);
+ };
+ });
+ for (var boardID = 0; boardID < app.boards.length; boardID++) {
+ var curBoard = app.boards[boardID];
+ for (var index = 0; index < curBoard.pecs.length; index++) {
+ var curPec = curBoard.pecs[index];
+ if (null == curPec) { continue; } //don't store nulls
+ var action = pecStore.get(curPec.word);
+ action.curPec = curPec;
+ action.boardID = boardID;
+ action.pecIndex = index;
+ action.onsuccess = (e)=>{
+ var record = e.target.result;
+ if (record == undefined) {
+ record = {
+ word: e.target.curPec.word,
+ image: e.target.curPec.image,
+ locate: e.target.boardID + "-" + e.target.pecIndex
+ };
+ } else {
+ record.locate = e.target.boardID + "-" + e.target.pecIndex;
+ }
+ pecStore.put(record);
+ };
+ }
+ }
+ saving.oncomplete = (e)=>{
+ masterLibrary.close();
+ saveOptions();
+ loadApp();
+ };
+ };
+}
+
+function saveOptions () {
+ localStorage.setItem("librepecSettings", JSON.stringify(app.options));
+}
+
+function loadOptions () {
+ var options = JSON.parse(localStorage.getItem("librepecSettings"));
+ if (null != options) { app.options = options; }
+ var darkmode = document.getElementById("darkmode-checkbox");
+ var kidsmode = document.getElementById("kidsmode-checkbox");
+ var feedback = document.getElementById("audio-feedback-toggle");
+ var floodLimit = document.getElementById("flood-limit");
+ var floodTimeout = document.getElementById("flood-timeout");
+ darkmode.checked = (undefined == app.options?.darkmode) ? false : (app.options.darkmode ? true : false);
+ toggleDarkmode(darkmode.checked);
+ kidsmode.checked = (undefined == app.options?.kidsmode) ? false : (app.options.kidsmode ? true : false);
+ feedback.checked = (undefined == app.options?.audioFeedback) ? false : (app.options.audioFeedback ? true : false);
+ floodLimit.value = (undefined == app.options?.feedbackFloodLimit) ? 3 : app.options.feedbackFloodLimit;
+ floodTimeout.value = (undefined == app.options?.feedbackTimeout) ? 60 : app.options.feedbackTimeout;
+}
+
+import { library as library } from './library.js';
+
+function initApp () {
+ // Create our initial board
+ app.boards = [];
+ app.boards.push(new pecBoard());
+ app.currentBoard = app.boards[0];
+ repopBoards(0);
+ repopGrid(app.currentBoard);
+
+ // Populate Library
+ app.library = library;
+ repopLibrary();
+
+ // Populate Options
+ app.options = {};
+ app.options.darkmode = false; // should always be an option
+ app.options.kidsMode = false; // disables most interactions
+ app.options.audioFeedback = false; // read word aloude
+ app.options.feedbackFloodLimit = 3;
+ app.options.feedbackTimeout = 60; // 60 seconds
+ // overload defaults with options stored in localstorage
+}
+
+function hardResetApp () {
+ alert("App ahs been hard reset");
+ initApp();
+ saveApp();
+}
+
+function loadAppPec (item) {
+ var locate = item.locate;
+ if ("library" == locate) {
+ app.library.push(new pec(item.word, item.image));
+ } else {
+ locate = locate.split("-").map(n=>parseInt(n));
+ if (!(app.boards[locate[0]] instanceof pecBoard)) {
+ app.boards[locate[0]] = new pecBoard();
+ }
+ app.boards[locate[0]].pecs[locate[1]] = new pec(item.word, item.image);
+ }
+}
+
+function loadApp () {
+ var idbHandle = window.indexedDB.open("masterLibrary");
+ idbHandle.onerror = (e) => {
+ systemMsg("Error loading database",2);
+ };
+ idbHandle.onupgradeneeded = initDatabase;
+ window.currentBoardID = app.boards.indexOf(app.currentBoard);
+ currentBoardID = isNaN(currentBoardID) ? 0 : currentBoardID;
+ idbHandle.onsuccess = (e) => {
+ var masterLibrary = idbHandle.result;
+ var loading = masterLibrary.transaction("pecs","readonly",{durability:"strict"});
+ var pecStore = loading.objectStore("pecs");
+ var lengthCheck = pecStore.count();
+ lengthCheck.onsuccess = (e)=>{
+ if (0 < e.target.result) {
+ app.library = []; // Clear out library cache
+ app.boards = []; // Clear out boards cache
+ app.boards.push(new pecBoard());
+ app.currentBoard = app.boards[0];
+ var cursor = pecStore.openCursor();
+ cursor.onsuccess = (e) => {
+ var c = e.target.result;
+ if (c) {
+ loadAppPec(c.value);
+ c.continue();
+ }
+ };
+ } else {
+ // DB is empty, reinit app because
+ // we have nothing to load
+ hardResetApp();
+ }
+ };
+ loading.oncomplete = (e) => {
+ masterLibrary.close();
+ loadOptions();
+ app.currentBoard = app.boards[currentBoardID];
+ repopLibrary();
+ repopBoards();
+ repopGrid(app.currentBoard);
+ };
+ };
+}
+
function toggleDarkmode () {
var html = document.documentElement;
- if (html.classList.contains("darkmode")) {
- html.classList.remove("darkmode");
+ if (app.options.darkmode) {
+ if (!(html.classList.contains("darkmode"))) {
+ html.classList.add("darkmode");
+ }
} else {
- html.classList.add("darkmode");
+ if (html.classList.contains("darkmode")) {
+ html.classList.remove("darkmode");
+ }
}
}
@@ -66,6 +242,7 @@ function inRange(target,min,max) {
}
function invokeLibrary(e) {
+ if (app.options.kidsmode) { return; }
// Breaking this out of event so its not an
// annon function, so we can swap it in and out
var targetID = ((e.currentTarget.getAttribute("id")).split("pec"))[1];
@@ -122,6 +299,7 @@ function repopBoards (current=0) {
if (i == app.boards.length) {
name = "+";
boardTab.addEventListener("click",(e)=>{
+ if (app.options.kidsmode) { return; }
var current = app.boards.findIndex(i=>i==app.currentBoard);
app.boards.push(new pecBoard());
repopBoards(current);
@@ -139,6 +317,7 @@ function repopBoards (current=0) {
} else {
boardTab.classList.add("active_board");
}
+ if (undefined == app.boards[i]) { app.boards[i] = new pecBoard(); }
if (undefined != app.boards[i].name) {
name = app.boards[i].name;
}
@@ -165,6 +344,7 @@ function useThisPec (e) {
var sourceID = ((e.currentTarget.getAttribute("id")).split("lPec"))[1];
app.gui.library.root.classList.remove("focused");
app.currentBoard.pecs[app.targetPecIndex] = app.library.splice(sourceID,1)[0];
+ saveApp();
repopLibrary();
repopGrid(app.currentBoard);
}
@@ -173,6 +353,7 @@ function createNewPec () {
var name = app.gui.newpec_name.value;
var image = app.gui.newpec_image.files[0];
app.library.push(new pec(name, URL.createObjectURL(image)));
+ saveApp();
repopLibrary();
app.gui.newpec.root.classList.remove("focused");
}
@@ -233,6 +414,7 @@ function repopLibrary () {
app.gui.library.body.appendChild(newPec);
}
+
// Initialize gui
window.app = {};
@@ -258,7 +440,25 @@ app.gui.main.append(app.gui.library.root);
app.gui.options = new auxillery_dialog("Options");
app.gui.options.body.classList.add("options_body");
app.gui.main.append(app.gui.options.root);
-app.gui.optionsButton.addEventListener("click", ()=>{ app.gui.options.root.classList.add("focused") });
+app.gui.optionsButton.addEventListener("click", ()=>{
+ if (app.options.kidsmode) { return; }
+ loadOptions();
+ app.gui.options.root.classList.add("focused");
+});
+app.gui.optionsButton.addEventListener("mousedown", ()=>{
+ if (!app.options.kidsmode) { return; }
+ app.gui.optionsButton.classList.add("holding");
+ app.optionHold = setTimeout(()=>{
+ app.gui.optionsButton.classList.remove("holding");
+ loadOptions();
+ app.gui.options.root.classList.add("focused");
+ },3000);
+});
+app.gui.optionsButton.addEventListener("mouseup", ()=>{
+ if (!app.options.kidsmode) { return; }
+ app.gui.optionsButton.classList.remove("holding");
+ clearTimeout(app.optionHold);
+});
// New Pec popup
app.gui.newpec = new auxillery_dialog("Create New Pec");
app.gui.newpec.body.classList.add("newpec_body");
@@ -273,48 +473,61 @@ for (var x = 0; x < 16; x++) {
clearPec(x);
app.gui.view.appendChild(thisPec);
}
-// Create our initial board
-app.boards = [];
-app.boards.push(new pecBoard());
-app.currentBoard = app.boards[0];
-repopBoards(0);
-repopGrid(app.currentBoard);
-
-// Populate Library
-import { library as library } from './library.js';
-app.library = library;
-repopLibrary();
-
-// Populate Options
-app.options = {};
-app.options.darkmode = false; // should always be an option
-app.options.audioFeedback = false; // read word aloude
-app.options.feedbackFloodLimit = 3;
-app.options.feedbackTimeout = 60; // 60 seconds
-// overload defaults with options stored in localstorage
// build Options UI
app.gui.options_darkmode = document.createElement("div");
app.gui.options.body.appendChild(app.gui.options_darkmode);
app.gui.options_darkmode.innerHTML = ' ';
-app.gui.options_darkmode.addEventListener("change", toggleDarkmode);
+app.gui.options_darkmode.addEventListener("change", (e)=>{
+ app.options.darkmode = e.target.checked;
+ toggleDarkmode();
+ saveOptions();
+});
+
+app.gui.options_kidsmode = document.createElement("div");
+app.gui.options.body.appendChild(app.gui.options_kidsmode);
+app.gui.options_kidsmode.innerHTML = ' ';
+app.gui.options_kidsmode.addEventListener("change", (e) => {
+ app.options.kidsmode = e.target.checked;
+ saveOptions();
+});
app.gui.options_audioFeedback = document.createElement("div");
app.gui.options.body.appendChild(app.gui.options_audioFeedback);
app.gui.options_audioFeedback.innerHTML = ' ';
+app.gui.options_audioFeedback.addEventListener("change", (e) => {
+ app.options.audioFeedback = e.target.checked;
+ saveOptions();
+});
app.gui.options_feedbackFloodLimit = document.createElement("div");
app.gui.options.body.appendChild(app.gui.options_feedbackFloodLimit);
app.gui.options_feedbackFloodLimit.innerHTML = ' ';
+app.gui.options_feedbackFloodLimit.addEventListener("change", (e) => {
+ app.options.feedbackFloodLimit = e.target.value;
+ saveOptions();
+});
app.gui.options_feedbackTimeout = document.createElement("div");
app.gui.options.body.appendChild(app.gui.options_feedbackTimeout);
app.gui.options_feedbackTimeout.innerHTML = ' ';
+app.gui.options_feedbackTimeout.addEventListener("change", (e) => {
+ app.options.feedbackTimeout = e.target.value;
+ saveOptions();
+});
+
+app.gui.options_reset = document.createElement("div");
+app.gui.options.body.appendChild(app.gui.options_reset);
+app.gui.options_reset.innerHTML = 'Completely Reset App (hold down for 3 seconds)Clear All Boards';
+app.gui.options_reset_hard = document.getElementById("reset-hard-reset");
+app.gui.options_reset_soft = document.getElementById("reset-soft-reset");
+// Add functionality for resets here
app.gui.options_about = document.createElement("div");
app.gui.options.body.appendChild(app.gui.options_about);
app.gui.options_about.innerHTML = 'App licenced Cards from
Project Source labs.murkfall.net';
+// Build New Pec UI
app.gui.newpec.body.innerHTML = '