Skip to content

Commit 03cdcbf

Browse files
committed
wrote storage js using indexedDB to store also larger stories. stores objects directly instead of stringified JSON
1 parent 1779c39 commit 03cdcbf

File tree

4 files changed

+186
-60
lines changed

4 files changed

+186
-60
lines changed

commons/storage.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
const db_name = "story_adventure";
2+
const db_version = 1;
3+
const store_name = "stories";
4+
5+
let db;
6+
7+
async function init() {
8+
return new Promise((resolve, reject) => {
9+
const open_request = window.indexedDB.open(db_name, db_version);
10+
11+
// Register two event handlers to act on the database being opened successfully, or not
12+
open_request.onerror = (event) => {
13+
console.error("Error loading database.", event);
14+
reject(event?.error);
15+
};
16+
17+
open_request.onupgradeneeded = (event) => {
18+
db = event.target.result;
19+
20+
db.onerror = (event) => {
21+
console.error("Error loading database.", event);
22+
reject(event?.error);
23+
};
24+
db.createObjectStore(store_name, {
25+
keyPath: "id",
26+
});
27+
console.log("Object store created.");
28+
};
29+
30+
open_request.onsuccess = function (event) {
31+
console.log("Database opened.");
32+
db = open_request.result;
33+
resolve(db);
34+
};
35+
});
36+
}
37+
38+
async function open_transaction() {
39+
if (!db) {
40+
await init();
41+
}
42+
const transaction = db.transaction([store_name], "readwrite");
43+
transaction.onerror = () => {
44+
console.error(`Transaction not opened due to error: ${transaction.error}`);
45+
};
46+
return transaction;
47+
}
48+
49+
export async function save_story(id, story) {
50+
console.debug("save", id);
51+
const transaction = await open_transaction();
52+
53+
return new Promise((resolve, reject) => {
54+
const new_item = {
55+
id: id,
56+
story: story,
57+
};
58+
59+
resolve_store_request(
60+
transaction.objectStore(store_name).get(id),
61+
() => {
62+
resolve_store_request(
63+
transaction.objectStore(store_name).put(new_item),
64+
resolve,
65+
reject
66+
);
67+
},
68+
() => {
69+
resolve_store_request(
70+
transaction.objectStore(store_name).add(new_item),
71+
resolve,
72+
reject
73+
);
74+
}
75+
);
76+
});
77+
}
78+
79+
function resolve_store_request(store_request, resolve, reject) {
80+
store_request.onsuccess = (event) => {
81+
const item = store_request?.result;
82+
console.debug("successful store event for key", item?.id);
83+
resolve(item?.story);
84+
};
85+
store_request.onerror = (event) => {
86+
const error = event?.error || event?.target?.error;
87+
console.log("Error in store event", event);
88+
reject(error);
89+
};
90+
}
91+
92+
export async function get_story(id) {
93+
console.debug("get", id);
94+
const transaction = await open_transaction();
95+
return new Promise((resolve, reject) => {
96+
resolve_store_request(
97+
transaction.objectStore(store_name).get(id),
98+
resolve,
99+
reject
100+
);
101+
});
102+
}

commons/utils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export function get_text_from_section(section, variables) {
5151
return replace_variables(text, variables);
5252
}
5353

