refactored spec, added focusLine, hashbus & XRWG (leftover)

This commit is contained in:
Leon van Kammen 2023-09-15 19:43:11 +02:00
parent 0d3959359b
commit cfcca8b66c
14 changed files with 2440 additions and 1865 deletions

File diff suppressed because one or more lines are too long

33
dist/xrfragment.js vendored
View File

@ -130,9 +130,6 @@ StringTools.rtrim = function(s) {
StringTools.trim = function(s) {
return StringTools.ltrim(StringTools.rtrim(s));
};
StringTools.replace = function(s,sub,by) {
return s.split(sub).join(by);
};
var haxe_iterators_ArrayIterator = function(array) {
this.current = 0;
this.array = array;
@ -220,7 +217,7 @@ xrfragment_Parser.parse = function(key,value,store) {
Frag_h["prio"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_INT;
Frag_h["src"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL;
Frag_h["href"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.T_PREDEFINED_VIEW;
Frag_h["class"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["tag"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["pos"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.T_STRING_OBJ | xrfragment_XRF.METADATA | xrfragment_XRF.NAVIGATOR;
Frag_h["q"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.METADATA;
Frag_h["scale"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA;
@ -273,7 +270,6 @@ xrfragment_Parser.parse = function(key,value,store) {
};
var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) {
this.isNumber = new EReg("^[0-9\\.]+$","");
this.isClass = new EReg("^[-]?class$","");
this.isRoot = new EReg("^[-]?/","");
this.isExclude = new EReg("^-","");
this.isProp = new EReg("^.*:[><=!]?","");
@ -288,14 +284,6 @@ xrfragment_Query.prototype = {
toObject: function() {
return this.q;
}
,expandAliases: function(token) {
var classAlias = new EReg("^(-)?\\.","");
if(classAlias.match(token)) {
return StringTools.replace(token,".","class:");
} else {
return token;
}
}
,get: function() {
return this.q;
}
@ -341,19 +329,14 @@ xrfragment_Query.prototype = {
if(oper.length == 0) {
oper = "=";
}
if(_gthis.isClass.match(k)) {
filter[prefix + k] = oper != "!=";
q[v] = filter;
var rule = { };
if(_gthis.isNumber.match(v)) {
rule[oper] = parseFloat(v);
} else {
var rule = { };
if(_gthis.isNumber.match(v)) {
rule[oper] = parseFloat(v);
} else {
rule[oper] = v;
}
filter["rules"].push(rule);
q[k] = filter;
rule[oper] = v;
}
filter["rules"].push(rule);
q[k] = filter;
return;
} else {
filter["id"] = _gthis.isExclude.match(str) ? false : true;
@ -371,7 +354,7 @@ xrfragment_Query.prototype = {
var _g1 = token.length;
while(_g < _g1) {
var i = _g++;
process(this.expandAliases(token[i]));
process(token[i]);
}
return this.q = q;
}

60
dist/xrfragment.lua vendored
View File

@ -1088,31 +1088,6 @@ end
StringTools.trim = function(s)
do return StringTools.ltrim(StringTools.rtrim(s)) end;
end
StringTools.replace = function(s,sub,by)
local idx = 1;
local ret = _hx_tab_array({}, 0);
while (idx ~= nil) do
local newidx = 0;
if (__lua_lib_luautf8_Utf8.len(sub) > 0) then
newidx = __lua_lib_luautf8_Utf8.find(s, sub, idx, true);
else
if (idx >= __lua_lib_luautf8_Utf8.len(s)) then
newidx = nil;
else
newidx = idx + 1;
end;
end;
if (newidx ~= nil) then
local match = __lua_lib_luautf8_Utf8.sub(s, idx, newidx - 1);
ret:push(match);
idx = newidx + __lua_lib_luautf8_Utf8.len(sub);
else
ret:push(__lua_lib_luautf8_Utf8.sub(s, idx, __lua_lib_luautf8_Utf8.len(s)));
idx = nil;
end;
end;
do return ret:join(by) end;
end
__haxe_IMap.new = {}
__haxe_IMap.__name__ = true
@ -1434,9 +1409,9 @@ __xrfragment_Parser.parse = function(key,value,store)
end;
local value1 = _hx_bit.bor(__xrfragment_XRF.ASSET,__xrfragment_XRF.T_STRING);
if (value1 == nil) then
Frag_h.class = __haxe_ds_StringMap.tnull;
Frag_h.tag = __haxe_ds_StringMap.tnull;
else
Frag_h.class = value1;
Frag_h.tag = value1;
end;
local value1 = _hx_bit.bor(_hx_bit.bor(_hx_bit.bor(_hx_bit.bor(_hx_bit.bor(__xrfragment_XRF.PV_OVERRIDE,__xrfragment_XRF.ROUNDROBIN),__xrfragment_XRF.T_VECTOR3),__xrfragment_XRF.T_STRING_OBJ),__xrfragment_XRF.METADATA),__xrfragment_XRF.NAVIGATOR);
if (value1 == nil) then
@ -1646,7 +1621,6 @@ __xrfragment_Query.new = function(str)
end
__xrfragment_Query.super = function(self,str)
self.isNumber = EReg.new("^[0-9\\.]+$", "");
self.isClass = EReg.new("^[-]?class$", "");
self.isRoot = EReg.new("^[-]?/", "");
self.isExclude = EReg.new("^-", "");
self.isProp = EReg.new("^.*:[><=!]?", "");
@ -1662,14 +1636,6 @@ __xrfragment_Query.prototype = _hx_e();
__xrfragment_Query.prototype.toObject = function(self)
do return self.q end
end
__xrfragment_Query.prototype.expandAliases = function(self,token)
local classAlias = EReg.new("^(-)?\\.", "");
if (classAlias:match(token)) then
do return StringTools.replace(token, ".", "class:") end;
else
do return token end;
end;
end
__xrfragment_Query.prototype.get = function(self)
do return self.q end
end
@ -1883,21 +1849,15 @@ __xrfragment_Query.prototype.parse = function(self,str)
if (__lua_lib_luautf8_Utf8.len(oper) == 0) then
oper = "=";
end;
if (_gthis.isClass:match(k)) then
local value = oper ~= "!=";
filter[Std.string(prefix) .. Std.string(k)] = value;
q[v] = filter;
local rule = _hx_e();
if (_gthis.isNumber:match(v)) then
local value = Std.parseFloat(v);
rule[oper] = value;
else
local rule = _hx_e();
if (_gthis.isNumber:match(v)) then
local value = Std.parseFloat(v);
rule[oper] = value;
else
rule[oper] = v;
end;
Reflect.field(filter, "rules"):push(rule);
q[k] = filter;
rule[oper] = v;
end;
Reflect.field(filter, "rules"):push(rule);
q[k] = filter;
do return end;
else
local value = (function()
@ -1954,7 +1914,7 @@ __xrfragment_Query.prototype.parse = function(self,str)
while (_g < _g1) do
_g = _g + 1;
local i = _g - 1;
process(self:expandAliases(token[i]));
process(token[i]);
end;
self.q = q do return self.q end
end

View File

@ -130,9 +130,6 @@ StringTools.rtrim = function(s) {
StringTools.trim = function(s) {
return StringTools.ltrim(StringTools.rtrim(s));
};
StringTools.replace = function(s,sub,by) {
return s.split(sub).join(by);
};
var haxe_iterators_ArrayIterator = function(array) {
this.current = 0;
this.array = array;
@ -220,7 +217,7 @@ xrfragment_Parser.parse = function(key,value,store) {
Frag_h["prio"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_INT;
Frag_h["src"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL;
Frag_h["href"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.T_PREDEFINED_VIEW;
Frag_h["class"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["tag"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["pos"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.T_STRING_OBJ | xrfragment_XRF.METADATA | xrfragment_XRF.NAVIGATOR;
Frag_h["q"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.METADATA;
Frag_h["scale"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA;
@ -273,7 +270,6 @@ xrfragment_Parser.parse = function(key,value,store) {
};
var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) {
this.isNumber = new EReg("^[0-9\\.]+$","");
this.isClass = new EReg("^[-]?class$","");
this.isRoot = new EReg("^[-]?/","");
this.isExclude = new EReg("^-","");
this.isProp = new EReg("^.*:[><=!]?","");
@ -288,14 +284,6 @@ xrfragment_Query.prototype = {
toObject: function() {
return this.q;
}
,expandAliases: function(token) {
var classAlias = new EReg("^(-)?\\.","");
if(classAlias.match(token)) {
return StringTools.replace(token,".","class:");
} else {
return token;
}
}
,get: function() {
return this.q;
}
@ -341,19 +329,14 @@ xrfragment_Query.prototype = {
if(oper.length == 0) {
oper = "=";
}
if(_gthis.isClass.match(k)) {
filter[prefix + k] = oper != "!=";
q[v] = filter;
var rule = { };
if(_gthis.isNumber.match(v)) {
rule[oper] = parseFloat(v);
} else {
var rule = { };
if(_gthis.isNumber.match(v)) {
rule[oper] = parseFloat(v);
} else {
rule[oper] = v;
}
filter["rules"].push(rule);
q[k] = filter;
rule[oper] = v;
}
filter["rules"].push(rule);
q[k] = filter;
return;
} else {
filter["id"] = _gthis.isExclude.match(str) ? false : true;
@ -371,7 +354,7 @@ xrfragment_Query.prototype = {
var _g1 = token.length;
while(_g < _g1) {
var i = _g++;
process(this.expandAliases(token[i]));
process(token[i]);
}
return this.q = q;
}

50
dist/xrfragment.py vendored
View File

@ -339,7 +339,7 @@ class Dynamic: pass
class StringTools:
_hx_class_name = "StringTools"
__slots__ = ()
_hx_statics = ["isSpace", "ltrim", "rtrim", "trim", "replace"]
_hx_statics = ["isSpace", "ltrim", "rtrim", "trim"]
@staticmethod
def isSpace(s,pos):
@ -377,11 +377,6 @@ class StringTools:
def trim(s):
return StringTools.ltrim(StringTools.rtrim(s))
@staticmethod
def replace(s,sub,by):
_this = (list(s) if ((sub == "")) else s.split(sub))
return by.join([python_Boot.toString1(x1,'') for x1 in _this])
class haxe_IMap:
_hx_class_name = "haxe.IMap"
@ -1297,7 +1292,7 @@ class xrfragment_Parser:
Frag.h["prio"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_INT)
Frag.h["src"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_URL)
Frag.h["href"] = ((xrfragment_XRF.ASSET | xrfragment_XRF.T_URL) | xrfragment_XRF.T_PREDEFINED_VIEW)
Frag.h["class"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
Frag.h["tag"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
Frag.h["pos"] = (((((xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.T_STRING_OBJ) | xrfragment_XRF.METADATA) | xrfragment_XRF.NAVIGATOR)
Frag.h["q"] = ((xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING) | xrfragment_XRF.METADATA)
Frag.h["scale"] = ((((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.ROUNDROBIN) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA)
@ -1346,13 +1341,12 @@ class xrfragment_Parser:
class xrfragment_Query:
_hx_class_name = "xrfragment.Query"
__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"]
__slots__ = ("str", "q", "isProp", "isExclude", "isRoot", "isNumber")
_hx_fields = ["str", "q", "isProp", "isExclude", "isRoot", "isNumber"]
_hx_methods = ["toObject", "get", "parse", "test", "testProperty"]
def __init__(self,_hx_str):
self.isNumber = EReg("^[0-9\\.]+$","")
self.isClass = EReg("^[-]?class$","")
self.isRoot = EReg("^[-]?/","")
self.isExclude = EReg("^-","")
self.isProp = EReg("^.*:[><=!]?","")
@ -1364,14 +1358,6 @@ class xrfragment_Query:
def toObject(self):
return self.q
def expandAliases(self,token):
classAlias = EReg("^(-)?\\.","")
classAlias.matchObj = python_lib_Re.search(classAlias.pattern,token)
if (classAlias.matchObj is not None):
return StringTools.replace(token,".","class:")
else:
return token
def get(self):
return self.q
@ -1418,24 +1404,16 @@ class xrfragment_Query:
v = HxString.substr(v,len(oper),None)
if (len(oper) == 0):
oper = "="
_this = _gthis.isClass
_this.matchObj = python_lib_Re.search(_this.pattern,k)
rule = _hx_AnonObject({})
_this = _gthis.isNumber
_this.matchObj = python_lib_Re.search(_this.pattern,v)
if (_this.matchObj is not None):
key = (("null" if prefix is None else prefix) + ("null" if k is None else k))
value = (oper != "!=")
setattr(_hx_filter,(("_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)),value)
setattr(q,(("_hx_" + v) if ((v in python_Boot.keywords)) else (("_hx_" + v) if (((((len(v) > 2) and ((ord(v[0]) == 95))) and ((ord(v[1]) == 95))) and ((ord(v[(len(v) - 1)]) != 95)))) else v)),_hx_filter)
value = Std.parseFloat(v)
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),value)
else:
rule = _hx_AnonObject({})
_this = _gthis.isNumber
_this.matchObj = python_lib_Re.search(_this.pattern,v)
if (_this.matchObj is not None):
value = Std.parseFloat(v)
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),value)
else:
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),v)
Reflect.field(Reflect.field(_hx_filter,"rules"),"push")(rule)
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)
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),v)
Reflect.field(Reflect.field(_hx_filter,"rules"),"push")(rule)
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.isExclude
@ -1461,7 +1439,7 @@ class xrfragment_Query:
while (_g < _g1):
i = _g
_g = (_g + 1)
process(self.expandAliases((token[i] if i >= 0 and i < len(token) else None)))
process((token[i] if i >= 0 and i < len(token) else None))
def _hx_local_2():
def _hx_local_1():
self.q = q

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -93,7 +93,7 @@ value: draft-XRFRAGMENTS-leonvankammen-00
.# Abstract
This draft offers a specification for 4D URLs & navigation, to link 3D scenes and text together with- or without a network-connection.<br>
This draft is a specification for 4D URLs & navigation, which links together space, time & text together, for hypermedia browsers with- or without a network-connection.<br>
The specification promotes spatial addressibility, sharing, navigation, query-ing and annotating interactive (text)objects across for (XR) Browsers.<br>
XR Fragments allows us to enrich existing dataformats, by recursive use of existing proven technologies like [URI Fragments](https://en.wikipedia.org/wiki/URI_fragment) and BibTags notation.<br>
@ -110,6 +110,7 @@ XR Fragments allows us to enrich/connect existing dataformats, by recursive use
1. addressibility and navigation of 3D scenes/objects: [URI Fragments](https://en.wikipedia.org/wiki/URI_fragment) + src/href spatial metadata
1. Interlinking text/& 3D by collapsing space into a Word Graph (XRWG) (and augmenting text with [bibs](https://github.com/coderofsalvation/tagbibs) / [BibTags](https://en.wikipedia.org/wiki/BibTeX) appendices (see [visual-meta](https://visual-meta.info) e.g.)
1. extend the hashtag-to-browser-viewport paradigm beyond 2D documents (XR documents)
> NOTE: The chapters in this document are ordered from highlevel to lowlevel (technical) as much as possible
@ -117,14 +118,42 @@ XR Fragments allows us to enrich/connect existing dataformats, by recursive use
XR Fragments strives to serve (nontechnical/fuzzy) humans first, and machine(implementations) later, by ensuring hasslefree text-vs-thought feedback loops.<br>
This also means that the repair-ability of machine-matters should be human friendly too (not too complex).<br>
XR Fragments tries to seek to connect the world of text (semantical web / RDF), and the world of pixels.<br>
Instead of combining them (in a game-editor e.g.), XR Fragments is opting for a more integrated path **towards** them, by describing how to make browsers **4D URL-ready**:
> "When a car breaks down, the ones **without** turbosupercharger are easier to fix"
| principle | XR 4D URL | HTML 2D URL |
|----------------------|----------------------------------------------|---------------------------------------|
| the XRWG | wordgraph (collapses 3D scene to tags) | Ctrl-F (find) |
| the hashbus | hashtags map to camera/scene-projections | hashtags map to document positions |
| spacetime hashtags | positions camera, triggers scene-preset/time | jumps/scrolls to chapter |
Let's always focus on average humans: our fuzzy symbolical mind must be served first, before serving a greater [categorized typesafe RDF hive mind](https://en.wikipedia.org/wiki/Borg)).
> XR Fragments does not look at XR (or the web) thru the lens of HTML.<br>But approaches things from a higherlevel browser-perspective:
> Humans first, machines (AI) later.
```
+----------------------------------------------------------------------------------------------+
| |
| the soul of any URL: ://macro /meso ?micro #nano |
| |
| 2D URL: ://library.com /document ?search #chapter |
| |
| 4D URL: ://park.com /4Dscene.fbx --> ?search --> #view ---> hashbus |
| │ | |
| XRWG <---------------------<------------+ |
| │ | |
| ├─ objects --------------->------------| |
| └─ text --------------->------------+ |
| |
| |
+----------------------------------------------------------------------------------------------+
```
Traditional webbrowsers can become 4D document-ready by:
* loading 3D assets (gltf/fbx e.g.) natively (not thru HTML).
* allowing assets to publish hashtags to themselves (the scene) using the hashbus (like hashtags controlling the scrollbar).
* collapsing the 3D scene to an wordgraph (for essential navigation purposes) controllable thru a hash(tag)bus
Thererfore, XR Fragments does not look at XR (or the web) thru the lens of HTML.<br>
XR Fragments itself is HTML-agnostic, though pseudo-XR Fragment browsers **can** be implemented on top of HTML/Javascript.
# Conventions and Definitions
@ -146,7 +175,7 @@ sub-delims = "," / "="
| `pos=1,2,3` | vector/coordinate argument e.g. |
| `pos=1,2,3&rot=0,90,0&q=.foo` | combinators |
> this is already implemented in all browsers
# List of URI Fragments
@ -155,7 +184,7 @@ sub-delims = "," / "="
| `#pos` | vector3 | `#pos=0.5,0,0` | positions camera to xyz-coord 0.5,0,0 |
| `#rot` | vector3 | `#rot=0,90,0` | rotates camera to xyz-coord 0.5,0,0 |
| `#t` | vector2 | `#t=500,1000` | sets animation-loop range between frame 500 and 1000 |
| `#......` | string | `#.cubes` `#cube` | object(s) of interest (fragment-to-object-or-classname) |
| `#......` | string | `#.cubes` `#cube` | object(s) of interest (fragment-to-object-or-tagname) |
> xyz coordinates are similar to ones found in SVG Media Fragments
@ -164,7 +193,7 @@ sub-delims = "," / "="
| key | type | example (JSON) | info |
|--------------|----------|------------------------|--------------------------------------------------------|
| `name` | string | `"name": "cube"` | available in all 3D fileformats & scenes |
| `class` | string | `"class": "cubes geo"` | available through custom property in 3D fileformats |
| `tag` | string | `"tag": "cubes geo"` | available through custom property in 3D fileformats |
| `href` | string | `"href": "b.gltf"` | available through custom property in 3D fileformats |
| `src` | string | `"src": "#cube"` | available through custom property in 3D fileformats |
@ -232,16 +261,16 @@ Include, exclude, hide/shows objects using space-separated strings:
| example | outcome |
|----------------------------------|------------------------------------------------------------------------------------|
| `#q=-sky` | show everything except object named `sky` |
| `#q=-.language .english` | hide everything with class `language`, but show all class `english` objects |
| `#q=-.language .english` | hide everything with tag `language`, but show all tag `english` objects |
| `#q=price:>2 price:<5` | of all objects with property `price`, show only objects with value between 2 and 5 |
It's simple but powerful syntax which allows <b>css</b>-like class/id-selectors with a searchengine prompt-style feeling:
It's simple but powerful syntax which allows <b>css</b>-like tag/id-selectors with a searchengine prompt-style feeling:
1. queries are a way to traverse a scene, and filter objects based on their class- or property-values.
1. words starting with `.` like `.german` match class-metadata of 3D objects like `"class":"german"`
1. words starting with `.` like `.german` match class-metadata of (BibTeX) tags in XR Text objects like `@german{KarlHeinz, ...` e.g.
1. queries are a way to traverse a scene, and filter objects based on their tag- or property-values.
1. words starting with `.` like `.german` match tag-metadata of 3D objects like `"tag":"german"`
1. words starting with `.` like `.german` match tag-metadata of (BibTeX) tags in XR Text objects like `@german{KarlHeinz, ...` e.g.
> **For example**: `#q=.foo` is a shorthand for `#q=class:foo`, which will select objects with custom property `class`:`foo`. Just a simple `#q=cube` will simply select an object named `cube`.
> **For example**: `#q=.foo` is a shorthand for `#q=tag:foo`, which will select objects with custom property `tag`:`foo`. Just a simple `#q=cube` will simply select an object named `cube`.
* see [an example video here](https://coderofsalvation.github.io/xrfragment.media/queries.mp4)
@ -251,7 +280,7 @@ It's simple but powerful syntax which allows <b>css</b>-like class/id-selectors
|----------|-------------------------------------------------------------------------------------------------------------------------------|
| `-` | removes/hides object(s) |
| `:` | indicates an object-embedded custom property key/value |
| `.` | alias for `"class" :".foo"` equals `class:foo` |
| `.` | alias for `"tag" :".foo"` equals `tag:foo` |
| `>` `<` | compare float or int number |
| `/` | reference to root-scene.<br>Useful in case of (preventing) showing/hiding objects in nested scenes (instanced by `src`) (*) |
@ -269,9 +298,9 @@ Here's how to write a query parser:
1. detect object id's & properties `foo:1` and `foo` (reference regex: `/^.*:[><=!]?/` )
1. detect excluders like `-foo`,`-foo:1`,`-.foo`,`-/foo` (reference regex: `/^-/` )
1. detect root selectors like `/foo` (reference regex: `/^[-]?\//` )
1. detect class selectors like `.foo` (reference regex: `/^[-]?class$/` )
1. detect tag selectors like `.foo` (reference regex: `/^[-]?tag$/` )
1. detect number values like `foo:1` (reference regex: `/^[0-9\.]+$/` )
1. expand aliases like `.foo` into `class:foo`
1. expand aliases like `.foo` into `tag:foo`
1. for every query token split string on `:`
1. create an empty array `rules`
1. then strip key-operator: convert "-foo" into "foo"
@ -325,9 +354,9 @@ XR Fragments does this by detecting Bib(s)Tex, without introducing a new languag
Hence:
1. XR Fragments promotes (de)serializing a scene to the XRWG
2. XR Fragments primes the XRWG, by collecting words from the `class` and name-property of 3D objects.
2. XR Fragments primes the XRWG, by collecting words from the `tag` and name-property of 3D objects.
3. XR Fragments primes the XRWG, by collecting words from **optional** metadata **at the end of content** of text (see default mimetype & Data URI)
4. [Bib's](https://github.com/coderofsalvation/hashtagbibs) and BibTex are first class citizens for priming the XRWG with words (from XR text)
4. [Bib's](https://github.com/coderofsalvation/hashtagbibs) and BibTex are first tag citizens for priming the XRWG with words (from XR text)
5. Like Bibs, XR Fragments generalizes the BibTex author/title-semantics (`author{title}`) into **this** points to **that** (`this{that}`)
6. The XRWG should be recalculated when textvalues (in `src`) change
7. HTML/RDF/JSON is still great, but is beyond the XRWG-scope (they fit better in the application-layer)
@ -337,7 +366,7 @@ Hence:
Example:
```
http://y.io/z.fbx | Derived XRWG (printed as BibTex)
http://y.io/z.fbx | Derived XRWG (shown as BibTex)
----------------------------------------------------------------------------+--------------------------------------
| @house{castle,
+-[src: data:.....]----------------------+ +-[3D mesh]-+ | url = {https://y.io/z.fbx#castle}
@ -348,7 +377,7 @@ Example:
| #john@baroque | +-----│-----+ | @baroque{john}
| | │ |
| | ├─ name: castle |
| | └─ class: house baroque |
| | └─ tag: house baroque |
+----------------------------------------+ |
[3D mesh ] |
| O ├─ name: john |
@ -357,7 +386,7 @@ Example:
+--------+ |
```
> the `#john@baroque`-bib associates both text `John` and objectname `john`, with class `baroque`
> the `#john@baroque`-bib associates both text `John` and objectname `john`, with tag `baroque`
```
@ -375,7 +404,7 @@ Another example:
| #john@baroque | +-----│-----+ | }
| @baroque{john} | │ | @baroque{john}
| | ├─ name: castle |
| | └─ class: house baroque |
| | └─ tag: house baroque |
+----------------------------------------+ | @house{baroque}
[3D mesh ] | @todo{baroque}
+-[remotestorage.io / localstorage]------+ | O + name: john |
@ -384,7 +413,7 @@ Another example:
+----------------------------------------+ +--------+ |
```
> both `#john@baroque`-bib and BibTex `@baroque{john}` result in the same XRWG, however on top of that 2 classes (`house` and `todo`) are now associated with text/objectname/class 'baroque'.
> both `#john@baroque`-bib and BibTex `@baroque{john}` result in the same XRWG, however on top of that 2 tages (`house` and `todo`) are now associated with text/objectname/tag 'baroque'.
As seen above, the XRWG can expand [bibs](https://github.com/coderofsalvation/hashtagbibs) (and the whole scene) to BibTeX.<br>
This allows hasslefree authoring and copy-paste of associations **for and by humans**, but also makes these URLs possible:
@ -393,7 +422,7 @@ This allows hasslefree authoring and copy-paste of associations **for and by hum
|---------------------------------------|---------------------------------------------------------------------------|
| `https://my.com/foo.gltf#.baroque` | highlights mesh `john`, 3D mesh `castle`, text `John built(..)` |
| `https://my.com/foo.gltf#john` | highlights mesh `john`, and the text `John built (..)` |
| `https://my.com/foo.gltf#house` | highlights mesh `castle`, and other objects with class `house` or `todo` |
| `https://my.com/foo.gltf#house` | highlights mesh `castle`, and other objects with tag `house` or `todo` |
> [hashtagbibs](https://github.com/coderofsalvation/hashtagbibs) potentially allow the enduser to annotate text/objects by **speaking/typing/scanning associations**, which the XR Browser saves to remotestorage (or localStorage per toplevel URL). As well as, referencing BibTags per URI later on: `https://y.io/z.fbx#@baroque@todo` e.g.
@ -402,7 +431,7 @@ The XRWG allows XR Browsers to show/hide relationships in realtime at various le
* wordmatch **inside** `src` text
* wordmatch **inside** `href` text
* wordmatch object-names
* wordmatch object-classnames
* wordmatch object-tagnames
Spatial wires can be rendered, words/objects can be highlighted/scaled etc.<br>
Some pointers for good UX (but not necessary to be XR Fragment compatible):
@ -412,7 +441,7 @@ Some pointers for good UX (but not necessary to be XR Fragment compatible):
12. respect multi-line BiBTeX metadata in text because of [the core principle](#core-principle)
13. Default font (unless specified otherwise) is a modern monospace font, for maximized tabular expressiveness (see [the core principle](#core-principle)).
14. anti-pattern: hardcoupling an XR Browser with a mandatory **markup/scripting-language** which departs from onubtrusive plain text (HTML/VRML/Javascript) (see [the core principle](#core-principle))
15. anti-pattern: limiting human introspection, by abandoning plain text as first class citizen.
15. anti-pattern: limiting human introspection, by abandoning plain text as first tag citizen.
> The simplicity of appending metadata (and leveling the metadata-playfield between humans and machines) is also demonstrated by [visual-meta](https://visual-meta.info) in greater detail.
@ -422,7 +451,7 @@ Fictional chat:
<John> Hey what about this: https://my.com/station.gltf#pos=0,0,1&rot=90,2,0&t=500,1000
<Sarah> I'm checking it right now
<Sarah> I don't see everything..where's our text from yesterday?
<John> Ah wait, that's tagged with class 'draft' (and hidden)..hold on, try this:
<John> Ah wait, that's tagged with tag 'draft' (and hidden)..hold on, try this:
<John> https://my.com/station.gltf#.draft&pos=0,0,1&rot=90,2,0&t=500,1000
<Sarah> how about we link the draft to the upcoming YELLO-event?
<John> ok I'm adding #draft@YELLO
@ -433,7 +462,7 @@ Fictional chat:
<Sarah> Btw. I stumbled upon this spatial book which references station.gltf in some chapters:
<Sarah> https://thecommunity.org/forum/foo/mytrainstory.txt
<John> interesting, I'm importing mytrainstory.txt into station.gltf
<John> ah yes, chapter three points to trainterminal_2A, cool
<John> ah yes, chapter three points to trainterminal_2A in the scene, cool
```
## Default Data URI mimetype
@ -610,7 +639,7 @@ here are some hashtagbibs followed by bibtex:
Since XR Text contains metadata too, the user should be able to set up tagging-rules, so the copy-paste feature can :
* filter out sensitive data when copy/pasting (XR text with `class:secret` e.g.)
* filter out sensitive data when copy/pasting (XR text with `tag:secret` e.g.)
# IANA Considerations
@ -631,6 +660,9 @@ This document has no IANA actions.
|3D object | an object inside a scene characterized by vertex-, face- and customproperty data. |
|metadata | custom properties of text, 3D Scene or Object(nodes), relevant to machines and a human minority (academics/developers) |
|XR fragment | URI Fragment with spatial hints like `#pos=0,0,0&t=1,100` e.g. |
|the XRWG | wordgraph (collapses 3D scene to tags) |
|the hashbus | hashtags map to camera/scene-projections |
|spacetime hashtags | positions camera, triggers scene-preset/time |
|src | (HTML-piggybacked) metadata of a 3D object which instances content |
|href | (HTML-piggybacked) metadata of a 3D object which links to content |
|query | an URI Fragment-operator which queries object(s) from a scene like `#q=cube` |

View File

@ -52,7 +52,7 @@
if( document.location.search.length > 2 )
$('#home').setAttribute('xrf', document.location.search.substr(1)+document.location.hash )
$('a-scene').addEventListener('loaded', () => {
$('a-scene').addEventListener('XRF', () => {
let XRF = window.AFRAME.XRF
setupConsole( $('textarea') )

File diff suppressed because one or more lines are too long

View File

@ -59,7 +59,6 @@ export function setupUrlBar(el,XRF){
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.addEventListener('updateHash', () => reflectUrl() )

File diff suppressed because one or more lines are too long

View File

@ -130,14 +130,11 @@ StringTools.rtrim = function(s) {
StringTools.trim = function(s) {
return StringTools.ltrim(StringTools.rtrim(s));
};
StringTools.replace = function(s,sub,by) {
return s.split(sub).join(by);
};
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"},{ fn : "url", expect : { fn : "testParsed", input : "_mycustom", out : true}, label : "test custom property", data : "http://foo.com?foo=1#mycustom=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([{ 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"},{ fn : "url", expect : { fn : "testParsed", input : "mycustom", out : true}, label : "test custom property", data : "http://foo.com?foo=1#mycustom=foo"}]);
Test.test([{ fn : "query", expect : { fn : "testProperty", input : ["tag","bar"], out : true}, data : "tag:bar"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : false}, data : "tag:bar -tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, data : "tag:bar -tag:foo tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","bar"], out : true}, data : "tag:bar -tag:bar tag:bar"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, label : "tag:foo", data : "tag:foo -tag:foo tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, label : "tag:foo", data : "tag:foo -tag:foo bar:5 tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, label : "tag:foo", data : "tag:foo -tag:foo bar:>5 tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, label : "tag:foo", data : "tag:foo -tag:foo bar:>5 tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, label : "tag:foo", data : "tag:foo -tag:foo tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["id","foo"], out : true}, label : "id:foo", data : "tag:foo -tag:foo tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["id","foo"], out : true}, label : "id:foo?", data : "tag: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) {
@ -334,7 +331,7 @@ xrfragment_Parser.parse = function(key,value,store) {
Frag_h["prio"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_INT;
Frag_h["src"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL;
Frag_h["href"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.T_PREDEFINED_VIEW;
Frag_h["class"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["tag"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["pos"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.T_STRING_OBJ | xrfragment_XRF.METADATA | xrfragment_XRF.NAVIGATOR;
Frag_h["q"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.METADATA;
Frag_h["scale"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA;
@ -387,7 +384,6 @@ xrfragment_Parser.parse = function(key,value,store) {
};
var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) {
this.isNumber = new EReg("^[0-9\\.]+$","");
this.isClass = new EReg("^[-]?class$","");
this.isRoot = new EReg("^[-]?/","");
this.isExclude = new EReg("^-","");
this.isProp = new EReg("^.*:[><=!]?","");
@ -402,14 +398,6 @@ xrfragment_Query.prototype = {
toObject: function() {
return this.q;
}
,expandAliases: function(token) {
var classAlias = new EReg("^(-)?\\.","");
if(classAlias.match(token)) {
return StringTools.replace(token,".","class:");
} else {
return token;
}
}
,get: function() {
return this.q;
}
@ -455,19 +443,14 @@ xrfragment_Query.prototype = {
if(oper.length == 0) {
oper = "=";
}
if(_gthis.isClass.match(k)) {
filter[prefix + k] = oper != "!=";
q[v] = filter;
var rule = { };
if(_gthis.isNumber.match(v)) {
rule[oper] = parseFloat(v);
} else {
var rule = { };
if(_gthis.isNumber.match(v)) {
rule[oper] = parseFloat(v);
} else {
rule[oper] = v;
}
filter["rules"].push(rule);
q[k] = filter;
rule[oper] = v;
}
filter["rules"].push(rule);
q[k] = filter;
return;
} else {
filter["id"] = _gthis.isExclude.match(str) ? false : true;
@ -485,7 +468,7 @@ xrfragment_Query.prototype = {
var _g1 = token.length;
while(_g < _g1) {
var i = _g++;
process(this.expandAliases(token[i]));
process(token[i]);
}
return this.q = q;
}

View File

@ -339,7 +339,7 @@ class Dynamic: pass
class StringTools:
_hx_class_name = "StringTools"
__slots__ = ()
_hx_statics = ["isSpace", "ltrim", "rtrim", "trim", "replace"]
_hx_statics = ["isSpace", "ltrim", "rtrim", "trim"]
@staticmethod
def isSpace(s,pos):
@ -377,11 +377,6 @@ class StringTools:
def trim(s):
return StringTools.ltrim(StringTools.rtrim(s))
@staticmethod
def replace(s,sub,by):
_this = (list(s) if ((sub == "")) else s.split(sub))
return by.join([python_Boot.toString1(x1,'') for x1 in _this])
class Test:
_hx_class_name = "Test"
@ -390,8 +385,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"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testParsed", 'input': "_mycustom", 'out': True}), 'label': "test custom property", 'data': "http://foo.com?foo=1#mycustom=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([_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"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testParsed", 'input': "mycustom", 'out': True}), 'label': "test custom property", 'data': "http://foo.com?foo=1#mycustom=foo"})])
Test.test([_hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "bar"], 'out': True}), 'data': "tag:bar"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': False}), 'data': "tag:bar -tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'data': "tag:bar -tag:foo tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "bar"], 'out': True}), 'data': "tag:bar -tag:bar tag:bar"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'label': "tag:foo", 'data': "tag:foo -tag:foo tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'label': "tag:foo", 'data': "tag:foo -tag:foo bar:5 tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'label': "tag:foo", 'data': "tag:foo -tag:foo bar:>5 tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'label': "tag:foo", 'data': "tag:foo -tag:foo bar:>5 tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'label': "tag:foo", 'data': "tag:foo -tag:foo tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["id", "foo"], 'out': True}), 'label': "id:foo", 'data': "tag:foo -tag:foo tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["id", "foo"], 'out': True}), 'label': "id:foo?", 'data': "tag: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):
@ -1414,7 +1409,7 @@ class xrfragment_Parser:
Frag.h["prio"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_INT)
Frag.h["src"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_URL)
Frag.h["href"] = ((xrfragment_XRF.ASSET | xrfragment_XRF.T_URL) | xrfragment_XRF.T_PREDEFINED_VIEW)
Frag.h["class"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
Frag.h["tag"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
Frag.h["pos"] = (((((xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.T_STRING_OBJ) | xrfragment_XRF.METADATA) | xrfragment_XRF.NAVIGATOR)
Frag.h["q"] = ((xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING) | xrfragment_XRF.METADATA)
Frag.h["scale"] = ((((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.ROUNDROBIN) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA)
@ -1463,13 +1458,12 @@ class xrfragment_Parser:
class xrfragment_Query:
_hx_class_name = "xrfragment.Query"
__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"]
__slots__ = ("str", "q", "isProp", "isExclude", "isRoot", "isNumber")
_hx_fields = ["str", "q", "isProp", "isExclude", "isRoot", "isNumber"]
_hx_methods = ["toObject", "get", "parse", "test", "testProperty"]
def __init__(self,_hx_str):
self.isNumber = EReg("^[0-9\\.]+$","")
self.isClass = EReg("^[-]?class$","")
self.isRoot = EReg("^[-]?/","")
self.isExclude = EReg("^-","")
self.isProp = EReg("^.*:[><=!]?","")
@ -1481,14 +1475,6 @@ class xrfragment_Query:
def toObject(self):
return self.q
def expandAliases(self,token):
classAlias = EReg("^(-)?\\.","")
classAlias.matchObj = python_lib_Re.search(classAlias.pattern,token)
if (classAlias.matchObj is not None):
return StringTools.replace(token,".","class:")
else:
return token
def get(self):
return self.q
@ -1535,24 +1521,16 @@ class xrfragment_Query:
v = HxString.substr(v,len(oper),None)
if (len(oper) == 0):
oper = "="
_this = _gthis.isClass
_this.matchObj = python_lib_Re.search(_this.pattern,k)
rule = _hx_AnonObject({})
_this = _gthis.isNumber
_this.matchObj = python_lib_Re.search(_this.pattern,v)
if (_this.matchObj is not None):
key = (("null" if prefix is None else prefix) + ("null" if k is None else k))
value = (oper != "!=")
setattr(_hx_filter,(("_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)),value)
setattr(q,(("_hx_" + v) if ((v in python_Boot.keywords)) else (("_hx_" + v) if (((((len(v) > 2) and ((ord(v[0]) == 95))) and ((ord(v[1]) == 95))) and ((ord(v[(len(v) - 1)]) != 95)))) else v)),_hx_filter)
value = Std.parseFloat(v)
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),value)
else:
rule = _hx_AnonObject({})
_this = _gthis.isNumber
_this.matchObj = python_lib_Re.search(_this.pattern,v)
if (_this.matchObj is not None):
value = Std.parseFloat(v)
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),value)
else:
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),v)
Reflect.field(Reflect.field(_hx_filter,"rules"),"push")(rule)
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)
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),v)
Reflect.field(Reflect.field(_hx_filter,"rules"),"push")(rule)
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.isExclude
@ -1578,7 +1556,7 @@ class xrfragment_Query:
while (_g < _g1):
i = _g
_g = (_g + 1)
process(self.expandAliases((token[i] if i >= 0 and i < len(token) else None)))
process((token[i] if i >= 0 and i < len(token) else None))
def _hx_local_2():
def _hx_local_1():
self.q = q