ticlab!
parent
a4e25fd2fd
commit
e57793cd6b
@ -1,3 +1,4 @@
|
|||||||
.ipynb_checkpoints/
|
.ipynb_checkpoints/
|
||||||
node_modules/
|
node_modules/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
build/
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
all: dist/codemirror.css dist/inspect_tic.js
|
all: build/codemirror.css build/ticeditor.js
|
||||||
|
|
||||||
dist/inspect_tic.js: src/inspect_tic.js
|
# dist/inspect_tic.js: src/inspect_tic.js
|
||||||
|
# npx webpack
|
||||||
|
|
||||||
|
build/ticeditor.js: src/ticeditor.js
|
||||||
npx webpack
|
npx webpack
|
||||||
|
|
||||||
dist/codemirror.css: node_modules/codemirror/lib/codemirror.css
|
build/codemirror.css: node_modules/codemirror/lib/codemirror.css
|
||||||
cp $< $@
|
cp $< $@
|
||||||
|
|
||||||
|
build/font-awesome.min.css:
|
||||||
|
wget http://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css -O $@
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,18 +1,53 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>TIC-80 files</title>
|
<title>TICLAB</title>
|
||||||
<link rel="stylesheet" href="dist/codemirror.css">
|
<link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
|
||||||
|
<!-- <link rel="stylesheet" href="build/codemirror.css"> -->
|
||||||
<!-- <link rel="stylesheet" href="node_modules/codemirror/theme/base16-dark.css"> -->
|
<!-- <link rel="stylesheet" href="node_modules/codemirror/theme/base16-dark.css"> -->
|
||||||
<!-- <link rel="stylesheet" href="node_modules/codemirror/theme/monokai.css"> -->
|
<!-- <link rel="stylesheet" href="node_modules/codemirror/theme/monokai.css"> -->
|
||||||
|
<link rel="stylesheet" href="node_modules/codemirror/lib/codemirror.css">
|
||||||
<style>
|
<style>
|
||||||
.CodeMirror { height: 500px }
|
|
||||||
|
#dialog {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10000;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #00000066;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#openfile {
|
||||||
|
width: 300px;
|
||||||
|
padding: 0px 20px;
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>TIC80 files</h1>
|
<!-- <h1>TIC80 files</h1>
|
||||||
<div id="listing"></div>
|
<div id="listing"></div>
|
||||||
<div id="code"></div>
|
<div id="code"></div>-->
|
||||||
<script src="dist/inspect_tic.js"></script>
|
<div id="dialog">
|
||||||
|
<div id="openfile">
|
||||||
|
<h2>Open file...</h2>
|
||||||
|
<p>
|
||||||
|
<input type="file" id="openfile_fileinput">
|
||||||
|
<button id="openfile_cancel" class="cancel">Cancel</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="build/ticeditor.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,22 +1,36 @@
|
|||||||
{
|
{
|
||||||
"name": "ticparse.js",
|
"name": "ticparse.js",
|
||||||
|
"private": true,
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "db.js",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"build": "webpack",
|
||||||
|
"clean": "rimraf build"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"css-loader": "^3.4.0",
|
||||||
|
"file-loader": "^5.0.2",
|
||||||
|
"rimraf": "^2.5.2",
|
||||||
|
"source-map-loader": "0.2.4",
|
||||||
|
"style-loader": "^1.0.2",
|
||||||
"webpack": "^5.16.0",
|
"webpack": "^5.16.0",
|
||||||
"webpack-cli": "^4.4.0"
|
"webpack-cli": "^4.4.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-free": "^5.15.2",
|
||||||
|
"@lumino/commands": "^1.12.0",
|
||||||
|
"@lumino/default-theme": "^0.9.0",
|
||||||
|
"@lumino/dragdrop": "^1.7.1",
|
||||||
|
"@lumino/messaging": "^1.4.3",
|
||||||
|
"@lumino/widgets": "^1.18.0",
|
||||||
"codemirror": "^5.59.2",
|
"codemirror": "^5.59.2",
|
||||||
"d3-selection": "^2.0.0",
|
"d3-selection": "^2.0.0",
|
||||||
|
"es6-promise": "^4.0.5",
|
||||||
"filesize": "^6.1.0",
|
"filesize": "^6.1.0",
|
||||||
"indexed-pdb": "^1.1.2"
|
"indexed-pdb": "^1.1.2",
|
||||||
|
"url-loader": "^4.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,177 @@
|
|||||||
|
import { CommandRegistry } from '@lumino/commands';
|
||||||
|
import { Message } from '@lumino/messaging';
|
||||||
|
import { BoxPanel, CommandPalette, ContextMenu, DockPanel, Menu, MenuBar, Widget } from '@lumino/widgets';
|
||||||
|
import '../style/index.css';
|
||||||
|
|
||||||
|
// import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
|
import { EditorWidget } from './editor.js';
|
||||||
|
import { ListingWidget } from './listing.js';
|
||||||
|
|
||||||
|
import * as ticdb from './ticdb.js';
|
||||||
|
// class ContentWidget extends Widget {
|
||||||
|
|
||||||
|
// static createNode() {
|
||||||
|
// let node = document.createElement('div');
|
||||||
|
// let content = document.createElement('div');
|
||||||
|
// let input = document.createElement('input');
|
||||||
|
// input.placeholder = 'Placeholder...';
|
||||||
|
// content.appendChild(input);
|
||||||
|
// node.appendChild(content);
|
||||||
|
// return node;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// constructor(name) {
|
||||||
|
// super({ node: ContentWidget.createNode() });
|
||||||
|
// this.setFlag(Widget.Flag.DisallowLayout);
|
||||||
|
// this.addClass('content');
|
||||||
|
// this.addClass(name.toLowerCase());
|
||||||
|
// this.title.label = name;
|
||||||
|
// this.title.closable = true;
|
||||||
|
// this.title.caption = `Long description for: ${name}`;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// get inputNode() {
|
||||||
|
// return this.node.getElementsByTagName('input')[0];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// onActivateRequest(Message) {
|
||||||
|
// if (this.isAttached) {
|
||||||
|
// this.inputNode.focus();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
window._tic = {};
|
||||||
|
const commands = new CommandRegistry();
|
||||||
|
|
||||||
|
|
||||||
|
function main () {
|
||||||
|
const dialog = document.getElementById("dialog"),
|
||||||
|
openfile = document.getElementById("openfile"),
|
||||||
|
openfile_fileinput = document.getElementById("openfile_fileinput"),
|
||||||
|
openfile_cancel = document.getElementById("openfile_cancel");
|
||||||
|
|
||||||
|
function dialog_is_open () {
|
||||||
|
return dialog.style.display != "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function close_dialog() {
|
||||||
|
dialog.style.display = "none";
|
||||||
|
openfile.style.display = "none";
|
||||||
|
openfile_fileinput.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_openfile() {
|
||||||
|
dialog.style.display = "flex";
|
||||||
|
openfile.style.display = "block";
|
||||||
|
openfile_fileinput.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
openfile_cancel.addEventListener("click", e=> {
|
||||||
|
close_dialog();
|
||||||
|
})
|
||||||
|
|
||||||
|
commands.addCommand('tic:open', {
|
||||||
|
label: 'Open...',
|
||||||
|
mnemonic: 1,
|
||||||
|
iconClass: 'fa fa-file',
|
||||||
|
execute: () => {
|
||||||
|
// console.log('Import...');
|
||||||
|
show_openfile();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
commands.addCommand('tic:save', {
|
||||||
|
label: 'Save',
|
||||||
|
mnemonic: 0,
|
||||||
|
iconClass: 'fa fa-save',
|
||||||
|
execute: async () => {
|
||||||
|
console.log('Save');
|
||||||
|
// current_cart.code.text = codesrc; // code.getValue();
|
||||||
|
if (window._tic.filename && window._tic.cart) {
|
||||||
|
let cart = window._tic.cart;
|
||||||
|
cart.code.text = window.code.getValue();
|
||||||
|
// console.log("saving code", cart.code.text);
|
||||||
|
await ticdb.save_cart(window._tic.filename, cart, window._tic.item.mode);
|
||||||
|
listing.sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
commands.addCommand('tic:save-as', {
|
||||||
|
label: 'Save as...',
|
||||||
|
mnemonic: 0,
|
||||||
|
iconClass: 'fa fa-save',
|
||||||
|
execute: async () => {
|
||||||
|
console.log('Save as...');
|
||||||
|
if (window._tic.cart) {
|
||||||
|
let filename = prompt("Save as...");
|
||||||
|
if (!filename) { return; }
|
||||||
|
window._tic.filename = filename;
|
||||||
|
let cart = window._tic.cart;
|
||||||
|
cart.code.text = window.code.getValue();
|
||||||
|
// console.log("saving code", cart.code.text);
|
||||||
|
await ticdb.save_cart(filename, cart, window._tic.item.mode);
|
||||||
|
listing.sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
commands.addKeyBinding({
|
||||||
|
keys: ['Accel S'],
|
||||||
|
selector: 'body',
|
||||||
|
command: 'tic:save'
|
||||||
|
});
|
||||||
|
|
||||||
|
commands.addKeyBinding({
|
||||||
|
keys: ['Accel O'],
|
||||||
|
selector: 'body',
|
||||||
|
command: 'tic:open'
|
||||||
|
});
|
||||||
|
|
||||||
|
let filemenu = new Menu({ commands });
|
||||||
|
filemenu.addItem({ command: 'tic:open' });
|
||||||
|
filemenu.addItem({ command: 'tic:save' });
|
||||||
|
filemenu.addItem({ command: 'tic:save-as' });
|
||||||
|
// filemenu.addItem({ type: 'separator' });
|
||||||
|
|
||||||
|
filemenu.title.label = 'File';
|
||||||
|
filemenu.title.mnemonic = 0;
|
||||||
|
|
||||||
|
let bar = new MenuBar();
|
||||||
|
bar.addMenu(filemenu);
|
||||||
|
bar.id = 'menuBar';
|
||||||
|
|
||||||
|
document.addEventListener('keydown', (event) => {
|
||||||
|
// console.log("keydown", event);
|
||||||
|
if (event.key == "Escape" && dialog_is_open()) {
|
||||||
|
close_dialog();
|
||||||
|
} else {
|
||||||
|
commands.processKeydownEvent(event);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let listing = new ListingWidget('Listing');
|
||||||
|
let editor = new EditorWidget('Editor');
|
||||||
|
|
||||||
|
let dock = new DockPanel();
|
||||||
|
dock.addWidget(listing);
|
||||||
|
dock.addWidget(editor, { mode: 'split-right', ref: listing });
|
||||||
|
// dock.addWidget(editor2, { ref: editor1 });
|
||||||
|
dock.id = 'dock';
|
||||||
|
|
||||||
|
BoxPanel.setStretch(dock, 1);
|
||||||
|
|
||||||
|
let main = new BoxPanel({ direction: 'left-to-right', spacing: 0 });
|
||||||
|
main.id = 'main';
|
||||||
|
// main.addWidget(palette);
|
||||||
|
main.addWidget(dock);
|
||||||
|
|
||||||
|
window.onresize = () => { main.update(); };
|
||||||
|
|
||||||
|
Widget.attach(bar, document.body);
|
||||||
|
Widget.attach(main, document.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = main;
|
@ -0,0 +1,63 @@
|
|||||||
|
import { Widget } from '@lumino/widgets';
|
||||||
|
|
||||||
|
import * as CodeMirror from 'codemirror';
|
||||||
|
import 'codemirror/mode/lua/lua.js';
|
||||||
|
import 'codemirror/mode/javascript/javascript.js';
|
||||||
|
import 'codemirror/addon/fold/foldcode.js';
|
||||||
|
import 'codemirror/addon/fold/foldgutter.js';
|
||||||
|
// import 'codemirror/lib/codemirror.css';
|
||||||
|
// import 'codemirror/theme/monokai.css';
|
||||||
|
|
||||||
|
const TIC_SPECIALS = ["TIC", "SCN", "OVR", "btn", "btnp", "clip", "cls", "circ", "circb", "exit", "fget", "font", "fset", "key", "keyp", "line", "map", "memcpy", "memset", "mget", "mouse", "mset", "music", "peek", "peek4", "pix", "pmem", "poke", "poke4", "print", "rect", "rectb", "reset", "sfx", "spr", "sync", "time", "tstamp", "trace", "tri", "textri"],
|
||||||
|
CM_OPTS = {
|
||||||
|
mode: {'name': 'lua', 'specials': TIC_SPECIALS, 'fold': true},
|
||||||
|
// mode: {'name': 'lua'},
|
||||||
|
theme: 'default',
|
||||||
|
lineNumbers: true,
|
||||||
|
lineWrapping: true,
|
||||||
|
// extraKeys: {"Ctrl-S": function(cm){ save(); }},
|
||||||
|
foldGutter: true,
|
||||||
|
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"]
|
||||||
|
};
|
||||||
|
|
||||||
|
export class EditorWidget extends Widget {
|
||||||
|
|
||||||
|
static createNode() {
|
||||||
|
let node = document.createElement('div');
|
||||||
|
let editor = document.createElement('div');
|
||||||
|
|
||||||
|
// let input = document.createElement('input');
|
||||||
|
// input.placeholder = 'Placeholder...';
|
||||||
|
// content.appendChild(input);
|
||||||
|
node.appendChild(editor);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(name) {
|
||||||
|
super({ node: EditorWidget.createNode() });
|
||||||
|
// let editor_div = this.node.getElementsByTagName('div')[0];
|
||||||
|
this.cm = CodeMirror(this.editorDiv, CM_OPTS);
|
||||||
|
window.code = this.cm;
|
||||||
|
this.setFlag(Widget.Flag.DisallowLayout);
|
||||||
|
this.addClass('content');
|
||||||
|
this.addClass(name.toLowerCase());
|
||||||
|
this.title.label = name;
|
||||||
|
this.title.closable = false;
|
||||||
|
this.title.caption = `Editor: ${name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get editorDiv () {
|
||||||
|
return this.node.getElementsByTagName('div')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
get inputNode() {
|
||||||
|
return this.node.getElementsByTagName('input')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onActivateRequest(Message) {
|
||||||
|
// if (this.isAttached) {
|
||||||
|
// this.inputNode.focus();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,139 @@
|
|||||||
|
import { Widget } from '@lumino/widgets';
|
||||||
|
import { openDB } from 'indexed-pdb'
|
||||||
|
import * as tic from './ticparse.js'
|
||||||
|
import * as filesize from 'filesize';
|
||||||
|
import {select, selectAll} from "d3-selection";
|
||||||
|
import * as CodeMirror from 'codemirror';
|
||||||
|
|
||||||
|
import * as ticdb from './ticdb.js';
|
||||||
|
|
||||||
|
|
||||||
|
export class ListingWidget extends Widget {
|
||||||
|
|
||||||
|
static createNode() {
|
||||||
|
let node = document.createElement('div');
|
||||||
|
let editor = document.createElement('div');
|
||||||
|
|
||||||
|
// let input = document.createElement('input');
|
||||||
|
// input.placeholder = 'Placeholder...';
|
||||||
|
// content.appendChild(input);
|
||||||
|
node.appendChild(editor);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(name) {
|
||||||
|
super({ node: ListingWidget.createNode() });
|
||||||
|
// let editor_div = this.node.getElementsByTagName('div')[0];
|
||||||
|
// this.cm = CodeMirror(this.editorDiv, CM_OPTS);
|
||||||
|
|
||||||
|
this.setFlag(Widget.Flag.DisallowLayout);
|
||||||
|
// this.addClass('content');
|
||||||
|
this.addClass(name.toLowerCase());
|
||||||
|
this.title.label = name;
|
||||||
|
this.title.closable = false;
|
||||||
|
this.title.caption = `Editor: ${name}`;
|
||||||
|
|
||||||
|
this.listing = select(this.node),
|
||||||
|
this.table = this.listing.append("table"),
|
||||||
|
this.thead = this.table.append("thead").append("tr"),
|
||||||
|
this.tbody = this.table.append("tbody");
|
||||||
|
this.thead.selectAll("th").data(["name", "size", "time", " "]).enter().append("th").html(d => d);
|
||||||
|
this.sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get inputNode() {
|
||||||
|
// return this.node.getElementsByTagName('input')[0];
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
onActivateRequest(Message) {
|
||||||
|
// if (this.isAttached) {
|
||||||
|
// this.inputNode.focus();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
async sync () {
|
||||||
|
console.log("listing.sync");
|
||||||
|
try {
|
||||||
|
const db = await openDB(ticdb.DB_NAME);
|
||||||
|
var objectStore = db.transaction([ticdb.DB_STORE], "readonly").objectStore(ticdb.DB_STORE);
|
||||||
|
var files = [];
|
||||||
|
await objectStore.openCursor().then(function push_item(cursor) {
|
||||||
|
if (!cursor) { return }
|
||||||
|
var filename = ticdb.filename_from_key(cursor.key);
|
||||||
|
if (filename && !filename.startsWith(".")) {
|
||||||
|
// console.log(cursor.value.contents);
|
||||||
|
var blob = new Blob([cursor.value.contents]);
|
||||||
|
// console.log("blob", blob, {type: "application/octet-stream"});
|
||||||
|
var objecturl = URL.createObjectURL(blob);
|
||||||
|
files.push({
|
||||||
|
key: cursor.key,
|
||||||
|
filename: filename,
|
||||||
|
size: cursor.value.contents.length,
|
||||||
|
timestamp: cursor.value.timestamp,
|
||||||
|
objecturl: objecturl
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
return cursor.continue().then(push_item)
|
||||||
|
})
|
||||||
|
|
||||||
|
// console.log("files", files);
|
||||||
|
let join = this.tbody.selectAll("tr").data(files, d=>d.key);
|
||||||
|
join.exit().remove();
|
||||||
|
let tr = join.enter().append("tr");
|
||||||
|
tr.append("td").attr("class", "link").append("a").attr("href", "#").html(d => d.filename).on("click", async (e, d) => {
|
||||||
|
e.preventDefault();
|
||||||
|
var filename = ticdb.filename_from_key(d.key);
|
||||||
|
if (filename) {
|
||||||
|
window._tic.filename = filename;
|
||||||
|
window._tic.item = await ticdb.load_key(ticdb.DB_NAME+"/"+window._tic.filename);
|
||||||
|
// console.log("loaded item", window._tic.item);
|
||||||
|
window._tic.cart = tic.parsetic(window._tic.item.contents.buffer);
|
||||||
|
// console.log("current_cart", current_cart);
|
||||||
|
window.code.setValue(window._tic.cart.code.text);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tr.append("td").attr("class", "size");
|
||||||
|
tr.append("td").attr("class", "timestamp");
|
||||||
|
tr.append("td").attr("class", "download").append("a").attr("href", d=>d.objecturl).attr("download", d=>d.filename).html("download");
|
||||||
|
|
||||||
|
// update Merged enter + join
|
||||||
|
let update = tr.merge(join);
|
||||||
|
update.select(".size").html(d => filesize(d.size));
|
||||||
|
update.select(".timestamp").html(d => d.timestamp.toLocaleString());
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error, 'any error during the process');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
listing.append("button").html("save as...").on("click", (e, d) => {
|
||||||
|
if (current_filename) {
|
||||||
|
var save_filename = prompt("key", current_filename);
|
||||||
|
if (save_filename) {
|
||||||
|
current_filename = save_filename;
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
listing.append("input").attr("type", "file").on("change", function (e, d) {
|
||||||
|
console.log("filechange", this.files);
|
||||||
|
if (this.files.length == 1) {
|
||||||
|
this.files[0].arrayBuffer().then(result => {
|
||||||
|
console.log("file", result);
|
||||||
|
var file_cart = tic.parsetic(result);
|
||||||
|
console.log("file_cart", file_cart);
|
||||||
|
})
|
||||||
|
// reader.readAsArrayBuffer(this.files[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
@ -0,0 +1,36 @@
|
|||||||
|
import { openDB } from 'indexed-pdb'
|
||||||
|
|
||||||
|
export const DB_NAME = "/com.nesbox.tic/TIC-80";
|
||||||
|
export const DB_STORE = "FILE_DATA";
|
||||||
|
|
||||||
|
export function filename_from_key (key) {
|
||||||
|
if (key.startsWith(DB_NAME+"/")) { return key.substr((DB_NAME+"/").length); }
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function load_key (key) {
|
||||||
|
const db = await openDB(DB_NAME),
|
||||||
|
objectStore = db.transaction([DB_STORE], "readonly").objectStore(DB_STORE);
|
||||||
|
return await objectStore.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function save_key (key, item) {
|
||||||
|
const db = await openDB(DB_NAME),
|
||||||
|
objectStore = db.transaction([DB_STORE], "readwrite").objectStore(DB_STORE);
|
||||||
|
return await objectStore.put(item, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function save_cart(filename, cart, mode) {
|
||||||
|
return await save_key(DB_NAME+"/"+filename, {timestamp: new Date(), contents: cart.tobuffer(), mode: mode});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compareBuffers (a, b) {
|
||||||
|
var ad = new DataView(a.buffer),
|
||||||
|
bd = new DataView(b.buffer);
|
||||||
|
if (ad.byteLength != bd.byteLength) { return false; }
|
||||||
|
for (var i=0; i<ad.byteLength; i++) {
|
||||||
|
if (ad.getUint8(i, 1) != bd.getUint8(i, 1)) { return false;}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
|||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
| Copyright (c) Jupyter Development Team.
|
||||||
|
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
||||||
|
|
|
||||||
|
| Distributed under the terms of the BSD 3-Clause License.
|
||||||
|
|
|
||||||
|
| The full license is in the file LICENSE, distributed with this software.
|
||||||
|
|----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
.content {
|
||||||
|
min-width: 50px;
|
||||||
|
min-height: 50px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
/*padding: 8px;*/
|
||||||
|
border: 1px solid #C0C0C0;
|
||||||
|
border-top: none;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content > div {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
/*border: 1px solid #C0C0C0;*/
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.content input {
|
||||||
|
margin: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.red > div {
|
||||||
|
background: #E74C3C;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.yellow > div {
|
||||||
|
background: #F1C40F;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.green > div {
|
||||||
|
background: #27AE60;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.blue > div {
|
||||||
|
background: #3498DB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
|||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
| Copyright (c) 2014-2018, PhosphorJS Contributors
|
||||||
|
|
|
||||||
|
| Distributed under the terms of the BSD 3-Clause License.
|
||||||
|
|
|
||||||
|
| The full license is in the file LICENSE, distributed with this software.
|
||||||
|
|----------------------------------------------------------------------------*/
|
||||||
|
@import '~@lumino/default-theme/style/index.css';
|
||||||
|
@import './content.css';
|
||||||
|
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#menuBar {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#main {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#palette {
|
||||||
|
min-width: 300px;
|
||||||
|
border-right: 1px solid #DDDDDD;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#dock {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
@ -1,10 +1,17 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: './src/inspect_tic.js',
|
entry: './src/app.js',
|
||||||
mode: "development",
|
mode: "development",
|
||||||
output: {
|
output: {
|
||||||
filename: 'inspect_tic.js',
|
filename: 'ticeditor.js',
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'build'),
|
||||||
},
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{ test: /\.js$/, use: ["source-map-loader"], enforce: "pre" },
|
||||||
|
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
|
||||||
|
{ test: /\.png$/, use: 'file-loader' },
|
||||||
|
]
|
||||||
|
}
|
||||||
};
|
};
|
Loading…
Reference in New Issue