vomebook commited on
Commit
d60c5d0
·
verified ·
1 Parent(s): d21599c

Persist the last search session

Browse files
Files changed (1) hide show
  1. static/app.js +50 -0
static/app.js CHANGED
@@ -89,6 +89,53 @@ const STATE = {
89
  _pageCache: {},
90
  _deferredAppendWhileDragging: false,
91
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  let searchAbortController = null;
93
  let searchPrefetchAbortController = null;
94
  let searchPrefetchKey = null;
@@ -1108,6 +1155,7 @@ const ROUTER = {
1108
  renderFilters(routeId);
1109
  }
1110
  routeInitialized = true;
 
1111
  },
1112
  updateUI() {
1113
  if (STATE.mode === "global") {
@@ -1180,6 +1228,7 @@ function syncStateToURL(replace = true) {
1180
  } else {
1181
  history.pushState(null, "", url);
1182
  }
 
1183
  }
1184
 
1185
  function syncURLToState() {
@@ -3071,6 +3120,7 @@ function setupResultDelegation() {
3071
 
3072
  async function init() {
3073
  cacheDOM();
 
3074
  setupReaderIntentWarming();
3075
  STATE.isDark = localStorage.getItem("theme") !== "light";
3076
  applyTheme();
 
89
  _pageCache: {},
90
  _deferredAppendWhileDragging: false,
91
  };
92
+
93
+ const SEARCH_SESSION_DB = "voiceofml-search-state";
94
+ function openSearchSessionDB() {
95
+ return new Promise((resolve, reject) => {
96
+ if (!window.indexedDB) return reject(new Error("IndexedDB unavailable"));
97
+ const request = indexedDB.open(SEARCH_SESSION_DB, 1);
98
+ request.onupgradeneeded = () => {
99
+ if (!request.result.objectStoreNames.contains("session")) request.result.createObjectStore("session");
100
+ };
101
+ request.onsuccess = () => resolve(request.result);
102
+ request.onerror = () => reject(request.error);
103
+ });
104
+ }
105
+
106
+ async function persistSearchSession() {
107
+ if (location.pathname.startsWith("/static/reader.html")) return;
108
+ try {
109
+ const db = await openSearchSessionDB();
110
+ const transaction = db.transaction("session", "readwrite");
111
+ transaction.objectStore("session").put({ version: 1, url: location.href, updatedAt: Date.now() }, "last-search");
112
+ await new Promise((resolve, reject) => {
113
+ transaction.oncomplete = resolve;
114
+ transaction.onerror = () => reject(transaction.error);
115
+ transaction.onabort = () => reject(transaction.error);
116
+ });
117
+ db.close();
118
+ } catch (_) {}
119
+ }
120
+
121
+ async function restoreSearchSession() {
122
+ if (location.pathname !== "/" || location.search || location.hash) return false;
123
+ try {
124
+ const db = await openSearchSessionDB();
125
+ const transaction = db.transaction("session", "readonly");
126
+ const request = transaction.objectStore("session").get("last-search");
127
+ const saved = await new Promise((resolve, reject) => {
128
+ request.onsuccess = () => resolve(request.result);
129
+ request.onerror = () => reject(request.error);
130
+ });
131
+ db.close();
132
+ if (!saved || saved.version !== 1 || typeof saved.url !== "string") return false;
133
+ const target = new URL(saved.url);
134
+ if (target.origin !== location.origin || target.pathname.split("/").filter(Boolean).length > 1 || target.pathname === "/static/reader.html") return false;
135
+ history.replaceState(null, "", target.href);
136
+ return true;
137
+ } catch (_) { return false; }
138
+ }
139
  let searchAbortController = null;
140
  let searchPrefetchAbortController = null;
141
  let searchPrefetchKey = null;
 
1155
  renderFilters(routeId);
1156
  }
1157
  routeInitialized = true;
1158
+ persistSearchSession();
1159
  },
1160
  updateUI() {
1161
  if (STATE.mode === "global") {
 
1228
  } else {
1229
  history.pushState(null, "", url);
1230
  }
1231
+ persistSearchSession();
1232
  }
1233
 
1234
  function syncURLToState() {
 
3120
 
3121
  async function init() {
3122
  cacheDOM();
3123
+ await restoreSearchSession();
3124
  setupReaderIntentWarming();
3125
  STATE.isDark = localStorage.getItem("theme") !== "light";
3126
  applyTheme();