1//-- indexedDB API 2_db = null; 3_db_init_called=false; 4_db_wait_counter=0; 5_db_retries=0; 6const _sleep = (milliseconds) => { 7 return new Promise(resolve => setTimeout(resolve, milliseconds)); 8} 9async function db(){ 10 let me_called_init=false; 11 //wait until _db created 12 while(_db==null) 13 { 14 if(_db_init_called==false) 15 { 16 _db_init_called=true; 17 me_called_init=true; 18 19 if(_db_retries>2) 20 { 21 let msg=`cannot open database... are you using private/incognito browsing? To enable storage use a normal browser window...`; 22 _db_retries=0; 23 _db_init_called=false; 24 throw new Error(msg); 25 } 26 console.error(`opening db ... ${_db_retries+1}.try`); 27 initDB(); 28 _db_retries+=1; 29 } 30 let wait_time=100; 31 await _sleep(wait_time); 32 if(me_called_init) 33 { 34 _db_wait_counter+=wait_time; 35 } 36 37 if(_db_wait_counter > 1500) 38 {//if opening db takes too long, retry 39 _db_init_called = false; 40 _db_wait_counter=0; 41 _me_called_init=false; 42 } 43 } 44 return _db; 45} 46 47 48function initDB() { 49 window.addEventListener('unhandledrejection', function(event) { 50 alert("Error: " + event.reason.message); 51 }); 52 53 54 let openReq = indexedDB.open('vc64db', 4); 55 56 openReq.onupgradeneeded = function (event){ 57 let _db = openReq.result; 58 switch (event.oldVersion) { 59 case 0: 60 //no db 61 break; 62 default: 63 break; 64 } 65 if(!_db.objectStoreNames.contains('snapshots')) 66 { 67 var snapshot_store=_db.createObjectStore('snapshots', {keyPath: 'id', autoIncrement: true}); 68 snapshot_store.createIndex("title", "title", { unique: false }); 69 } 70 if(!_db.objectStoreNames.contains('apps')) 71 { 72 var apps_store=_db.createObjectStore('apps', {keyPath: 'title'}); 73 } 74 75 //db.deleteObjectStore('custom_buttons'); 76 if(!_db.objectStoreNames.contains('custom_buttons')) 77 { 78 //alert("create two local object stores"); 79 var custom_buttons_store=_db.createObjectStore('custom_buttons', {keyPath: 'title'}); 80 } 81 82 }; 83 openReq.onerror = function() { 84 console.error("Error", openReq.error); 85 _db_wait_counter=1600; //flag this wait as unsuccessful 86 /*alert('error while open db: '+openReq.error);*/ 87 } 88 openReq.onsuccess = function() { 89 _db=openReq.result; 90 } 91} 92 93 94async function save_snapshot(the_name, the_data) { 95 //beim laden in die drop zone den Titel merken 96 //dann beim take snapshot, den titel automatisch mitgeben 97 //im Snapshotbrowser jeden titel als eigene row darstellen 98 //erste row autosnapshot, danach kommen die Titel 99 //extra user snapshot ist dann unnötig 100 let the_snapshot = { 101 title: the_name, 102 data: the_data //, 103// created: new Date() 104 }; 105 106 let tx_apps = (await db()).transaction('apps', 'readwrite'); 107 let req_apps = tx_apps.objectStore('apps').put({title: the_name}); 108 req_apps.onsuccess= function(e){ 109 console.log("wrote app with id="+e.target.result) 110 }; 111 112 113 let tx = (await db()).transaction('snapshots', 'readwrite'); 114 tx.oncomplete = function() { 115 console.log("Transaction is complete"); 116 }; 117 tx.onabort = function() { 118 console.log("Transaction is aborted"); 119 }; 120 121 try { 122 let req = tx.objectStore('snapshots').add(the_snapshot); 123 req.onsuccess= function(e){ 124 console.log("wrote snapshot with id="+e.target.result) 125 }; 126 req.onerror = function(e){ 127 console.error("could not write snapshot: ", req.error) 128 }; 129 } catch(err) { 130 if (err.name == 'ConstraintError') { 131 alert("Such snapshot exists already"); 132 } else { 133 throw err; 134 } 135 } 136} 137 138async function get_stored_app_titles(callback_fn) 139{ 140 let transaction = (await db()).transaction("apps"); // readonly 141 let apps = transaction.objectStore("apps"); 142 143 let request = apps.getAllKeys(); 144 145 request.onsuccess = function() { 146 if (request.result !== undefined) { 147 callback_fn(request.result); 148 } else { 149 console.log("No titles found"); 150 } 151 }; 152} 153 154function stored_app_titles() { 155 return new Promise((resolve, reject) => { 156 get_stored_app_titles((result) => { 157 resolve(result); 158 }); 159 }); 160} 161 162function get_snapshots_for_app_title(app_title) 163{ 164 return new Promise(async (resolve, reject) => { 165 let transaction = (await db()).transaction("snapshots"); 166 let snapshots = transaction.objectStore("snapshots"); 167 let titleIndex = snapshots.index("title"); 168 let request = titleIndex.getAll(app_title); 169 170 request.onsuccess = function() { 171 resolve(request.result); 172 }; 173 }); 174} 175 176 177async function get_snapshot_per_id(the_id, callback_fn) 178{ 179 let transaction = (await db()).transaction("snapshots"); 180 let snapshots = transaction.objectStore("snapshots"); 181 182 let request = snapshots.get(parseInt(the_id)); 183 184 request.onsuccess = function() { 185 callback_fn(request.result); 186 }; 187} 188 189function delete_snapshot_per_id(the_id) 190{ 191 get_snapshot_per_id(the_id, 192 async function(the_snapshot) { 193 let transaction = (await db()).transaction("snapshots", 'readwrite'); 194 let snapshots = transaction.objectStore("snapshots"); 195 snapshots.delete(parseInt(the_id)); 196 //check if this was the last snapshot of the game title 197 get_snapshots_for_app_title(0, the_snapshot.title, 198 async function (ctx, app_title, snapshot_list) { 199 if(snapshot_list.length == 0) 200 {//when it was the last one, then also delete the app title 201 let tx_apps = (await db()).transaction("apps", 'readwrite'); 202 let apps = tx_apps.objectStore("apps"); 203 apps.delete(app_title); 204 } 205 } 206 ); 207 }); 208} 209 210 211//--- local storage API --- 212 213 214function local_storage_get(name) { 215 try{ 216 return localStorage.getItem(name); 217 } 218 catch(e) { 219 console.error(e.message); 220 return null; 221 } 222} 223function local_storage_set(name, value) { 224 try{ 225 localStorage.setItem(name,value); 226 } 227 catch(e) { 228 console.error(e.message); 229 } 230} 231function local_storage_remove(name) { 232 try{ 233 localStorage.removeItem(name); 234 } 235 catch(e) { 236 console.error(e.message); 237 } 238} 239 240 241 242 243function load_setting(name, default_value) { 244 var value = local_storage_get(name); 245 if(value === null) 246 { 247 return default_value; 248 } 249 else 250 { 251 if(value=='true') 252 return true; 253 else if(value=='false') 254 return false;
255 else 256 return value; 257 } 258} 259 260function save_setting(name, value) { 261 if (value!= null) { 262 local_storage_set(name, value); 263 } else { 264 local_storage_remove(name); 265 } 266} 267 268 269 270 271 272 273//-------------- custom buttons 274 275function save_new_empty_group(the_name) { 276 save_custom_buttons_scope(the_name, []); 277} 278 279function save_custom_buttons(the_name, the_data) { 280 var app_specific_data=[]; 281 var global_data=[]; 282 283 for(button_def_id in the_data) 284 { 285 var button_def=the_data[button_def_id]; 286 if(button_def.transient !== undefined && button_def.transient) 287 { 288 //don't save transient buttons 289 } 290 else if(button_def.app_scope) 291 { 292 app_specific_data.push(button_def); 293 } 294 else 295 { 296 global_data.push(button_def); 297 } 298 } 299 save_custom_buttons_scope(the_name, app_specific_data); 300 save_custom_buttons_scope('__global_scope__', global_data); 301} 302 303 304 305async function save_custom_buttons_scope(the_name, the_data) { 306 let the_custom_buttons = { 307 title: the_name, 308 data: the_data 309 }; 310 311 let tx_apps = (await db()).transaction('apps', 'readwrite'); 312 let req_apps = tx_apps.objectStore('apps').put({title: the_name}); 313 req_apps.onsuccess= function(e){ 314 console.log("wrote app with id="+e.target.result) 315 }; 316 317 318 let tx = (await db()).transaction('custom_buttons', 'readwrite'); 319 tx.oncomplete = function() { 320 console.log("Transaction is complete"); 321 }; 322 tx.onabort = function() { 323 console.log("Transaction is aborted"); 324 }; 325 326 try { 327 let req = tx.objectStore('custom_buttons').put(the_custom_buttons); 328 req.onsuccess= function(e){ 329 console.log("wrote custom_buttons with id="+e.target.result) 330 }; 331 req.onerror = function(e){ 332 console.error("could not write custom_buttons: ", req.error) 333 }; 334 } catch(err) { 335 throw err; 336 } 337} 338 339 340 341var buttons_from_mixed_scopes = null; 342function get_custom_buttons(the_app_title, callback_fn) 343{ 344 get_custom_buttons_app_scope(the_app_title, 345 function(the_buttons) { 346 buttons_from_mixed_scopes = the_buttons; 347 348 //add globals 349 get_custom_buttons_app_scope('__global_scope__', 350 function(the_global_buttons) { 351 352 var last_id_in_appscope= buttons_from_mixed_scopes.data.length-1; 353 for(gb_id in the_global_buttons.data) 354 { 355 var gb = the_global_buttons.data[gb_id]; 356 last_id_in_appscope++; 357 gb.id=last_id_in_appscope; 358 buttons_from_mixed_scopes.data.push(gb); 359 } 360 callback_fn(buttons_from_mixed_scopes.data); 361 } 362 ); 363 } 364 ); 365} 366 367 368async function get_custom_buttons_app_scope(the_app_title, callback_fn) 369{ 370// if(_db === undefined) 371// return; 372 try 373 { 374 let transaction = (await db()).transaction("custom_buttons"); 375 let custom_buttons = transaction.objectStore("custom_buttons"); 376 377 let request = custom_buttons.get(the_app_title); 378 379 request.onsuccess = function() { 380 if(request.result !== undefined) 381 { 382 for(button_id in request.result.data) 383 { 384 var action_button = request.result.data[button_id]; 385 if(action_button.app_scope === undefined) 386 { 387 action_button.app_scope= true; 388 } 389 if(action_button.lang === undefined) 390 { 391 //migration of js: prefix to lang property, can be removed in a later version ... 392 if(action_button.script.startsWith("js:")) 393 { 394 action_button.script = action_button.script.substring(3); 395 action_button.lang = "javascript"; 396 } 397 else 398 { 399 action_button.lang = "actionscript"; 400 } 401 } 402 } 403 404 callback_fn(request.result); 405 } 406 else 407 { 408 let empty_custom_buttons = { 409 title: the_app_title, 410 data: [] 411 }; 412 413 callback_fn(empty_custom_buttons); 414 } 415 }; 416 }
417 catch(e) 418 { 419 console.error(e.message); 420 let empty_custom_buttons = { 421 title: the_app_title, 422 data: [] 423 }; 424 callback_fn(empty_custom_buttons); 425 } 426} 427 428async function get_stored_groups(callback_fn) 429{ 430 let transaction = (await db()).transaction("custom_buttons"); // readonly 431 let custom_buttons = transaction.objectStore("custom_buttons"); 432 433 let request = custom_buttons.getAllKeys(); 434 435 request.onsuccess = function() { 436 if (request.result !== undefined) { 437 callback_fn(request.result); 438 } else { 439 console.log("No titles found"); 440 } 441 }; 442} 443function stored_groups() { 444 return new Promise((resolve, reject) => { 445 get_stored_groups((result) => { 446 resolve(result); 447 }); 448 }); 449} 450 451async function delete_button_group(key) 452{ 453 let tx_apps = (await db()).transaction("custom_buttons", 'readwrite'); 454 let custom_buttons = tx_apps.objectStore("custom_buttons"); 455 custom_buttons.delete(key); 456}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.