use localForage for file store
This commit is contained in:
parent
436a476aff
commit
beea5c3774
|
@ -19,3 +19,6 @@
|
||||||
[submodule "gif.js"]
|
[submodule "gif.js"]
|
||||||
path = gif.js
|
path = gif.js
|
||||||
url = https://github.com/sehugg/gif.js
|
url = https://github.com/sehugg/gif.js
|
||||||
|
[submodule "localForage"]
|
||||||
|
path = localForage
|
||||||
|
url = https://github.com/localForage/localForage
|
||||||
|
|
|
@ -205,7 +205,7 @@ ga('send', 'pageview');
|
||||||
|
|
||||||
<script src="javatari.js/release/javatari/javatari.js"></script>
|
<script src="javatari.js/release/javatari/javatari.js"></script>
|
||||||
<script src="src/cpu/z80fast.js"></script>
|
<script src="src/cpu/z80fast.js"></script>
|
||||||
<script src="src/cpu/6809.js"></script>
|
<!--<script src="src/cpu/6809.js"></script>-->
|
||||||
<!--
|
<!--
|
||||||
<script src="jsnes/build/jsnes.min.js"></script>
|
<script src="jsnes/build/jsnes.min.js"></script>
|
||||||
<script src="jsnes/lib/dynamicaudio-min.js" type="text/javascript" charset="utf-8"></script>
|
<script src="jsnes/lib/dynamicaudio-min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
@ -222,7 +222,9 @@ ga('send', 'pageview');
|
||||||
<script src="FileSaver.js/FileSaver.min.js"></script>
|
<script src="FileSaver.js/FileSaver.min.js"></script>
|
||||||
<script src="octokat.js/dist/octokat.js"></script>
|
<script src="octokat.js/dist/octokat.js"></script>
|
||||||
<script src="gif.js/dist/gif.js"></script>
|
<script src="gif.js/dist/gif.js"></script>
|
||||||
|
<script src="localForage/dist/localforage.nopromises.js"></script>
|
||||||
|
|
||||||
|
<script src="src/store.js"></script>
|
||||||
<script src="src/vlist.js"></script>
|
<script src="src/vlist.js"></script>
|
||||||
<script src="src/emu.js"></script>
|
<script src="src/emu.js"></script>
|
||||||
<script src="src/audio.js"></script>
|
<script src="src/audio.js"></script>
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 7428cfc4a6fd60ac00346619b923bfb8e17e399a
|
|
@ -11,7 +11,7 @@ typedef unsigned char byte;
|
||||||
typedef signed char sbyte;
|
typedef signed char sbyte;
|
||||||
typedef unsigned short word;
|
typedef unsigned short word;
|
||||||
|
|
||||||
const byte** BASL = 0x28;
|
static byte** BASL = (byte**) 0x28;
|
||||||
|
|
||||||
byte getchar(byte x, byte y) {
|
byte getchar(byte x, byte y) {
|
||||||
// JSR VTABZ
|
// JSR VTABZ
|
||||||
|
@ -108,7 +108,7 @@ void move_player(Player* p) {
|
||||||
cputcxy(p->x, p->y, p->tail_attr);
|
cputcxy(p->x, p->y, p->tail_attr);
|
||||||
p->x += DIR_X[p->dir];
|
p->x += DIR_X[p->dir];
|
||||||
p->y += DIR_Y[p->dir];
|
p->y += DIR_Y[p->dir];
|
||||||
if (getchar(p->x, p->y) & 0x7f != ' ')
|
if ((getchar(p->x, p->y) & 0x7f) != ' ')
|
||||||
p->collided = 1;
|
p->collided = 1;
|
||||||
draw_player(p);
|
draw_player(p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var OldFileStore = function(storage, prefix) {
|
||||||
|
var self = this;
|
||||||
|
this.saveFile = function(name, text) {
|
||||||
|
storage.setItem(prefix + name, text);
|
||||||
|
}
|
||||||
|
this.loadFile = function(name) {
|
||||||
|
return storage.getItem(prefix + name) || storage.getItem(name);
|
||||||
|
}
|
||||||
|
this.getFiles = function(prefix2) {
|
||||||
|
// iterate over files with <platform>/<dir> prefix
|
||||||
|
var files = [];
|
||||||
|
for (var i = 0; i < storage.length; i++) {
|
||||||
|
var key = storage.key(i);
|
||||||
|
if (key.startsWith(prefix + prefix2)) {
|
||||||
|
var name = key.substring(prefix.length + prefix2.length);
|
||||||
|
files.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
this.deleteFile = function(name) {
|
||||||
|
storage.removeItem(prefix + name);
|
||||||
|
storage.removeItem(prefix + 'local/' + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// localforage-compatible driver for old file store format
|
||||||
|
var OldFileStoreDriver = {
|
||||||
|
_driver: 'oldFileStoreDriver',
|
||||||
|
_initStorage: function(options) {
|
||||||
|
this._store = new OldFileStore(localStorage, options.name + '/');
|
||||||
|
},
|
||||||
|
clear: function(callback) {
|
||||||
|
// Custom implementation here...
|
||||||
|
},
|
||||||
|
getItem: function(key, callback) {
|
||||||
|
callback(null, this._store.loadFile(key));
|
||||||
|
},
|
||||||
|
iterate: function(iteratorCallback, successCallback) {
|
||||||
|
// Custom implementation here...
|
||||||
|
},
|
||||||
|
key: function(n, callback) {
|
||||||
|
// Custom implementation here...
|
||||||
|
},
|
||||||
|
keys: function(callback) {
|
||||||
|
callback(this._store.getFiles(''));
|
||||||
|
},
|
||||||
|
length: function(callback) {
|
||||||
|
callback(this._store.getFiles('').length);
|
||||||
|
},
|
||||||
|
removeItem: function(key, callback) {
|
||||||
|
this._store.deleteFile(key);
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
setItem: function(key, value, callback) {
|
||||||
|
this._store.saveFile(key, value);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
localforage.defineDriver(OldFileStoreDriver);
|
||||||
|
|
||||||
|
// copy localStorage to new driver
|
||||||
|
function copyFromOldStorageFormat(platform_id, newstore) {
|
||||||
|
var alreadyMigratedKey = "__migrated_" + platform_id;
|
||||||
|
//localStorage.removeItem(alreadyMigratedKey);
|
||||||
|
if (localStorage.getItem(alreadyMigratedKey))
|
||||||
|
return;
|
||||||
|
var oldstore = new OldFileStore(localStorage, platform_id + '/');
|
||||||
|
var keys = oldstore.getFiles('');
|
||||||
|
// no files to convert?
|
||||||
|
if (keys.length == 0) {
|
||||||
|
localStorage.setItem(alreadyMigratedKey, 'true');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// convert function
|
||||||
|
function migrateNext() {
|
||||||
|
var key = keys.shift();
|
||||||
|
var value = oldstore.loadFile(key);
|
||||||
|
newstore.setItem(key, value, function(err, result) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
} else {
|
||||||
|
console.log("Converted " + key);
|
||||||
|
if (keys.length) {
|
||||||
|
migrateNext();
|
||||||
|
} else {
|
||||||
|
newstore.length(function(err, len) {
|
||||||
|
console.log("Migrated " + len + " local files to new data store");
|
||||||
|
if (len) {
|
||||||
|
localStorage.setItem(alreadyMigratedKey, 'true');
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
migrateNext(); // start the conversion
|
||||||
|
}
|
218
src/ui.js
218
src/ui.js
|
@ -41,73 +41,6 @@ var userPaused;
|
||||||
|
|
||||||
var toolbar = $("#controls_top");
|
var toolbar = $("#controls_top");
|
||||||
|
|
||||||
function getBiggestItems(storage) {
|
|
||||||
var items = [];
|
|
||||||
for (var i = 0; i < storage.length; i++) {
|
|
||||||
var key = storage.key(i);
|
|
||||||
var len = storage.getItem(key).length;
|
|
||||||
if (len>=100)
|
|
||||||
items.push([lpad(len+"", 12), key]);
|
|
||||||
}
|
|
||||||
items.sort();
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
var s = "";
|
|
||||||
for (var i=items.length-5; i<items.length; i++) {
|
|
||||||
s += items[i] + "\n";
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
var FileStore = function(storage, prefix) {
|
|
||||||
var self = this;
|
|
||||||
this.saveFile = function(name, text) {
|
|
||||||
try {
|
|
||||||
storage.setItem(prefix + name, text);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.name == 'NS_ERROR_DOM_QUOTA_REACHED') {
|
|
||||||
console.log(e);
|
|
||||||
if (confirm("Sorry, you've reached your local storage quota for this browser.\n\nGo to local storage editor?")) {
|
|
||||||
window.location = 'editstorage.html';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.loadFile = function(name) {
|
|
||||||
return storage.getItem(prefix + name) || storage.getItem(name);
|
|
||||||
}
|
|
||||||
this.getFiles = function(prefix2) {
|
|
||||||
// rename items for compatibility
|
|
||||||
for (var i = 0; i < storage.length; i++) {
|
|
||||||
var key = storage.key(i);
|
|
||||||
if (key.startsWith(prefix2) && platform_id == 'vcs') {
|
|
||||||
this.saveFile(key, storage.getItem(key));
|
|
||||||
storage.removeItem(key);
|
|
||||||
console.log("Renamed",key,'to',prefix+key);
|
|
||||||
i=-1; // reset loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// iterate over files with <platform>/<dir> prefix
|
|
||||||
var files = [];
|
|
||||||
for (var i = 0; i < storage.length; i++) {
|
|
||||||
var key = storage.key(i);
|
|
||||||
if (key.startsWith(prefix + prefix2)) {
|
|
||||||
var name = key.substring(prefix.length + prefix2.length);
|
|
||||||
files.push(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
this.deleteFile = function(name) {
|
|
||||||
storage.removeItem(prefix + name);
|
|
||||||
storage.removeItem(prefix + 'local/' + name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var SourceFile = function(lines, text) {
|
var SourceFile = function(lines, text) {
|
||||||
lines = lines || [];
|
lines = lines || [];
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
@ -237,7 +170,7 @@ function updatePreset(current_preset_id, text) {
|
||||||
// TODO: do we have to save all Verilog thingies?
|
// TODO: do we have to save all Verilog thingies?
|
||||||
if (text.trim().length &&
|
if (text.trim().length &&
|
||||||
(originalFileID != current_preset_id || text != originalText || platform_id=='verilog')) {
|
(originalFileID != current_preset_id || text != originalText || platform_id=='verilog')) {
|
||||||
store.saveFile(current_preset_id, text);
|
store.setItem(current_preset_id, text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,34 +188,37 @@ function loadCode(text, fileid) {
|
||||||
function loadFile(fileid, filename, index) {
|
function loadFile(fileid, filename, index) {
|
||||||
current_preset_id = fileid;
|
current_preset_id = fileid;
|
||||||
current_preset_index = index;
|
current_preset_index = index;
|
||||||
var text = store.loadFile(fileid) || "";
|
store.getItem(fileid, function(err, text) {
|
||||||
if (text) {
|
if (err) console.log(err);
|
||||||
loadCode(text, fileid);
|
if (!text) text = '';
|
||||||
} else if (!text && index >= 0) {
|
if (text) {
|
||||||
if (filename.indexOf('.') <= 0)
|
loadCode(text, fileid);
|
||||||
filename += ".a";
|
} else if (!text && index >= 0) {
|
||||||
console.log("Loading preset", fileid, filename, index, PRESETS[index]);
|
if (filename.indexOf('.') <= 0)
|
||||||
if (text.length == 0) {
|
filename += ".a";
|
||||||
console.log("Fetching", filename);
|
console.log("Loading preset", fileid, filename, index, PRESETS[index]);
|
||||||
$.get( filename, function( text ) {
|
if (text.length == 0) {
|
||||||
console.log("GET",text.length,'bytes');
|
console.log("Fetching", filename);
|
||||||
|
$.get( filename, function( text ) {
|
||||||
|
console.log("GET",text.length,'bytes');
|
||||||
|
loadCode(text, fileid);
|
||||||
|
}, 'text')
|
||||||
|
.fail(function() {
|
||||||
|
alert("Could not load preset " + fileid);
|
||||||
|
loadCode("", fileid);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var ext = platform.getToolForFilename(fileid);
|
||||||
|
$.get( "presets/"+platform_id+"/skeleton."+ext, function( text ) {
|
||||||
loadCode(text, fileid);
|
loadCode(text, fileid);
|
||||||
}, 'text')
|
}, 'text')
|
||||||
.fail(function() {
|
.fail(function() {
|
||||||
alert("Could not load preset " + fileid);
|
alert("Could not load skeleton for " + platform_id + "/" + ext);
|
||||||
loadCode("", fileid);
|
loadCode("", fileid);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
var ext = platform.getToolForFilename(fileid);
|
|
||||||
$.get( "presets/"+platform_id+"/skeleton."+ext, function( text ) {
|
|
||||||
loadCode(text, fileid);
|
|
||||||
}, 'text')
|
|
||||||
.fail(function() {
|
|
||||||
alert("Could not load skeleton for " + platform_id + "/" + ext);
|
|
||||||
loadCode("", fileid);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadPreset(preset_id) {
|
function loadPreset(preset_id) {
|
||||||
|
@ -378,29 +314,38 @@ function _downloadSourceFile(e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateExamples(sel) {
|
function populateExamples(sel) {
|
||||||
sel.append($("<option />").text("--------- Examples ---------").attr('disabled',true));
|
// make sure to use callback so it follows other sections
|
||||||
for (var i=0; i<PRESETS.length; i++) {
|
store.length(function(err, len) {
|
||||||
var preset = PRESETS[i];
|
sel.append($("<option />").text("--------- Examples ---------").attr('disabled',true));
|
||||||
var name = preset.chapter ? (preset.chapter + ". " + preset.name) : preset.name;
|
for (var i=0; i<PRESETS.length; i++) {
|
||||||
sel.append($("<option />").val(preset.id).text(name).attr('selected',preset.id==current_preset_id));
|
var preset = PRESETS[i];
|
||||||
}
|
var name = preset.chapter ? (preset.chapter + ". " + preset.name) : preset.name;
|
||||||
|
sel.append($("<option />").val(preset.id).text(name).attr('selected',preset.id==current_preset_id));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateFiles(sel, name, prefix) {
|
function populateFiles(sel, category, prefix) {
|
||||||
sel.append($("<option />").text("------- " + name + " -------").attr('disabled',true));
|
store.keys(function(err, keys) {
|
||||||
var filenames = store.getFiles(prefix);
|
var foundSelected = false;
|
||||||
var foundSelected = false;
|
var numFound = 0;
|
||||||
for (var i = 0; i < filenames.length; i++) {
|
if (!keys) keys = [];
|
||||||
var name = filenames[i];
|
for (var i = 0; i < keys.length; i++) {
|
||||||
var key = prefix + name;
|
var key = keys[i];
|
||||||
sel.append($("<option />").val(key).text(name).attr('selected',key==current_preset_id));
|
if (key.startsWith(prefix)) {
|
||||||
if (key == current_preset_id) foundSelected = true;
|
if (numFound++ == 0)
|
||||||
}
|
sel.append($("<option />").text("------- " + category + " -------").attr('disabled',true));
|
||||||
if (!foundSelected && current_preset_id && current_preset_id.startsWith(prefix)) {
|
var name = key.substring(prefix.length);
|
||||||
var name = current_preset_id.slice(prefix.length);
|
sel.append($("<option />").val(key).text(name).attr('selected',key==current_preset_id));
|
||||||
var key = prefix + name;
|
if (key == current_preset_id) foundSelected = true;
|
||||||
sel.append($("<option />").val(key).text(name).attr('selected',true));
|
}
|
||||||
}
|
}
|
||||||
|
if (!foundSelected && current_preset_id && current_preset_id.startsWith(prefix)) {
|
||||||
|
var name = current_preset_id.slice(prefix.length);
|
||||||
|
var key = prefix + name;
|
||||||
|
sel.append($("<option />").val(key).text(name).attr('selected',true));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSelector() {
|
function updateSelector() {
|
||||||
|
@ -422,33 +367,47 @@ function updateSelector() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFileDependencies(text) {
|
function loadFileDependencies(text, callback) {
|
||||||
var arr = [];
|
var filenames = [];
|
||||||
if (platform_id == 'verilog') {
|
if (platform_id == 'verilog') {
|
||||||
var re = /^(`include|[.]include)\s+"(.+?)"/gm;
|
var re = /^(`include|[.]include)\s+"(.+?)"/gm;
|
||||||
var m;
|
var m;
|
||||||
while (m = re.exec(text)) {
|
while (m = re.exec(text)) {
|
||||||
arr.push({
|
filenames.push(m[2]);
|
||||||
filename:m[2],
|
}
|
||||||
prefix:platform_id,
|
}
|
||||||
text:store.loadFile(m[2]) || store.loadFile('local/'+m[2]) // TODO??
|
var result = [];
|
||||||
|
function loadNextDependency() {
|
||||||
|
var fn = filenames.shift();
|
||||||
|
if (!fn) {
|
||||||
|
callback(result);
|
||||||
|
} else {
|
||||||
|
store.getItem(fn, function(err, value) {
|
||||||
|
result.push({
|
||||||
|
filename:fn,
|
||||||
|
prefix:platform_id,
|
||||||
|
text:value // might be null, that's ok
|
||||||
|
});
|
||||||
|
loadNextDependency();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return arr;
|
loadNextDependency(); // load first dependency
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCode(text) {
|
function setCode(text) {
|
||||||
if (pendingWorkerMessages++ > 0)
|
if (pendingWorkerMessages++ > 0)
|
||||||
return;
|
return;
|
||||||
worker.postMessage({
|
|
||||||
code:text,
|
|
||||||
dependencies:loadFileDependencies(text),
|
|
||||||
platform:platform_id,
|
|
||||||
tool:platform.getToolForFilename(current_preset_id)
|
|
||||||
});
|
|
||||||
toolbar.addClass("is-busy");
|
toolbar.addClass("is-busy");
|
||||||
$('#compile_spinner').css('visibility', 'visible');
|
$('#compile_spinner').css('visibility', 'visible');
|
||||||
|
loadFileDependencies(text, function(depends) {
|
||||||
|
worker.postMessage({
|
||||||
|
code:text,
|
||||||
|
dependencies:depends,
|
||||||
|
platform:platform_id,
|
||||||
|
tool:platform.getToolForFilename(current_preset_id)
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function arrayCompare(a,b) {
|
function arrayCompare(a,b) {
|
||||||
|
@ -1427,7 +1386,14 @@ function preloadWorker(fileid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function initPlatform() {
|
function initPlatform() {
|
||||||
store = new FileStore(localStorage, platform_id + '/');
|
//store = new FileStore(localStorage, platform_id + '/');
|
||||||
|
store = localforage.createInstance({
|
||||||
|
//driver: 'oldFileStoreDriver', //localforage.LOCALSTORAGE,
|
||||||
|
name: platform_id,
|
||||||
|
//storeName: platform_id,
|
||||||
|
version: "2.0"
|
||||||
|
});
|
||||||
|
copyFromOldStorageFormat(platform_id, store);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showBookLink() {
|
function showBookLink() {
|
||||||
|
@ -1525,7 +1491,7 @@ function startUI(loadplatform) {
|
||||||
// reset file?
|
// reset file?
|
||||||
if (qs['file'] && qs['reset']) {
|
if (qs['file'] && qs['reset']) {
|
||||||
initPlatform();
|
initPlatform();
|
||||||
store.deleteFile(qs['file']);
|
store.removeItem(qs['file']);
|
||||||
qs['reset'] = '';
|
qs['reset'] = '';
|
||||||
gotoNewLocation();
|
gotoNewLocation();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1034,7 +1034,7 @@ function linkSDLDZ80(step)
|
||||||
|
|
||||||
var sdcc;
|
var sdcc;
|
||||||
function compileSDCC(step) {
|
function compileSDCC(step) {
|
||||||
|
|
||||||
gatherFiles(step, {
|
gatherFiles(step, {
|
||||||
mainFilePath:"main.c" // not used
|
mainFilePath:"main.c" // not used
|
||||||
});
|
});
|
||||||
|
@ -1304,7 +1304,7 @@ var jsasm_module_output;
|
||||||
var jsasm_module_key;
|
var jsasm_module_key;
|
||||||
|
|
||||||
function compileJSASM(asmcode, platform, options, is_inline) {
|
function compileJSASM(asmcode, platform, options, is_inline) {
|
||||||
load("assembler");
|
load("../assembler");
|
||||||
var asm = new Assembler();
|
var asm = new Assembler();
|
||||||
var includes = [];
|
var includes = [];
|
||||||
asm.loadJSON = function(filename) {
|
asm.loadJSON = function(filename) {
|
||||||
|
@ -1401,7 +1401,7 @@ function compileVerilator(step) {
|
||||||
var topmod = detectTopModuleName(code);
|
var topmod = detectTopModuleName(code);
|
||||||
var FS = verilator_mod['FS'];
|
var FS = verilator_mod['FS'];
|
||||||
FS.writeFile(topmod+".v", code);
|
FS.writeFile(topmod+".v", code);
|
||||||
writeDependencies(options.dependencies, FS, errors, function(d, code) {
|
writeDependencies(step.dependencies, FS, errors, function(d, code) {
|
||||||
return compileInlineASM(code, platform, options, errors, null);
|
return compileInlineASM(code, platform, options, errors, null);
|
||||||
});
|
});
|
||||||
starttime();
|
starttime();
|
||||||
|
|
Loading…
Reference in New Issue