diff --git a/dist/xrfragment.aframe.js b/dist/xrfragment.aframe.js index 1d2ce49..8edf5e3 100644 --- a/dist/xrfragment.aframe.js +++ b/dist/xrfragment.aframe.js @@ -265,7 +265,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) { var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) { this.isNumber = new EReg("^[0-9\\.]+$",""); this.isClass = new EReg("^[-]?class$",""); - this.isAddition = new EReg("^\\+",""); + this.isRoot = new EReg("^/",""); this.isExclude = new EReg("^-",""); this.isProp = new EReg("^.*:[><=!]?",""); this.q = { }; @@ -329,9 +329,6 @@ xrfragment_Query.prototype = { if(_gthis.isExclude.match(k)) { oper = "!="; k = HxOverrides.substr(k,1,null); - } else if(_gthis.isAddition.match(k)) { - oper = "+="; - k = HxOverrides.substr(k,1,null); } else { v = HxOverrides.substr(v,oper.length,null); } @@ -353,6 +350,12 @@ xrfragment_Query.prototype = { } return; } else { + if(_gthis.isRoot.match(k)) { + str = HxOverrides.substr(k,1,null); + filter["root"] = true; + } else if(filter["root"] == true) { + Reflect.deleteField(filter,"root"); + } filter["id"] = _gthis.isExclude.match(str) ? false : true; var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str; q[key] = filter; @@ -1066,7 +1069,7 @@ xrf.frag.href = function(v, opts){ quat: new THREE.Quaternion() } // detect equirectangular image - let texture = mesh.material.map + let texture = mesh.material && mesh.material.map ? mesh.material.map : null if( texture && texture.source.data.height == texture.source.data.width/2 ){ texture.mapping = THREE.ClampToEdgeWrapping texture.needsUpdate = true @@ -1113,7 +1116,7 @@ xrf.frag.href = function(v, opts){ `, }); mesh.material.needsUpdate = true - }else mesh.material = mesh.material.clone() + }else if( mesh.material){ mesh.material = mesh.material.clone() } let click = mesh.userData.XRF.href.exec = (e) => { xrf @@ -1128,8 +1131,10 @@ xrf.frag.href = function(v, opts){ let selected = (state) => () => { if( mesh.selected == state ) return // nothing changed - if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state - else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0 + if( mesh.material ){ + if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state + else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0 + } // update mouse cursor if( !renderer.domElement.lastCursor ) renderer.domElement.lastCursor = renderer.domElement.style.cursor @@ -1181,11 +1186,12 @@ const doPredefinedView = (opts) => { const selectionOfInterest = (frag,scene,mesh) => { let id = frag.string - // Selection of Interest if predefined_view matches object name + if(!id) return id // important: ignore empty strings if( mesh.selection ){ scene.remove(mesh.selection) delete mesh.selection } + // Selection of Interest if predefined_view matches object name if( id == mesh.name || id.substr(1) == mesh.userData.class ){ xrf.emit('selection',{...opts,frag}) .then( () => { @@ -1202,9 +1208,10 @@ const doPredefinedView = (opts) => { } const predefinedView = (frag,scene,mesh) => { - let id = frag.string - if( mesh.userData[`#${id}`] ){ - let frag = xrf.URI.parse( mesh.userData[id], xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED ) + let id = frag.string + if( !id ) return // prevent empty matches + if( mesh.userData[`#${id}`] ){ // get alias + frag = xrf.URI.parse( mesh.userData[`#${id}`], xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED ) for ( let k in frag ){ let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE } xrf.emit('predefinedView',{...opts,frag}) @@ -1271,14 +1278,14 @@ xrf.frag.q = function(v, opts){ target.mesh.rotation.set(0,0,0) } } - // remove negative selectors - let remove = [] + // hide negative selectors + let negative = [] v.scene.traverse( (mesh) => { for ( let i in v.query ) { - if( mesh.name == i && v.query[i].id === false ) remove.push(mesh) + if( mesh.name == i && v.query[i].id === false ) negative.push(mesh) } }) - remove.map( (mesh) => mesh.parent.remove( mesh ) ) + negative.map( (mesh) => mesh.visible = false ) } const showHide = () => { @@ -1326,7 +1333,7 @@ xrf.frag.src = function(v, opts){ xrf.eval.fragment(i, Object.assign(opts,{frag, model,scene})) } if( frag.q.query ){ - let srcScene = frag.q.scene + let srcScene = frag.q.scene // three/xrf/q.js initializes .scene if( !srcScene || !srcScene.visible ) return console.log(" └ inserting "+i+" (srcScene)") srcScene.position.set(0,0,0) @@ -1334,6 +1341,7 @@ xrf.frag.src = function(v, opts){ srcScene.traverse( (m) => { if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion xrf.eval.mesh(m,{scene,recursive:true}) + m.name = mesh.name+"."+m.name // prefix meshname so predefined views don't affect objectnames anymore }) if( srcScene.visible ) src.add( srcScene ) } diff --git a/dist/xrfragment.js b/dist/xrfragment.js index 83c98bc..253f4a6 100644 --- a/dist/xrfragment.js +++ b/dist/xrfragment.js @@ -265,7 +265,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) { var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) { this.isNumber = new EReg("^[0-9\\.]+$",""); this.isClass = new EReg("^[-]?class$",""); - this.isAddition = new EReg("^\\+",""); + this.isRoot = new EReg("^/",""); this.isExclude = new EReg("^-",""); this.isProp = new EReg("^.*:[><=!]?",""); this.q = { }; @@ -329,9 +329,6 @@ xrfragment_Query.prototype = { if(_gthis.isExclude.match(k)) { oper = "!="; k = HxOverrides.substr(k,1,null); - } else if(_gthis.isAddition.match(k)) { - oper = "+="; - k = HxOverrides.substr(k,1,null); } else { v = HxOverrides.substr(v,oper.length,null); } @@ -353,6 +350,12 @@ xrfragment_Query.prototype = { } return; } else { + if(_gthis.isRoot.match(k)) { + str = HxOverrides.substr(k,1,null); + filter["root"] = true; + } else if(filter["root"] == true) { + Reflect.deleteField(filter,"root"); + } filter["id"] = _gthis.isExclude.match(str) ? false : true; var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str; q[key] = filter; diff --git a/dist/xrfragment.lua b/dist/xrfragment.lua index 7d35dba..5af60f0 100644 --- a/dist/xrfragment.lua +++ b/dist/xrfragment.lua @@ -1633,7 +1633,7 @@ end __xrfragment_Query.super = function(self,str) self.isNumber = EReg.new("^[0-9\\.]+$", ""); self.isClass = EReg.new("^[-]?class$", ""); - self.isAddition = EReg.new("^\\+", ""); + self.isRoot = EReg.new("^/", ""); self.isExclude = EReg.new("^-", ""); self.isProp = EReg.new("^.*:[><=!]?", ""); self.q = _hx_e(); @@ -1852,42 +1852,22 @@ __xrfragment_Query.prototype.parse = function(self,str,recurse) end; k = __lua_lib_luautf8_Utf8.sub(k, pos + 1, pos + len); else - if (_gthis.isAddition:match(k)) then - oper = "+="; - local pos = 1; - local len = nil; - if ((len == nil) or (len > (pos + __lua_lib_luautf8_Utf8.len(k)))) then - len = __lua_lib_luautf8_Utf8.len(k); - else - if (len < 0) then - len = __lua_lib_luautf8_Utf8.len(k) + len; - end; - end; - if (pos < 0) then - pos = __lua_lib_luautf8_Utf8.len(k) + pos; - end; - if (pos < 0) then - pos = 0; - end; - k = __lua_lib_luautf8_Utf8.sub(k, pos + 1, pos + len); + local pos = __lua_lib_luautf8_Utf8.len(oper); + local len = nil; + if ((len == nil) or (len > (pos + __lua_lib_luautf8_Utf8.len(v)))) then + len = __lua_lib_luautf8_Utf8.len(v); else - local pos = __lua_lib_luautf8_Utf8.len(oper); - local len = nil; - if ((len == nil) or (len > (pos + __lua_lib_luautf8_Utf8.len(v)))) then - len = __lua_lib_luautf8_Utf8.len(v); - else - if (len < 0) then - len = __lua_lib_luautf8_Utf8.len(v) + len; - end; + if (len < 0) then + len = __lua_lib_luautf8_Utf8.len(v) + len; end; - if (pos < 0) then - pos = __lua_lib_luautf8_Utf8.len(v) + pos; - end; - if (pos < 0) then - pos = 0; - end; - v = __lua_lib_luautf8_Utf8.sub(v, pos + 1, pos + len); end; + if (pos < 0) then + pos = __lua_lib_luautf8_Utf8.len(v) + pos; + end; + if (pos < 0) then + pos = 0; + end; + v = __lua_lib_luautf8_Utf8.sub(v, pos + 1, pos + len); end; if (__lua_lib_luautf8_Utf8.len(oper) == 0) then oper = "="; @@ -1909,6 +1889,29 @@ __xrfragment_Query.prototype.parse = function(self,str,recurse) end; do return end; else + if (_gthis.isRoot:match(k)) then + local pos = 1; + local len = nil; + if ((len == nil) or (len > (pos + __lua_lib_luautf8_Utf8.len(k)))) then + len = __lua_lib_luautf8_Utf8.len(k); + else + if (len < 0) then + len = __lua_lib_luautf8_Utf8.len(k) + len; + end; + end; + if (pos < 0) then + pos = __lua_lib_luautf8_Utf8.len(k) + pos; + end; + if (pos < 0) then + pos = 0; + end; + str = __lua_lib_luautf8_Utf8.sub(k, pos + 1, pos + len); + filter.root = true; + else + if (Reflect.field(filter, "root") == true) then + Reflect.deleteField(filter, "root"); + end; + end; local value = (function() local _hx_7 if (_gthis.isExclude:match(str)) then diff --git a/dist/xrfragment.module.js b/dist/xrfragment.module.js index 0b8a5b4..0d2b1d5 100644 --- a/dist/xrfragment.module.js +++ b/dist/xrfragment.module.js @@ -265,7 +265,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) { var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) { this.isNumber = new EReg("^[0-9\\.]+$",""); this.isClass = new EReg("^[-]?class$",""); - this.isAddition = new EReg("^\\+",""); + this.isRoot = new EReg("^/",""); this.isExclude = new EReg("^-",""); this.isProp = new EReg("^.*:[><=!]?",""); this.q = { }; @@ -329,9 +329,6 @@ xrfragment_Query.prototype = { if(_gthis.isExclude.match(k)) { oper = "!="; k = HxOverrides.substr(k,1,null); - } else if(_gthis.isAddition.match(k)) { - oper = "+="; - k = HxOverrides.substr(k,1,null); } else { v = HxOverrides.substr(v,oper.length,null); } @@ -353,6 +350,12 @@ xrfragment_Query.prototype = { } return; } else { + if(_gthis.isRoot.match(k)) { + str = HxOverrides.substr(k,1,null); + filter["root"] = true; + } else if(filter["root"] == true) { + Reflect.deleteField(filter,"root"); + } filter["id"] = _gthis.isExclude.match(str) ? false : true; var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str; q[key] = filter; diff --git a/dist/xrfragment.py b/dist/xrfragment.py index b86afdf..2c7b6a4 100644 --- a/dist/xrfragment.py +++ b/dist/xrfragment.py @@ -1338,14 +1338,14 @@ class xrfragment_Parser: class xrfragment_Query: _hx_class_name = "xrfragment.Query" - __slots__ = ("str", "q", "isProp", "isExclude", "isAddition", "isClass", "isNumber") - _hx_fields = ["str", "q", "isProp", "isExclude", "isAddition", "isClass", "isNumber"] + __slots__ = ("str", "q", "isProp", "isExclude", "isRoot", "isClass", "isNumber") + _hx_fields = ["str", "q", "isProp", "isExclude", "isRoot", "isClass", "isNumber"] _hx_methods = ["toObject", "expandAliases", "get", "parse", "test", "testProperty"] def __init__(self,_hx_str): self.isNumber = EReg("^[0-9\\.]+$","") self.isClass = EReg("^[-]?class$","") - self.isAddition = EReg("^\\+","") + self.isRoot = EReg("^/","") self.isExclude = EReg("^-","") self.isProp = EReg("^.*:[><=!]?","") self.q = _hx_AnonObject({}) @@ -1409,13 +1409,7 @@ class xrfragment_Query: oper = "!=" k = HxString.substr(k,1,None) else: - _this = _gthis.isAddition - _this.matchObj = python_lib_Re.search(_this.pattern,k) - if (_this.matchObj is not None): - oper = "+=" - k = HxString.substr(k,1,None) - else: - v = HxString.substr(v,len(oper),None) + v = HxString.substr(v,len(oper),None) if (len(oper) == 0): oper = "=" _this = _gthis.isClass @@ -1438,6 +1432,13 @@ class xrfragment_Query: setattr(q,(("_hx_" + k) if ((k in python_Boot.keywords)) else (("_hx_" + k) if (((((len(k) > 2) and ((ord(k[0]) == 95))) and ((ord(k[1]) == 95))) and ((ord(k[(len(k) - 1)]) != 95)))) else k)),_hx_filter) return else: + _this = _gthis.isRoot + _this.matchObj = python_lib_Re.search(_this.pattern,k) + if (_this.matchObj is not None): + _hx_str = HxString.substr(k,1,None) + setattr(_hx_filter,(("_hx_" + "root") if (("root" in python_Boot.keywords)) else (("_hx_" + "root") if (((((len("root") > 2) and ((ord("root"[0]) == 95))) and ((ord("root"[1]) == 95))) and ((ord("root"[(len("root") - 1)]) != 95)))) else "root")),True) + elif (Reflect.field(_hx_filter,"root") == True): + Reflect.deleteField(_hx_filter,"root") _this = _gthis.isExclude _this.matchObj = python_lib_Re.search(_this.pattern,_hx_str) value = (False if ((_this.matchObj is not None)) else True) diff --git a/dist/xrfragment.three.js b/dist/xrfragment.three.js index 98957da..befe22d 100644 --- a/dist/xrfragment.three.js +++ b/dist/xrfragment.three.js @@ -265,7 +265,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) { var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) { this.isNumber = new EReg("^[0-9\\.]+$",""); this.isClass = new EReg("^[-]?class$",""); - this.isAddition = new EReg("^\\+",""); + this.isRoot = new EReg("^/",""); this.isExclude = new EReg("^-",""); this.isProp = new EReg("^.*:[><=!]?",""); this.q = { }; @@ -329,9 +329,6 @@ xrfragment_Query.prototype = { if(_gthis.isExclude.match(k)) { oper = "!="; k = HxOverrides.substr(k,1,null); - } else if(_gthis.isAddition.match(k)) { - oper = "+="; - k = HxOverrides.substr(k,1,null); } else { v = HxOverrides.substr(v,oper.length,null); } @@ -353,6 +350,12 @@ xrfragment_Query.prototype = { } return; } else { + if(_gthis.isRoot.match(k)) { + str = HxOverrides.substr(k,1,null); + filter["root"] = true; + } else if(filter["root"] == true) { + Reflect.deleteField(filter,"root"); + } filter["id"] = _gthis.isExclude.match(str) ? false : true; var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str; q[key] = filter; @@ -1066,7 +1069,7 @@ xrf.frag.href = function(v, opts){ quat: new THREE.Quaternion() } // detect equirectangular image - let texture = mesh.material.map + let texture = mesh.material && mesh.material.map ? mesh.material.map : null if( texture && texture.source.data.height == texture.source.data.width/2 ){ texture.mapping = THREE.ClampToEdgeWrapping texture.needsUpdate = true @@ -1113,7 +1116,7 @@ xrf.frag.href = function(v, opts){ `, }); mesh.material.needsUpdate = true - }else mesh.material = mesh.material.clone() + }else if( mesh.material){ mesh.material = mesh.material.clone() } let click = mesh.userData.XRF.href.exec = (e) => { xrf @@ -1128,8 +1131,10 @@ xrf.frag.href = function(v, opts){ let selected = (state) => () => { if( mesh.selected == state ) return // nothing changed - if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state - else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0 + if( mesh.material ){ + if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state + else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0 + } // update mouse cursor if( !renderer.domElement.lastCursor ) renderer.domElement.lastCursor = renderer.domElement.style.cursor @@ -1181,11 +1186,12 @@ const doPredefinedView = (opts) => { const selectionOfInterest = (frag,scene,mesh) => { let id = frag.string - // Selection of Interest if predefined_view matches object name + if(!id) return id // important: ignore empty strings if( mesh.selection ){ scene.remove(mesh.selection) delete mesh.selection } + // Selection of Interest if predefined_view matches object name if( id == mesh.name || id.substr(1) == mesh.userData.class ){ xrf.emit('selection',{...opts,frag}) .then( () => { @@ -1202,9 +1208,10 @@ const doPredefinedView = (opts) => { } const predefinedView = (frag,scene,mesh) => { - let id = frag.string - if( mesh.userData[`#${id}`] ){ - let frag = xrf.URI.parse( mesh.userData[id], xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED ) + let id = frag.string + if( !id ) return // prevent empty matches + if( mesh.userData[`#${id}`] ){ // get alias + frag = xrf.URI.parse( mesh.userData[`#${id}`], xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED ) for ( let k in frag ){ let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE } xrf.emit('predefinedView',{...opts,frag}) @@ -1271,14 +1278,14 @@ xrf.frag.q = function(v, opts){ target.mesh.rotation.set(0,0,0) } } - // remove negative selectors - let remove = [] + // hide negative selectors + let negative = [] v.scene.traverse( (mesh) => { for ( let i in v.query ) { - if( mesh.name == i && v.query[i].id === false ) remove.push(mesh) + if( mesh.name == i && v.query[i].id === false ) negative.push(mesh) } }) - remove.map( (mesh) => mesh.parent.remove( mesh ) ) + negative.map( (mesh) => mesh.visible = false ) } const showHide = () => { @@ -1326,7 +1333,7 @@ xrf.frag.src = function(v, opts){ xrf.eval.fragment(i, Object.assign(opts,{frag, model,scene})) } if( frag.q.query ){ - let srcScene = frag.q.scene + let srcScene = frag.q.scene // three/xrf/q.js initializes .scene if( !srcScene || !srcScene.visible ) return console.log(" └ inserting "+i+" (srcScene)") srcScene.position.set(0,0,0) @@ -1334,6 +1341,7 @@ xrf.frag.src = function(v, opts){ srcScene.traverse( (m) => { if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion xrf.eval.mesh(m,{scene,recursive:true}) + m.name = mesh.name+"."+m.name // prefix meshname so predefined views don't affect objectnames anymore }) if( srcScene.visible ) src.add( srcScene ) } diff --git a/dist/xrfragment.three.module.js b/dist/xrfragment.three.module.js index fb9fd75..55d3d3e 100644 --- a/dist/xrfragment.three.module.js +++ b/dist/xrfragment.three.module.js @@ -265,7 +265,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) { var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) { this.isNumber = new EReg("^[0-9\\.]+$",""); this.isClass = new EReg("^[-]?class$",""); - this.isAddition = new EReg("^\\+",""); + this.isRoot = new EReg("^/",""); this.isExclude = new EReg("^-",""); this.isProp = new EReg("^.*:[><=!]?",""); this.q = { }; @@ -329,9 +329,6 @@ xrfragment_Query.prototype = { if(_gthis.isExclude.match(k)) { oper = "!="; k = HxOverrides.substr(k,1,null); - } else if(_gthis.isAddition.match(k)) { - oper = "+="; - k = HxOverrides.substr(k,1,null); } else { v = HxOverrides.substr(v,oper.length,null); } @@ -353,6 +350,12 @@ xrfragment_Query.prototype = { } return; } else { + if(_gthis.isRoot.match(k)) { + str = HxOverrides.substr(k,1,null); + filter["root"] = true; + } else if(filter["root"] == true) { + Reflect.deleteField(filter,"root"); + } filter["id"] = _gthis.isExclude.match(str) ? false : true; var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str; q[key] = filter; @@ -1066,7 +1069,7 @@ xrf.frag.href = function(v, opts){ quat: new THREE.Quaternion() } // detect equirectangular image - let texture = mesh.material.map + let texture = mesh.material && mesh.material.map ? mesh.material.map : null if( texture && texture.source.data.height == texture.source.data.width/2 ){ texture.mapping = THREE.ClampToEdgeWrapping texture.needsUpdate = true @@ -1113,7 +1116,7 @@ xrf.frag.href = function(v, opts){ `, }); mesh.material.needsUpdate = true - }else mesh.material = mesh.material.clone() + }else if( mesh.material){ mesh.material = mesh.material.clone() } let click = mesh.userData.XRF.href.exec = (e) => { xrf @@ -1128,8 +1131,10 @@ xrf.frag.href = function(v, opts){ let selected = (state) => () => { if( mesh.selected == state ) return // nothing changed - if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state - else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0 + if( mesh.material ){ + if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state + else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0 + } // update mouse cursor if( !renderer.domElement.lastCursor ) renderer.domElement.lastCursor = renderer.domElement.style.cursor @@ -1181,11 +1186,12 @@ const doPredefinedView = (opts) => { const selectionOfInterest = (frag,scene,mesh) => { let id = frag.string - // Selection of Interest if predefined_view matches object name + if(!id) return id // important: ignore empty strings if( mesh.selection ){ scene.remove(mesh.selection) delete mesh.selection } + // Selection of Interest if predefined_view matches object name if( id == mesh.name || id.substr(1) == mesh.userData.class ){ xrf.emit('selection',{...opts,frag}) .then( () => { @@ -1202,9 +1208,10 @@ const doPredefinedView = (opts) => { } const predefinedView = (frag,scene,mesh) => { - let id = frag.string - if( mesh.userData[`#${id}`] ){ - let frag = xrf.URI.parse( mesh.userData[id], xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED ) + let id = frag.string + if( !id ) return // prevent empty matches + if( mesh.userData[`#${id}`] ){ // get alias + frag = xrf.URI.parse( mesh.userData[`#${id}`], xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED ) for ( let k in frag ){ let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE } xrf.emit('predefinedView',{...opts,frag}) @@ -1271,14 +1278,14 @@ xrf.frag.q = function(v, opts){ target.mesh.rotation.set(0,0,0) } } - // remove negative selectors - let remove = [] + // hide negative selectors + let negative = [] v.scene.traverse( (mesh) => { for ( let i in v.query ) { - if( mesh.name == i && v.query[i].id === false ) remove.push(mesh) + if( mesh.name == i && v.query[i].id === false ) negative.push(mesh) } }) - remove.map( (mesh) => mesh.parent.remove( mesh ) ) + negative.map( (mesh) => mesh.visible = false ) } const showHide = () => { @@ -1326,7 +1333,7 @@ xrf.frag.src = function(v, opts){ xrf.eval.fragment(i, Object.assign(opts,{frag, model,scene})) } if( frag.q.query ){ - let srcScene = frag.q.scene + let srcScene = frag.q.scene // three/xrf/q.js initializes .scene if( !srcScene || !srcScene.visible ) return console.log(" └ inserting "+i+" (srcScene)") srcScene.position.set(0,0,0) @@ -1334,6 +1341,7 @@ xrf.frag.src = function(v, opts){ srcScene.traverse( (m) => { if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion xrf.eval.mesh(m,{scene,recursive:true}) + m.name = mesh.name+"."+m.name // prefix meshname so predefined views don't affect objectnames anymore }) if( srcScene.visible ) src.add( srcScene ) } diff --git a/src/Test.hx b/src/Test.hx index 0c6b299..8861bbe 100644 --- a/src/Test.hx +++ b/src/Test.hx @@ -16,7 +16,8 @@ class Test { static public function main():Void { test( Spec.load("src/spec/url.json") ); - test( Spec.load("src/spec/query.class.json") ); + test( Spec.load("src/spec/query.selectors.json") ); + test( Spec.load("src/spec/query.root.json") ); test( Spec.load("src/spec/query.rules.json") ); //test( Spec.load("src/spec/tmp.json") ); if( errors > 1 ) trace("\n-----\n[ ❌] "+errors+" errors :/"); @@ -43,6 +44,10 @@ class Test { if( item.expect.fn == "equal.xy" ) valid = equalXY(res,item); if( item.expect.fn == "equal.xyz" ) valid = equalXYZ(res,item); if( item.expect.fn == "equal.multi" ) valid = equalMulti(res, item); + if( item.expect.fn == "testQueryRoot" ){ + if( !item.expect.out ) valid = !q.get()[ item.expect.input[0] ].root; + else valid = item.expect.out == q.get()[ item.expect.input[0] ].root; + } var ok:String = valid ? "[ ✔ ] " : "[ ❌] "; trace( ok + item.fn + ": '" + item.data + "'" + (item.label ? " (" + (item.label?item.label:item.expect.fn) +")" : "")); if( !valid ) errors += 1; diff --git a/src/spec/query.root.json b/src/spec/query.root.json new file mode 100644 index 0000000..0d4f101 --- /dev/null +++ b/src/spec/query.root.json @@ -0,0 +1,2 @@ +[ +] diff --git a/src/spec/query.class.json b/src/spec/query.selectors.json similarity index 80% rename from src/spec/query.class.json rename to src/spec/query.selectors.json index 5cf9b38..15bfe77 100644 --- a/src/spec/query.class.json +++ b/src/spec/query.selectors.json @@ -10,5 +10,7 @@ {"fn":"query","data":".foo -.foo bar:>5 .foo", "expect":{ "fn":"testProperty","input":["class","foo"],"out":true},"label":"class:foo"}, {"fn":"query","data":".foo -.foo .foo", "expect":{ "fn":"testProperty","input":["class","foo"],"out":true},"label":"class:foo"}, {"fn":"query","data":".foo -.foo .foo", "expect":{ "fn":"testProperty","input":["id","foo"],"out":false},"label":"!id:foo"}, - {"fn":"query","data":"foo -foo foo", "expect":{ "fn":"testProperty","input":["id","foo"],"out":true},"label":"id:foo?"} + {"fn":"query","data":"foo -foo foo", "expect":{ "fn":"testProperty","input":["id","foo"],"out":true},"label":"id:foo?"}, + {"fn":"query","data":"/foo", "expect":{ "fn":"testQueryRoot","input":["foo"],"out":true},"label":"foo should be root-only"}, + {"fn":"query","data":"/foo foo", "expect":{ "fn":"testQueryRoot","input":["foo"],"out":false},"label":"foo should recursively selected"} ] diff --git a/src/xrfragment/Query.hx b/src/xrfragment/Query.hx index d75736b..c995be7 100644 --- a/src/xrfragment/Query.hx +++ b/src/xrfragment/Query.hx @@ -44,7 +44,7 @@ class Query { private var q:haxe.DynamicAccess = {}; private var isProp:EReg = ~/^.*:[><=!]?/; private var isExclude:EReg = ~/^-/; - private var isAddition:EReg = ~/^\+/; + private var isRoot:EReg = ~/^\//; private var isClass:EReg = ~/^[-]?class$/; private var isNumber:EReg = ~/^[0-9\.]+$/; @@ -89,13 +89,9 @@ class Query { if( str.indexOf("<=") != -1 ) oper = "<="; if( isExclude.match(k) ){ oper = "!="; - k = k.substr(1); // convert "-foo" into "foo" - }else if( isAddition.match(k) ){ - oper = "+="; - k = k.substr(1); // convert "+foo" into "foo" + k = k.substr(1); // convert "-foo" into "foo" }else v = v.substr(oper.length); // change ">=foo" into "foo" (strip operator) if( oper.length == 0 ) oper = "="; - if( isClass.match(k) ){ filter[ prefix+ k ] = oper != "!="; q.set(v,filter); @@ -108,6 +104,10 @@ class Query { } return; }else{ // id + if( isRoot.match(k) ){ + str = k.substr(1); // convert "/foo" to "foo" + filter[ "root" ] = true; + }else if( filter[ "root" ] == true ) filter.remove("root"); // undo root-only filter[ "id" ] = isExclude.match(str) ? false: true; q.set( (isExclude.match(str) ? str.substr(1) : str ) ,filter ); }