diff --git a/app/apptiler.js b/app/apptiler.js deleted file mode 100644 index 3559069..0000000 --- a/app/apptiler.js +++ /dev/null @@ -1,298 +0,0 @@ -// -// this is just an AFRAME wrapper for golden-layout v2 (docs: https://golden-layout.github.io/golden-layout/) -// -// -AFRAME.registerComponent('apptiler', { - schema: { - }, - - requires:{ - goldenlayout_css1: "https://unpkg.com/golden-layout@2.6.0/dist/css/goldenlayout-base.css", - goldenlayout_css2: "https://unpkg.com/golden-layout@2.6.0/dist/css/themes/goldenlayout-dark-theme.css", - }, - - dom: { - events: [], - - // for stylesheet see bottom of file - html: (me) => ` -
-
-
`, - - }, - - events:{ - DOMready: async function(){ - await this.initLayout(this) - AFRAME.app.foreach( (opts) => { - this.add( opts.component, opts.app.el.dom) - if( opts.component != 'apptiler' ) opts.app.el.dom.classList.add(['tile']) - }) - setTimeout( () => document.querySelector('#overlay').classList.add(['apptiler']), 100 ) - // surf to entrypoint of other xrsh worlds - // - //AFRAME.XRF.navigator.to("https://coderofsalvation.github.io/xrsh-media/assets/background.glb") - }, - - }, - - init: function () { - this.require( this.requires ) - }, - - initLayout: async function(){ - if( this.goldenLayout !== undefined || !this.el.dom.querySelector(".modals")) return console.warn("TODO: fix duplicate ready-events") - - let { GoldenLayout } = await import("https://cdn.skypack.dev/pin/golden-layout@v2.5.0-dAz3xMzxIRpbnbfEAik0/mode=imports/optimized/golden-layout.js"); - - class Modal { - constructor(container) { - this.container = container; - this.rootElement = container.element; - this.rootElement.innerHTML = '' - this.resizeWithContainerAutomatically = true; - } - } - const myLayout = { - root: { - type: 'row', - content: [] - } - }; - - this.goldenLayout = new GoldenLayout( this.el.dom.querySelector('.modals')); - this.goldenLayout.registerComponent('Modal', Modal); - this.goldenLayout.loadLayout(myLayout); - }, - - add: function(title,el){ - if( title == 'apptiler' ) return // dont add yourself to yourself please - let item = this.goldenLayout.addComponent('Modal', undefined, title ) - try{ - item.parentItem.contentItems[ item.parentItem.contentItems.length-1 ].element.querySelector('.lm_content').appendChild(el) - }catch(e){} // ignore elements which are already appended - }, - - manifest: { // HTML5 manifest to identify app to xrsh - "short_name": "windowmanager", - "name": "Window Manager", - "icons": [ - { - "src": "/images/icons-vector.svg", - "type": "image/svg+xml", - "sizes": "512x512" - } - ], - "id": "/?source=pwa", - "start_url": "/?source=pwa", - "background_color": "#3367D6", - "display": "standalone", - "scope": "/", - "theme_color": "#3367D6", - "shortcuts": [], - "description": "2D/3D management of windows", - "screenshots": [ - { - "src": "/images/screenshot1.png", - "type": "image/png", - "sizes": "540x720", - "form_factor": "narrow" - } - ], - "help":` -Window Manager - -The window manager manages all the windows in 2D/XR. -This is a core XRSH system application - ` - } - -}); - -document.head.innerHTML += ` - -` diff --git a/app/helloworld-html.js b/app/helloworld-html.js new file mode 100644 index 0000000..f9cfb0b --- /dev/null +++ b/app/helloworld-html.js @@ -0,0 +1,104 @@ +AFRAME.registerComponent('helloworld-html', { + schema: { + foo: { type:"string"} + }, + + init: function () { + + }, + + requires:{ + html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME + }, + + dom: { + scale: 3, + events: ['click'], + html: (me) => `
+
helloworld-html: ${me.data.foo} ${me.data.myvalue} +
`, + + css: `.helloworld-html { + color: var(--xrsh-dark-gray); /* see index.css */ + } + `, + }, + + events:{ + + // component events + html: function( ){ console.log("html-mesh requirement mounted") }, + ready: function(e){ console.log("requires are loaded") }, + + // combined AFRAME+DOM reactive events + keydown: function(e){ }, // + click: function(e){ + console.dir(e) + }, // + + // reactive events for this.data updates + myvalue: function(e){ this.el.dom.querySelector('b').innerText = this.data.myvalue }, + + + DOMready: function( ){ + console.log("this.el.dom has been added to DOM") + this.el.dom.children[0].id = this.el.uid // important hint for html-mesh + this.data.myvalue = 1 + setInterval( () => this.data.myvalue++, 100 ) + } + + }, + + manifest: { // HTML5 manifest to identify app to xrsh + "short_name": "Hello world", + "name": "Hello world", + "icons": [ + { + "src": "/images/icons-vector.svg", + "type": "image/svg+xml", + "sizes": "512x512" + } + ], + "id": "/?source=pwa", + "start_url": "/?source=pwa", + "background_color": "#3367D6", + "display": "standalone", + "scope": "/", + "theme_color": "#3367D6", + "shortcuts": [ + { + "name": "What is the latest news?", + "cli":{ + "usage": "helloworld [options]", + "example": "helloworld news", + "args":{ + "--latest": {type:"string"} + } + }, + "short_name": "Today", + "description": "View weather information for today", + "url": "/today?source=pwa", + "icons": [{ "src": "/images/today.png", "sizes": "192x192" }] + } + ], + "description": "Hello world information", + "screenshots": [ + { + "src": "/images/screenshot1.png", + "type": "image/png", + "sizes": "540x720", + "form_factor": "narrow" + } + ], + "help":` +Helloworld application + +This is a help file which describes the application. +It will be rendered thru troika text, and will contain +headers based on non-punctualized lines separated by linebreaks, +in above's case "\nHelloworld application\n" will qualify as header. + ` + } + +}); + diff --git a/app/helloworld-htmlform.js b/app/helloworld-htmlform.js new file mode 100644 index 0000000..de86fdd --- /dev/null +++ b/app/helloworld-htmlform.js @@ -0,0 +1,139 @@ +AFRAME.registerComponent('helloworld-htmlform', { + schema: { + foo: { type:"string"} + }, + + init: function () { + + }, + + requires:{ + html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME + winboxjs: "https://unpkg.com/winbox@0.2.82/dist/winbox.bundle.min.js", // deadsimple windows: https://nextapps-de.github.io/winbox + winboxcss: "https://unpkg.com/winbox@0.2.82/dist/css/winbox.min.css", // deadsimple windows: https://nextapps-de.github.io/winbox + stylis: "https://unpkg.com/stylis@4.3.1/dist/umd/stylis.js", // modern CSS (https://stylis.js.org) + }, + + dom: { + scale: 3, + events: ['click','input'], + html: (me) => `
+
+ Colour +
+
+
+
+ Material: +
+
+
+ Size: + +
+ +
`, + css: `.helloworld-htmlform { + div { + padding:11px; + } + } + `, + }, + + events:{ + + // component events + html: function( ){ console.log("html-mesh requirement mounted") }, + stylis: function( ){ console.log("stylis requirement mounted") }, + + // combined AFRAME+DOM reactive events + click: function(e){ }, // + input: function(e){ + if( !e.detail.target ) return + if( e.detail.target.id == 'myRange' ) this.data.myvalue = e.detail.target.value // reactive demonstration + }, + + // reactive events for this.data updates + myvalue: function(e){ this.el.dom.querySelector('#myvalue').innerText = this.data.myvalue }, + + // requires are loaded + ready: function(e){ + setTimeout( () => { + new WinBox("Hello World",{ + width: 250, + height: 315, + minwidth:250, + maxwidth:250, + maxheight:315, + minheight:315, + x: 100, + y: 100, + id: this.el.uid, // important hint for html-mesh + root: document.querySelector("#overlay"), + mount: this.el.dom + }); + },500) /*FIXME*/ + + }, + + DOMready: function( ){ + console.log("this.el.dom has been added to DOM") + this.data.myvalue = 1 + } + + }, + + manifest: { // HTML5 manifest to identify app to xrsh + "short_name": "Hello world", + "name": "Hello world", + "icons": [ + { + "src": "/images/icons-vector.svg", + "type": "image/svg+xml", + "sizes": "512x512" + } + ], + "id": "/?source=pwa", + "start_url": "/?source=pwa", + "background_color": "#3367D6", + "display": "standalone", + "scope": "/", + "theme_color": "#3367D6", + "shortcuts": [ + { + "name": "What is the latest news?", + "cli":{ + "usage": "helloworld [options]", + "example": "helloworld news", + "args":{ + "--latest": {type:"string"} + } + }, + "short_name": "Today", + "description": "View weather information for today", + "url": "/today?source=pwa", + "icons": [{ "src": "/images/today.png", "sizes": "192x192" }] + } + ], + "description": "Hello world information", + "screenshots": [ + { + "src": "/images/screenshot1.png", + "type": "image/png", + "sizes": "540x720", + "form_factor": "narrow" + } + ], + "help":` +Helloworld application + +This is a help file which describes the application. +It will be rendered thru troika text, and will contain +headers based on non-punctualized lines separated by linebreaks, +in above's case "\nHelloworld application\n" will qualify as header. + ` + } + +}); + diff --git a/app/helloworld-window.js b/app/helloworld-window.js new file mode 100644 index 0000000..2ffda16 --- /dev/null +++ b/app/helloworld-window.js @@ -0,0 +1,121 @@ +AFRAME.registerComponent('helloworld-window', { + schema: { + foo: { type:"string"} + }, + + init: function () { + + }, + + requires:{ + html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME + winboxjs: "https://unpkg.com/winbox@0.2.82/dist/winbox.bundle.min.js", // deadsimple windows: https://nextapps-de.github.io/winbox + winboxcss: "https://unpkg.com/winbox@0.2.82/dist/css/winbox.min.css", // deadsimple windows: https://nextapps-de.github.io/winbox + stylis: "https://unpkg.com/stylis@4.3.1/dist/umd/stylis.js", // modern CSS (https://stylis.js.org) + }, + + dom: { + scale: 3, + events: ['click','keydown'], + html: (me) => `
+
${me.data.foo} ${me.data.myvalue} +
`, + css: `.helloworld-window { + div { + .pad { padding:11px; } + } + } + `, + }, + + events:{ + + // component events + html: function( ){ console.log("html-mesh requirement mounted") }, + stylis: function( ){ console.log("stylis requirement mounted") }, + + // combined AFRAME+DOM reactive events + click: function(e){ }, // + keydown: function(e){ }, // + + // reactive events for this.data updates + myvalue: function(e){ this.el.dom.querySelector('b').innerText = this.data.myvalue }, + + // requires are loaded + ready: function(e){ + + setTimeout( () => { + new WinBox("Hello World",{ + width: 250, + height: 150, + x:"center", + y:"center", + id: this.el.uid, // important hint for html-mesh + root: document.querySelector("#overlay"), + mount: this.el.dom + }); + }, 500 ) + + }, + + DOMready: function( ){ + console.log("this.el.dom has been added to DOM") + this.data.myvalue = 1 + setInterval( () => this.data.myvalue++, 100 ) + } + + }, + + manifest: { // HTML5 manifest to identify app to xrsh + "short_name": "Hello world", + "name": "Hello world", + "icons": [ + { + "src": "/images/icons-vector.svg", + "type": "image/svg+xml", + "sizes": "512x512" + } + ], + "id": "/?source=pwa", + "start_url": "/?source=pwa", + "background_color": "#3367D6", + "display": "standalone", + "scope": "/", + "theme_color": "#3367D6", + "shortcuts": [ + { + "name": "What is the latest news?", + "cli":{ + "usage": "helloworld [options]", + "example": "helloworld news", + "args":{ + "--latest": {type:"string"} + } + }, + "short_name": "Today", + "description": "View weather information for today", + "url": "/today?source=pwa", + "icons": [{ "src": "/images/today.png", "sizes": "192x192" }] + } + ], + "description": "Hello world information", + "screenshots": [ + { + "src": "/images/screenshot1.png", + "type": "image/png", + "sizes": "540x720", + "form_factor": "narrow" + } + ], + "help":` +Helloworld application + +This is a help file which describes the application. +It will be rendered thru troika text, and will contain +headers based on non-punctualized lines separated by linebreaks, +in above's case "\nHelloworld application\n" will qualify as header. + ` + } + +}); + diff --git a/app/helloworld.js b/app/helloworld.js index 60890a4..ec96a47 100644 --- a/app/helloworld.js +++ b/app/helloworld.js @@ -3,76 +3,20 @@ AFRAME.registerComponent('helloworld', { foo: { type:"string"} }, - requires:{ - html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME - stylis: "https://unpkg.com/stylis@4.3.1/dist/umd/stylis.js", // modern CSS (https://stylis.js.org) + init: function () { + this.el.setAttribute("geometry","primitive: octahedron") }, - dom: { - scale: 3, - events: ['click','input'], - html: (me) => ` - `, - css: `.modal.hello { - position:relative; - top:0; - width:200px; - .title { font-weight:bold; } /* modern nested buildless css thanks to stylis */ - }` + requires:{ + // somecomponent: "https://unpkg.com/some-aframe-component/mycom.min.js" }, events:{ - html: function( ){ console.log("html-mesh requirement mounted") }, - stylis: function( ){ console.log("stylis requirement mounted") }, + // component events + somecomponent: function( ){ console.log("component requirement mounted") }, + ready: function(e){ console.log("requires are loaded") }, - DOMready: function(e){ - // our reactive dom element has been added to the dom (DOMElement = this.el.dom) - }, - - click: function(e){ // a click was detected on this.el.dom or AFRAME entity - let el = e.detail.target || e.detail.srcElement - if( !el ) return - if( el.className.match("fold") ) this.el.toggleFold() - if( el.className.match("close") ) this.el.close() - }, - - input: function(e){ - if( !e.detail.target ) return - if( e.detail.target.id == 'myRange' ) this.data.value = e.detail.target.value // reactive demonstration - }, - - value: function(e){ this.el.dom.querySelector("#value").innerHTML = e.detail.v }, // auto-emitted when this.data.value gets updated - - }, - - init: function () { - this.require( this.requires ) - - this.scene.addEventListener('apps:2D', () => this.el.setAttribute('visible', false) ) - this.scene.addEventListener('apps:XR', () => { - this.el.setAttribute('visible', true) - this.el.setAttribute("html",`html:#${this.el.uid}; cursor:#cursor`) - }) }, manifest: { // HTML5 manifest to identify app to xrsh diff --git a/app/helloworld.old.js b/app/helloworld.old.js new file mode 100644 index 0000000..db483ed --- /dev/null +++ b/app/helloworld.old.js @@ -0,0 +1,137 @@ +AFRAME.registerComponent('helloworld', { + schema: { + foo: { type:"string"} + }, + + requires:{ + html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME + stylis: "https://unpkg.com/stylis@4.3.1/dist/umd/stylis.js", // modern CSS (https://stylis.js.org) + }, + + dom: { + scale: 3, + events: ['click','input'], + html: (me) => ` + `, + css: ` + /* +* * HTML-2-WebGL limitations / guidelines for html-mesh compatibility: + * no icon libraries (favicon e.g.) + * in case of 'border-radius: 2px 3px 4px 5px' (2px will apply to all corners) + * dont use transform: scale(1.2) e.g. +* */ + .modal.hello { + position:relative; + top:0; + width:200px; + .title { font-weight:bold; } /* modern nested buildless css thanks to stylis */ + }` + }, + + events:{ + + html: function( ){ console.log("html-mesh requirement mounted") }, + stylis: function( ){ console.log("stylis requirement mounted") }, + + DOMready: function(e){ + // our reactive dom element has been added to the dom (DOMElement = this.el.dom) + }, + + click: function(e){ // a click was detected on this.el.dom or AFRAME entity + let el = e.detail.target || e.detail.srcElement + if( !el ) return + if( el.className.match("fold") ) this.el.toggleFold() + if( el.className.match("close") ) this.el.close() + }, + + input: function(e){ + if( !e.detail.target ) return + if( e.detail.target.id == 'myRange' ) this.data.value = e.detail.target.value // reactive demonstration + }, + + value: function(e){ this.el.dom.querySelector("#value").innerHTML = e.detail.v }, // auto-emitted when this.data.value gets updated + + }, + + init: function () { + this.require( this.requires ) + + this.scene.addEventListener('apps:2D', () => this.el.setAttribute('visible', false) ) + this.scene.addEventListener('apps:XR', () => { + this.el.setAttribute('visible', true) + this.el.setAttribute("html",`html:#${this.el.uid}; cursor:#cursor`) + }) + }, + + manifest: { // HTML5 manifest to identify app to xrsh + "short_name": "Hello world", + "name": "Hello world", + "icons": [ + { + "src": "/images/icons-vector.svg", + "type": "image/svg+xml", + "sizes": "512x512" + } + ], + "id": "/?source=pwa", + "start_url": "/?source=pwa", + "background_color": "#3367D6", + "display": "standalone", + "scope": "/", + "theme_color": "#3367D6", + "shortcuts": [ + { + "name": "What is the latest news?", + "cli":{ + "usage": "helloworld [options]", + "example": "helloworld news", + "args":{ + "--latest": {type:"string"} + } + }, + "short_name": "Today", + "description": "View weather information for today", + "url": "/today?source=pwa", + "icons": [{ "src": "/images/today.png", "sizes": "192x192" }] + } + ], + "description": "Hello world information", + "screenshots": [ + { + "src": "/images/screenshot1.png", + "type": "image/png", + "sizes": "540x720", + "form_factor": "narrow" + } + ], + "help":` +Helloworld application + +This is a help file which describes the application. +It will be rendered thru troika text, and will contain +headers based on non-punctualized lines separated by linebreaks, +in above's case "\nHelloworld application\n" will qualify as header. + ` + } + +}); + diff --git a/app/manual.js b/app/manual.js index 842db20..e80fdb8 100644 --- a/app/manual.js +++ b/app/manual.js @@ -3,53 +3,87 @@ AFRAME.registerComponent('manual', { foo: { type:"string"} }, - requires:{}, + init: function () { + + }, + + requires:{ + html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME + winboxjs: "https://unpkg.com/winbox@0.2.82/dist/winbox.bundle.min.js", // deadsimple windows: https://nextapps-de.github.io/winbox + winboxcss: "https://unpkg.com/winbox@0.2.82/dist/css/winbox.min.css", // deadsimple windows: https://nextapps-de.github.io/winbox + stylis: "https://unpkg.com/stylis@4.3.1/dist/umd/stylis.js", // modern CSS (https://stylis.js.org) + }, dom: { - events: ['click'], - html: (me) => ` -
-

