various fixes predefined views, selections, roundrobin & queries

This commit is contained in:
Leon van Kammen 2023-06-22 08:49:24 +02:00
parent 5584d22e25
commit bc38f58329
16 changed files with 663 additions and 666 deletions

View File

@ -43,7 +43,7 @@
window.$ = (s) => document.querySelector(s)
window.notify = notify(window)
console.log = ( (log) => function(str){
if( String(str).match(/(camera)/) ) window.notify(str)
if( String(str).match(/#.*=/) ) window.notify(str)
log(str)
})(console.log)

View File

@ -118,6 +118,10 @@ html.a-fullscreen a#source{
margin-right:10px;
}
html{
max-width:unset;
}
.render {
position:absolute;
top:0;

View File

@ -43,7 +43,7 @@ export function setupConsole(el){
console.log = ( (log) => function(){
let str = ([...arguments]).join(" ")
let s = new Date().toISOString().substr(11).substr(0,8) + " " + str.replace(/.*[0-9]: /,"")
let s = str;
log(s)
let lines = String($console.innerHTML + "\n"+s).split("\n")
while( lines.length > 200 ) lines.shift()
@ -55,15 +55,12 @@ export function setupConsole(el){
export function setupUrlBar(el,XRF){
var isIframe = (window === window.parent || window.opener) ? false : true;
if( isIframe ){
if( isIframe || document.location.href.match(/localhost/) ){
// show internal URL bar to test XR fragments interactively
el.style.display = 'block'
let nav = XRF.navigator
XRF.navigator.to = ((to) => (url,e) => {
to(url,e)
reflectUrl(url)
})(XRF.navigator.to)
XRF.addEventListener('updateHash', () => reflectUrl() )
const reflectUrl = (url) => el.value = url || document.location.search.substr(1) + document.location.hash
reflectUrl()
@ -80,7 +77,7 @@ function SnackBar(userOptions) {
var _OptionDefaults = {
message: "Operation performed successfully.",
dismissible: true,
timeout: 5000,
timeout: 7000,
status: ""
}
var _Options = _OptionDefaults;

File diff suppressed because one or more lines are too long

View File

@ -4,6 +4,9 @@ window.AFRAME.registerComponent('xrf', {
init: function () {
if( !AFRAME.XRF ) this.initXRFragments()
if( this.data ){
if( document.location.search || document.location.hash.length > 1 ){ // override url
this.data = `${document.location.search.substr(1)}${document.location.hash}`
}
AFRAME.XRF.navigator.to(this.data)
.then( (model) => {
let gets = [ ...document.querySelectorAll('[xrf-get]') ]

View File

@ -25,6 +25,7 @@ xrf.addEventListener = function(eventName, callback) {
};
xrf.emit = function(eventName, data){
if( typeof data != 'object' ) throw 'emit() requires passing objects'
return xrf.emit.promise(eventName,data)
}

View File

@ -59,11 +59,13 @@ xrf.eval = function( url, model, flags ){ // evaluate fragments in url
model = model || xrf.model
let { THREE, camera } = xrf
let frag = xrf.URI.parse( url, flags || xrf.XRF.NAVIGATOR )
for ( let k in frag ){
let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('eval',opts)
.then( () => xrf.eval.fragment(k,opts) )
}
let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('eval',opts)
.then( () => {
for ( let k in frag ){
xrf.eval.fragment(k,opts)
}
})
}
xrf.eval.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) inside mesh of model

View File

@ -1,14 +1,14 @@
xrf.navigator = {}
xrf.navigator.to = (url,event) => {
xrf.navigator.to = (url,flags) => {
if( !url ) throw 'xrf.navigator.to(..) no url given'
return new Promise( (resolve,reject) => {
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
console.log("xrfragment: navigating to "+url)
console.log(url)
if( !file || xrf.model.file == file ){ // we're already loaded
document.location.hash = `#${hash}` // just update the hash
xrf.eval( url, xrf.model ) // and eval local URI XR fragments
xrf.eval( url, xrf.model, flags ) // and eval local URI XR fragments
return resolve(xrf.model)
}
@ -22,10 +22,13 @@ xrf.navigator.to = (url,event) => {
loader.load( file, function(model){
model.file = file
xrf.add( model.scene )
// only change url when loading *another* file
if( xrf.model ) xrf.navigator.pushState( `${dir}${file}`, hash )
xrf.model = model
xrf.eval( '#', model ) // execute the default projection '#' (if exist)
xrf.eval( url, model ) // and eval URI XR fragments
xrf.navigator.pushState( `${dir}${file}`, hash )
xrf.eval( '#', model ) // execute the default projection '#' (if exist)
xrf.eval( url, model ) // and eval URI XR fragments
if( !hash.match(/pos=/) )
xrf.eval( '#pos=0,0,0' ) // set default position if not specified
resolve(model)
})
})
@ -34,7 +37,7 @@ xrf.navigator.to = (url,event) => {
xrf.navigator.init = () => {
if( xrf.navigator.init.inited ) return
window.addEventListener('popstate', function (event){
xrf.navigator.to( document.location.search.substr(1) + document.location.hash, event)
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
})
xrf.navigator.material = {
selection: new xrf.THREE.LineBasicMaterial({color:0xFF00FF,linewidth:2})
@ -42,6 +45,12 @@ xrf.navigator.init = () => {
xrf.navigator.init.inited = true
}
xrf.navigator.updateHash = (hash) => {
if( hash == document.location.hash || hash.match(/\|/) ) return // skip unnecesary pushState triggers
document.location.hash = hash
xrf.emit('updateHash', {hash} )
}
xrf.navigator.pushState = (file,hash) => {
if( file == document.location.search.substr(1) ) return // page is in its default state
window.history.pushState({},`${file}#${hash}`, document.location.pathname + `?${file}#${hash}` )

View File

@ -1,35 +1,11 @@
xrf.frag.env = function(v, opts){
let { mesh, model, camera, scene, renderer, THREE} = opts
let env = mesh.getObjectByName(v.string)
if( !env ) return console.warn("xrf.env "+v.string+" not found")
env.material.map.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = env.material.map
//scene.texture = env.material.map
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 2;
// apply to meshes *DISABLED* renderer.environment does this
const maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
setTimeout( () => {
scene.traverse( (mesh) => {
//if (mesh.material && mesh.material.map && mesh.material.metalness == 1.0) {
// mesh.material = new THREE.MeshBasicMaterial({ map: mesh.material.map });
// mesh.material.dithering = true
// mesh.material.map.anisotropy = maxAnisotropy;
// mesh.material.needsUpdate = true;
//}
//if (mesh.material && mesh.material.metalness == 1.0 ){
// mesh.material = new THREE.MeshBasicMaterial({
// color:0xffffff,
// emissive: mesh.material.map,
// envMap: env.material.map,
// side: THREE.DoubleSide,
// flatShading: true
// })
// mesh.material.needsUpdate = true
// //mesh.material.envMap = env.material.map;
// //mesh.material.envMap.intensity = 5;
// //mesh.material.needsUpdate = true;
//}
});
},500)
console.log(` └ applied image '${v.string}' as environment map`)
}

View File

@ -40,7 +40,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
@ -87,23 +87,23 @@ 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
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
.then( () => {
if( v.string[0] == '#' && v.string.match(/(\||#q)/) ){ // apply modifications to scene *TODO* decide on queries...
console.log("ja")
xrf.eval( v.string, xrf.model, xrf.XRF.PV_OVERRIDE )
}else xrf.navigator.to(v.string) // or let's surf to HREF!
const flags = v.string[0] == '#' && v.string.match(/(\||#q)/) ? xrf.XRF.PV_OVERRIDE : undefined
xrf.navigator.to(v.string,flags) // or let's surf to HREF!
})
}
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

View File

@ -1,6 +1,5 @@
xrf.frag.pos = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(" └ setting camera position to "+v.string)
if( !frag.q ){
camera.position.x = v.x

View File

@ -1,14 +1,12 @@
const doPredefinedView = (opts) => {
const updatePredefinedView = (opts) => {
let {frag,scene} = opts
const selectionOfInterest = (frag,scene,mesh) => {
let id = frag.string
if(!id) return id // important: ignore empty strings
if( mesh.selection ) return mesh
// Selection of Interest if predefined_view matches object name
if( mesh.selection ){
scene.remove(mesh.selection)
delete mesh.selection
}
if( id == mesh.name || id.substr(1) == mesh.userData.class ){
if( mesh.visible && (id == mesh.name || id.substr(1) == mesh.userData.class) ){
xrf.emit('selection',{...opts,frag})
.then( () => {
const margin = 1.2
@ -24,42 +22,55 @@ 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 )
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})
.then( () => xrf.eval.fragment(k,opts) )
}
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 )
xrf.emit('predefinedView',{...opts,frag})
.then( () => {
for ( let k in frag ){
let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.eval.fragment(k,opts)
}
})
}
}
const traverseScene = (v,scene) => {
let remove = []
if( !scene ) return
scene.traverse( (mesh) => {
remove.push( selectionOfInterest( v, scene, mesh ) )
predefinedView( v , scene, mesh )
})
remove.filter( (e) => e ).map( (mesh) => {
scene.remove(mesh.selection)
delete mesh.selection
})
}
let pviews = []
for ( let i in frag ) {
let v = frag[i]
if( v.is( xrf.XRF.PV_EXECUTE ) ){
if( v.args ) v = v.args[ xrf.roundrobin(v,xrf.model) ]
// wait for nested instances to arrive at the scene
setTimeout( () => {
if( !scene ) return
scene.traverse( (mesh) => {
selectionOfInterest( v, scene, mesh )
predefinedView( v , scene, mesh )
})
},100)
}
setTimeout( () => traverseScene(v,scene), 100 )
console.dir(v)
if( v.string ) pviews.push(v.string)
}else if( v.is( xrf.XRF.NAVIGATOR ) ) pviews.push(`${i}=${v.string}`)
}
if( pviews.length ) xrf.navigator.updateHash( pviews.join("&") )
}
// when predefined view occurs in url changes
xrf.addEventListener('eval', doPredefinedView )
xrf.addEventListener('eval', updatePredefinedView )
// clicking href url with predefined view
xrf.addEventListener('href', (opts) => {
if( !opts.click || opts.xrf.string[0] != '#' ) return
let frag = xrf.URI.parse( opts.xrf.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.EMBEDDED )
doPredefinedView({frag,scene:xrf.scene})
updatePredefinedView({frag,scene:xrf.scene,href:opts.xrf})
})
//let updateUrl = (opts) => {

View File

@ -23,14 +23,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 = () => {
@ -40,6 +40,7 @@ xrf.frag.q = function(v, opts){
let isMeshId = q[i].id != undefined
let isMeshClass = q[i].class != undefined
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId && !isMeshClass
if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.)
if( isMeshId && i == mesh.name ) mesh.visible = q[i].id
if( isMeshClass && i == mesh.userData.class ) mesh.visible = q[i].class
if( isMeshProperty && mesh.userData[i] ) mesh.visible = (new xrf.Query(frag.q.string)).testProperty(i,mesh.userData[i])

View File

@ -16,22 +16,25 @@ 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)
srcScene.rotation.set(0,0,0)
// add interactive elements (href's e.g.)
srcScene.add( xrf.interactive.clone() )
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.isSRC = true
})
console.dir(xrf)
if( srcScene.visible ) src.add( srcScene )
}
src.position.copy( mesh.position )
src.rotation.copy( mesh.rotation )
src.scale.copy( mesh.scale )
mesh.add(src)
console.dir(opts)
if( !opts.recursive ) mesh.material.visible = false // lets hide the preview object because deleting disables animations+nested objs
},10)
}

View File

@ -137,10 +137,11 @@ var Test = function() { };
Test.__name__ = true;
Test.main = function() {
Test.test([{ fn : "url", expect : { fn : "equal.xyz", input : "pos", out : false}, label : "equal.xyz: should trigger incompatible type)", data : "http://foo.com?foo=1#pos=1.2,2.2"},{ fn : "url", expect : { fn : "equal.xyz", input : "pos", out : "1.2,2.2,3"}, label : "equal.xyz", data : "http://foo.com?foo=1#pos=1.2,2.2,3"},{ fn : "url", expect : { fn : "equal.xy", input : "t", out : "1,100"}, label : "a equal.xy", data : "http://foo.com?foo=1#t=1,100"},{ fn : "url", expect : { fn : "testParsed", input : "prio", out : false}, label : "should trigger incompatible type", data : "http://foo.com?foo=1#prio=foo"},{ fn : "url", expect : { fn : "equal.multi", input : "pos", out : "c|d|1,2,3"}, label : "b equal.multi", data : "http://foo.com?foo=1#pos=c|d|1,2,3"},{ fn : "url", expect : { fn : "testBrowserOverride", input : "t", out : true}, label : "browser URI can override t (defined in asset)", data : "http://foo.com?foo=1#t=2,500"},{ fn : "url", expect : { fn : "testBrowserOverride", input : "q", out : false}, label : "browser URI cannot override q (defined in asset)", data : "http://foo.com?foo=1#q=-bar"},{ fn : "url", expect : { fn : "testBrowserOverride", input : "scale", out : false}, label : "scale does not have NAVIGATOR set", data : "http://foo.com?foo=1#scale=2,2,2"},{ fn : "url", expect : { fn : "testEmbedOverride", input : "scale", out : true}, label : "embedded (src) URI can override scale", data : "http://foo.com?foo=1#scale=2,2,2"},{ fn : "url", expect : { fn : "testPredefinedView", input : "mypredefinedview", out : true}, label : "test predefined view executed", data : "http://foo.com?foo=1#mypredefinedview"},{ fn : "url", expect : { fn : "testPredefinedView", input : "another", out : true}, label : "test predefined view executed (multiple)", data : "http://foo.com?foo=1#mypredefinedview&another"},{ fn : "url", expect : { fn : "testPredefinedView", input : "mypredefinedview", out : true}, label : "test predefined view executed (multiple)", data : "http://foo.com?foo=1#mypredefinedview&another"},{ fn : "url", expect : { fn : "testPropertyAssign", input : "cube.position.x", out : true}, label : "test data assign", data : "#cube.position.x=music.position.x"},{ fn : "url", expect : { fn : "testPropertyAssign", input : "cube.position.x", out : true}, label : "test one-way data bind", data : "#cube.position.x=@music.position.x"}]);
Test.test([{ fn : "query", expect : { fn : "testProperty", input : ["class","bar"], out : true}, data : "class:bar"},{ fn : "query", expect : { fn : "testProperty", input : ["class","bar"], out : true}, label : ".bar shorthand", data : ".bar"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : false}, data : ".bar -.foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, data : ".bar -.foo .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","bar"], out : true}, data : ".bar -.bar .bar"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, label : "class:foo", data : ".foo -.foo .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, label : "class:foo", data : ".foo -.foo bar:5 .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, label : "class:foo", data : ".foo -.foo bar:>5 .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, label : "class:foo", data : ".foo -.foo bar:>5 .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, label : "class:foo", data : ".foo -.foo .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["id","foo"], out : false}, label : "!id:foo", data : ".foo -.foo .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["id","foo"], out : true}, label : "id:foo?", data : "foo -foo foo"}]);
Test.test([{ fn : "query", expect : { fn : "testProperty", input : ["class","bar"], out : true}, data : "class:bar"},{ fn : "query", expect : { fn : "testProperty", input : ["class","bar"], out : true}, label : ".bar shorthand", data : ".bar"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : false}, data : ".bar -.foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, data : ".bar -.foo .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","bar"], out : true}, data : ".bar -.bar .bar"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, label : "class:foo", data : ".foo -.foo .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, label : "class:foo", data : ".foo -.foo bar:5 .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, label : "class:foo", data : ".foo -.foo bar:>5 .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, label : "class:foo", data : ".foo -.foo bar:>5 .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["class","foo"], out : true}, label : "class:foo", data : ".foo -.foo .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["id","foo"], out : false}, label : "!id:foo", data : ".foo -.foo .foo"},{ fn : "query", expect : { fn : "testProperty", input : ["id","foo"], out : true}, label : "id:foo?", data : "foo -foo foo"},{ fn : "query", expect : { fn : "testQueryRoot", input : ["foo"], out : true}, label : "foo should be root-only", data : "/foo"},{ fn : "query", expect : { fn : "testQueryRoot", input : ["foo"], out : false}, label : "foo should recursively selected", data : "/foo foo"}]);
Test.test([]);
Test.test([{ fn : "query", expect : { fn : "testProperty", input : ["price","10"], out : true}, data : "price:>=5"},{ fn : "query", expect : { fn : "testProperty", input : ["price","10"], out : false}, data : "price:>=15"},{ fn : "query", expect : { fn : "testProperty", input : ["price","4"], out : false}, data : "price:>=5"},{ fn : "query", expect : { fn : "testProperty", input : ["price","0"], out : false}, data : "price:>=5"},{ fn : "query", expect : { fn : "testProperty", input : ["price","2"], out : true}, data : "price:>=2"},{ fn : "query", expect : { fn : "testProperty", input : ["price","1"], out : false}, label : "price=1", data : "price:>=5 price:0"},{ fn : "query", expect : { fn : "testProperty", input : ["price","0"], out : true}, label : "price=0", data : "price:>=5 price:0"},{ fn : "query", expect : { fn : "testProperty", input : ["price","6"], out : true}, label : "price=6", data : "price:>=5 price:0"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, data : "tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : false}, data : "-tag:foo"},{ fn : "query", expect : { fn : "testPropertyExclude", input : ["tag","foo"], out : true}, label : "testExclude", data : "-tag:foo"},{ fn : "query", expect : { fn : "test", input : [{ price : 5}], out : true}, data : ".foo price:5 -tag:foo"},{ fn : "query", expect : { fn : "test", input : [{ tag : "foo", price : 5}], out : false}, data : ".foo price:5 -tag:foo"}]);
if(Test.errors > 1) {
console.log("src/Test.hx:22:","\n-----\n[ ❌] " + Test.errors + " errors :/");
console.log("src/Test.hx:23:","\n-----\n[ ❌] " + Test.errors + " errors :/");
}
};
Test.test = function(spec) {
@ -199,8 +200,11 @@ Test.test = function(spec) {
if(item.expect.fn == "equal.multi") {
valid = Test.equalMulti(res,item);
}
if(item.expect.fn == "testQueryRoot") {
valid = item.expect.out == q.get()[item.expect.input[0]].root;
}
var ok = valid ? "[ ✔ ] " : "[ ❌] ";
console.log("src/Test.hx:47:",ok + Std.string(item.fn) + ": '" + Std.string(item.data) + "'" + (item.label ? " (" + (item.label ? item.label : item.expect.fn) + ")" : ""));
console.log("src/Test.hx:49:",ok + Std.string(item.fn) + ": '" + Std.string(item.data) + "'" + (item.label ? " (" + (item.label ? item.label : item.expect.fn) + ")" : ""));
if(!valid) {
Test.errors += 1;
}
@ -349,7 +353,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) {
Frag_h["unit"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["description"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["session"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.EMBEDDED | xrfragment_XRF.PROMPT;
if(value.length == 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
if(value.length == 0 && key.length > 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) {
var v = new xrfragment_XRF(key,xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR);
v.validate(key);
resultMap[key] = v;
@ -375,7 +379,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 = { };
@ -439,9 +443,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);
}
@ -464,8 +465,14 @@ xrfragment_Query.prototype = {
return;
} else {
filter["id"] = _gthis.isExclude.match(str) ? false : true;
var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str;
q[key] = filter;
filter["root"] = _gthis.isRoot.match(str);
if(_gthis.isExclude.match(str)) {
str = HxOverrides.substr(str,1,null);
}
if(_gthis.isRoot.match(str)) {
str = HxOverrides.substr(str,1,null);
}
q[str] = filter;
}
};
var _g = 0;

View File

@ -391,7 +391,8 @@ class Test:
@staticmethod
def main():
Test.test([_hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xyz", 'input': "pos", 'out': False}), 'label': "equal.xyz: should trigger incompatible type)", 'data': "http://foo.com?foo=1#pos=1.2,2.2"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xyz", 'input': "pos", 'out': "1.2,2.2,3"}), 'label': "equal.xyz", 'data': "http://foo.com?foo=1#pos=1.2,2.2,3"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xy", 'input': "t", 'out': "1,100"}), 'label': "a equal.xy", 'data': "http://foo.com?foo=1#t=1,100"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testParsed", 'input': "prio", 'out': False}), 'label': "should trigger incompatible type", 'data': "http://foo.com?foo=1#prio=foo"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.multi", 'input': "pos", 'out': "c|d|1,2,3"}), 'label': "b equal.multi", 'data': "http://foo.com?foo=1#pos=c|d|1,2,3"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testBrowserOverride", 'input': "t", 'out': True}), 'label': "browser URI can override t (defined in asset)", 'data': "http://foo.com?foo=1#t=2,500"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testBrowserOverride", 'input': "q", 'out': False}), 'label': "browser URI cannot override q (defined in asset)", 'data': "http://foo.com?foo=1#q=-bar"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testBrowserOverride", 'input': "scale", 'out': False}), 'label': "scale does not have NAVIGATOR set", 'data': "http://foo.com?foo=1#scale=2,2,2"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testEmbedOverride", 'input': "scale", 'out': True}), 'label': "embedded (src) URI can override scale", 'data': "http://foo.com?foo=1#scale=2,2,2"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testPredefinedView", 'input': "mypredefinedview", 'out': True}), 'label': "test predefined view executed", 'data': "http://foo.com?foo=1#mypredefinedview"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testPredefinedView", 'input': "another", 'out': True}), 'label': "test predefined view executed (multiple)", 'data': "http://foo.com?foo=1#mypredefinedview&another"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testPredefinedView", 'input': "mypredefinedview", 'out': True}), 'label': "test predefined view executed (multiple)", 'data': "http://foo.com?foo=1#mypredefinedview&another"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testPropertyAssign", 'input': "cube.position.x", 'out': True}), 'label': "test data assign", 'data': "#cube.position.x=music.position.x"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testPropertyAssign", 'input': "cube.position.x", 'out': True}), 'label': "test one-way data bind", 'data': "#cube.position.x=@music.position.x"})])
Test.test([_hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "bar"], 'out': True}), 'data': "class:bar"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "bar"], 'out': True}), 'label': ".bar shorthand", 'data': ".bar"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': False}), 'data': ".bar -.foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'data': ".bar -.foo .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "bar"], 'out': True}), 'data': ".bar -.bar .bar"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'label': "class:foo", 'data': ".foo -.foo .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'label': "class:foo", 'data': ".foo -.foo bar:5 .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'label': "class:foo", 'data': ".foo -.foo bar:>5 .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'label': "class:foo", 'data': ".foo -.foo bar:>5 .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'label': "class:foo", 'data': ".foo -.foo .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["id", "foo"], 'out': False}), 'label': "!id:foo", 'data': ".foo -.foo .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["id", "foo"], 'out': True}), 'label': "id:foo?", 'data': "foo -foo foo"})])
Test.test([_hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "bar"], 'out': True}), 'data': "class:bar"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "bar"], 'out': True}), 'label': ".bar shorthand", 'data': ".bar"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': False}), 'data': ".bar -.foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'data': ".bar -.foo .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "bar"], 'out': True}), 'data': ".bar -.bar .bar"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'label': "class:foo", 'data': ".foo -.foo .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'label': "class:foo", 'data': ".foo -.foo bar:5 .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'label': "class:foo", 'data': ".foo -.foo bar:>5 .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'label': "class:foo", 'data': ".foo -.foo bar:>5 .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["class", "foo"], 'out': True}), 'label': "class:foo", 'data': ".foo -.foo .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["id", "foo"], 'out': False}), 'label': "!id:foo", 'data': ".foo -.foo .foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["id", "foo"], 'out': True}), 'label': "id:foo?", 'data': "foo -foo foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testQueryRoot", 'input': ["foo"], 'out': True}), 'label': "foo should be root-only", 'data': "/foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testQueryRoot", 'input': ["foo"], 'out': False}), 'label': "foo should recursively selected", 'data': "/foo foo"})])
Test.test([])
Test.test([_hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "10"], 'out': True}), 'data': "price:>=5"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "10"], 'out': False}), 'data': "price:>=15"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "4"], 'out': False}), 'data': "price:>=5"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "0"], 'out': False}), 'data': "price:>=5"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "2"], 'out': True}), 'data': "price:>=2"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "1"], 'out': False}), 'label': "price=1", 'data': "price:>=5 price:0"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "0"], 'out': True}), 'label': "price=0", 'data': "price:>=5 price:0"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "6"], 'out': True}), 'label': "price=6", 'data': "price:>=5 price:0"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'data': "tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': False}), 'data': "-tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testPropertyExclude", 'input': ["tag", "foo"], 'out': True}), 'label': "testExclude", 'data': "-tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "test", 'input': [_hx_AnonObject({'price': 5})], 'out': True}), 'data': ".foo price:5 -tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "test", 'input': [_hx_AnonObject({'tag': "foo", 'price': 5})], 'out': False}), 'data': ".foo price:5 -tag:foo"})])
if (Test.errors > 1):
print(str((("\n-----\n[ ❌] " + Std.string(Test.errors)) + " errors :/")))
@ -436,6 +437,8 @@ class Test:
valid = Test.equalXYZ(res,item)
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "equal.multi"):
valid = Test.equalMulti(res,item)
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testQueryRoot"):
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == HxOverrides.arrayGet(q.get(), HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0)).root)
ok = ("[ ✔ ] " if valid else "[ ❌] ")
print(str((((((("null" if ok is None else ok) + Std.string(Reflect.field(item,"fn"))) + ": '") + Std.string(Reflect.field(item,"data"))) + "'") + HxOverrides.stringOrNull(((((" (" + HxOverrides.stringOrNull(((Reflect.field(item,"label") if (Reflect.field(item,"label")) else Reflect.field(Reflect.field(item,"expect"),"fn"))))) + ")") if (Reflect.field(item,"label")) else ""))))))
if (not valid):
@ -1430,7 +1433,7 @@ class xrfragment_Parser:
Frag.h["unit"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
Frag.h["description"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
Frag.h["session"] = (((((xrfragment_XRF.ASSET | xrfragment_XRF.T_URL) | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.EMBEDDED) | xrfragment_XRF.PROMPT)
if ((len(value) == 0) and (not (key in Frag.h))):
if (((len(value) == 0) and ((len(key) > 0))) and (not (key in Frag.h))):
v = xrfragment_XRF(key,(xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR))
v.validate(key)
setattr(resultMap,(("_hx_" + key) if ((key in python_Boot.keywords)) else (("_hx_" + key) if (((((len(key) > 2) and ((ord(key[0]) == 95))) and ((ord(key[1]) == 95))) and ((ord(key[(len(key) - 1)]) != 95)))) else key)),v)
@ -1452,14 +1455,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({})
@ -1523,13 +1526,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
@ -1556,10 +1553,19 @@ class xrfragment_Query:
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
value = (False if ((_this.matchObj is not None)) else True)
setattr(_hx_filter,(("_hx_" + "id") if (("id" in python_Boot.keywords)) else (("_hx_" + "id") if (((((len("id") > 2) and ((ord("id"[0]) == 95))) and ((ord("id"[1]) == 95))) and ((ord("id"[(len("id") - 1)]) != 95)))) else "id")),value)
_this = _gthis.isRoot
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
value = (_this.matchObj is not 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")),value)
_this = _gthis.isExclude
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
key = (HxString.substr(_hx_str,1,None) if ((_this.matchObj is not None)) else _hx_str)
setattr(q,(("_hx_" + key) if ((key in python_Boot.keywords)) else (("_hx_" + key) if (((((len(key) > 2) and ((ord(key[0]) == 95))) and ((ord(key[1]) == 95))) and ((ord(key[(len(key) - 1)]) != 95)))) else key)),_hx_filter)
if (_this.matchObj is not None):
_hx_str = HxString.substr(_hx_str,1,None)
_this = _gthis.isRoot
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
if (_this.matchObj is not None):
_hx_str = HxString.substr(_hx_str,1,None)
setattr(q,(("_hx_" + _hx_str) if ((_hx_str in python_Boot.keywords)) else (("_hx_" + _hx_str) if (((((len(_hx_str) > 2) and ((ord(_hx_str[0]) == 95))) and ((ord(_hx_str[1]) == 95))) and ((ord(_hx_str[(len(_hx_str) - 1)]) != 95)))) else _hx_str)),_hx_filter)
process = _hx_local_0
_g = 0
_g1 = len(token)
@ -1599,8 +1605,8 @@ class xrfragment_Query:
fails = 0
qualify = 0
def _hx_local_2(expr):
nonlocal conds
nonlocal fails
nonlocal conds
conds = (conds + 1)
fails = (fails + (0 if expr else 1))
return expr