54+
5455
export const tools_files = {
5556
files: ["LICENSE"],
5657
folders: {

editor/code.js

Lines changed: 82 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
tools_files,
1313
} from "./utils.js";
1414

15+
import { save_story, get_story } from "./storage.js";
16+
1517
const data_url_regexp = /^data:image\/([a-z]*);base64,(.*)$/;
1618

1719
var story = {};
@@ -712,15 +714,20 @@ async function download_graph_split() {
712714

713715
folder.file(get_file_safe_title() + ".json", JSON.stringify(story_deep_copy));
714716

715-
add_stroy_adventure_files(zip).then(() => {
716-
toast_ok("Generating Zip");
717-
zip.generateAsync({ type: "base64" }).then(function (content) {
718-
trigger_data_dl(
719-
"data:application/zip;base64," + content,
720-
get_file_safe_title() + ".zip"
721-
);
717+
add_stroy_adventure_files(zip)
718+
.then(() => {
719+
toast_ok("Generating Zip");
720+
zip.generateAsync({ type: "base64" }).then(function (content) {
721+
trigger_data_dl(
722+
"data:application/zip;base64," + content,
723+
get_file_safe_title() + ".zip"
724+
);
725+
});
726+
})
727+
.catch((err) => {
728+
console.error("Error generating story adventure zip", err);
729+
toast_alert("Error generating bundle.");
722730
});
723-
});
724731
}
725732

726733
async function add_to_zip(zip, folder, global_path = "../") {
@@ -996,53 +1003,10 @@ function add_action() {
9961003
text_editor_load(active_section);
9971004
}
9981005

999-
text_area.addEventListener("change", handle_text_change);
1000-
1001-
text_area.addEventListener("paste", paste_image);
1002-
1003-
delete_button.addEventListener("click", handle_delete);
1004-
add_node_button.addEventListener("click", handle_add_node);
1005-
add_edge_button.addEventListener("click", handle_add_edge);
1006-
1007-
document
1008-
.getElementById("download_as_is_button")
1009-
.addEventListener("click", download_as_is);
1010-
document
1011-
.getElementById("download_in_one_button")
1012-
.addEventListener("click", download_graph_in_one);
1013-
document
1014-
.getElementById("download_split_button")
1015-
.addEventListener("click", download_graph_split);
1016-
load_button.addEventListener("click", load_graph);
1017-
document
1018-
.getElementById("clear_all_button")
1019-
.addEventListener("click", new_story);
1020-
add_media_button.addEventListener("click", add_or_remove_media);
1021-
document
1022-
.getElementById("redraw_button")
1023-
.addEventListener("click", redraw_adventure_graph);
1024-
1025-
document
1026-
.getElementById("linearize_button")
1027-
.addEventListener("click", create_linear_story);
1028-
1029-
document.addEventListener("keydown", handle_global_key_down);
1030-
1031-
document
1032-
.getElementById("story_modal")
1033-
.addEventListener("shown.bs.modal", () => {
1034-
document.getElementById("story_code").innerHTML = JSON.stringify(
1035-
story,
1036-
null,
1037-
2
1038-
);
1039-
});
1040-
10411006
async function load_last_story_or_example() {
10421007
try {
1043-
const storyJson = localStorage.getItem(current_editor_story_key);
1044-
if (storyJson) {
1045-
story = JSON.parse(storyJson);
1008+
story = await get_story(current_editor_story_key);
1009+
if (story) {
10461010
return;
10471011
}
10481012
} catch (err) {
@@ -1141,7 +1105,10 @@ async function depth_first_search(linearized_history, end_at, passing_through) {
11411105
console.debug("dfs reached target", end_at);
11421106
if (passing_through) {
11431107
for (const passing of passing_through) {
1144-
if (!linearized_history.includes(String(passing)) && !linearized_history.includes(Number(passing)) ) {
1108+
if (
1109+
!linearized_history.includes(String(passing)) &&
1110+
!linearized_history.includes(Number(passing))
1111+
) {
11451112
console.debug(linearized_history, "not passing through", passing);
11461113
return null;
11471114
}
@@ -1182,12 +1149,22 @@ async function depth_first_search(linearized_history, end_at, passing_through) {
11821149
return null;
11831150
}
11841151

1185-
function local_save() {
1186-
console.debug("local save");
1187-
localStorage.setItem(
1188-
current_editor_story_key,
1189-
JSON.stringify(story, null, 2)
1190-
);
1152+
var error_in_autosave_reported = false;
1153+
async function local_save() {
1154+
try {
1155+
console.debug("local save");
1156+
await save_story(current_editor_story_key, story);
1157+
if (error_in_autosave_reported) {
1158+
toast_ok("Autosaving is working.");
1159+
}
1160+
error_in_autosave_reported = false;
1161+
} catch (err) {
1162+
console.error("Error in autosave", err);
1163+
if (!error_in_autosave_reported) {
1164+
toast_alert("Error auto-saving the story.");
1165+
}
1166+
error_in_autosave_reported = true;
1167+
}
11911168
}
11921169

11931170
function set_save_interval() {
@@ -1200,8 +1177,53 @@ function on_load() {
12001177
}
12011178

12021179
async function init() {
1180+
add_listeners();
12031181
load_last_story_or_example().then(on_load);
12041182
set_save_interval();
12051183
}
12061184

1185+
function add_listeners() {
1186+
text_area.addEventListener("change", handle_text_change);
1187+
1188+
text_area.addEventListener("paste", paste_image);
1189+
1190+
delete_button.addEventListener("click", handle_delete);
1191+
add_node_button.addEventListener("click", handle_add_node);
1192+
add_edge_button.addEventListener("click", handle_add_edge);
1193+
1194+
document
1195+
.getElementById("download_as_is_button")
1196+
.addEventListener("click", download_as_is);
1197+
document
1198+
.getElementById("download_in_one_button")
1199+
.addEventListener("click", download_graph_in_one);
1200+
document
1201+
.getElementById("download_split_button")
1202+
.addEventListener("click", download_graph_split);
1203+
load_button.addEventListener("click", load_graph);
1204+
document
1205+
.getElementById("clear_all_button")
1206+
.addEventListener("click", new_story);
1207+
add_media_button.addEventListener("click", add_or_remove_media);
1208+
document
1209+
.getElementById("redraw_button")
1210+
.addEventListener("click", redraw_adventure_graph);
1211+
1212+
document
1213+
.getElementById("linearize_button")
1214+
.addEventListener("click", create_linear_story);
1215+
1216+
document.addEventListener("keydown", handle_global_key_down);
1217+
1218+
document
1219+
.getElementById("story_modal")
1220+
.addEventListener("shown.bs.modal", () => {
1221+
document.getElementById("story_code").innerHTML = JSON.stringify(
1222+
story,
1223+
null,
1224+
2
1225+
);
1226+
});
1227+
}
1228+
12071229
init();

editor/storage.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../commons/storage.js

0 commit comments

Comments
 (0)