diff --git a/app/helloworld.js b/app/helloworld.js
index b1e2bed..0db7cb5 100644
--- a/app/helloworld.js
+++ b/app/helloworld.js
@@ -11,9 +11,13 @@ AFRAME.registerComponent('helloworld', {
dom: {
scale: 3.5,
events: ['click','input'],
- html: `
-
-
Hello world
+ html: (me) => `
+
`,
- css: `div{ #hello {position:relative;top:0;width:300px} }`
+ css: `.modal.hello {
+ position:relative;top:0;width:200px
+ foo { /* modern css supported via stylis */ }
+ }`
},
events:{
html: function( ){ console.log("htmlmesh component mounted!") }, // html-component was added to this AFRAME entity
- title: function(e){ this.dom.el.querySelector("b").innerHTML = e.detail.v }, // this.data.title was changed
- click: function(e){ // a click was detected on this.dom.el or AFRAME entity
- if( !e.detail.target ) return
- if( e.detail.target.className == 'close' ){
- this.dom.el.remove()
- this.el.removeAttribute("html")
- }
+ 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.title = e.detail.target.value // reactive demonstration
- }
+ 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 }, // this.data.title was changed
},
init: function () {
this.require( this.dependencies )
.then( () => {
- document.body.appendChild(this.dom.el)
- this.el.setAttribute("html",'html:#hello; cursor:#cursor')
+ this.el.setAttribute("html",`html:#${this.el.uid}; cursor:#cursor`)
})
},
diff --git a/com/app.js b/com/app.js
index c078e49..569d24c 100644
--- a/com/app.js
+++ b/com/app.js
@@ -5,13 +5,14 @@ AFRAME.registerComponent('app', {
"uri":{ type:"string"}
},
init: function() {
- this.require([ this.data.uri ])
- .then( () => {
- let id = this.data.uri.split("/").pop() // 'a/b/c/mycom.js' => 'mycom.js'
- let component = id.split(".js").shift() // 'mycom.js' => 'mycom'
+ let id = this.data.uri.split("/").pop() // 'a/b/c/mycom.js' => 'mycom.js'
+ let component = id.split(".js").shift() // 'mycom.js' => 'mycom'
+ let mount = () => {
let entity = document.createElement("a-entity")
this.el.setAttribute(component,this.data)
- })
+ }
+ if( AFRAME.components[component] || document.head.querySelector(`script#${id}`) ) mount()
+ else this.require([ this.data.uri ]).then( mount ).catch(console.error)
},
@@ -68,24 +69,75 @@ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){
return function(){
updateProperties.apply(this,arguments)
if( this.dom && this.data){
- let 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})
- }
- })
- let el = document.createElement('div')
- el.innerHTML = this.dom.html
- this.data = reactify( el, this.el )
- this.dom.el = el.childNodes[0]
- this.dom.events.map( (e) => this.dom.el.addEventListener(e, (ev) => this.el.emit(e,ev) ) )
- // add css if any
- if( this.dom.css && !document.head.querySelector(`style#${this.attrName}`) ){
- document.head.innerHTML += ``
+
+ tasks = {
+
+ generateUniqueId: () => {
+ this.el.uid = String(Math.random()).substr(2)
+ return tasks
+ },
+
+ ensureOverlay: () => {
+ let overlay = document.querySelector('#overlay')
+ if( !overlay ){
+ overlay = document.createElement('div')
+ overlay.id = "#overlay"
+ document.body.appendChild(overlay)
+ document.querySelector("a-scene").setAttribute("webxr","overlayElement:#overlay")
+ }
+ tasks.overlay = overlay
+ return tasks
+ },
+
+ 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.innerHTML = this.dom.html(this)
+ this.data = reactify( this.dom.el, this.el )
+ this.dom.events.map( (e) => this.el.dom.addEventListener(e, (ev) => this.el.emit(e,ev) ) )
+ return tasks
+ },
+
+ addCSS: () => {
+ if( this.dom.css && !document.head.querySelector(`style#${this.attrName}`) ){
+ document.head.innerHTML += ``
+ }
+ return tasks
+ },
+
+ scaleDOMvsXR: () => {
+ if( this.dom.scale ) this.el.setAttribute('scale',`${this.dom.scale} ${this.dom.scale} ${this.dom.scale}`)
+ return tasks
+ },
+
+ addModalFunctions: () => {
+ this.el.close = () => {
+ this.el.dom.remove()
+ this.el.removeAttribute("html")
+ }
+ this.el.toggleFold = () => {
+ this.el.dom.querySelector(".modal").classList.toggle('fold')
+ this.el.dom.querySelector('.top .fold').innerText = this.el.dom.querySelector('.modal').className.match(/fold/) ? '▢' : '_'
+ }
+ return tasks
+ },
}
- if( this.dom.scale ) this.el.setAttribute('scale',`${this.dom.scale} ${this.dom.scale} ${this.dom.scale}`)
- //('[helloworld]').object3D.children[0].material.map.magFilter = THREE.NearestFilter
+
+ tasks
+ .generateUniqueId()
+ .ensureOverlay()
+ .addCSS()
+ .createReactiveDOMElement()
+ .scaleDOMvsXR()
+ .addModalFunctions()
+ // finally lets add the bad boy to the DOM
+ tasks.overlay.appendChild(this.el.dom)
}
}
}( AFRAME.AComponent.prototype.updateProperties)
@@ -93,6 +145,10 @@ AFRAME.AComponent.prototype.updateProperties = function(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 += `