Welcome to XRSHell

-
- -

- The xrsh (xrshell) brings the FOSS- and Linux-soul to WebXR, promoting the use of (interactive text) terminal and user-provided operating systems inside WebXR. -

Technically, xrsh is a bundle of freshly created re-usable FOSS WebXR components.
These provide a common filesystem interface for interacting with WebXR, offering the well-known linux/unix toolchain including a commandline to invoke, store, edit and run WebXR utilities - regardless of their implementation. -

Think of it as termux for the VR/AR headset browser, which can be used to e.g. livecode (using terminal auto-completion!) for XR component (registries). + scale: 3, + events: ['click','keydown'], + html: (me) => `
-
- +

Welcome to XRSHell

+
+ +

+ The xrsh (xrshell) brings the FOSS- and Linux-soul to WebXR, promoting the use of (interactive text) terminal and user-provided operating systems inside WebXR. +

Technically, xrsh is a bundle of freshly created re-usable FOSS WebXR components.
These provide a common filesystem interface for interacting with WebXR, offering the well-known linux/unix toolchain including a commandline to invoke, store, edit and run WebXR utilities - regardless of their implementation. +

Think of it as termux for the VR/AR headset browser, which can be used to e.g. livecode (using terminal auto-completion!) for XR component (registries). -
`, - css: ` - #manual { - padding:15px; +
+ + +
`, + css: `.manual { + div { + padding:11px; + } } - #manual img{ - width: 100%; - max-width: 550px; - border-radius: 7px; - } - - ` + `, }, events:{ - DOMready: function(e){}, - click: function(e){}, // click was detected on this.el.dom or AFRAME entity - }, - init: function () { - this.require( this.requires ) + // component events + html: function( ){ console.log("html-mesh requirement mounted") }, + stylis: function( ){ console.log("stylis requirement mounted") }, + + // combined AFRAME+DOM reactive events + click: function(e){ }, // + keydown: function(e){ }, // + + // reactive events for this.data updates + myvalue: function(e){ this.el.dom.querySelector('b').innerText = this.data.myvalue }, + + // requires are loaded + ready: function(e){ + + setTimeout( () => { + new WinBox("XRSH manual",{ + width:300, + height:300, + x:"center", + y:"center", + id: this.el.uid, // important hint for html-mesh + root: document.querySelector("#overlay"), + mount: this.el.dom + }); + }, 500 ) + + }, + + DOMready: function( ){ + console.log("this.el.dom has been added to DOM") + this.data.myvalue = 1 + setInterval( () => this.data.myvalue++, 100 ) + } + }, manifest: { // HTML5 manifest to identify app to xrsh - "short_name": "XRSH Manual", - "name": "XRSH Manual", + "short_name": "Hello world", + "name": "Hello world", "icons": [ { "src": "/images/icons-vector.svg", @@ -67,10 +101,10 @@ AFRAME.registerComponent('manual', { { "name": "What is the latest news?", "cli":{ - "usage": "man xrsh", - "example": "", + "usage": "helloworld [options]", + "example": "helloworld news", "args":{ - "topic": {type:"string"} + "--latest": {type:"string"} } }, "short_name": "Today", @@ -79,7 +113,7 @@ AFRAME.registerComponent('manual', { "icons": [{ "src": "/images/today.png", "sizes": "192x192" }] } ], - "description": "XRSH Manual information", + "description": "Hello world information", "screenshots": [ { "src": "/images/screenshot1.png", diff --git a/com/app.js b/com/app.js index 9e87b60..cfecab0 100644 --- a/com/app.js +++ b/com/app.js @@ -53,33 +53,35 @@ AFRAME.registerComponent('app', { let deps = [] if( !packages.map ) packages = Object.values(packages) packages.map( (package) => { - let id = package.split("/").pop() - // prevent duplicate requests - if( AFRAME.required[id] ) return - AFRAME.required[id] = true + try{ + let id = package.split("/").pop() + // prevent duplicate requests + if( AFRAME.required[id] ) return + AFRAME.required[id] = true - if( !document.head.querySelector(`script#${id}`) ){ - let {id,component,type} = this.parseAppURI(package) - let p = new Promise( (resolve,reject) => { - switch(type){ - case "js": let script = document.createElement("script") - script.id = id - script.src = package - script.onload = () => resolve() - script.onerror = (e) => reject(e) - document.head.appendChild(script) - break; - case "css": let link = document.createElement("link") - link.id = id - link.href = package - link.rel = 'stylesheet' - document.head.appendChild(link) - resolve() - break; - } - }) - deps.push(p) - } + if( !document.head.querySelector(`script#${id}`) ){ + let {component,type} = this.parseAppURI(package) + let p = new Promise( (resolve,reject) => { + switch(type){ + case "js": let script = document.createElement("script") + script.id = id + script.src = package + script.onload = () => resolve() + script.onerror = (e) => reject(e) + document.head.appendChild(script) + break; + case "css": let link = document.createElement("link") + link.id = id + link.href = package + link.rel = 'stylesheet' + document.head.appendChild(link) + resolve() + break; + } + }) + deps.push(p) + } + }catch(e){ console.error(`package ${package} could not be retrieved..aborting :(`); throw e; } }) Promise.all(deps).then( () => this.el.emit( readyEvent||'ready', packages) ) } @@ -106,15 +108,24 @@ AFRAME.AComponent.prototype.initComponent = function(initComponent){ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){ return function(){ updateProperties.apply(this,arguments) - if( this.dom && this.data && this.data.uri ){ + + + const reactify = (el,aframe) => new Proxy(this.data,{ + get(me,k,v) { return me[k] + }, + set(me,k,v){ + me[k] = v + aframe.emit(k,{el,k,v}) + } + }) + + if( !this.data ) return + + // reactify components with dom-definition + if( this.data.uri && this.dom && !this.el.dom ){ tasks = { - generateUniqueId: () => { - this.el.uid = String(Math.random()).substr(10) - return tasks - }, - ensureOverlay: () => { let overlay = document.querySelector('#overlay') if( !overlay ){ @@ -128,13 +139,6 @@ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){ }, createReactiveDOMElement: () => { - const reactify = (el,aframe) => new Proxy(this.data,{ - get(me,k,v) { return me[k] }, - set(me,k,v){ - me[k] = v - aframe.emit(k,{el,k,v}) - } - }) this.el.dom = document.createElement('div') this.el.dom.className = this.parseAppURI(this.data.uri).component this.el.dom.innerHTML = this.dom.html(this) @@ -155,35 +159,38 @@ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){ return tasks }, - addModalFunctions: () => { - this.el.close = () => { - this.el.dom.remove() - this.el.removeAttribute("html") - } + requireDependencies: () => { + this.require( this.requires ) + return tasks + }, + + setupListeners: () => { + this.scene.addEventListener('apps:2D', () => this.el.setAttribute('visible', false) ) + this.scene.addEventListener('apps:XR', () => { + this.el.setAttribute('visible', true) + this.el.setAttribute("html",`html:#${this.el.uid}; cursor:#cursor`) + }) return tasks } + } tasks - .generateUniqueId() .ensureOverlay() .addCSS() .createReactiveDOMElement() .scaleDOMvsXR() - .addModalFunctions() + .requireDependencies() + .setupListeners() tasks.overlay.appendChild(this.el.dom) this.el.emit('DOMready',{el: this.el.dom}) - } + + } + // assign unique app id + if( !this.el.uid ) this.el.uid = '_'+String(Math.random()).substr(10) } }( AFRAME.AComponent.prototype.updateProperties) -// -// base CSS for XRSH apps -// -// limitations / some guidelines for html-mesh compatibility: -// * no icon libraries (favicon e.g.) -// * 'border-radius: 2px 3px 4px 5px' (applies 2px to all corners) -// document.head.innerHTML += `