Compare commits
33 commits
feat/remot
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 0407a23747 | |||
| cbc9daa8cd | |||
| 92590d6ecc | |||
| e486111105 | |||
| 11674a1509 | |||
| 06ea1c56c8 | |||
|
|
6b2b9834ac | ||
| 468cee87af | |||
| 8ac69c4aed | |||
| f2d0c36f09 | |||
| a38fe0a16d | |||
| a74e1dd60d | |||
| 628357019c | |||
| 2cf3cb6808 | |||
| 310d7304a4 | |||
| 6f8dfc7bc3 | |||
| c17c2e4808 | |||
| 277bc79e78 | |||
| d2698c5e8e | |||
| 95c91c72d8 | |||
| d424328c9a | |||
| aca83f7235 | |||
| bd9de85ffc | |||
| ab5efe4a33 | |||
| 9a9994a105 | |||
| e72d296726 | |||
| 139f12031f | |||
| 05a2858ef7 | |||
| 14bdd5fff3 | |||
| b48f9f47cc | |||
| 5a35281c33 | |||
| 5a3de2604d | |||
| f9ca00efb8 |
15 changed files with 8445 additions and 60286 deletions
77
index.html
77
index.html
File diff suppressed because one or more lines are too long
6
make
6
make
|
|
@ -68,6 +68,7 @@ standalone(){ # build standalone xrsh.com binary
|
|||
echo " fbterm: true,"
|
||||
echo " fbtermjs: true,"
|
||||
echo " remotekeyboard: true"
|
||||
echo " remotestorage: true"
|
||||
echo " };"
|
||||
} > xrsh.js
|
||||
ls -lh xrsh.js
|
||||
|
|
@ -80,9 +81,10 @@ standalone(){ # build standalone xrsh.com binary
|
|||
dev(){ # start dev http server
|
||||
set -x
|
||||
cd "$DIR"
|
||||
test -f xrsh.com || standalone
|
||||
wget "$REDBEAN_VERSION" -O /tmp/server.com
|
||||
chmod +x /tmp/server.com
|
||||
test -f /tmp/cert.pem || openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout /tmp/key.pem -out /tmp/cert.pem
|
||||
./xrsh.com -c 0 -C /tmp/cert.pem -K /tmp/key.pem -D . "$@"
|
||||
/tmp/server.com -c 0 -C /tmp/cert.pem -K /tmp/key.pem -D . "$@"
|
||||
}
|
||||
|
||||
shell(){ # run xrsh shell via docker
|
||||
|
|
|
|||
416
src/assets/aframe-remotestorage.min.js
vendored
Normal file
416
src/assets/aframe-remotestorage.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7696
src/assets/xrfragment.aframe.js
Normal file
7696
src/assets/xrfragment.aframe.js
Normal file
File diff suppressed because one or more lines are too long
BIN
src/engine.glb
BIN
src/engine.glb
Binary file not shown.
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
:root {
|
||||
--xrsh-primary: #3a51ff;
|
||||
--xrsh-primary: #00AA;
|
||||
--xrsh-primary-fg: #FFF;
|
||||
--xrsh-light-primary: #00a3Ff;
|
||||
--xrsh-secondary: #872eff;
|
||||
|
|
@ -17,9 +17,11 @@
|
|||
--xrsh-dark-gray: #343334;
|
||||
--xrsh-gray: #424280;
|
||||
--xrsh-white: #fdfdfd;
|
||||
--xrsh-black: #001c;
|
||||
--xrsh-light-gray: #efefef;
|
||||
--xrsh-lighter-gray: #e4e2fb96;
|
||||
--xrsh-window-radius: 10px;
|
||||
--xrsh-control-radius: 7px;
|
||||
--xrsh-font-sans-serif: system-ui, -apple-system, segoe ui, roboto, ubuntu, helvetica, cantarell, noto sans, sans-serif;
|
||||
--xrsh-font-monospace: menlo, monaco, lucida console, liberation mono, dejavu sans mono, bitstream vera sans mono, courier new, monospace, serif;
|
||||
--xrsh-font-size-0: 12px;
|
||||
|
|
@ -54,7 +56,7 @@ a,a:visited,a:active{
|
|||
*/
|
||||
|
||||
button,.btn,input[type=submit]{
|
||||
border-radius:7px;
|
||||
border-radius: var(--xrsh-control-radius);
|
||||
background: var(--xrsh-primary);
|
||||
color: var(--xrsh-primary-fg);
|
||||
transition:0.3s;
|
||||
|
|
@ -98,31 +100,55 @@ button,input,.btn{
|
|||
*/
|
||||
.winbox {
|
||||
box-shadow:none !important;
|
||||
background:transparent !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
.winbox .wb-body{
|
||||
background: var(--xrsh-dark-gray);
|
||||
margin-top: -6px !important;
|
||||
/*margin-top: -6px !important;*/
|
||||
z-index: 100;
|
||||
border: 1px solid #FFF3;
|
||||
border-radius:7px;
|
||||
border-radius:0px 0px var(--xrsh-window-radius) var(--xrsh-window-radius);
|
||||
}
|
||||
.winbox .wb-header{
|
||||
background:transparent !important;
|
||||
background: var(--xrsh-dark-gray);
|
||||
z-index:1000;
|
||||
font-weight: bold;
|
||||
border-radius: var(--xrsh-window-radius) var(--xrsh-window-radius) 0px 0px;
|
||||
line-height:36px;
|
||||
|
||||
}
|
||||
.winbox.max .wb-header{
|
||||
border-radius:0px;
|
||||
}
|
||||
|
||||
.XR .winbox .wb-header{
|
||||
border-radius:0px !important;
|
||||
margin-top:0px;
|
||||
}
|
||||
|
||||
.XR .winbox .wb-control .xr {
|
||||
display:block;
|
||||
}
|
||||
.winbox .wb-control .xr {
|
||||
display:none;
|
||||
background:transparent !important;
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
cursor:pointer;
|
||||
}
|
||||
.winbox .wb-control .xr.xr-wb-close,
|
||||
.winbox .wb-control .xr.xr-wb-min{
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
.winbox .wb-body{
|
||||
top:0px;
|
||||
top: 35 !important;
|
||||
padding-top:35px;
|
||||
}
|
||||
.winbox .wb-control{
|
||||
padding-right:5px;
|
||||
height:29px;
|
||||
color:#FFF;
|
||||
z-index:1001;
|
||||
}
|
||||
.winbox .wb-drag{
|
||||
padding-left:19px;
|
||||
|
|
@ -160,7 +186,6 @@ button,input,.btn{
|
|||
background: var(--xrsh-white);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* icons for non-XR (please source from https://css.gg
|
||||
*
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<link rel="stylesheet" href="./index.css"></link>
|
||||
<script src="./assets/aframe.min.js"></script>
|
||||
<script src="./assets/xrfragment.aframe.js"></script>
|
||||
|
||||
<script src="com/require.js"></script>
|
||||
<script src="com/isoterminal.js"></script>
|
||||
|
|
|
|||
|
|
@ -1,37 +1,56 @@
|
|||
term = document.querySelector('[isoterminal]').components.isoterminal.term
|
||||
convert = ISOTerminal.prototype.convert
|
||||
isoterminal = document.querySelector("[isoterminal]")
|
||||
|
||||
console.test("com/isoterminal/ISOTerminal.js", async () => {
|
||||
isoterminal.addEventListener("ready", function(){
|
||||
|
||||
term = isoterminal.components.isoterminal.term
|
||||
convert = ISOTerminal.prototype.convert
|
||||
|
||||
console.test.tests = {} // empty previous tests
|
||||
|
||||
console.test("com/isoterminal/ISOTerminal.js", async () => {
|
||||
|
||||
term.worker.create_file("foo", convert.toUint8Array("hello") )
|
||||
.then( (res) => {
|
||||
term.worker.read_file("foo")
|
||||
.then( (res) => {
|
||||
try{
|
||||
let data = convert.Uint8ArrayToString( res )
|
||||
console.assert( data == "hello", "worker.create_file")
|
||||
}catch(e){
|
||||
console.assert( false, "worker.create_file")
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(console.error)
|
||||
.finally(console.dir)
|
||||
|
||||
term.worker.read_file("root/.profile")
|
||||
.then( (res) => {
|
||||
try{
|
||||
let data = convert.Uint8ArrayToString( res )
|
||||
console.assert( data.length, "worker.postMessage.promise()")
|
||||
}catch(e){
|
||||
console.assert( false, "worker.postMessage.promise()")
|
||||
}
|
||||
})
|
||||
.catch(console.error)
|
||||
.finally(console.dir)
|
||||
|
||||
})
|
||||
console.test("com/isoterminal/ISOTerminal.js", async () => {
|
||||
|
||||
console.test("com/isoterminal/ISOTerminal.js", async () => {
|
||||
|
||||
term.worker.create_file("foo", convert.toUint8Array("hello") )
|
||||
.then( (res) => {
|
||||
term.worker.read_file("foo")
|
||||
.then( (res) => {
|
||||
try{
|
||||
let data = convert.Uint8ArrayToString( res )
|
||||
console.assert( data == "hello", "worker.create_file")
|
||||
console.assert( data.length && data == "hello", "worker.postMessage.promise()")
|
||||
}catch(e){
|
||||
console.assert( false, "worker.create_file")
|
||||
console.assert( false, "worker.postMessage.promise()")
|
||||
}
|
||||
})
|
||||
.catch(console.error)
|
||||
.finally(console.dir)
|
||||
|
||||
})
|
||||
.catch(console.error)
|
||||
.finally(console.dir)
|
||||
|
||||
|
||||
console.test.run()
|
||||
|
||||
})
|
||||
|
||||
console.test("com/isoterminal.js", async () => {
|
||||
console.assert( AFRAME.components.isoterminal != undefined, "AFRAME.components.isoterminal")
|
||||
})
|
||||
|
||||
console.test("xrsh.iso", async () => {
|
||||
console.assert( false, "create testsuite.zip package which tests iso")
|
||||
})
|
||||
|
|
|
|||
10
src/tests/index.js
Normal file
10
src/tests/index.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
const run = async function(){
|
||||
await AFRAME.utils.require({
|
||||
"test_util": "tests/util.js",
|
||||
"test_isoterminal":"tests/ISOTerminal.js"
|
||||
})
|
||||
console.test.run()
|
||||
}
|
||||
|
||||
run()
|
||||
|
|
@ -1,20 +1,23 @@
|
|||
|
||||
// minimalistc testrunner
|
||||
console.test = async (name,cb) => {
|
||||
window.console.test = async (name,cb) => {
|
||||
let tests = console.test.tests = console.test.tests || {}
|
||||
tests[name] = tests[name] || []
|
||||
tests[name].push(cb)
|
||||
console.test.run = async () => {
|
||||
for( let name in tests ){
|
||||
console.log("\x1b[34m\x1b[36;49m"+name+"\x1B[m")
|
||||
for( let test in tests[name] ){
|
||||
await tests[name][test]()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.assert = ((assert) => (a,reason,data) => {
|
||||
window.console.test.run = async (cb) => {
|
||||
const tests = window.console.test.tests
|
||||
for( let name in tests ){
|
||||
console.log("\x1b[34m\x1b[36;49m"+name+"\x1B[m")
|
||||
for( let test in tests[name] ){
|
||||
await tests[name][test]()
|
||||
}
|
||||
}
|
||||
if( cb ) cb()
|
||||
}
|
||||
|
||||
window.console.assert = ((assert) => (a,reason,data) => {
|
||||
console.log("\x1b[34m\x1b[36;49m♥ \x1B[m"+reason)
|
||||
assert.call( console, a, {reason} )
|
||||
if( !a ){
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 9d549454d62671f52b007fa91098453008c37768
|
||||
Subproject commit 10bbfd27e21a1b7368c38432178309263662aef6
|
||||
60139
src/xrsh.html
60139
src/xrsh.html
File diff suppressed because one or more lines are too long
BIN
xrsh.com
BIN
xrsh.com
Binary file not shown.
|
|
@ -1 +1 @@
|
|||
d25cabf0091a73f78e13c6a3135aad6178dc4708c02733446ab659b018cdfe96 xrsh.com
|
||||
e791dba58adf568d34648eeed71e047d60b126b3dd5a6d81306a4307c5b7c3ad xrsh.com
|
||||
|
|
|
|||
253
xrsh.js
253
xrsh.js
|
|
@ -14,7 +14,7 @@ document.head.innerHTML += `<style type='text/css'>
|
|||
*/
|
||||
|
||||
:root {
|
||||
--xrsh-primary: #3a51ff;
|
||||
--xrsh-primary: #00AA;
|
||||
--xrsh-primary-fg: #FFF;
|
||||
--xrsh-light-primary: #00a3Ff;
|
||||
--xrsh-secondary: #872eff;
|
||||
|
|
@ -23,9 +23,11 @@ document.head.innerHTML += `<style type='text/css'>
|
|||
--xrsh-dark-gray: #343334;
|
||||
--xrsh-gray: #424280;
|
||||
--xrsh-white: #fdfdfd;
|
||||
--xrsh-black: #001c;
|
||||
--xrsh-light-gray: #efefef;
|
||||
--xrsh-lighter-gray: #e4e2fb96;
|
||||
--xrsh-window-radius: 10px;
|
||||
--xrsh-control-radius: 7px;
|
||||
--xrsh-font-sans-serif: system-ui, -apple-system, segoe ui, roboto, ubuntu, helvetica, cantarell, noto sans, sans-serif;
|
||||
--xrsh-font-monospace: menlo, monaco, lucida console, liberation mono, dejavu sans mono, bitstream vera sans mono, courier new, monospace, serif;
|
||||
--xrsh-font-size-0: 12px;
|
||||
|
|
@ -60,7 +62,7 @@ a,a:visited,a:active{
|
|||
*/
|
||||
|
||||
button,.btn,input[type=submit]{
|
||||
border-radius:7px;
|
||||
border-radius: var(--xrsh-control-radius);
|
||||
background: var(--xrsh-primary);
|
||||
color: var(--xrsh-primary-fg);
|
||||
transition:0.3s;
|
||||
|
|
@ -104,31 +106,55 @@ button,input,.btn{
|
|||
*/
|
||||
.winbox {
|
||||
box-shadow:none !important;
|
||||
background:transparent !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
.winbox .wb-body{
|
||||
background: var(--xrsh-dark-gray);
|
||||
margin-top: -6px !important;
|
||||
/*margin-top: -6px !important;*/
|
||||
z-index: 100;
|
||||
border: 1px solid #FFF3;
|
||||
border-radius:7px;
|
||||
border-radius:0px 0px var(--xrsh-window-radius) var(--xrsh-window-radius);
|
||||
}
|
||||
.winbox .wb-header{
|
||||
background:transparent !important;
|
||||
background: var(--xrsh-dark-gray);
|
||||
z-index:1000;
|
||||
font-weight: bold;
|
||||
border-radius: var(--xrsh-window-radius) var(--xrsh-window-radius) 0px 0px;
|
||||
line-height:36px;
|
||||
|
||||
}
|
||||
.winbox.max .wb-header{
|
||||
border-radius:0px;
|
||||
}
|
||||
|
||||
.XR .winbox .wb-header{
|
||||
border-radius:0px !important;
|
||||
margin-top:0px;
|
||||
}
|
||||
|
||||
.XR .winbox .wb-control .xr {
|
||||
display:block;
|
||||
}
|
||||
.winbox .wb-control .xr {
|
||||
display:none;
|
||||
background:transparent !important;
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
cursor:pointer;
|
||||
}
|
||||
.winbox .wb-control .xr.xr-wb-close,
|
||||
.winbox .wb-control .xr.xr-wb-min{
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
.winbox .wb-body{
|
||||
top:0px;
|
||||
top: 35 !important;
|
||||
padding-top:35px;
|
||||
}
|
||||
.winbox .wb-control{
|
||||
padding-right:5px;
|
||||
height:29px;
|
||||
color:#FFF;
|
||||
z-index:1001;
|
||||
}
|
||||
.winbox .wb-drag{
|
||||
padding-left:19px;
|
||||
|
|
@ -166,7 +192,6 @@ button,input,.btn{
|
|||
background: var(--xrsh-white);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* icons for non-XR (please source from https://css.gg
|
||||
*
|
||||
|
|
@ -251,6 +276,7 @@ e.removeClass=function(a){this.g.classList.remove(a);return this};e.toggleClass=
|
|||
*
|
||||
* | property | type | default | info |
|
||||
* |-------------------|-----------|------------------------|------|
|
||||
* | `title` | `string` | 'xrsh.iso' | window title |
|
||||
* | `iso` | `string` | https`//forgejo.isvery.ninja/assets/xrsh-buildroot/main/xrsh.iso" | |
|
||||
* | `overlayfs` | `string` | '' | zip URL/file to autoextract on top of filesystem |
|
||||
* | `width` | `number` | 800 ||
|
||||
|
|
@ -310,6 +336,7 @@ if( typeof AFRAME != 'undefined '){
|
|||
schema: {
|
||||
iso: { type:"string", "default":"https://forgejo.isvery.ninja/assets/xrsh-buildroot/main/xrsh.iso" },
|
||||
overlayfs: { type:"string"},
|
||||
title: { type:"string", "default":"xrsh.iso"},
|
||||
width: { type: 'number',"default": 800 },
|
||||
height: { type: 'number',"default": 600 },
|
||||
depth: { type: 'number',"default": 0.03 },
|
||||
|
|
@ -380,6 +407,8 @@ if( typeof AFRAME != 'undefined '){
|
|||
|
||||
.isoterminal{
|
||||
padding: ${me.com.data.padding}px;
|
||||
margin-top:-60px;
|
||||
padding-bottom:60px;
|
||||
width:100%;
|
||||
height:99%;
|
||||
resize: both;
|
||||
|
|
@ -482,18 +511,19 @@ if( typeof AFRAME != 'undefined '){
|
|||
-webkit-animation:none;
|
||||
}
|
||||
|
||||
.wb-body:has(> .isoterminal){
|
||||
background: #000C;
|
||||
.winbox#${me.el.uid} .wb-header{
|
||||
background: var(--xrsh-black) !important;
|
||||
}
|
||||
|
||||
.wb-body:has(> .isoterminal){
|
||||
background: var(--xrsh-black);
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.XR .wb-body:has(> .isoterminal){
|
||||
background: transparent;
|
||||
.XR .isoterminal{
|
||||
background: #000 !important;
|
||||
}
|
||||
|
||||
.XR .isoterminal{
|
||||
background: #000;
|
||||
}
|
||||
.isoterminal *{
|
||||
font-size: 14px;
|
||||
font-family: "Cousine",Liberation Mono,DejaVu Sans Mono,Courier New,monospace;
|
||||
|
|
@ -542,15 +572,20 @@ if( typeof AFRAME != 'undefined '){
|
|||
remotekeyboard: "com/isoterminal/feat/remotekeyboard.js",
|
||||
indexhtml: "com/isoterminal/feat/index.html.js",
|
||||
indexjs: "com/isoterminal/feat/index.js.js",
|
||||
autorestore: "com/isoterminal/feat/autorestore.js",
|
||||
pastedropFeat: "com/isoterminal/feat/pastedrop.js",
|
||||
httpfs: "com/isoterminal/feat/httpfs.js",
|
||||
autorestore: "com/isoterminal/feat/autorestore.js",
|
||||
}
|
||||
if( document.location.hash.match(/#test/) || this.data.debug ){
|
||||
features['tests'] = "tests/index.js"
|
||||
}
|
||||
if( this.data.emulator == 'fbterm' ){
|
||||
features['fbtermjs'] = "com/isoterminal/term.js"
|
||||
features['fbterm'] = "com/isoterminal/feat/term.js"
|
||||
}
|
||||
await AFRAME.utils.require(features)
|
||||
// this one extends autorestore.js
|
||||
await AFRAME.utils.require({remotestorage: "com/isoterminal/feat/remotestorage.js"})
|
||||
|
||||
this.el.setAttribute("selfcontainer","")
|
||||
|
||||
|
|
@ -575,7 +610,7 @@ if( typeof AFRAME != 'undefined '){
|
|||
this.term.emit('term_init', {instance, aEntity:this})
|
||||
//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}; class: no-full, no-max, no-resize; grabbable: components.html.el.object3D.children.${this.el.children.length}`)
|
||||
instance.setAttribute("window", `title: ${this.data.title}; uid: ${instance.uid}; attach: #overlay; dom: #${instance.dom.id}; ${size}; min: ${this.data.minimized}; max: ${this.data.maximized}; class: no-full, no-min, no-close, no-max, no-resize; grabbable: components.html.el.object3D.children.${this.el.children.length}`)
|
||||
})
|
||||
|
||||
instance.addEventListener('window.oncreate', (e) => {
|
||||
|
|
@ -603,7 +638,6 @@ if( typeof AFRAME != 'undefined '){
|
|||
this.term.addEventListener('ready', (e) => {
|
||||
instance.dom.classList.remove('blink')
|
||||
this.term.emit('status',"running")
|
||||
if( this.data.debug ) this.runTests()
|
||||
})
|
||||
|
||||
this.term.addEventListener('status', function(e){
|
||||
|
|
@ -623,6 +657,23 @@ if( typeof AFRAME != 'undefined '){
|
|||
instance.addEventListener('window.onmaximize', resize )
|
||||
|
||||
const focus = (e) => {
|
||||
|
||||
if( event.target == document.activeElement ){
|
||||
// if we're already focused, the keyboard is already triggerend
|
||||
// therefore we blur() the element for correctness
|
||||
// which allows the WebXR keyboard dissappear if implemented at all
|
||||
// [Meta Quest 2 does not do this]
|
||||
event.target.blur()
|
||||
}
|
||||
|
||||
// calculate distance between thumb and indexfinger to detect pinch
|
||||
// which should prevent focus-event (annoying to have keyboard popping up during pinch)
|
||||
if( e.detail?.withEl?.components['hand-tracking-controls'] ){
|
||||
const hand = e.detail.withEl.components['hand-tracking-controls']
|
||||
const thumb = hand.bones.find( (b) => b.name == 'thumb-tip' )
|
||||
const diff = thumb.position.distanceTo(hand.indexTipPosition)
|
||||
if( diff < 0.02) return // pinching! don't trigger keyboard (focus)
|
||||
}
|
||||
this.el.emit('focus',e.detail)
|
||||
}
|
||||
|
||||
|
|
@ -641,14 +692,6 @@ if( typeof AFRAME != 'undefined '){
|
|||
}
|
||||
},
|
||||
|
||||
runTests: async function(){
|
||||
await AFRAME.utils.require({
|
||||
"test_util": "tests/util.js",
|
||||
"test_isoterminal":"tests/ISOTerminal.js"
|
||||
})
|
||||
console.test.run()
|
||||
},
|
||||
|
||||
setupPasteDrop: function(){
|
||||
this.el.addEventListener('pasteFile', (e) => {
|
||||
e.preventDefault() // prevent bubbling up to window (which is triggering this initially)
|
||||
|
|
@ -672,9 +715,10 @@ if( typeof AFRAME != 'undefined '){
|
|||
this.el.addEventListener('exec', (e) => this.term.exec( e.detail ) )
|
||||
this.el.addEventListener('hook', (e) => this.term.hook( e.detail[0], e.detail[1] ) )
|
||||
this.el.addEventListener('send', (e) => this.term.send( e.detail[0], e.detail[1] || 0 ) )
|
||||
this.el.addEventListener('create_file', async (e) => await this.term.worker.create_file( e.detail[0], this.term.convert.toUint8Array(e.detail[1]) ) )
|
||||
this.el.addEventListener('update_file', async (e) => await this.term.worker.update_file( e.detail[0], this.term.convert.toUint8Array(e.detail[1]) ) )
|
||||
this.el.addEventListener('append_file', async (e) => await this.term.worker.append_file( e.detail[0], this.term.convert.toUint8Array(e.detail[1]) ) )
|
||||
this.el.addEventListener('create_file', async (e) => await this.term.worker.create_file( e.detail[0], e.detail[1] ) )
|
||||
this.el.addEventListener('create_file_from_url', async (e) => await this.term.worker.create_file_from_url( e.detail[0], e.detail[1] ) )
|
||||
this.el.addEventListener('update_file', async (e) => await this.term.worker.update_file( e.detail[0], e.detail[1] ) )
|
||||
this.el.addEventListener('append_file', async (e) => await this.term.worker.append_file( e.detail[0], e.detail[1] ) )
|
||||
this.el.addEventListener('read_file', async (e) => {
|
||||
const buf = await this.term.worker.read_file( e.detail[0] )
|
||||
const str = new TextDecoder().decode(buf)
|
||||
|
|
@ -722,6 +766,7 @@ if( typeof AFRAME != 'undefined '){
|
|||
"scope": "/",
|
||||
"theme_color": "#3367D6",
|
||||
"shortcuts": [
|
||||
/*
|
||||
{
|
||||
"name": "What is the latest news?",
|
||||
"cli":{
|
||||
|
|
@ -736,8 +781,9 @@ if( typeof AFRAME != 'undefined '){
|
|||
"url": "/today?source=pwa",
|
||||
"icons": [{ "src": "/images/today.png", "sizes": "192x192" }]
|
||||
}
|
||||
*/
|
||||
],
|
||||
"description": "Hello world information",
|
||||
"description": "Runs an .iso file",
|
||||
"screenshots": [
|
||||
{
|
||||
"src": "/images/screenshot1.png",
|
||||
|
|
@ -747,7 +793,7 @@ if( typeof AFRAME != 'undefined '){
|
|||
}
|
||||
],
|
||||
"help":`
|
||||
Helloworld application
|
||||
XRSH application
|
||||
|
||||
This is a help file which describes the application.
|
||||
It will be rendered thru troika text, and will contain
|
||||
|
|
@ -860,9 +906,9 @@ if( !AFRAME.components.dom ){
|
|||
|
||||
this
|
||||
.ensureOverlay()
|
||||
.addCSS()
|
||||
.createReactiveDOMElement()
|
||||
.assignUniqueID()
|
||||
.addCSS()
|
||||
.scaleDOMvsXR()
|
||||
.triggerKeyboardForInputs()
|
||||
|
||||
|
|
@ -1395,16 +1441,6 @@ AFRAME.registerComponent('window', {
|
|||
setupWindow: async function(){
|
||||
await AFRAME.utils.require(this.dependencies)
|
||||
if( !this.el.dom ) return console.error('window element requires dom-component as dependency')
|
||||
|
||||
const close = () => {
|
||||
let e = {halt:false}
|
||||
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()
|
||||
return false
|
||||
}
|
||||
this.el.addEventListener('close', () => {
|
||||
close()
|
||||
this.el.winbox.close()
|
||||
|
|
@ -1433,8 +1469,12 @@ AFRAME.registerComponent('window', {
|
|||
this.el.components['obb-collider'].data.trackedObject3D = this.data.grabbable
|
||||
this.el.components['obb-collider'].update()
|
||||
},1000)
|
||||
|
||||
this.patchButtons(e)
|
||||
},
|
||||
onclose: close
|
||||
onminimize: this.onminimize,
|
||||
onrestore: this.onrestore,
|
||||
onclose: this.onclose.bind(this),
|
||||
|
||||
});
|
||||
this.data.dom.style.display = '' // show
|
||||
|
|
@ -1454,7 +1494,46 @@ AFRAME.registerComponent('window', {
|
|||
|
||||
show: function(state){
|
||||
this.el.dom.closest('.winbox').style.display = state ? '' : 'none'
|
||||
},
|
||||
|
||||
onminimize: function(e){
|
||||
if( AFRAME.scenes[0].renderer.xr.isPresenting ){
|
||||
this.window.style.display = 'none'
|
||||
}
|
||||
},
|
||||
|
||||
onrestore: function(e){
|
||||
if( AFRAME.scenes[0].renderer.xr.isPresenting ){
|
||||
this.window.style.display = ''
|
||||
}
|
||||
},
|
||||
|
||||
onclose: function(){
|
||||
let e = {halt:false}
|
||||
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()
|
||||
return false
|
||||
},
|
||||
|
||||
|
||||
// the buttons don't work in XR because HTMLMesh does not understand onclick on divs
|
||||
patchButtons: function(e){
|
||||
let wEl = e.mount;
|
||||
let controls = [...wEl.closest(".winbox").querySelectorAll(".wb-control span")]
|
||||
controls.map( (c) => {
|
||||
if( c.className.match(/wb-(close|min)/) ){
|
||||
let btn = document.createElement("button")
|
||||
btn.className = `xr xr-${c.className}`
|
||||
btn.innerText = c.className == "wb-close" ? "x" : "_"
|
||||
btn.addEventListener("click", (e) => { } )// this will bubble up (to click ancestor in XR)
|
||||
c.appendChild(btn)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
AFRAME.utils.positionObjectNextToNeighbor = function positionObjectNextToNeighbor(object, lastNeighbor = null, margin ){
|
||||
|
|
@ -2172,14 +2251,17 @@ function ISOTerminal(instance,opts){
|
|||
ISOTerminal.prototype.emit = function(event,data,sender){
|
||||
data = data || false
|
||||
const evObj = new CustomEvent(event, {detail: data} )
|
||||
this.preventFrameDrop( () => {
|
||||
// forward event to worker/instance/AFRAME element or component-function
|
||||
// this feels complex, but actually keeps event- and function-names more concise in codebase
|
||||
// forward event to worker/instance/AFRAME element or component-function
|
||||
// this feels complex, but actually keeps event- and function-names more concise in codebase
|
||||
let fire = () => {
|
||||
this.dispatchEvent( evObj )
|
||||
if( sender != "instance" && this.instance ) this.instance.dispatchEvent(evObj)
|
||||
if( sender != "worker" && this.worker ) this.worker.postMessage({event,data}, PromiseWorker.prototype.getTransferable(data) )
|
||||
if( sender !== undefined && typeof this[event] == 'function' ) this[event].apply(this, data && data.push ? data : [data] )
|
||||
})
|
||||
}
|
||||
if( event.match(/^serial/) ){
|
||||
this.preventFrameDrop( fire )
|
||||
}else fire()
|
||||
}
|
||||
|
||||
ISOTerminal.addEventListener = (event,cb) => {
|
||||
|
|
@ -2191,20 +2273,18 @@ ISOTerminal.addEventListener = (event,cb) => {
|
|||
ISOTerminal.prototype.exec = function(opts){
|
||||
const shellscript = opts[0];
|
||||
const cb = opts[1];
|
||||
let cmd = `printf "\n\r"; { sh<<EOF\n ${shellscript}; \nEOF\n} &> /mnt/exec;\n`
|
||||
console.log(cmd)
|
||||
if( cb ){
|
||||
window.cb = cb
|
||||
this.send(`printf "\n\r"; ${shellscript} &> /mnt/exec; js '
|
||||
document.querySelector("[isoterminal]").emit("read_file", ["exec", window.cb ])
|
||||
';
|
||||
\n`,1)
|
||||
}else{
|
||||
this.send(`printf "\n\r"; ${shellscript} \n`,1)
|
||||
cmd += `js 'document.querySelector("[isoterminal]").emit("read_file", ["exec", window.cb ])';\n`
|
||||
}
|
||||
this.send( cmd, 1 )
|
||||
}
|
||||
|
||||
ISOTerminal.prototype.hook = function(hookname,args){
|
||||
let cmd = `{ type hook || source /etc/profile.sh; }; hook ${hookname} "${args.join('" "')}"`
|
||||
this.exec(cmd)
|
||||
this.exec([cmd])
|
||||
}
|
||||
|
||||
ISOTerminal.prototype.serial_input = 0; // can be set to 0,1,2,3 to define stdinput tty (xterm plugin)
|
||||
|
|
@ -2295,8 +2375,14 @@ ISOTerminal.prototype.start = function(opts){
|
|||
},
|
||||
cmdline: "rw root=host9p rootfstype=9p rootflags=trans=virtio,cache=loose modules=virtio_pci tsc=reliable init_on_freg|=on vga=ask", //vga=0x122",
|
||||
net_device:{
|
||||
relay_url:"fetch", // or websocket proxy "wss://relay.widgetry.org/",
|
||||
type:"virtio"
|
||||
//type:"ne2k",
|
||||
relay_url:"fetch"
|
||||
//relay_url:"wss://relay.widgetry.org/"
|
||||
|
||||
//local_http: true,
|
||||
//type:"virtio",
|
||||
//relay_url:"fetch",
|
||||
//cors_proxy: "https://corsproxy.io/"
|
||||
},
|
||||
//bzimage_initrd_from_filesystem: true,
|
||||
//filesystem: {
|
||||
|
|
@ -2413,6 +2499,7 @@ ISOTerminal.prototype.startVM = function(opts){
|
|||
this.v86opts = opts
|
||||
|
||||
this.addEventListener('emulator-started', async (e) => {
|
||||
if( this.boot.fromImage ) return this.emit('serial-output-string', "\r[!] downloading session...please wait\n\r[!] this could take a while depending on your connection..\n\r")
|
||||
|
||||
let line = ''
|
||||
this.ready = false
|
||||
|
|
@ -2435,12 +2522,17 @@ ISOTerminal.prototype.startVM = function(opts){
|
|||
}
|
||||
|
||||
ISOTerminal.prototype.bootISO = function(){
|
||||
const getImage = (str) => decodeURIComponent(
|
||||
str.match(/\&img=/) ? str.replace(/.*img=/,'').replace(/\&.*/,'') : ''
|
||||
)
|
||||
let msglib = this.getLoaderMsg()
|
||||
this.emit('status',msglib.loadmsg)
|
||||
let msg = "\n\r" + msglib.empowermsg + msglib.text_color + msglib.loadmsg + msglib.text_reset
|
||||
this.emit('serial-output-string', msg)
|
||||
this.emit('runISO',{...this.v86opts, bufferLatency: this.opts.bufferLatency })
|
||||
|
||||
if( getImage(this.boot.hash) ){
|
||||
this.boot.fromImage = true
|
||||
}
|
||||
this.emit('runISO',{...this.v86opts, bufferLatency: this.opts.bufferLatency, img: getImage(this.boot.hash) })
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -3971,7 +4063,7 @@ Term.prototype.resizePixel = function (new_width, new_height)
|
|||
return true;
|
||||
}
|
||||
ISOTerminal.addEventListener('ready', function(e){
|
||||
setTimeout( () => this.boot(), 50 ) // because of autorestore.js
|
||||
setTimeout( () => this.boot(), 50 ) // allow other features/plugins to settle first (autorestore.js e.g.)
|
||||
})
|
||||
|
||||
ISOTerminal.prototype.bootMenu = function(e){
|
||||
|
|
@ -3989,13 +4081,13 @@ ISOTerminal.prototype.bootMenu = function(e){
|
|||
|
||||
}else{ // autoboot
|
||||
if( this.term ){
|
||||
this.term.handler( e.detail.bootMenu || e.detail.bootMenuURL )
|
||||
this.term.handler( String(e.detail.bootMenu || e.detail.bootMenuURL).charAt(0) )
|
||||
this.term.handler("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ISOTerminal.addEventListener('bootMenu', function(e){ this.bootMenu(e) } )
|
||||
ISOTerminal.addEventListener('bootMenu', function(e){this.bootMenu(e) })
|
||||
|
||||
ISOTerminal.prototype.boot = async function(e){
|
||||
// set environment
|
||||
|
|
@ -4005,10 +4097,17 @@ ISOTerminal.prototype.boot = async function(e){
|
|||
'export BROWSER=1',
|
||||
]
|
||||
for ( let i in document.location ){
|
||||
if( typeof document.location[i] == 'string' ){
|
||||
if( typeof document.location[i] == 'string' && !String(i).match(/(hash|search)/) ){
|
||||
env.push( 'export '+String(i).toUpperCase()+'="'+decodeURIComponent( document.location[i]+'"') )
|
||||
}
|
||||
}
|
||||
|
||||
// we export the cached hash/query (because they might be gone due to remotestorage plugin)
|
||||
if( this.boot.hash.charAt(2) == '&' ){ // strip bootoption
|
||||
this.boot.hashExBoot = `#` + this.boot.hash.substr(3)
|
||||
}
|
||||
env.push( 'export HASH="'+decodeURIComponent( this.boot.hashExBoot || this.boot.hash ) +'"' )
|
||||
env.push( 'export QUERY="'+decodeURIComponent( this.boot.query ) +'"' )
|
||||
await this.worker.create_file("profile.browser", this.convert.toUint8Array( env.join('\n') ) )
|
||||
|
||||
if( this.serial_input == 0 ){
|
||||
|
|
@ -4019,8 +4118,12 @@ ISOTerminal.prototype.boot = async function(e){
|
|||
|
||||
}
|
||||
|
||||
// here REPL's can be defined
|
||||
ISOTerminal.prototype.boot.fromImage = false
|
||||
ISOTerminal.prototype.boot.menu = []
|
||||
ISOTerminal.prototype.boot.hash = document.location.hash
|
||||
ISOTerminal.prototype.boot.query = document.location.search
|
||||
|
||||
// here REPL's can be defined
|
||||
|
||||
// REPL: iso
|
||||
if( typeof window.PromiseWorker != 'undefined' ){ // if xrsh v86 is able to run in in worker
|
||||
|
|
@ -4046,10 +4149,10 @@ if( typeof window.PromiseWorker != 'undefined' ){ // if xrsh v86 is able to run
|
|||
}
|
||||
|
||||
ISOTerminal.prototype.redirectConsole = function(handler){
|
||||
const log = console.log;
|
||||
const dir = console.dir;
|
||||
const err = console.error;
|
||||
const warn = console.warn;
|
||||
const log = console._log = console.log;
|
||||
const dir = console._dir = console.dir;
|
||||
const err = console._error = console.error;
|
||||
const warn = console._warn = console.warn;
|
||||
const addLineFeeds = (str) => typeof str == 'string' ? str.replace(/\n/g,"\r\n") : str
|
||||
|
||||
console.log = (...args)=>{
|
||||
|
|
@ -4084,12 +4187,13 @@ ISOTerminal.prototype.enableConsole = function(opts){
|
|||
let _str = typeof str == 'string' ? str : JSON.stringify(str)
|
||||
let finalStr = "";
|
||||
prefix = prefix ? prefix+' ' : ''
|
||||
_str.trim().split("\n").map( (line) => {
|
||||
String(_str).trim().split("\n").map( (line) => {
|
||||
finalStr += `${opts.stdout ? '' : "\x1b[38;5;165m/dev/browser: \x1b[0m"}`+prefix+line+'\n'
|
||||
})
|
||||
if( opts.stdout ){
|
||||
this.emit('serial-output-string', finalStr)
|
||||
this.emit('serial-output-string', finalStr, "worker")
|
||||
}else this.emit('append_file', ["/dev/browser/console",finalStr])
|
||||
this.lastStr = finalStr
|
||||
})
|
||||
|
||||
window.addEventListener('error', function(event) {
|
||||
|
|
@ -4180,12 +4284,6 @@ ISOTerminal.prototype.TermInit = function(){
|
|||
// patch Term-class
|
||||
Term.prototype.move_textarea = function(){} /* *TODO* *FIXME* does not work in winbox */
|
||||
|
||||
Term.prototype.pasteHandler = function(original){
|
||||
return function (ev){
|
||||
original.apply(this,[ev])
|
||||
}
|
||||
}( Term.prototype.pasteHandler )
|
||||
|
||||
Term.prototype.keyDownHandler = function(original){
|
||||
return function (e){
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'v') {
|
||||
|
|
@ -4400,5 +4498,6 @@ AFRAME.utils.require.required = {
|
|||
httpfs: true,
|
||||
fbterm: true,
|
||||
fbtermjs: true,
|
||||
remotekeyboard: true
|
||||
remotekeyboard: true,
|
||||
remotestorage: true
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue