diff --git a/com/codemirror.js b/com/codemirror.js index de18dfd..061fcd2 100644 --- a/com/codemirror.js +++ b/com/codemirror.js @@ -2,11 +2,17 @@ if( AFRAME.components.codemirror ) delete AFRAME.components.codemirror AFRAME.registerComponent('codemirror', { schema: { - foo: { type:"string"} + file: { type:"string"}, + term: { type:"selector", default: "[isoterminal]" }, }, init: function () { this.el.object3D.visible = false + if( !this.data.term || !this.data.term.components ) throw 'codemirror cannot get isoterminal' + if( this.data.file && this.data.file[0] != '/'){ + this.data.file = "root/"+this.data.file + } + this.isoterminal = this.data.term.components.isoterminal.isoterminal //this.el.innerHTML = ` ` this.requireAll() }, @@ -17,10 +23,7 @@ AFRAME.registerComponent('codemirror', { }, requires:{ - window: "com/window.js", - codemirror: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/codemirror.js", - codemirrorcss: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.35.0/codemirror.css", - cmtheme: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.35.0/theme/shadowfox.css" + window: "com/window.js" }, dom: { @@ -49,28 +52,54 @@ AFRAME.registerComponent('codemirror', { ` }, + createEditor: function(value){ + this.el.setAttribute("window", `title: codemirror; uid: ${this.el.dom.id}; attach: #overlay; dom: #${this.el.dom.id};`) + this.editor = CodeMirror( this.el.dom, { + value, + mode: "htmlmixed", + lineNumbers: true, + styleActiveLine: true, + matchBrackets: true, + Tab: "indentMore", + defaultTab: function(cm) { + if (cm.somethingSelected()) cm.indentSelection("add"); + else cm.replaceSelection(" ", "end"); + } + }) + this.editor.setOption("theme", "shadowfox") + this.editor.updateFile = AFRAME.utils.throttleLeadingAndTrailing( (file,str) => { + this.updateFile(file,str), + 2000 + }) + this.editor.on('change', (instance,changeObj) => { + this.editor.updateFile( this.data.file, instance.getValue() ) + }) + + setTimeout( () => { + this.el.setAttribute("html-as-texture-in-xr", `domid: #${this.el.dom.id}`) // only show aframe-html in xr + },1500) + }, + + updateFile: async function(file,str){ + // we don't do via shellcmd: isoterminal.exec(`echo '${str}' > ${file}`,1) + // as it would require all kindof ugly stringescaping + console.log("updating "+file) + await this.isoterminal.emulator.fs9p.update_file( file, str) + }, + events:{ // component events DOMready: function(e){ - console.log(`title: codemirror; uid: ${this.el.dom.id}; attach: #overlay; dom: #${this.el.dom.id};`) - this.el.setAttribute("window", `title: codemirror; uid: ${this.el.dom.id}; attach: #overlay; dom: #${this.el.dom.id};`) - this.editor = CodeMirror( this.el.dom, { - value: "function myScript(){return 100;}\n", - mode: "javascript", - lineNumbers: true, - styleActiveLine: true, - matchBrackets: true, - Tab: "indentMore", - defaultTab: function(cm) { - if (cm.somethingSelected()) cm.indentSelection("add"); - else cm.replaceSelection(" ", "end"); - } + this.isoterminal.emulator.read_file( this.data.file ) + .then( this.isoterminal.convert.Uint8ArrayToString ) + .then( (str) => { + this.createEditor( str ) + }) + .catch( (e) => { + console.log("error opening "+this.data.file+", creating new one") + this.createEditor("") }) - this.editor.setOption("theme", "shadowfox") - setTimeout( () => { - this.el.setAttribute("html-as-texture-in-xr", `domid: #${this.el.dom.id}`) // only show aframe-html in xr - },1500) }, }, diff --git a/com/isoterminal.js b/com/isoterminal.js index 2416643..942703a 100644 --- a/com/isoterminal.js +++ b/com/isoterminal.js @@ -40,7 +40,7 @@ if( typeof AFRAME != 'undefined '){ minimized: { type: 'boolean',"default":false}, maximized: { type: 'boolean',"default":true}, transparent: { type:'boolean', "default":false }, // need good gpu - xterm: { type: 'boolean', "default":true }, // use xterm.js (slower) + xterm: { type: 'boolean', "default":true }, // use xterm.js? (=slower) memory: { type: 'number', "default":48 } // VM memory (in MB) }, diff --git a/com/isoterminal/feat/9pfs_utils.js b/com/isoterminal/feat/9pfs_utils.js index 18ca419..737bcaf 100644 --- a/com/isoterminal/feat/9pfs_utils.js +++ b/com/isoterminal/feat/9pfs_utils.js @@ -8,16 +8,17 @@ ISOTerminal.addEventListener('emulator-started', function(){ if(p.id === -1) { - return Promise.resolve(null); + return emulator.create_file(file,data) } const inode = this.GetInode(p.id); - const buf = typeof data == 'string' ? isoterminal.toUint8Array(data) : data + const buf = typeof data == 'string' ? isoterminal.convert.toUint8Array(data) : data await this.Write(p.id,0, buf.length, buf ) // update inode inode.size = buf.length const now = Math.round(Date.now() / 1000); inode.atime = inode.mtime = now; + isoterminal.exec(`touch ${file}`) // update inode return new Promise( (resolve,reject) => resolve(buf) ) } @@ -32,7 +33,7 @@ ISOTerminal.addEventListener('emulator-started', function(){ } const inode = this.GetInode(p.id); - const buf = typeof data == 'string' ? isoterminal.toUint8Array(data) : data + const buf = typeof data == 'string' ? isoterminal.convert.toUint8Array(data) : data await this.Write(p.id, inode.size, buf.length, buf ) // update inode inode.size = inode.size + buf.length diff --git a/com/isoterminal/feat/autorestore.js b/com/isoterminal/feat/autorestore.js index d4663a1..d53d92b 100644 --- a/com/isoterminal/feat/autorestore.js +++ b/com/isoterminal/feat/autorestore.js @@ -2,28 +2,6 @@ ISOTerminal.addEventListener('emulator-started', function(e){ this.autorestore(e) }) -ISOTerminal.prototype.convert = { - - arrayBufferToBase64: function(buffer){ - let binary = ''; - const bytes = new Uint8Array(buffer); - const len = bytes.byteLength; - for (let i = 0; i < len; i++) binary += String.fromCharCode(bytes[i]); - return window.btoa(binary); - }, - - base64ToArrayBuffer: function(base64) { - const binaryString = window.atob(base64); - const len = binaryString.length; - const bytes = new Uint8Array(len); - - for (let i = 0; i < len; i++) { - bytes[i] = binaryString.charCodeAt(i); - } - return bytes.buffer; - } -} - ISOTerminal.prototype.autorestore = async function(e){ localforage.setDriver([ @@ -32,7 +10,7 @@ ISOTerminal.prototype.autorestore = async function(e){ localforage.LOCALSTORAGE ]).then( () => { - localforage.getItem("state", (err,stateBase64) => { + localforage.getItem("state", async (err,stateBase64) => { if( !err && confirm('continue last session?') ){ this.noboot = true // see feat/boot.js state = this.convert.base64ToArrayBuffer( stateBase64 ) @@ -40,7 +18,19 @@ ISOTerminal.prototype.autorestore = async function(e){ this.emit('postReady',e) setTimeout( () => { this.emit('ready',e) - this.send("alert last session restored\n") + // press CTRL+a l (=gnu screen redisplay) + setTimeout( () => this.send("l\n"),400 ) + // reload index.js + this.emulator.read_file("root/index.js") + .then( this.convert.Uint8ArrayToString ) + .then( this.runJavascript ) + .catch( console.error ) + // reload index.html + this.emulator.read_file("root/index.html") + .then( this.convert.Uint8ArrayToString ) + .then( this.runHTML ) + .catch( console.error ) + }, 500 ) } }) @@ -50,6 +40,13 @@ ISOTerminal.prototype.autorestore = async function(e){ console.log( String(this.convert.arrayBufferToBase64(state)).substr(0,5) ) localforage.setItem("state", this.convert.arrayBufferToBase64(state) ) } + + window.addEventListener("beforeunload", function (e) { + var confirmationMessage = "Sure you want to leave?\nTIP: enter 'save' to continue this session later"; + (e || window.event).returnValue = confirmationMessage; //Gecko + IE + return confirmationMessage; //Webkit, Safari, Chrome + }); + }) } diff --git a/com/isoterminal/feat/boot.js b/com/isoterminal/feat/boot.js index cfc943c..ee42e8a 100644 --- a/com/isoterminal/feat/boot.js +++ b/com/isoterminal/feat/boot.js @@ -9,7 +9,7 @@ ISOTerminal.prototype.boot = async function(e){ if( typeof document.location[i] == 'string' ) env.push( 'export '+String(i).toUpperCase()+'="'+document.location[i]+'"') } - await this.emulator.create_file("profile.browser", this.toUint8Array( env.join('\n') ) ) + await this.emulator.create_file("profile.browser", this.convert.toUint8Array( env.join('\n') ) ) if( this.serial_input == 0 ){ if( !this.noboot ){ diff --git a/com/isoterminal/feat/index.html.js b/com/isoterminal/feat/index.html.js index b36220c..504adc7 100644 --- a/com/isoterminal/feat/index.html.js +++ b/com/isoterminal/feat/index.html.js @@ -10,14 +10,7 @@ ISOTerminal.addEventListener('init', function(){ const decoder = new TextDecoder('utf-8'); const html = decoder.decode(buf) try{ - let $scene = document.querySelector("a-scene") - let $root = document.querySelector("a-entity#root") - if( !$root ){ - $root = document.createElement("a-entity") - $root.id = "root" - $scene.appendChild($root) - } - $root.innerHTML = html + this.runHTML(html) }catch(e){ console.error(e) } @@ -27,3 +20,13 @@ ISOTerminal.addEventListener('init', function(){ }) +ISOTerminal.prototype.runHTML = function(html){ + let $scene = document.querySelector("a-scene") + let $root = document.querySelector("a-entity#root") + if( !$root ){ + $root = document.createElement("a-entity") + $root.id = "root" + $scene.appendChild($root) + } + $root.innerHTML = html +} diff --git a/com/isoterminal/feat/index.js.js b/com/isoterminal/feat/index.js.js index 4482d0e..de3dee2 100644 --- a/com/isoterminal/feat/index.js.js +++ b/com/isoterminal/feat/index.js.js @@ -10,13 +10,7 @@ ISOTerminal.addEventListener('init', function(){ const decoder = new TextDecoder('utf-8'); const js = decoder.decode(buf) try{ - let $root = document.querySelector("script#root") - if( !$root ){ - $root = document.createElement("script") - $root.id = "root" - document.body.appendChild($root) - } - $root.innerHTML = js + this.runJavascript(js) }catch(e){ console.error(e) } @@ -26,3 +20,13 @@ ISOTerminal.addEventListener('init', function(){ }) +ISOTerminal.prototype.runJavascript = function(js){ + let $root = document.querySelector("script#root") + if( !$root ){ + $root = document.createElement("script") + $root.id = "root" + document.body.appendChild($root) + } + $root.innerHTML = js +} + diff --git a/com/isoterminal/feat/javascript.js b/com/isoterminal/feat/javascript.js index 960918f..f2b981a 100644 --- a/com/isoterminal/feat/javascript.js +++ b/com/isoterminal/feat/javascript.js @@ -7,8 +7,7 @@ ISOTerminal.addEventListener('init', function(){ // unix to js device this.readFromPipe( '/mnt/js', async (data) => { const buf = await emulator.read_file("js") - const decoder = new TextDecoder('utf-8'); - const script = decoder.decode(buf) + const script = this.convert.Uint8ArrayToString(buf) let PID="?" try{ if( script.match(/^PID/) ){ @@ -18,7 +17,7 @@ ISOTerminal.addEventListener('init', function(){ if( res && typeof res != 'string' ) res = JSON.stringify(res,null,2) // write output to 9p with PID as filename // *FIXME* not flexible / robust - emulator.create_file(PID, this.toUint8Array(res) ) + emulator.create_file(PID, this.convert.toUint8Array(res) ) }catch(e){ console.error(e) } diff --git a/com/window.js b/com/window.js index 1ebb60b..6a6af9c 100644 --- a/com/window.js +++ b/com/window.js @@ -54,8 +54,8 @@ AFRAME.registerComponent('window', { this.el.emit('window.onclose',e) if( e.halt ) return true this.data.dom.style.display = 'none'; + if( this.el.parentNode ) this.el.remove() //parentElement.remove( this.el ) this.data.dom.parentElement.remove() - this.el.parentElement.remove( this.el ) return false }, });