reworked autorestore + added touchkeyboard compatibility
This commit is contained in:
parent
ce44449fc4
commit
4f83e1af0b
|
@ -36,7 +36,7 @@ AFRAME.registerComponent('codemirror', {
|
|||
|
||||
css: (me) => `.CodeMirror{
|
||||
width: ${me.com.data.width}px !important;
|
||||
height: ${me.com.data.height}px !important;
|
||||
height: ${me.com.data.height-30}px !important;
|
||||
}
|
||||
.codemirror *{
|
||||
font-size: 14px;
|
||||
|
@ -45,7 +45,10 @@ AFRAME.registerComponent('codemirror', {
|
|||
letter-spacing: 0 !important;
|
||||
text-shadow: 0px 0px 10px #F075;
|
||||
}
|
||||
#${me.dom.id} .wb-body { overflow:hidden; }
|
||||
|
||||
.wb-body:has(> .codemirror){
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
margin-top:18px;
|
||||
|
@ -78,11 +81,30 @@ AFRAME.registerComponent('codemirror', {
|
|||
this.editor.updateFile( this.data.file, instance.getValue() )
|
||||
})
|
||||
|
||||
this
|
||||
.handleFocus()
|
||||
|
||||
setTimeout( () => {
|
||||
this.el.setAttribute("html-as-texture-in-xr", `domid: #${this.el.dom.id}`) // only show aframe-html in xr
|
||||
},1500)
|
||||
},
|
||||
|
||||
handleFocus: function(){
|
||||
const focus = (showdom) => (e) => {
|
||||
if( this.editor ){
|
||||
this.editor.focus()
|
||||
}
|
||||
if( this.el.components.window && this.data.renderer == 'canvas'){
|
||||
this.el.components.window.show( showdom )
|
||||
}
|
||||
}
|
||||
this.el.addEventListener('obbcollisionstarted', focus(false) )
|
||||
this.el.sceneEl.addEventListener('enter-vr', focus(false) )
|
||||
this.el.sceneEl.addEventListener('enter-ar', focus(false) )
|
||||
this.el.sceneEl.addEventListener('exit-vr', focus(true) )
|
||||
this.el.sceneEl.addEventListener('exit-ar', focus(true) )
|
||||
},
|
||||
|
||||
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
|
||||
|
|
|
@ -21,7 +21,7 @@ if( !AFRAME.components['html-as-texture-in-xr'] ){
|
|||
this.el.setAttribute("html",`html: ${this.data.domid}; cursor:#cursor; xrlayer: true`)
|
||||
this.el.setAttribute("visible", AFRAME.utils.XD() == '3D' ? 'true' : 'false' )
|
||||
if( this.data.faceuser ){
|
||||
this.el.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(0.5) )
|
||||
this.el.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(0.8) )
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ if( typeof AFRAME != 'undefined '){
|
|||
overlayfs: { type:"string"},
|
||||
width: { type: 'number',"default": -1 },
|
||||
height: { type: 'number',"default": -1 },
|
||||
depth: { type: 'number',"default": 0.03 },
|
||||
lineHeight: { type: 'number',"default": 18 },
|
||||
padding: { type: 'number',"default": 18 },
|
||||
minimized: { type: 'boolean',"default":false},
|
||||
|
@ -44,19 +45,18 @@ if( typeof AFRAME != 'undefined '){
|
|||
muteUntilPrompt:{ type: 'boolean',"default":true}, // mute stdout until a prompt is detected in ISO
|
||||
HUD: { type: 'boolean',"default":false}, // link to camera movement
|
||||
transparent: { type:'boolean', "default":false }, // need good gpu
|
||||
memory: { type: 'number', "default":64 }, // VM memory (in MB)
|
||||
bufferLatency: { type: 'number', "default":30 }, // in ms: bufferlatency from webworker to xterm (batch-update every char to texture)
|
||||
memory: { type: 'number', "default":40 }, // VM memory (in MB) [NOTE: quest or smartphone might crash > 40mb ]
|
||||
bufferLatency: { type: 'number', "default":1 }, // in ms: bufferlatency from webworker to xterm (batch-update every char to texture)
|
||||
debug: { type: 'boolean', "default":false }
|
||||
},
|
||||
|
||||
init: function(){
|
||||
this.el.object3D.visible = false
|
||||
if( this.data.width == -1 ) this.data.width = document.body.offsetWidth
|
||||
if( this.data.height == -1 ) this.data.height = document.body.offsetHeight
|
||||
this.data.width -= this.data.padding*2
|
||||
this.data.height -= this.data.padding*2
|
||||
|
||||
this.calculateDimension()
|
||||
this.initHud()
|
||||
this.setupBox()
|
||||
|
||||
fetch(this.data.iso,{method: 'HEAD'})
|
||||
.then( (res) => {
|
||||
if( res.status != 200 ) throw 'not found'
|
||||
|
@ -79,17 +79,17 @@ if( typeof AFRAME != 'undefined '){
|
|||
selfcontain: "com/selfcontainer.js",
|
||||
// html to texture
|
||||
htmlinxr: "com/html-as-texture-in-xr.js",
|
||||
// isoterminal features
|
||||
// isoterminal global features
|
||||
PromiseWorker: "com/isoterminal/PromiseWorker.js",
|
||||
ISOTerminal: "com/isoterminal/ISOTerminal.js",
|
||||
localforage: "https://cdn.rawgit.com/mozilla/localForage/master/dist/localforage.js"
|
||||
localforage: "com/isoterminal/localforage.js",
|
||||
},
|
||||
|
||||
dom: {
|
||||
scale: 1.0,
|
||||
scale: 0.66,
|
||||
events: ['click','keydown'],
|
||||
html: (me) => `<div class="isoterminal">
|
||||
<div id="vt100" tabindex="0">
|
||||
<div id="term" tabindex="0">
|
||||
<pre></pre>
|
||||
</div>
|
||||
</div>`,
|
||||
|
@ -105,7 +105,7 @@ if( typeof AFRAME != 'undefined '){
|
|||
position:relative;
|
||||
line-height: ${me.com.data.lineHeight}px;
|
||||
}
|
||||
#vt100 {
|
||||
#term {
|
||||
outline: none !important;
|
||||
}
|
||||
@font-face {
|
||||
|
@ -127,10 +127,6 @@ if( typeof AFRAME != 'undefined '){
|
|||
border:none;
|
||||
padding:none;
|
||||
}
|
||||
span blink:last-of-type{
|
||||
border-right: 8px solid #F07;
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
#overlay .winbox:has(> .isoterminal){
|
||||
background:transparent;
|
||||
|
@ -218,8 +214,10 @@ if( typeof AFRAME != 'undefined '){
|
|||
this.term = new ISOTerminal(instance,this.data)
|
||||
|
||||
instance.addEventListener('DOMready', () => {
|
||||
instance.setAttribute("html-as-texture-in-xr", `domid: #${this.el.dom.id}; faceuser: true`)
|
||||
setTimeout( () => this.setupVT100(instance),100)
|
||||
this.setupVT100(instance)
|
||||
setTimeout( () => {
|
||||
instance.setAttribute("html-as-texture-in-xr", `domid: #term; faceuser: true`)
|
||||
},100)
|
||||
//instance.winbox.resize(720,380)
|
||||
let size = `width: ${this.data.width}; height: ${this.data.height}`
|
||||
instance.setAttribute("window", `title: xrsh.iso; uid: ${instance.uid}; attach: #overlay; dom: #${instance.dom.id}; ${size}; min: ${this.data.minimized}; max: ${this.data.maximized}`)
|
||||
|
@ -231,6 +229,8 @@ if( typeof AFRAME != 'undefined '){
|
|||
// run iso
|
||||
let opts = {dom:instance.dom}
|
||||
for( let i in this.data ) opts[i] = this.data[i]
|
||||
opts.cols = this.cols
|
||||
opts.rows = this.rows
|
||||
this.term.start(opts)
|
||||
})
|
||||
|
||||
|
@ -262,6 +262,7 @@ if( typeof AFRAME != 'undefined '){
|
|||
if( this.el.components.window && this.data.renderer == 'canvas'){
|
||||
this.el.components.window.show( showdom )
|
||||
}
|
||||
this.el.emit('focus',e.detail)
|
||||
}
|
||||
|
||||
this.el.addEventListener('obbcollisionstarted', focus(false) )
|
||||
|
@ -290,17 +291,20 @@ if( typeof AFRAME != 'undefined '){
|
|||
},
|
||||
|
||||
setupVT100: function(instance){
|
||||
const el = this.el.dom.querySelector('#vt100')
|
||||
this.vt100 = new VT100(
|
||||
Math.floor(this.data.width/this.data.lineHeight),
|
||||
Math.floor(this.data.height*0.8/this.data.lineHeight),
|
||||
el,
|
||||
100
|
||||
)
|
||||
const el = this.el.dom.querySelector('#term')
|
||||
const opts = {
|
||||
cols: this.cols,
|
||||
rows: this.rows,
|
||||
el_or_id: el,
|
||||
max_scroll_lines: 100,
|
||||
nodim: true
|
||||
}
|
||||
this.vt100 = new VT100( opts )
|
||||
this.vt100.el = el
|
||||
this.vt100.curs_set( 1, true)
|
||||
el.focus()
|
||||
this.el.addEventListener('focus', () => el.focus())
|
||||
this.vt100.getch( (ch,t) => {
|
||||
console.log(ch)
|
||||
this.term.send( ch )
|
||||
this.vt100.curs_set( 0, true)
|
||||
})
|
||||
|
@ -323,6 +327,27 @@ if( typeof AFRAME != 'undefined '){
|
|||
//})
|
||||
},
|
||||
|
||||
setupBox: function(){
|
||||
// setup slightly bigger black backdrop (this.el.getObject3D("mesh"))
|
||||
const w = this.data.width/950;
|
||||
const h = this.data.height/950;
|
||||
this.el.box = document.createElement('a-entity')
|
||||
this.el.box.setAttribute("geometry",`primitive: box; width:${w}; height:${h}; depth: -${this.data.depth}`)
|
||||
this.el.box.setAttribute("material","shader:flat; color:black; opacity:0.9; transparent:true; ")
|
||||
this.el.box.setAttribute("position",`0 0 ${(this.data.depth/2)-0.001}`)
|
||||
this.el.appendChild(this.el.box)
|
||||
},
|
||||
|
||||
calculateDimension: function(){
|
||||
if( this.data.width == -1 ) this.data.width = document.body.offsetWidth
|
||||
if( this.data.height == -1 ) this.data.height = document.body.offsetHeight
|
||||
if( this.data.height > this.data.width ) this.data.height = this.data.width // mobile smartphone fix
|
||||
this.data.width -= this.data.padding*2
|
||||
this.data.height -= this.data.padding*2
|
||||
this.cols = Math.floor(this.data.width/this.data.lineHeight*1.9)
|
||||
this.rows = Math.floor(this.data.height*0.5/this.data.lineHeight*1.7) // keep extra height for mobile browser bottom-bar (android)
|
||||
},
|
||||
|
||||
events:{
|
||||
|
||||
// combined AFRAME+DOM reactive events
|
||||
|
|
|
@ -61,11 +61,11 @@ ISOTerminal.prototype.convert = {
|
|||
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);
|
||||
return btoa(binary);
|
||||
},
|
||||
|
||||
base64ToArrayBuffer: function(base64) {
|
||||
const binaryString = window.atob(base64);
|
||||
const binaryString = atob(base64);
|
||||
const len = binaryString.length;
|
||||
const bytes = new Uint8Array(len);
|
||||
|
||||
|
@ -211,11 +211,14 @@ ISOTerminal.prototype.startVM = function(opts){
|
|||
\r[38;5;165m ▬▬▬▬▬▬▬▬ https://xrsh.isvery.ninja ▬▬▬▬▬▬▬▬▬▬▬▬
|
||||
\r[38;5;165m local-first, polyglot, unixy WebXR IDE & runtime
|
||||
\r
|
||||
\r credits: NLnet | @nlnet@nlnet.nl
|
||||
\r Leon van Kammen | @lvk@mastodon.online
|
||||
\r Fabien Benetou | @utopiah@mastodon.pirateparty.be
|
||||
\r Mr Doob | THREE.js
|
||||
\r Diego Marcos | AFRAME.js
|
||||
\r credits
|
||||
\r -------
|
||||
\r @nlnet@nlnet.nl
|
||||
\r @lvk@mastodon.online
|
||||
\r @utopiah@mastodon.pirateparty.be
|
||||
\r https://www.w3.org/TR/webxr
|
||||
\r https://three.org
|
||||
\r https://aframe.org
|
||||
`
|
||||
|
||||
const text_color = "\r[38;5;129m"
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
// https://raw.githubusercontent.com/vsinitsyn/vt100/refs/heads/coffeescript/public/javascripts/VT100.js
|
||||
// https://raw.githubusercontent.com/vetupinitsyn/vt100/refs/heads/coffeescript/public/javascripts/VT100.js
|
||||
//
|
||||
// VT100.js -- a text terminal emulator in JavaScript with a ncurses-like
|
||||
// interface and a POSIX-like interface. (The POSIX-like calls are
|
||||
// implemented on top of the ncurses-like calls, not the other way round.)
|
||||
//
|
||||
// required markup:
|
||||
//
|
||||
// <div id="term" tabindex="0">
|
||||
// <pre></pre>
|
||||
// </div>
|
||||
|
||||
//
|
||||
// Released under the GNU LGPL v2.1, by Frank Bi <bi@zompower.tk>
|
||||
//
|
||||
|
@ -77,8 +84,10 @@
|
|||
// interpreted and acted on.
|
||||
|
||||
// constructor
|
||||
function VT100(wd, ht, el_or_id, max_scroll_lines, fg, bg)
|
||||
function VT100(opts)
|
||||
{
|
||||
this.opts = opts
|
||||
let {cols, rows, el_or_id, max_scroll_lines, fg, bg, nodim} = opts
|
||||
if (!max_scroll_lines) {
|
||||
max_scroll_lines = 1000;
|
||||
}
|
||||
|
@ -92,20 +101,20 @@ function VT100(wd, ht, el_or_id, max_scroll_lines, fg, bg)
|
|||
var r;
|
||||
var c;
|
||||
var scr = typeof el_or_id == 'string' ? document.getElementById(el_or_id) : el_or_id
|
||||
this.wd_ = wd;
|
||||
this.ht_ = ht;
|
||||
this.wd_ = cols;
|
||||
this.ht_ = rows;
|
||||
// Keep up to max_scroll_lines of scrollback history.
|
||||
this.max_ht_ = max_scroll_lines;
|
||||
this._set_colors(fg, bg);
|
||||
this.text_ = new Array(ht);
|
||||
this.attr_ = new Array(ht);
|
||||
this.redraw_ = new Array(ht);
|
||||
this.scroll_region_ = [0, ht-1];
|
||||
this.text_ = new Array(rows);
|
||||
this.attr_ = new Array(rows);
|
||||
this.redraw_ = new Array(rows);
|
||||
this.scroll_region_ = [0, rows-1];
|
||||
this.start_row_id = 0;
|
||||
this.num_rows_ = ht;
|
||||
for (r = 0; r < ht; ++r) {
|
||||
this.text_[r] = new Array(wd);
|
||||
this.attr_[r] = new Array(wd);
|
||||
this.num_rows_ = rows;
|
||||
for (r = 0; r < rows; ++r) {
|
||||
this.text_[r] = new Array(cols);
|
||||
this.attr_[r] = new Array(cols);
|
||||
this.redraw_[r] = 1;
|
||||
}
|
||||
this.scr_ = scr;
|
||||
|
@ -116,10 +125,14 @@ function VT100(wd, ht, el_or_id, max_scroll_lines, fg, bg)
|
|||
this.key_buf_ = [];
|
||||
this.echo_ = false;
|
||||
this.esc_state_ = 0;
|
||||
this.log_level_ = VT100.DEBUG //WARN;
|
||||
this.log_level_ = VT100.WARN
|
||||
|
||||
this.clear_all();
|
||||
this.refresh();
|
||||
|
||||
// rate limit this.refresh
|
||||
this.refresh = this.throttleSmart( VT100.prototype.refresh.bind(this), 100)
|
||||
|
||||
this.setupTouchInputFallback() // smartphone
|
||||
}
|
||||
|
||||
// public constants -- colours and colour pairs
|
||||
|
@ -172,6 +185,7 @@ VT100.handle_onkeypress_ = function VT100_handle_onkeypress(event,cb)
|
|||
var vt = VT100.the_vt_, ch;
|
||||
if (vt === undefined)
|
||||
return true;
|
||||
|
||||
//if ( event.keyCode != undefined || !event.charCode){
|
||||
// ch = event.keyCode;
|
||||
// if (ch == 13)
|
||||
|
@ -180,11 +194,11 @@ VT100.handle_onkeypress_ = function VT100_handle_onkeypress(event,cb)
|
|||
// return true;
|
||||
// ch = String.fromCharCode(ch);
|
||||
//} else {
|
||||
ch = event.charCode;
|
||||
//dump("ch: " + ch + "\n");
|
||||
//dump("ctrl?: " + event.ctrlKey + "\n");
|
||||
vt.debug("onkeypress:: keyCode: " + event.keyCode + ", ch: " + event.charCode);
|
||||
if (ch) {
|
||||
vt.debug("onkeypress:: ch: " + event.code + " ,key: "+event.key);
|
||||
if (event.key.length == 1) {
|
||||
ch = event.key.charCodeAt(0)
|
||||
if (ch > 255)
|
||||
return true;
|
||||
if (event.ctrlKey && event.shiftKey) {
|
||||
|
@ -203,51 +217,52 @@ VT100.handle_onkeypress_ = function VT100_handle_onkeypress(event,cb)
|
|||
}
|
||||
} else {
|
||||
switch (event.key) {
|
||||
case "Backspace":
|
||||
ch = '\b';
|
||||
break;
|
||||
case "Tab":
|
||||
ch = '\t';
|
||||
break;
|
||||
case event.DOM_VK_RETURN:
|
||||
case event.DOM_VK_ENTER:
|
||||
ch = '\r';
|
||||
break;
|
||||
case event.DOM_VK_UP:
|
||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||
case "Backspace":
|
||||
ch = '\b';
|
||||
break;
|
||||
case "Tab":
|
||||
ch = '\t';
|
||||
break;
|
||||
case "Enter":
|
||||
ch = '\n';
|
||||
break;
|
||||
case "ArrowUp":
|
||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||
ch = '\x1b[A';
|
||||
else
|
||||
else
|
||||
ch = '\x1bOA';
|
||||
break;
|
||||
case event.DOM_VK_DOWN:
|
||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||
break;
|
||||
case "ArrowDown":
|
||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||
ch = '\x1b[B';
|
||||
else
|
||||
else
|
||||
ch = '\x1bOB';
|
||||
break;
|
||||
case event.DOM_VK_RIGHT:
|
||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||
break;
|
||||
case "ArrowRight":
|
||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||
ch = '\x1b[C';
|
||||
else
|
||||
else
|
||||
ch = '\x1bOC';
|
||||
break;
|
||||
case event.DOM_VK_LEFT:
|
||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||
break;
|
||||
case "ArrowLeft":
|
||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||
ch = '\x1b[D';
|
||||
else
|
||||
else
|
||||
ch = '\x1bOD';
|
||||
break;
|
||||
case event.DOM_VK_DELETE:
|
||||
ch = '\x1b[3~';
|
||||
break;
|
||||
case event.DOM_VK_HOME:
|
||||
ch = '\x1b[H';
|
||||
break;
|
||||
case event.DOM_VK_ESCAPE:
|
||||
ch = '\x1b';
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
break;
|
||||
case "Delete":
|
||||
ch = '\x1b[3~';
|
||||
break;
|
||||
case "Home":
|
||||
ch = '\x1b[H';
|
||||
break;
|
||||
case "Escape":
|
||||
ch = '\x1b';
|
||||
case "Control":
|
||||
break;
|
||||
default:
|
||||
return true
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Stop the event from doing anything else.
|
||||
|
@ -311,39 +326,39 @@ VT100.prototype.html_colours_ = function VT100_html_colours_(attr)
|
|||
var fg, bg, co0, co1;
|
||||
fg = attr.fg;
|
||||
bg = attr.bg;
|
||||
switch (attr.mode & (VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD)) {
|
||||
case 0:
|
||||
case VT100.A_DIM | VT100.A_BOLD:
|
||||
co0 = '00';
|
||||
if (bg == VT100.COLOR_WHITE)
|
||||
co1 = 'ff';
|
||||
else
|
||||
co1 = 'c0';
|
||||
break;
|
||||
case VT100.A_BOLD:
|
||||
co0 = '00'; co1 = 'ff';
|
||||
break;
|
||||
case VT100.A_DIM:
|
||||
if (fg == VT100.COLOR_BLACK)
|
||||
co0 = '40';
|
||||
else
|
||||
co0 = '00';
|
||||
co1 = '40';
|
||||
break;
|
||||
case VT100.A_REVERSE:
|
||||
case VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD:
|
||||
co0 = 'c0'; co1 = '40';
|
||||
break;
|
||||
case VT100.A_REVERSE | VT100.A_BOLD:
|
||||
co0 = 'c0'; co1 = '00';
|
||||
break;
|
||||
default:
|
||||
if (fg == VT100.COLOR_BLACK)
|
||||
co0 = '80';
|
||||
else
|
||||
co0 = 'c0';
|
||||
co1 = 'c0';
|
||||
}
|
||||
switch (attr.mode & (VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD)) {
|
||||
case 0:
|
||||
case VT100.A_DIM | VT100.A_BOLD:
|
||||
co0 = '00';
|
||||
if (bg == VT100.COLOR_WHITE)
|
||||
co1 = 'ff';
|
||||
else
|
||||
co1 = 'c0';
|
||||
break;
|
||||
case VT100.A_BOLD:
|
||||
co0 = '00'; co1 = 'ff';
|
||||
break;
|
||||
case VT100.A_DIM:
|
||||
if (fg == VT100.COLOR_BLACK)
|
||||
co0 = '40';
|
||||
else
|
||||
co0 = '00';
|
||||
co1 = '40';
|
||||
break;
|
||||
case VT100.A_REVERSE:
|
||||
case VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD:
|
||||
co0 = 'c0'; co1 = 'ff';
|
||||
break;
|
||||
case VT100.A_REVERSE | VT100.A_BOLD:
|
||||
co0 = 'c0'; co1 = '00';
|
||||
break;
|
||||
default:
|
||||
if (fg == VT100.COLOR_BLACK)
|
||||
co0 = '80';
|
||||
else
|
||||
co0 = 'c0';
|
||||
co1 = 'c0';
|
||||
}
|
||||
return {
|
||||
f: '#' + (fg & 4 ? co1 : co0) +
|
||||
(fg & 2 ? co1 : co0) +
|
||||
|
@ -1283,6 +1298,52 @@ VT100.prototype.warn = function VT100_warn(message) {
|
|||
}
|
||||
}
|
||||
|
||||
VT100.prototype.throttleSmart = function throttleSmart(fn, wait) {
|
||||
let timeout, lastArgs;
|
||||
return (...args) => {
|
||||
lastArgs = lastArgs || []
|
||||
if (!timeout) {
|
||||
fn(...args); timeout = setTimeout(() => { fn(...lastArgs); timeout = null; }, wait);
|
||||
} else lastArgs = args;
|
||||
};
|
||||
}
|
||||
|
||||
VT100.prototype.setupTouchInputFallback = function(){
|
||||
this.scr_.addEventListener('touchend', () => {
|
||||
if( !this.input ){
|
||||
this.form = document.createElement("form")
|
||||
this.form.addEventListener("submit", (e) => {
|
||||
e.preventDefault()
|
||||
this.key_buf_.push('\n')
|
||||
setTimeout(VT100.go_getch_, 0);
|
||||
})
|
||||
this.input = document.createElement("input")
|
||||
this.input.setAttribute("cols", this.opts.cols )
|
||||
this.input.setAttribute("rows", this.opts.rows )
|
||||
this.input.style.opacity = '0'
|
||||
this.input.style.position = 'absolute'
|
||||
this.input.style.left = '-9999px'
|
||||
this.form.appendChild(this.input)
|
||||
this.scr_.parentElement.appendChild(this.form)
|
||||
|
||||
this.input.handler = () => {
|
||||
let ch = this.input.value
|
||||
// detect backspace
|
||||
//if( e.inputType == 'deleteContentBackward' ) ch = '\b'
|
||||
this.input.value = ''
|
||||
if( !ch ) return
|
||||
this.key_buf_.push(ch);
|
||||
setTimeout(VT100.go_getch_, 0);
|
||||
this.input.valueLast = this.input.value
|
||||
}
|
||||
this.input.addEventListener('input', this.input.handler )
|
||||
|
||||
}
|
||||
setTimeout( () => this.input.focus(), 10 )
|
||||
})
|
||||
}
|
||||
|
||||
function dump(x) {
|
||||
// Do nothing
|
||||
console.log(x)
|
||||
}
|
||||
|
|
|
@ -1,15 +1,31 @@
|
|||
if( typeof emulator != 'undefined' ){
|
||||
// inside worker-thread
|
||||
importScripts("localforage.js") // we don't instance it again here (just use its functions)
|
||||
|
||||
this['emulator.restore_state'] = async function(data){
|
||||
await emulator.restore_state(data)
|
||||
console.log("restored state")
|
||||
this.postMessage({event:"state_restored",data:false})
|
||||
return new Promise( (resolve,reject) => {
|
||||
localforage.getItem("state", async (err,stateBase64) => {
|
||||
if( stateBase64 && !err ){
|
||||
state = ISOTerminal.prototype.convert.base64ToArrayBuffer( stateBase64 )
|
||||
await emulator.restore_state(state)
|
||||
console.log("restored state")
|
||||
}else return reject("worker.js: emulator.restore_state (could not get state from localforage)")
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
this['emulator.save_state'] = async function(){
|
||||
console.log("saving session")
|
||||
let state = await emulator.save_state()
|
||||
this.postMessage({event:"state_saved",data:state},[state])
|
||||
localforage.setDriver([
|
||||
localforage.INDEXEDDB,
|
||||
localforage.WEBSQL,
|
||||
localforage.LOCALSTORAGE
|
||||
]).then( () => {
|
||||
localforage.setItem("state", ISOTerminal.prototype.convert.arrayBufferToBase64(state) )
|
||||
console.log("state saved")
|
||||
})
|
||||
console.dir(state)
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,30 +46,21 @@ if( typeof emulator != 'undefined' ){
|
|||
localforage.getItem("state", async (err,stateBase64) => {
|
||||
if( stateBase64 && !err && confirm('continue last session?') ){
|
||||
this.noboot = true // see feat/boot.js
|
||||
state = this.convert.base64ToArrayBuffer( stateBase64 )
|
||||
|
||||
this.addEventListener('state_restored', function(){
|
||||
try{
|
||||
await this.worker['emulator.restore_state']()
|
||||
// simulate / fastforward boot events
|
||||
this.postBoot( () => {
|
||||
this.send("l\n")
|
||||
this.send("hook wakeup\n")
|
||||
})
|
||||
})
|
||||
|
||||
this.worker.postMessage({event:'emulator.restore_state',data:state})
|
||||
}catch(e){ console.error(e) }
|
||||
}
|
||||
})
|
||||
|
||||
this.save = async () => {
|
||||
const state = await this.worker.postMessage({event:"emulator.save_state",data:false})
|
||||
await this.worker['emulator.save_state']()
|
||||
}
|
||||
|
||||
this.addEventListener('state_saved', function(e){
|
||||
const state = e.detail
|
||||
localforage.setItem("state", this.convert.arrayBufferToBase64(state) )
|
||||
console.log("state saved")
|
||||
})
|
||||
|
||||
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
|
||||
|
|
|
@ -4,7 +4,11 @@ ISOTerminal.addEventListener('ready', function(e){
|
|||
|
||||
ISOTerminal.prototype.boot = async function(e){
|
||||
// set environment
|
||||
let env = ['export BROWSER=1']
|
||||
let env = [
|
||||
`export LINES=${this.opts.rows}`,
|
||||
`export COLUMNS=${this.opts.cols}`,
|
||||
'export BROWSER=1',
|
||||
]
|
||||
for ( let i in document.location ){
|
||||
if( typeof document.location[i] == 'string' ){
|
||||
env.push( 'export '+String(i).toUpperCase()+'="'+decodeURIComponent( document.location[i]+'"') )
|
||||
|
|
Loading…
Reference in New Issue