release v0.5.2
This commit is contained in:
		
							parent
							
								
									45b46f788c
								
							
						
					
					
						commit
						6ad8f146c7
					
				
					 21 changed files with 5714 additions and 373 deletions
				
			
		
							
								
								
									
										
											BIN
										
									
								
								dist/__pycache__/__init__.cpython-310.pyc
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/__pycache__/__init__.cpython-310.pyc
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										4
									
								
								dist/aframe.min.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								dist/aframe.min.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										450
									
								
								dist/xrfragment.aframe.all.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										450
									
								
								dist/xrfragment.aframe.all.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										448
									
								
								dist/xrfragment.aframe.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										448
									
								
								dist/xrfragment.aframe.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * v0.5.1 generated at Tue Mar 19 10:04:25 AM UTC 2024
 | 
			
		||||
 * v0.5.1 generated at Tue Apr 16 12:47:01 PM UTC 2024
 | 
			
		||||
 * https://xrfragment.org
 | 
			
		||||
 * SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -1138,9 +1138,13 @@ xrfragment_Parser.getMetaData = function() {
 | 
			
		|||
	var meta = { title : ["title","og:title","dc.title"], description : ["aria-description","og:description","dc.description"], author : ["author","dc.creator"], publisher : ["publisher","dc.publisher"], website : ["og:site_name","og:url","dc.publisher"], license : ["SPDX","dc.rights"]};
 | 
			
		||||
	return meta;
 | 
			
		||||
};
 | 
			
		||||
var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() { };
 | 
			
		||||
var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() {
 | 
			
		||||
	this.XRF = { };
 | 
			
		||||
	this.hash = { };
 | 
			
		||||
	this.fragment = "";
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.__name__ = true;
 | 
			
		||||
xrfragment_URI.parse = function(url,filter) {
 | 
			
		||||
xrfragment_URI.parseFragment = function(url,filter) {
 | 
			
		||||
	var store = { };
 | 
			
		||||
	if(url == null || url.indexOf("#") == -1) {
 | 
			
		||||
		return store;
 | 
			
		||||
| 
						 | 
				
			
			@ -1192,6 +1196,232 @@ xrfragment_URI.template = function(uri,vars) {
 | 
			
		|||
	parts[1] = frag;
 | 
			
		||||
	return parts.join("#");
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.parse = function(stringUrl,flags) {
 | 
			
		||||
	var r = new EReg("^(?:(?![^:@]+:[^:@/]*@)([^:/?#.]+):)?(?://)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:/?#]*)(?::(\\d*))?)(((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[?#]|$)))*/?)?([^?#/]*))(?:\\?([^#]*))?(?:#(.*))?)","");
 | 
			
		||||
	if(stringUrl.indexOf("://") == -1 && stringUrl.charAt(0) != "/") {
 | 
			
		||||
		stringUrl = "/" + stringUrl;
 | 
			
		||||
	}
 | 
			
		||||
	r.match(stringUrl);
 | 
			
		||||
	var url = new xrfragment_URI();
 | 
			
		||||
	var _g = 0;
 | 
			
		||||
	var _g1 = xrfragment_URI._parts.length;
 | 
			
		||||
	while(_g < _g1) {
 | 
			
		||||
		var i = _g++;
 | 
			
		||||
		url[xrfragment_URI._parts[i]] = r.matched(i);
 | 
			
		||||
	}
 | 
			
		||||
	if(xrfragment_URI.isRelative(url) == true) {
 | 
			
		||||
		if(url.directory == null && url.host != null) {
 | 
			
		||||
			url.file = url.host;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	url.hash = { };
 | 
			
		||||
	if(url.fragment != null && url.fragment.length > 0) {
 | 
			
		||||
		url.XRF = xrfragment_URI.parseFragment("#" + url.fragment,flags);
 | 
			
		||||
		var key;
 | 
			
		||||
		var _g = 0;
 | 
			
		||||
		var _g1 = Reflect.fields(url.XRF);
 | 
			
		||||
		while(_g < _g1.length) {
 | 
			
		||||
			var key = _g1[_g];
 | 
			
		||||
			++_g;
 | 
			
		||||
			var v = url.XRF[key];
 | 
			
		||||
			url.hash[key] = v["string"];
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	xrfragment_URI.computeVars(url);
 | 
			
		||||
	return url;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.computeVars = function(url) {
 | 
			
		||||
	var r_r = new RegExp("//","g".split("u").join(""));
 | 
			
		||||
	if(url.directory != null && url.directory.indexOf("//") != -1) {
 | 
			
		||||
		url.directory = url.directory.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	if(url.path != null && url.path.indexOf("//") != -1) {
 | 
			
		||||
		url.path = url.path.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	if(url.file != null && url.file.indexOf("//") != -1) {
 | 
			
		||||
		url.file = url.file.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	url.URN = url.scheme + "://" + url.host;
 | 
			
		||||
	if(url.port != null) {
 | 
			
		||||
		url.URN += ":" + url.port;
 | 
			
		||||
	}
 | 
			
		||||
	url.URN += url.directory;
 | 
			
		||||
	if(url.file != null) {
 | 
			
		||||
		var parts = url.file.split(".");
 | 
			
		||||
		if(parts.length > 1) {
 | 
			
		||||
			url.fileExt = parts.pop();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.toString = function(url) {
 | 
			
		||||
	var result = "";
 | 
			
		||||
	if(url.scheme != null) {
 | 
			
		||||
		result += url.scheme + "://";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.user != null) {
 | 
			
		||||
		result += url.user + ":";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.password != null) {
 | 
			
		||||
		result += url.password + "@";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.host != null) {
 | 
			
		||||
		result += url.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.port != null) {
 | 
			
		||||
		result += ":" + url.port;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		result += url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.file != null) {
 | 
			
		||||
		result += url.file;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.query != null) {
 | 
			
		||||
		result += "?" + url.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.fragment != null) {
 | 
			
		||||
		result += "#" + url.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendURI = function(url,appendedURI) {
 | 
			
		||||
	if(xrfragment_URI.isRelative(url) == true) {
 | 
			
		||||
		return xrfragment_URI.appendToRelativeURI(url,appendedURI);
 | 
			
		||||
	} else {
 | 
			
		||||
		return xrfragment_URI.appendToAbsoluteURI(url,appendedURI);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.isRelative = function(url) {
 | 
			
		||||
	return url.scheme == null;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendToRelativeURI = function(url,appendedURI) {
 | 
			
		||||
	if(url.directory == null || url.host == null) {
 | 
			
		||||
		return xrfragment_URI.cloneURI(appendedURI);
 | 
			
		||||
	}
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	resultURI.host = url.host;
 | 
			
		||||
	resultURI.directory = url.directory;
 | 
			
		||||
	if(appendedURI.host != null) {
 | 
			
		||||
		resultURI.directory += appendedURI.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.directory != null) {
 | 
			
		||||
		var directory = appendedURI.directory;
 | 
			
		||||
		if(appendedURI.host == null) {
 | 
			
		||||
			resultURI.directory += HxOverrides.substr(directory,1,null);
 | 
			
		||||
		} else {
 | 
			
		||||
			resultURI.directory += directory;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.file != null) {
 | 
			
		||||
		resultURI.file = appendedURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(appendedURI.query != null) {
 | 
			
		||||
		resultURI.query = appendedURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = appendedURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendToAbsoluteURI = function(url,appendedURI) {
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	if(url.scheme != null) {
 | 
			
		||||
		resultURI.scheme = url.scheme;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.host != null) {
 | 
			
		||||
		resultURI.host = url.host;
 | 
			
		||||
	}
 | 
			
		||||
	var directory = "";
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		directory = url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.host != null) {
 | 
			
		||||
		appendedURI.directory += appendedURI.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.directory != null) {
 | 
			
		||||
		directory += appendedURI.directory;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.directory = directory;
 | 
			
		||||
	if(appendedURI.file != null) {
 | 
			
		||||
		resultURI.file = appendedURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(appendedURI.query != null) {
 | 
			
		||||
		resultURI.query = appendedURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = appendedURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.toAbsolute = function(url,newUrl) {
 | 
			
		||||
	var newURI = xrfragment_URI.parse(newUrl,0);
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	resultURI.port = url.port;
 | 
			
		||||
	resultURI.source = newUrl;
 | 
			
		||||
	if(newURI.scheme != null) {
 | 
			
		||||
		resultURI.scheme = newURI.scheme;
 | 
			
		||||
	} else {
 | 
			
		||||
		resultURI.scheme = url.scheme;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.host != null && newURI.host.length > 0) {
 | 
			
		||||
		resultURI.host = newURI.host;
 | 
			
		||||
		resultURI.port = null;
 | 
			
		||||
		resultURI.fragment = null;
 | 
			
		||||
		resultURI.hash = { };
 | 
			
		||||
		resultURI.XRF = { };
 | 
			
		||||
		if(newURI.port != null) {
 | 
			
		||||
			resultURI.port = newURI.port;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		resultURI.host = url.host;
 | 
			
		||||
	}
 | 
			
		||||
	var directory = "";
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		directory = url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.directory != null) {
 | 
			
		||||
		if(newUrl.charAt(0) != "/" && newUrl.indexOf("://") == -1) {
 | 
			
		||||
			directory += newURI.directory;
 | 
			
		||||
		} else {
 | 
			
		||||
			directory = newURI.directory;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.directory = directory;
 | 
			
		||||
	if(newURI.file != null) {
 | 
			
		||||
		resultURI.file = newURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(newURI.query != null) {
 | 
			
		||||
		resultURI.query = newURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = newURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.hash = newURI.hash;
 | 
			
		||||
	resultURI.XRF = newURI.XRF;
 | 
			
		||||
	xrfragment_URI.computeVars(resultURI);
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.cloneURI = function(url) {
 | 
			
		||||
	var clonedURI = new xrfragment_URI();
 | 
			
		||||
	clonedURI.url = url.url;
 | 
			
		||||
	clonedURI.source = url.source;
 | 
			
		||||
	clonedURI.scheme = url.scheme;
 | 
			
		||||
	clonedURI.authority = url.authority;
 | 
			
		||||
	clonedURI.userInfo = url.userInfo;
 | 
			
		||||
	clonedURI.password = url.password;
 | 
			
		||||
	clonedURI.host = url.host;
 | 
			
		||||
	clonedURI.port = url.port;
 | 
			
		||||
	clonedURI.relative = url.relative;
 | 
			
		||||
	clonedURI.path = url.path;
 | 
			
		||||
	clonedURI.directory = url.directory;
 | 
			
		||||
	clonedURI.file = url.file;
 | 
			
		||||
	clonedURI.query = url.query;
 | 
			
		||||
	clonedURI.fragment = url.fragment;
 | 
			
		||||
	return clonedURI;
 | 
			
		||||
};
 | 
			
		||||
var xrfragment_XRF = $hx_exports["xrfragment"]["XRF"] = function(_fragment,_flags,_index) {
 | 
			
		||||
	this.floats = [];
 | 
			
		||||
	this.shift = [];
 | 
			
		||||
| 
						 | 
				
			
			@ -1302,6 +1532,7 @@ haxe_Template.hxKeepArrayIterator = new haxe_iterators_ArrayIterator([]);
 | 
			
		|||
xrfragment_Parser.error = "";
 | 
			
		||||
xrfragment_Parser.debug = false;
 | 
			
		||||
xrfragment_URI.__meta__ = { statics : { template : { keep : null}}};
 | 
			
		||||
xrfragment_URI._parts = ["source","scheme","authority","userInfo","user","password","host","port","relative","path","directory","file","query","fragment"];
 | 
			
		||||
xrfragment_XRF.IMMUTABLE = 1;
 | 
			
		||||
xrfragment_XRF.PROP_BIND = 2;
 | 
			
		||||
xrfragment_XRF.QUERY_OPERATOR = 4;
 | 
			
		||||
| 
						 | 
				
			
			@ -1589,7 +1820,7 @@ let pub = function( url, node_or_model, flags ){  // evaluate fragments in url
 | 
			
		|||
  if( !url ) return 
 | 
			
		||||
  if( !url.match(/#/) ) url = `#${url}`
 | 
			
		||||
  let { THREE, camera } = xrf
 | 
			
		||||
  let frag     = xrf.URI.parse( url, flags )
 | 
			
		||||
  let frag     = xrf.URI.parse( url, flags ).XRF
 | 
			
		||||
  let fromNode = node_or_model != xrf.model
 | 
			
		||||
  let isNode   = node_or_model && node_or_model.children
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1756,24 +1987,6 @@ xrf.reset = () => {
 | 
			
		|||
  xrf.layers = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.parseUrl = (url) => {
 | 
			
		||||
  let urlExHash = url.replace(/#.*/,'')
 | 
			
		||||
  let urlObj,file
 | 
			
		||||
  let   store = {}
 | 
			
		||||
  try{
 | 
			
		||||
    urlObj = new URL( urlExHash.match(/:\/\//) ? urlExHash : String(`https://fake.com/${url}`).replace(/\/\//,'/') )
 | 
			
		||||
    file = urlObj.pathname.substring(urlObj.pathname.lastIndexOf('/') + 1);
 | 
			
		||||
    let   search = urlObj.search.substr(1).split("&")
 | 
			
		||||
    for( let i in search )  store[  (search[i].split("=")[0])  ]  = search[i].split("=")[1] || ''
 | 
			
		||||
  }catch(e){ }
 | 
			
		||||
  let   hashmap = url.match("#") ? url.replace(/.*#/,'').split("&") : []
 | 
			
		||||
  for( let i in hashmap ) store[  (hashmap[i].split("=")[0]) ]  = hashmap[i].split("=")[1] || ''
 | 
			
		||||
  let   dir  = url.substring(0, url.lastIndexOf('/') + 1)
 | 
			
		||||
  const hash = url.match(/#/) ? url.replace(/.*#/,'') : ''
 | 
			
		||||
  const ext  = file.split('.').pop()
 | 
			
		||||
  return {urlObj,dir,file,hash,ext,store}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.add = (object) => {
 | 
			
		||||
  object.isXRF = true // mark for easy deletion when replacing scene
 | 
			
		||||
  xrf.scene.add(object)
 | 
			
		||||
| 
						 | 
				
			
			@ -1784,42 +1997,52 @@ xrf.hasNoMaterial = (mesh) => {
 | 
			
		|||
  const hasMaterialName   = mesh.material && mesh.material.name.length > 0 
 | 
			
		||||
  return mesh.geometry && !hasMaterialName && !hasTexture
 | 
			
		||||
}
 | 
			
		||||
xrf.navigator = {}
 | 
			
		||||
xrf.navigator = {URI:{}}
 | 
			
		||||
 | 
			
		||||
xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		||||
  if( !url ) throw 'xrf.navigator.to(..) no url given'
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.navigator.origin = xrf.parseUrl(url)
 | 
			
		||||
  let hashChange = (!file && hash) || !data && xrf.model.file == file
 | 
			
		||||
  let hasPos     = String(hash).match(/pos=/)
 | 
			
		||||
 | 
			
		||||
  let URI = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  URI.hash          = xrf.navigator.reactifyHash(URI.hash)
 | 
			
		||||
  let fileChange    = URI.URN + URI.file != xrf.navigator.URI.URN + xrf.navigator.URI.file 
 | 
			
		||||
  let external      = URI.URN != document.location.origin + document.location.pathname 
 | 
			
		||||
  let hasPos        = URI.hash.pos 
 | 
			
		||||
  let hashChange    = String(xrf.navigator.URI.fragment||"") != String(URI.fragment||"")
 | 
			
		||||
  let hashbus       = xrf.hashbus
 | 
			
		||||
  xrf.navigator.URI = URI
 | 
			
		||||
  let {directory,file,fragment,fileExt} = URI;
 | 
			
		||||
 | 
			
		||||
  let hashbus = xrf.hashbus
 | 
			
		||||
  const evalFragment  = () => {
 | 
			
		||||
    if( URI.fragment ){
 | 
			
		||||
      hashbus.pub( URI.fragment, xrf.model, flags )     // eval local URI XR fragments 
 | 
			
		||||
      xrf.navigator.updateHash(fragment)                // which don't require 
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return new Promise( (resolve,reject) => {
 | 
			
		||||
    xrf
 | 
			
		||||
    .emit('navigate', {url,loader,data})
 | 
			
		||||
    .then( () => {
 | 
			
		||||
 | 
			
		||||
      if( ext && !loader ){  
 | 
			
		||||
        const Loader = xrf.loaders[ext]
 | 
			
		||||
      const Loader = xrf.loaders[fileExt]
 | 
			
		||||
 | 
			
		||||
      if( fileExt && !loader ){  
 | 
			
		||||
        if( !Loader ) return resolve()
 | 
			
		||||
        loader = loader || new Loader().setPath( dir )
 | 
			
		||||
        loader = loader || new Loader().setPath( URI.URN )
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if( !hash && !file && !ext ) return resolve(xrf.model) // nothing we can do here
 | 
			
		||||
      if( !URI.fragment && !URI.file && !URI.fileExt ) return resolve(xrf.model) // nothing we can do here
 | 
			
		||||
 | 
			
		||||
      if( hashChange && !hasPos ){
 | 
			
		||||
        hashbus.pub( url, xrf.model, flags )     // eval local URI XR fragments 
 | 
			
		||||
        xrf.navigator.updateHash(hash)           // which don't require 
 | 
			
		||||
        return resolve(xrf.model)                // positional navigation
 | 
			
		||||
      if( xrf.model && !fileChange && hashChange && !hasPos  ){
 | 
			
		||||
        evalFragment()
 | 
			
		||||
        return resolve(xrf.model)                         // positional navigation
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      xrf
 | 
			
		||||
      .emit('navigateLoading', {url,loader,data})
 | 
			
		||||
      .then( () => {
 | 
			
		||||
        if( hashChange && hasPos ){                 // we're already loaded
 | 
			
		||||
          hashbus.pub( url, xrf.model, flags )     // and eval local URI XR fragments 
 | 
			
		||||
          xrf.navigator.updateHash(hash)
 | 
			
		||||
        if( (!fileChange || !file) && hashChange && hasPos ){                 // we're already loaded
 | 
			
		||||
          evalFragment()
 | 
			
		||||
          xrf.emit('navigateLoaded',{url})
 | 
			
		||||
          return resolve(xrf.model) 
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1829,17 +2052,20 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
        xrf.reset() 
 | 
			
		||||
 | 
			
		||||
        // force relative path for files which dont include protocol or relative path
 | 
			
		||||
        if( dir ) dir = dir[0] == '.' || dir.match("://") ? dir : `.${dir}`
 | 
			
		||||
        url = url.replace(dir,"")
 | 
			
		||||
        loader = loader || new Loader().setPath( dir )
 | 
			
		||||
        if( directory ) directory = directory[0] == '.' || directory.match("://") ? directory : `.${directory}`
 | 
			
		||||
 | 
			
		||||
        loader = loader || new Loader().setPath( URI.URN )
 | 
			
		||||
        const onLoad = (model) => {
 | 
			
		||||
 | 
			
		||||
          model.file = file
 | 
			
		||||
          model.file = URI.file
 | 
			
		||||
          // only change url when loading *another* file
 | 
			
		||||
          if( xrf.model ) xrf.navigator.pushState( `${dir}${file}`, hash )
 | 
			
		||||
          if( xrf.model ){
 | 
			
		||||
            xrf.navigator.pushState( external ? URI.URN + URI.file : URI.file, fragment )
 | 
			
		||||
          }
 | 
			
		||||
          //if( xrf.model ) xrf.navigator.pushState( `${ document.location.pathname != URI.directory ? URI.directory: ''}${URI.file}`, fragment )
 | 
			
		||||
          xrf.model = model 
 | 
			
		||||
 | 
			
		||||
          if( !model.isXRF ) xrf.parseModel(model,url) // this marks the model as an XRF model
 | 
			
		||||
          if( !model.isXRF ) xrf.parseModel(model,url.replace(directory,"")) // this marks the model as an XRF model
 | 
			
		||||
 | 
			
		||||
          if(xrf.debug ) model.animations.map( (a) => console.log("anim: "+a.name) )
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1847,17 +2073,16 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
          xrf.XRWG.generate({model,scene:model.scene})
 | 
			
		||||
 | 
			
		||||
          // spec: 2. init metadata inside model for non-SRC data
 | 
			
		||||
          if( !model.isSRC ){ 
 | 
			
		||||
          if( !model.isSRC ){
 | 
			
		||||
            model.scene.traverse( (mesh) => xrf.parseModel.metadataInMesh(mesh,model) )
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          // spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
 | 
			
		||||
          xrf.frag.defaultPredefinedViews({model,scene:model.scene})
 | 
			
		||||
          // spec: predefined view(s) & objects-of-interest-in-XRWG from URL (https://xrfragment.org/#predefined_view)
 | 
			
		||||
          // spec: predefined view(s) & objects-of-interest-in-XRWG from URI (https://xrfragment.org/#predefined_view)
 | 
			
		||||
          let frag = xrf.hashbus.pub( url, model) // and eval URI XR fragments 
 | 
			
		||||
 | 
			
		||||
          xrf.add( model.scene )
 | 
			
		||||
          if( hash ) xrf.navigator.updateHash(hash)
 | 
			
		||||
          if( fragment ) xrf.navigator.updateHash(fragment)
 | 
			
		||||
          xrf.emit('navigateLoaded',{url,model})
 | 
			
		||||
          resolve(model)
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1866,7 +2091,7 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
          loader.parse(data, "", onLoad )
 | 
			
		||||
        }else{
 | 
			
		||||
          try{
 | 
			
		||||
            loader.load(url, onLoad )
 | 
			
		||||
            loader.load(file, onLoad )
 | 
			
		||||
          }catch(e){ 
 | 
			
		||||
            console.error(e)
 | 
			
		||||
            xrf.emit('navigateError',{url})
 | 
			
		||||
| 
						 | 
				
			
			@ -1880,9 +2105,12 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
xrf.navigator.init = () => {
 | 
			
		||||
  if( xrf.navigator.init.inited ) return
 | 
			
		||||
 | 
			
		||||
  xrf.navigator.URI = xrfragment.URI.parse(document.location.href)
 | 
			
		||||
 | 
			
		||||
  window.addEventListener('popstate', function (event){
 | 
			
		||||
    if( !xrf.navigator.updateHash.active ){ // ignore programmatic hash updates (causes infinite recursion)
 | 
			
		||||
      xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
 | 
			
		||||
      //xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
 | 
			
		||||
      xrf.navigator.to( document.location.href.replace(/\?/,'') )
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  
 | 
			
		||||
| 
						 | 
				
			
			@ -1908,10 +2136,10 @@ xrf.navigator.setupNavigateFallbacks = () => {
 | 
			
		|||
 | 
			
		||||
  xrf.addEventListener('navigate', (opts) => {
 | 
			
		||||
    let {url} = opts
 | 
			
		||||
    let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
    let {fileExt} = xrfragment.URI.parse(url)
 | 
			
		||||
 | 
			
		||||
    // handle http links
 | 
			
		||||
    if( url.match(/^http/) && !xrf.loaders[ext] ){
 | 
			
		||||
    if( url.match(/^http/) && !xrf.loaders[fileExt] ){
 | 
			
		||||
      let inIframe
 | 
			
		||||
      try { inIframe = window.self !== window.top; } catch (e) { inIframe = true; }
 | 
			
		||||
      return inIframe ? window.parent.postMessage({ url }, '*') : window.open( url, '_blank')
 | 
			
		||||
| 
						 | 
				
			
			@ -1931,7 +2159,7 @@ xrf.navigator.setupNavigateFallbacks = () => {
 | 
			
		|||
 | 
			
		||||
xrf.navigator.updateHash = (hash,opts) => {
 | 
			
		||||
  if( hash.replace(/^#/,'') == document.location.hash.substr(1) || hash.match(/\|/) ) return  // skip unnecesary pushState triggers
 | 
			
		||||
  console.log(`URL: ${document.location.search.substr(1)}#${hash}`)
 | 
			
		||||
  console.log(`URI: ${document.location.search.substr(1)}#${hash}`)
 | 
			
		||||
  xrf.navigator.updateHash.active = true  // important to prevent recursion
 | 
			
		||||
  document.location.hash = hash
 | 
			
		||||
  xrf.navigator.updateHash.active = false
 | 
			
		||||
| 
						 | 
				
			
			@ -1942,6 +2170,23 @@ xrf.navigator.pushState = (file,hash) => {
 | 
			
		|||
  window.history.pushState({},`${file}#${hash}`, document.location.pathname + `?${file}#${hash}` )
 | 
			
		||||
  xrf.emit('pushState', {file, hash} )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.navigator.reactifyHash = ( obj ) => {
 | 
			
		||||
  return new Proxy(obj,{
 | 
			
		||||
    get(me,k)  { return me[k] },
 | 
			
		||||
    set(me,k,v){ 
 | 
			
		||||
      me[k] = v 
 | 
			
		||||
      xrf.navigator.to( "#" + this.toString(me) )
 | 
			
		||||
    },
 | 
			
		||||
    toString(me){
 | 
			
		||||
      let parts = []
 | 
			
		||||
      Object.keys(me).map( (k) => {
 | 
			
		||||
        parts.push( me[k] ? `${k}=${encodeURIComponent(me[k])}` : k ) 
 | 
			
		||||
      })
 | 
			
		||||
      return parts.join('&')
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * navigation, portals & mutations
 | 
			
		||||
| 
						 | 
				
			
			@ -1993,7 +2238,6 @@ xrf.frag.href = function(v, opts){
 | 
			
		|||
    .emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
 | 
			
		||||
    .then( () => {
 | 
			
		||||
 | 
			
		||||
      let {urlObj,dir,file,hash,ext} = xrf.parseUrl(v.string)
 | 
			
		||||
      const isLocal = v.string[0] == '#'
 | 
			
		||||
      const hasPos  = isLocal && v.string.match(/pos=/)
 | 
			
		||||
      const flags   = isLocal ? xrf.XRF.PV_OVERRIDE : undefined
 | 
			
		||||
| 
						 | 
				
			
			@ -2153,6 +2397,32 @@ xrf.frag.pos = function(v, opts){
 | 
			
		|||
  camera.updateMatrixWorld()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.frag.pos.get = function(precision,randomize){
 | 
			
		||||
    if( !precision ) precision = 2;
 | 
			
		||||
    if( typeof THREE == 'undefined' ) THREE = xrf.THREE
 | 
			
		||||
    let radToDeg  = THREE.MathUtils.radToDeg
 | 
			
		||||
    let toDeg     = (x) => x / (Math.PI / 180)
 | 
			
		||||
    let camera    = xrf.camera 
 | 
			
		||||
    if( randomize ){
 | 
			
		||||
      camera.position.x += Math.random()/10
 | 
			
		||||
      camera.position.z += Math.random()/10
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // *TODO* add camera direction
 | 
			
		||||
    let direction = new xrf.THREE.Vector3()
 | 
			
		||||
    camera.getWorldDirection(direction)
 | 
			
		||||
    const pitch   = Math.asin(direction.y);
 | 
			
		||||
    const yaw     = Math.atan2(direction.x, direction.z);
 | 
			
		||||
    const pitchInDegrees = pitch * 180 / Math.PI;
 | 
			
		||||
    const yawInDegrees = yaw * 180 / Math.PI;
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      x: String(camera.position.x.toFixed(2)),
 | 
			
		||||
      y: String(camera.position.y.toFixed(2)),
 | 
			
		||||
      z: String(camera.position.z.toFixed(2)),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.addEventListener('reset', (opts) => {
 | 
			
		||||
  // set the player to position 0,0,0
 | 
			
		||||
  xrf.camera.position.set(0,0,0)
 | 
			
		||||
| 
						 | 
				
			
			@ -2207,7 +2477,7 @@ xrf.frag.src = function(v, opts){
 | 
			
		|||
  if( mesh.isSRC ) return // only embed src once 
 | 
			
		||||
 | 
			
		||||
  let url       = xrf.frag.src.expandURI( mesh, v.string )
 | 
			
		||||
  let srcFrag   = opts.srcFrag = xrfragment.URI.parse(url)
 | 
			
		||||
  let srcFrag   = opts.srcFrag = xrfragment.URI.parse(url).XRF
 | 
			
		||||
  opts.isLocal  = v.string[0] == '#'
 | 
			
		||||
  opts.isPortal = xrf.frag.src.renderAsPortal(mesh)
 | 
			
		||||
  opts.isSRC    = mesh.isSRC = true 
 | 
			
		||||
| 
						 | 
				
			
			@ -2294,7 +2564,7 @@ xrf.frag.src.externalSRC = (url,frag,opts) => {
 | 
			
		|||
  fetch(url, { method: 'HEAD' })
 | 
			
		||||
  .then( (res) => {
 | 
			
		||||
    let mimetype = res.headers.get('Content-type')
 | 
			
		||||
    if(xrf.debug != undefined ) console.log("HEAD "+url+" => "+mimetype)
 | 
			
		||||
    if(xrf.debug > 0 ) console.log("HEAD "+url+" => "+mimetype)
 | 
			
		||||
    if( url.replace(/#.*/,'').match(/\.(gltf|glb)$/)     ) mimetype = 'gltf'
 | 
			
		||||
    if( url.replace(/#.*/,'').match(/\.(frag|fs|glsl)$/) ) mimetype = 'x-shader/x-fragment'
 | 
			
		||||
    if( url.replace(/#.*/,'').match(/\.(vert|vs)$/)      ) mimetype = 'x-shader/x-fragment'
 | 
			
		||||
| 
						 | 
				
			
			@ -3195,8 +3465,8 @@ xrf.addEventListener('render', (opts) => {
 | 
			
		|||
 | 
			
		||||
let loadAudio = (mimetype) => function(url,opts){
 | 
			
		||||
  let {mesh,src,camera,THREE} = opts
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
  let frag = xrf.URI.parse( url )
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  xrf.init.audio()
 | 
			
		||||
  let isPositionalAudio = !(mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -3207,8 +3477,8 @@ let loadAudio = (mimetype) => function(url,opts){
 | 
			
		|||
  mesh.media = mesh.media || {}
 | 
			
		||||
  mesh.media.audio = { set: (mediafragment,v) => mesh.media.audio[mediafragment] = v }
 | 
			
		||||
 | 
			
		||||
  let finalUrl = url.replace(/#.*/,'')
 | 
			
		||||
  if( xrf.debug != undefined ) console.log("GET "+finalUrl)
 | 
			
		||||
  let finalUrl = URL.URN + URL.file 
 | 
			
		||||
  if( xrf.debug > 0 ) console.log("GET "+finalUrl)
 | 
			
		||||
  audioLoader.load( finalUrl, function( buffer ) {
 | 
			
		||||
 | 
			
		||||
    sound.setBuffer( buffer );
 | 
			
		||||
| 
						 | 
				
			
			@ -3318,7 +3588,8 @@ audioMimeTypes.map( (mimetype) =>  xrf.frag.src.type[ mimetype ] = loadAudio(mim
 | 
			
		|||
xrf.frag.src.type['fbx'] = function( url, opts ){
 | 
			
		||||
  return new Promise( async (resolve,reject) => {
 | 
			
		||||
    let {mesh,src} = opts
 | 
			
		||||
    let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
    let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
    let frag = URL.XRF 
 | 
			
		||||
    let loader
 | 
			
		||||
 | 
			
		||||
    let {THREE}        = await import('https://unpkg.com/three@0.161.0/build/three.module.js')
 | 
			
		||||
| 
						 | 
				
			
			@ -3346,14 +3617,17 @@ xrf.frag.src.type['fbx'] = function( url, opts ){
 | 
			
		|||
xrf.frag.src.type['x-shader/x-fragment'] = function(url,opts){
 | 
			
		||||
  let {mesh,THREE} = opts
 | 
			
		||||
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  let isFragmentShader = /\.(fs|frag|glsl)$/
 | 
			
		||||
  let isVertexShader   = /\.(vs|vert)$/
 | 
			
		||||
 | 
			
		||||
  let shaderReqs = []
 | 
			
		||||
  let shaderCode = {}
 | 
			
		||||
  let shader   = {
 | 
			
		||||
    fragment: { code: '', url: url.match( isFragmentShader ) ? url : '' },
 | 
			
		||||
    vertex:   { code: '', url: url.match( isVertexShader   ) ? url : '' }
 | 
			
		||||
    fragment: { code: '', url: url.match( isFragmentShader ) ? URL.URN + URL.file : '' },
 | 
			
		||||
    vertex:   { code: '', url: url.match( isVertexShader   ) ? URL.URN + URL.file : '' }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  var onShaderLoaded = ((args) => (type, status, code) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -3412,19 +3686,15 @@ xrf.frag.src.type['x-shader/x-vertex']   = xrf.frag.src.type['x-shader/x-fragmen
 | 
			
		|||
xrf.frag.src.type['gltf'] = function( url, opts ){
 | 
			
		||||
  return new Promise( (resolve,reject) => {
 | 
			
		||||
    let {mesh,src} = opts
 | 
			
		||||
    let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
    let URL = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
    let {directory,file,fileExt,URN} = URL;
 | 
			
		||||
    let loader
 | 
			
		||||
 | 
			
		||||
    const Loader = xrf.loaders[ext]
 | 
			
		||||
    const Loader = xrf.loaders[fileExt]
 | 
			
		||||
    if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext 
 | 
			
		||||
    if( !dir.match("://") ){ // force relative path 
 | 
			
		||||
      dir = dir.substr(0,2) == './' ? dir : `./${dir}`
 | 
			
		||||
      loader = new Loader().setPath( dir )
 | 
			
		||||
    }else{
 | 
			
		||||
      loader = new Loader() 
 | 
			
		||||
    }
 | 
			
		||||
    loader = new Loader().setPath( URN )
 | 
			
		||||
 | 
			
		||||
    loader.load(url, (model) => {
 | 
			
		||||
    loader.load(file, (model) => {
 | 
			
		||||
      model.isSRC = true
 | 
			
		||||
      resolve(model)
 | 
			
		||||
    })
 | 
			
		||||
| 
						 | 
				
			
			@ -3435,7 +3705,7 @@ xrf.frag.src.type['gltf'] = function( url, opts ){
 | 
			
		|||
let loadHTML = (mimetype) => function(url,opts){
 | 
			
		||||
  let {mesh,src,camera} = opts
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
  let frag = xrf.URI.parse( url )
 | 
			
		||||
  let frag = xrf.URI.parse( url ).XRF
 | 
			
		||||
  console.warn("todo: html viewer for src not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3452,6 +3722,8 @@ htmlMimeTypes.map( (mimetype) =>  xrf.frag.src.type[ mimetype ] = loadHTML(mimet
 | 
			
		|||
xrf.frag.src.type['image/png'] = function(url,opts){
 | 
			
		||||
  let {mesh,THREE} = opts
 | 
			
		||||
  let restrictTo3DBoundingBox = mesh.geometry
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  mesh.material = new xrf.THREE.MeshBasicMaterial({ 
 | 
			
		||||
    map: null, 
 | 
			
		||||
| 
						 | 
				
			
			@ -3495,7 +3767,7 @@ xrf.frag.src.type['image/png'] = function(url,opts){
 | 
			
		|||
    renderImage(texture)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  new THREE.TextureLoader().load( url, onLoad, null, console.error );
 | 
			
		||||
  new THREE.TextureLoader().load( URL.URN + URL.file, onLoad, null, console.error );
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3701,9 +3973,9 @@ xrf.portalNonEuclidian.stencilRef = 1
 | 
			
		|||
 | 
			
		||||
let loadVideo = (mimetype) => function(url,opts){
 | 
			
		||||
  let {mesh,src,camera} = opts
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
  const THREE = xrf.THREE
 | 
			
		||||
  let frag = xrf.URI.parse( url )
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  mesh.media = mesh.media || {}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3725,7 +3997,7 @@ let loadVideo = (mimetype) => function(url,opts){
 | 
			
		|||
    },false)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  video.src = url
 | 
			
		||||
  video.src = URL.URN + URL.file 
 | 
			
		||||
  video.speed = 1.0
 | 
			
		||||
  video.looping = false
 | 
			
		||||
  video.set = (mediafragment,v) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -4161,6 +4433,17 @@ AFRAME.registerComponent('movement-controls', {
 | 
			
		|||
 | 
			
		||||
  }())
 | 
			
		||||
});
 | 
			
		||||
AFRAME.components['hand-tracking-controls'].Component.prototype.onModelLoaded = function(onModelLoaded){
 | 
			
		||||
  return function(e){
 | 
			
		||||
    onModelLoaded.apply(this);
 | 
			
		||||
    // re-attach children 
 | 
			
		||||
    ([...this.el.children]).map( (c) => {
 | 
			
		||||
      if( c.object3D ){
 | 
			
		||||
        this.el.object3D.getObjectByName("wrist").add(c.object3D)
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}(AFRAME.components['hand-tracking-controls'].Component.prototype.onModelLoaded)
 | 
			
		||||
// look-controls turns off autoUpdateMatrix (of player) which 
 | 
			
		||||
// will break teleporting and other stuff
 | 
			
		||||
// overriding this is easier then adding updateMatrixWorld() everywhere else
 | 
			
		||||
| 
						 | 
				
			
			@ -4280,7 +4563,7 @@ AFRAME.registerComponent('pressable', {
 | 
			
		|||
                this.el.emit('click');
 | 
			
		||||
                this.pressed = setTimeout( () => {
 | 
			
		||||
                  this.el.emit('pressedended');
 | 
			
		||||
                  this.pressed = null 
 | 
			
		||||
                  this.pressed = false 
 | 
			
		||||
                },300)
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -4438,8 +4721,10 @@ window.AFRAME.registerComponent('xrf-button', {
 | 
			
		|||
        this.el.addEventListener('mouseenter', (e) => this.onMouseEnter(e) );
 | 
			
		||||
        this.el.addEventListener('mouseleave', (e) => this.onMouseLeave(e) );
 | 
			
		||||
 | 
			
		||||
        let cb = new Function(this.data.action)
 | 
			
		||||
 | 
			
		||||
        if( this.data.action ){ 
 | 
			
		||||
          this.el.addEventListener('click', new Function(this.data.action) )
 | 
			
		||||
          this.el.addEventListener('click', AFRAME.utils.throttle(cb, 500 ) )
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    bindMethods: function() {
 | 
			
		||||
| 
						 | 
				
			
			@ -4611,6 +4896,8 @@ window.AFRAME.registerComponent('xrf-get', {
 | 
			
		|||
    var el = this.el;
 | 
			
		||||
    var meshname = this.data.name || this.data;
 | 
			
		||||
 | 
			
		||||
    if( !meshname || typeof meshname != 'string' ) return
 | 
			
		||||
 | 
			
		||||
    this.el.addEventListener('update', (evt) => {
 | 
			
		||||
 | 
			
		||||
      setTimeout( () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -4647,7 +4934,8 @@ window.AFRAME.registerComponent('xrf-get', {
 | 
			
		|||
          this.el.object3D.child = mesh    // keep reference (because .children will be empty)
 | 
			
		||||
 | 
			
		||||
          if( !this.el.id ) this.el.setAttribute("id",`xrf-${mesh.name}`)
 | 
			
		||||
        }else console.warn("xrf-get ignore: "+JSON.stringify(this.data))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      }, evt && evt.timeout ? evt.timeout: 500)
 | 
			
		||||
 | 
			
		||||
    })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										235
									
								
								dist/xrfragment.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										235
									
								
								dist/xrfragment.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1133,9 +1133,13 @@ xrfragment_Parser.getMetaData = function() {
 | 
			
		|||
	var meta = { title : ["title","og:title","dc.title"], description : ["aria-description","og:description","dc.description"], author : ["author","dc.creator"], publisher : ["publisher","dc.publisher"], website : ["og:site_name","og:url","dc.publisher"], license : ["SPDX","dc.rights"]};
 | 
			
		||||
	return meta;
 | 
			
		||||
};
 | 
			
		||||
var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() { };
 | 
			
		||||
var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() {
 | 
			
		||||
	this.XRF = { };
 | 
			
		||||
	this.hash = { };
 | 
			
		||||
	this.fragment = "";
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.__name__ = true;
 | 
			
		||||
xrfragment_URI.parse = function(url,filter) {
 | 
			
		||||
xrfragment_URI.parseFragment = function(url,filter) {
 | 
			
		||||
	var store = { };
 | 
			
		||||
	if(url == null || url.indexOf("#") == -1) {
 | 
			
		||||
		return store;
 | 
			
		||||
| 
						 | 
				
			
			@ -1187,6 +1191,232 @@ xrfragment_URI.template = function(uri,vars) {
 | 
			
		|||
	parts[1] = frag;
 | 
			
		||||
	return parts.join("#");
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.parse = function(stringUrl,flags) {
 | 
			
		||||
	var r = new EReg("^(?:(?![^:@]+:[^:@/]*@)([^:/?#.]+):)?(?://)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:/?#]*)(?::(\\d*))?)(((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[?#]|$)))*/?)?([^?#/]*))(?:\\?([^#]*))?(?:#(.*))?)","");
 | 
			
		||||
	if(stringUrl.indexOf("://") == -1 && stringUrl.charAt(0) != "/") {
 | 
			
		||||
		stringUrl = "/" + stringUrl;
 | 
			
		||||
	}
 | 
			
		||||
	r.match(stringUrl);
 | 
			
		||||
	var url = new xrfragment_URI();
 | 
			
		||||
	var _g = 0;
 | 
			
		||||
	var _g1 = xrfragment_URI._parts.length;
 | 
			
		||||
	while(_g < _g1) {
 | 
			
		||||
		var i = _g++;
 | 
			
		||||
		url[xrfragment_URI._parts[i]] = r.matched(i);
 | 
			
		||||
	}
 | 
			
		||||
	if(xrfragment_URI.isRelative(url) == true) {
 | 
			
		||||
		if(url.directory == null && url.host != null) {
 | 
			
		||||
			url.file = url.host;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	url.hash = { };
 | 
			
		||||
	if(url.fragment != null && url.fragment.length > 0) {
 | 
			
		||||
		url.XRF = xrfragment_URI.parseFragment("#" + url.fragment,flags);
 | 
			
		||||
		var key;
 | 
			
		||||
		var _g = 0;
 | 
			
		||||
		var _g1 = Reflect.fields(url.XRF);
 | 
			
		||||
		while(_g < _g1.length) {
 | 
			
		||||
			var key = _g1[_g];
 | 
			
		||||
			++_g;
 | 
			
		||||
			var v = url.XRF[key];
 | 
			
		||||
			url.hash[key] = v["string"];
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	xrfragment_URI.computeVars(url);
 | 
			
		||||
	return url;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.computeVars = function(url) {
 | 
			
		||||
	var r_r = new RegExp("//","g".split("u").join(""));
 | 
			
		||||
	if(url.directory != null && url.directory.indexOf("//") != -1) {
 | 
			
		||||
		url.directory = url.directory.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	if(url.path != null && url.path.indexOf("//") != -1) {
 | 
			
		||||
		url.path = url.path.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	if(url.file != null && url.file.indexOf("//") != -1) {
 | 
			
		||||
		url.file = url.file.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	url.URN = url.scheme + "://" + url.host;
 | 
			
		||||
	if(url.port != null) {
 | 
			
		||||
		url.URN += ":" + url.port;
 | 
			
		||||
	}
 | 
			
		||||
	url.URN += url.directory;
 | 
			
		||||
	if(url.file != null) {
 | 
			
		||||
		var parts = url.file.split(".");
 | 
			
		||||
		if(parts.length > 1) {
 | 
			
		||||
			url.fileExt = parts.pop();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.toString = function(url) {
 | 
			
		||||
	var result = "";
 | 
			
		||||
	if(url.scheme != null) {
 | 
			
		||||
		result += url.scheme + "://";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.user != null) {
 | 
			
		||||
		result += url.user + ":";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.password != null) {
 | 
			
		||||
		result += url.password + "@";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.host != null) {
 | 
			
		||||
		result += url.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.port != null) {
 | 
			
		||||
		result += ":" + url.port;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		result += url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.file != null) {
 | 
			
		||||
		result += url.file;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.query != null) {
 | 
			
		||||
		result += "?" + url.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.fragment != null) {
 | 
			
		||||
		result += "#" + url.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendURI = function(url,appendedURI) {
 | 
			
		||||
	if(xrfragment_URI.isRelative(url) == true) {
 | 
			
		||||
		return xrfragment_URI.appendToRelativeURI(url,appendedURI);
 | 
			
		||||
	} else {
 | 
			
		||||
		return xrfragment_URI.appendToAbsoluteURI(url,appendedURI);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.isRelative = function(url) {
 | 
			
		||||
	return url.scheme == null;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendToRelativeURI = function(url,appendedURI) {
 | 
			
		||||
	if(url.directory == null || url.host == null) {
 | 
			
		||||
		return xrfragment_URI.cloneURI(appendedURI);
 | 
			
		||||
	}
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	resultURI.host = url.host;
 | 
			
		||||
	resultURI.directory = url.directory;
 | 
			
		||||
	if(appendedURI.host != null) {
 | 
			
		||||
		resultURI.directory += appendedURI.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.directory != null) {
 | 
			
		||||
		var directory = appendedURI.directory;
 | 
			
		||||
		if(appendedURI.host == null) {
 | 
			
		||||
			resultURI.directory += HxOverrides.substr(directory,1,null);
 | 
			
		||||
		} else {
 | 
			
		||||
			resultURI.directory += directory;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.file != null) {
 | 
			
		||||
		resultURI.file = appendedURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(appendedURI.query != null) {
 | 
			
		||||
		resultURI.query = appendedURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = appendedURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendToAbsoluteURI = function(url,appendedURI) {
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	if(url.scheme != null) {
 | 
			
		||||
		resultURI.scheme = url.scheme;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.host != null) {
 | 
			
		||||
		resultURI.host = url.host;
 | 
			
		||||
	}
 | 
			
		||||
	var directory = "";
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		directory = url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.host != null) {
 | 
			
		||||
		appendedURI.directory += appendedURI.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.directory != null) {
 | 
			
		||||
		directory += appendedURI.directory;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.directory = directory;
 | 
			
		||||
	if(appendedURI.file != null) {
 | 
			
		||||
		resultURI.file = appendedURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(appendedURI.query != null) {
 | 
			
		||||
		resultURI.query = appendedURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = appendedURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.toAbsolute = function(url,newUrl) {
 | 
			
		||||
	var newURI = xrfragment_URI.parse(newUrl,0);
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	resultURI.port = url.port;
 | 
			
		||||
	resultURI.source = newUrl;
 | 
			
		||||
	if(newURI.scheme != null) {
 | 
			
		||||
		resultURI.scheme = newURI.scheme;
 | 
			
		||||
	} else {
 | 
			
		||||
		resultURI.scheme = url.scheme;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.host != null && newURI.host.length > 0) {
 | 
			
		||||
		resultURI.host = newURI.host;
 | 
			
		||||
		resultURI.port = null;
 | 
			
		||||
		resultURI.fragment = null;
 | 
			
		||||
		resultURI.hash = { };
 | 
			
		||||
		resultURI.XRF = { };
 | 
			
		||||
		if(newURI.port != null) {
 | 
			
		||||
			resultURI.port = newURI.port;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		resultURI.host = url.host;
 | 
			
		||||
	}
 | 
			
		||||
	var directory = "";
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		directory = url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.directory != null) {
 | 
			
		||||
		if(newUrl.charAt(0) != "/" && newUrl.indexOf("://") == -1) {
 | 
			
		||||
			directory += newURI.directory;
 | 
			
		||||
		} else {
 | 
			
		||||
			directory = newURI.directory;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.directory = directory;
 | 
			
		||||
	if(newURI.file != null) {
 | 
			
		||||
		resultURI.file = newURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(newURI.query != null) {
 | 
			
		||||
		resultURI.query = newURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = newURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.hash = newURI.hash;
 | 
			
		||||
	resultURI.XRF = newURI.XRF;
 | 
			
		||||
	xrfragment_URI.computeVars(resultURI);
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.cloneURI = function(url) {
 | 
			
		||||
	var clonedURI = new xrfragment_URI();
 | 
			
		||||
	clonedURI.url = url.url;
 | 
			
		||||
	clonedURI.source = url.source;
 | 
			
		||||
	clonedURI.scheme = url.scheme;
 | 
			
		||||
	clonedURI.authority = url.authority;
 | 
			
		||||
	clonedURI.userInfo = url.userInfo;
 | 
			
		||||
	clonedURI.password = url.password;
 | 
			
		||||
	clonedURI.host = url.host;
 | 
			
		||||
	clonedURI.port = url.port;
 | 
			
		||||
	clonedURI.relative = url.relative;
 | 
			
		||||
	clonedURI.path = url.path;
 | 
			
		||||
	clonedURI.directory = url.directory;
 | 
			
		||||
	clonedURI.file = url.file;
 | 
			
		||||
	clonedURI.query = url.query;
 | 
			
		||||
	clonedURI.fragment = url.fragment;
 | 
			
		||||
	return clonedURI;
 | 
			
		||||
};
 | 
			
		||||
var xrfragment_XRF = $hx_exports["xrfragment"]["XRF"] = function(_fragment,_flags,_index) {
 | 
			
		||||
	this.floats = [];
 | 
			
		||||
	this.shift = [];
 | 
			
		||||
| 
						 | 
				
			
			@ -1297,6 +1527,7 @@ haxe_Template.hxKeepArrayIterator = new haxe_iterators_ArrayIterator([]);
 | 
			
		|||
xrfragment_Parser.error = "";
 | 
			
		||||
xrfragment_Parser.debug = false;
 | 
			
		||||
xrfragment_URI.__meta__ = { statics : { template : { keep : null}}};
 | 
			
		||||
xrfragment_URI._parts = ["source","scheme","authority","userInfo","user","password","host","port","relative","path","directory","file","query","fragment"];
 | 
			
		||||
xrfragment_XRF.IMMUTABLE = 1;
 | 
			
		||||
xrfragment_XRF.PROP_BIND = 2;
 | 
			
		||||
xrfragment_XRF.QUERY_OPERATOR = 4;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										383
									
								
								dist/xrfragment.lua
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										383
									
								
								dist/xrfragment.lua
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -2899,10 +2899,19 @@ __xrfragment_Parser.getMetaData = function()
 | 
			
		|||
  do return meta end;
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
__xrfragment_URI.new = {}
 | 
			
		||||
__xrfragment_URI.new = function() 
 | 
			
		||||
  local self = _hx_new(__xrfragment_URI.prototype)
 | 
			
		||||
  __xrfragment_URI.super(self)
 | 
			
		||||
  return self
 | 
			
		||||
end
 | 
			
		||||
__xrfragment_URI.super = function(self) 
 | 
			
		||||
  self.XRF = _hx_e();
 | 
			
		||||
  self.hash = _hx_e();
 | 
			
		||||
  self.fragment = "";
 | 
			
		||||
end
 | 
			
		||||
_hx_exports["xrfragment"]["URI"] = __xrfragment_URI
 | 
			
		||||
__xrfragment_URI.__name__ = true
 | 
			
		||||
__xrfragment_URI.parse = function(url,filter) 
 | 
			
		||||
__xrfragment_URI.parseFragment = function(url,filter) 
 | 
			
		||||
  local store = _hx_e();
 | 
			
		||||
  local tmp;
 | 
			
		||||
  if (url ~= nil) then 
 | 
			
		||||
| 
						 | 
				
			
			@ -3063,6 +3072,374 @@ __xrfragment_URI.template = function(uri,vars)
 | 
			
		|||
  parts[1] = frag;
 | 
			
		||||
  do return parts:join("#") end;
 | 
			
		||||
end
 | 
			
		||||
__xrfragment_URI.parse = function(stringUrl,flags) 
 | 
			
		||||
  local r = EReg.new("^(?:(?![^:@]+:[^:@/]*@)([^:/?#.]+):)?(?://)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:/?#]*)(?::(\\d*))?)(((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[?#]|$)))*/?)?([^?#/]*))(?:\\?([^#]*))?(?:#(.*))?)", "");
 | 
			
		||||
  local startIndex = nil;
 | 
			
		||||
  if (startIndex == nil) then 
 | 
			
		||||
    startIndex = 1;
 | 
			
		||||
  else
 | 
			
		||||
    startIndex = startIndex + 1;
 | 
			
		||||
  end;
 | 
			
		||||
  local r1 = __lua_lib_luautf8_Utf8.find(stringUrl, "://", startIndex, true);
 | 
			
		||||
  if (((function() 
 | 
			
		||||
    local _hx_1
 | 
			
		||||
    if ((r1 ~= nil) and (r1 > 0)) then 
 | 
			
		||||
    _hx_1 = r1 - 1; else 
 | 
			
		||||
    _hx_1 = -1; end
 | 
			
		||||
    return _hx_1
 | 
			
		||||
  end )() == -1) and (__lua_lib_luautf8_Utf8.sub(stringUrl, 1, 1) ~= "/")) then 
 | 
			
		||||
    stringUrl = Std.string("/") .. Std.string(stringUrl);
 | 
			
		||||
  end;
 | 
			
		||||
  r:match(stringUrl);
 | 
			
		||||
  local url = __xrfragment_URI.new();
 | 
			
		||||
  local _g = 0;
 | 
			
		||||
  local _g1 = __xrfragment_URI._parts.length;
 | 
			
		||||
  while (_g < _g1) do 
 | 
			
		||||
    _g = _g + 1;
 | 
			
		||||
    local i = _g - 1;
 | 
			
		||||
    url[__xrfragment_URI._parts[i]] = r:matched(i);
 | 
			
		||||
  end;
 | 
			
		||||
  if (__xrfragment_URI.isRelative(url) == true) then 
 | 
			
		||||
    if ((url.directory == nil) and (url.host ~= nil)) then 
 | 
			
		||||
      url.file = url.host;
 | 
			
		||||
    end;
 | 
			
		||||
  end;
 | 
			
		||||
  url.hash = _hx_e();
 | 
			
		||||
  if ((url.fragment ~= nil) and (__lua_lib_luautf8_Utf8.len(url.fragment) > 0)) then 
 | 
			
		||||
    url.XRF = __xrfragment_URI.parseFragment(Std.string("#") .. Std.string(url.fragment), flags);
 | 
			
		||||
    local key;
 | 
			
		||||
    local _g = 0;
 | 
			
		||||
    local _g1 = Reflect.fields(url.XRF);
 | 
			
		||||
    while (_g < _g1.length) do 
 | 
			
		||||
      local key = _g1[_g];
 | 
			
		||||
      _g = _g + 1;
 | 
			
		||||
      local v = Reflect.field(url.XRF, key);
 | 
			
		||||
      local this1 = url.hash;
 | 
			
		||||
      local value = Reflect.field(v, "string");
 | 
			
		||||
      this1[key] = value;
 | 
			
		||||
    end;
 | 
			
		||||
  end;
 | 
			
		||||
  __xrfragment_URI.computeVars(url);
 | 
			
		||||
  do return url end;
 | 
			
		||||
end
 | 
			
		||||
__xrfragment_URI.computeVars = function(url) 
 | 
			
		||||
  local r = EReg.new("//", "g");
 | 
			
		||||
  local tmp;
 | 
			
		||||
  if (url.directory ~= nil) then 
 | 
			
		||||
    local _this = url.directory;
 | 
			
		||||
    local startIndex = nil;
 | 
			
		||||
    if (startIndex == nil) then 
 | 
			
		||||
      startIndex = 1;
 | 
			
		||||
    else
 | 
			
		||||
      startIndex = startIndex + 1;
 | 
			
		||||
    end;
 | 
			
		||||
    local r = __lua_lib_luautf8_Utf8.find(_this, "//", startIndex, true);
 | 
			
		||||
    tmp = (function() 
 | 
			
		||||
      local _hx_1
 | 
			
		||||
      if ((r ~= nil) and (r > 0)) then 
 | 
			
		||||
      _hx_1 = r - 1; else 
 | 
			
		||||
      _hx_1 = -1; end
 | 
			
		||||
      return _hx_1
 | 
			
		||||
    end )() ~= -1;
 | 
			
		||||
  else
 | 
			
		||||
    tmp = false;
 | 
			
		||||
  end;
 | 
			
		||||
  if (tmp) then 
 | 
			
		||||
    url.directory = r:replace(url.directory, "/");
 | 
			
		||||
  end;
 | 
			
		||||
  local tmp;
 | 
			
		||||
  if (url.path ~= nil) then 
 | 
			
		||||
    local _this = url.path;
 | 
			
		||||
    local startIndex = nil;
 | 
			
		||||
    if (startIndex == nil) then 
 | 
			
		||||
      startIndex = 1;
 | 
			
		||||
    else
 | 
			
		||||
      startIndex = startIndex + 1;
 | 
			
		||||
    end;
 | 
			
		||||
    local r = __lua_lib_luautf8_Utf8.find(_this, "//", startIndex, true);
 | 
			
		||||
    tmp = (function() 
 | 
			
		||||
      local _hx_2
 | 
			
		||||
      if ((r ~= nil) and (r > 0)) then 
 | 
			
		||||
      _hx_2 = r - 1; else 
 | 
			
		||||
      _hx_2 = -1; end
 | 
			
		||||
      return _hx_2
 | 
			
		||||
    end )() ~= -1;
 | 
			
		||||
  else
 | 
			
		||||
    tmp = false;
 | 
			
		||||
  end;
 | 
			
		||||
  if (tmp) then 
 | 
			
		||||
    url.path = r:replace(url.path, "/");
 | 
			
		||||
  end;
 | 
			
		||||
  local tmp;
 | 
			
		||||
  if (url.file ~= nil) then 
 | 
			
		||||
    local _this = url.file;
 | 
			
		||||
    local startIndex = nil;
 | 
			
		||||
    if (startIndex == nil) then 
 | 
			
		||||
      startIndex = 1;
 | 
			
		||||
    else
 | 
			
		||||
      startIndex = startIndex + 1;
 | 
			
		||||
    end;
 | 
			
		||||
    local r = __lua_lib_luautf8_Utf8.find(_this, "//", startIndex, true);
 | 
			
		||||
    tmp = (function() 
 | 
			
		||||
      local _hx_3
 | 
			
		||||
      if ((r ~= nil) and (r > 0)) then 
 | 
			
		||||
      _hx_3 = r - 1; else 
 | 
			
		||||
      _hx_3 = -1; end
 | 
			
		||||
      return _hx_3
 | 
			
		||||
    end )() ~= -1;
 | 
			
		||||
  else
 | 
			
		||||
    tmp = false;
 | 
			
		||||
  end;
 | 
			
		||||
  if (tmp) then 
 | 
			
		||||
    url.file = r:replace(url.file, "/");
 | 
			
		||||
  end;
 | 
			
		||||
  url.URN = Std.string(Std.string(url.scheme) .. Std.string("://")) .. Std.string(url.host);
 | 
			
		||||
  if (url.port ~= nil) then 
 | 
			
		||||
    local url1 = url;
 | 
			
		||||
    url1.URN = Std.string(url1.URN) .. Std.string((Std.string(":") .. Std.string(url.port)));
 | 
			
		||||
  end;
 | 
			
		||||
  local url1 = url;
 | 
			
		||||
  url1.URN = Std.string(url1.URN) .. Std.string(url.directory);
 | 
			
		||||
  if (url.file ~= nil) then 
 | 
			
		||||
    local _this = url.file;
 | 
			
		||||
    local idx = 1;
 | 
			
		||||
    local ret = _hx_tab_array({}, 0);
 | 
			
		||||
    while (idx ~= nil) do 
 | 
			
		||||
      local newidx = 0;
 | 
			
		||||
      if (__lua_lib_luautf8_Utf8.len(".") > 0) then 
 | 
			
		||||
        newidx = __lua_lib_luautf8_Utf8.find(_this, ".", idx, true);
 | 
			
		||||
      else
 | 
			
		||||
        if (idx >= __lua_lib_luautf8_Utf8.len(_this)) then 
 | 
			
		||||
          newidx = nil;
 | 
			
		||||
        else
 | 
			
		||||
          newidx = idx + 1;
 | 
			
		||||
        end;
 | 
			
		||||
      end;
 | 
			
		||||
      if (newidx ~= nil) then 
 | 
			
		||||
        local match = __lua_lib_luautf8_Utf8.sub(_this, idx, newidx - 1);
 | 
			
		||||
        ret:push(match);
 | 
			
		||||
        idx = newidx + __lua_lib_luautf8_Utf8.len(".");
 | 
			
		||||
      else
 | 
			
		||||
        ret:push(__lua_lib_luautf8_Utf8.sub(_this, idx, __lua_lib_luautf8_Utf8.len(_this)));
 | 
			
		||||
        idx = nil;
 | 
			
		||||
      end;
 | 
			
		||||
    end;
 | 
			
		||||
    local parts = ret;
 | 
			
		||||
    if (parts.length > 1) then 
 | 
			
		||||
      url.fileExt = parts:pop();
 | 
			
		||||
    end;
 | 
			
		||||
  end;
 | 
			
		||||
end
 | 
			
		||||
__xrfragment_URI.toString = function(url) 
 | 
			
		||||
  local result = "";
 | 
			
		||||
  if (url.scheme ~= nil) then 
 | 
			
		||||
    result = Std.string(result) .. Std.string((Std.string(url.scheme) .. Std.string("://")));
 | 
			
		||||
  end;
 | 
			
		||||
  if (url.user ~= nil) then 
 | 
			
		||||
    result = Std.string(result) .. Std.string((Std.string(url.user) .. Std.string(":")));
 | 
			
		||||
  end;
 | 
			
		||||
  if (url.password ~= nil) then 
 | 
			
		||||
    result = Std.string(result) .. Std.string((Std.string(url.password) .. Std.string("@")));
 | 
			
		||||
  end;
 | 
			
		||||
  if (url.host ~= nil) then 
 | 
			
		||||
    result = Std.string(result) .. Std.string(url.host);
 | 
			
		||||
  end;
 | 
			
		||||
  if (url.port ~= nil) then 
 | 
			
		||||
    result = Std.string(result) .. Std.string((Std.string(":") .. Std.string(url.port)));
 | 
			
		||||
  end;
 | 
			
		||||
  if (url.directory ~= nil) then 
 | 
			
		||||
    result = Std.string(result) .. Std.string(url.directory);
 | 
			
		||||
  end;
 | 
			
		||||
  if (url.file ~= nil) then 
 | 
			
		||||
    result = Std.string(result) .. Std.string(url.file);
 | 
			
		||||
  end;
 | 
			
		||||
  if (url.query ~= nil) then 
 | 
			
		||||
    result = Std.string(result) .. Std.string((Std.string("?") .. Std.string(url.query)));
 | 
			
		||||
  end;
 | 
			
		||||
  if (url.fragment ~= nil) then 
 | 
			
		||||
    result = Std.string(result) .. Std.string((Std.string("#") .. Std.string(url.fragment)));
 | 
			
		||||
  end;
 | 
			
		||||
  do return result end;
 | 
			
		||||
end
 | 
			
		||||
__xrfragment_URI.appendURI = function(url,appendedURI) 
 | 
			
		||||
  if (__xrfragment_URI.isRelative(url) == true) then 
 | 
			
		||||
    do return __xrfragment_URI.appendToRelativeURI(url, appendedURI) end;
 | 
			
		||||
  else
 | 
			
		||||
    do return __xrfragment_URI.appendToAbsoluteURI(url, appendedURI) end;
 | 
			
		||||
  end;
 | 
			
		||||
end
 | 
			
		||||
__xrfragment_URI.isRelative = function(url) 
 | 
			
		||||
  do return url.scheme == nil end;
 | 
			
		||||
end
 | 
			
		||||
__xrfragment_URI.appendToRelativeURI = function(url,appendedURI) 
 | 
			
		||||
  if ((url.directory == nil) or (url.host == nil)) then 
 | 
			
		||||
    do return __xrfragment_URI.cloneURI(appendedURI) end;
 | 
			
		||||
  end;
 | 
			
		||||
  local resultURI = __xrfragment_URI.new();
 | 
			
		||||
  resultURI.host = url.host;
 | 
			
		||||
  resultURI.directory = url.directory;
 | 
			
		||||
  if (appendedURI.host ~= nil) then 
 | 
			
		||||
    local resultURI = resultURI;
 | 
			
		||||
    resultURI.directory = Std.string(resultURI.directory) .. Std.string(appendedURI.host);
 | 
			
		||||
  end;
 | 
			
		||||
  if (appendedURI.directory ~= nil) then 
 | 
			
		||||
    local directory = appendedURI.directory;
 | 
			
		||||
    if (appendedURI.host == nil) then 
 | 
			
		||||
      local resultURI = resultURI;
 | 
			
		||||
      local pos = 1;
 | 
			
		||||
      local len = nil;
 | 
			
		||||
      if ((len == nil) or (len > (pos + __lua_lib_luautf8_Utf8.len(directory)))) then 
 | 
			
		||||
        len = __lua_lib_luautf8_Utf8.len(directory);
 | 
			
		||||
      else
 | 
			
		||||
        if (len < 0) then 
 | 
			
		||||
          len = __lua_lib_luautf8_Utf8.len(directory) + len;
 | 
			
		||||
        end;
 | 
			
		||||
      end;
 | 
			
		||||
      if (pos < 0) then 
 | 
			
		||||
        pos = __lua_lib_luautf8_Utf8.len(directory) + pos;
 | 
			
		||||
      end;
 | 
			
		||||
      if (pos < 0) then 
 | 
			
		||||
        pos = 0;
 | 
			
		||||
      end;
 | 
			
		||||
      resultURI.directory = Std.string(resultURI.directory) .. Std.string(__lua_lib_luautf8_Utf8.sub(directory, pos + 1, pos + len));
 | 
			
		||||
    else
 | 
			
		||||
      local resultURI = resultURI;
 | 
			
		||||
      resultURI.directory = Std.string(resultURI.directory) .. Std.string(directory);
 | 
			
		||||
    end;
 | 
			
		||||
  end;
 | 
			
		||||
  if (appendedURI.file ~= nil) then 
 | 
			
		||||
    resultURI.file = appendedURI.file;
 | 
			
		||||
  end;
 | 
			
		||||
  resultURI.path = Std.string(resultURI.directory) .. Std.string(resultURI.file);
 | 
			
		||||
  if (appendedURI.query ~= nil) then 
 | 
			
		||||
    resultURI.query = appendedURI.query;
 | 
			
		||||
  end;
 | 
			
		||||
  if (appendedURI.fragment ~= nil) then 
 | 
			
		||||
    resultURI.fragment = appendedURI.fragment;
 | 
			
		||||
  end;
 | 
			
		||||
  do return resultURI end;
 | 
			
		||||
end
 | 
			
		||||
__xrfragment_URI.appendToAbsoluteURI = function(url,appendedURI) 
 | 
			
		||||
  local resultURI = __xrfragment_URI.new();
 | 
			
		||||
  if (url.scheme ~= nil) then 
 | 
			
		||||
    resultURI.scheme = url.scheme;
 | 
			
		||||
  end;
 | 
			
		||||
  if (url.host ~= nil) then 
 | 
			
		||||
    resultURI.host = url.host;
 | 
			
		||||
  end;
 | 
			
		||||
  local directory = "";
 | 
			
		||||
  if (url.directory ~= nil) then 
 | 
			
		||||
    directory = url.directory;
 | 
			
		||||
  end;
 | 
			
		||||
  if (appendedURI.host ~= nil) then 
 | 
			
		||||
    local appendedURI1 = appendedURI;
 | 
			
		||||
    appendedURI1.directory = Std.string(appendedURI1.directory) .. Std.string(appendedURI.host);
 | 
			
		||||
  end;
 | 
			
		||||
  if (appendedURI.directory ~= nil) then 
 | 
			
		||||
    directory = Std.string(directory) .. Std.string(appendedURI.directory);
 | 
			
		||||
  end;
 | 
			
		||||
  resultURI.directory = directory;
 | 
			
		||||
  if (appendedURI.file ~= nil) then 
 | 
			
		||||
    resultURI.file = appendedURI.file;
 | 
			
		||||
  end;
 | 
			
		||||
  resultURI.path = Std.string(resultURI.directory) .. Std.string(resultURI.file);
 | 
			
		||||
  if (appendedURI.query ~= nil) then 
 | 
			
		||||
    resultURI.query = appendedURI.query;
 | 
			
		||||
  end;
 | 
			
		||||
  if (appendedURI.fragment ~= nil) then 
 | 
			
		||||
    resultURI.fragment = appendedURI.fragment;
 | 
			
		||||
  end;
 | 
			
		||||
  do return resultURI end;
 | 
			
		||||
end
 | 
			
		||||
__xrfragment_URI.toAbsolute = function(url,newUrl) 
 | 
			
		||||
  local newURI = __xrfragment_URI.parse(newUrl, 0);
 | 
			
		||||
  local resultURI = __xrfragment_URI.new();
 | 
			
		||||
  resultURI.port = url.port;
 | 
			
		||||
  resultURI.source = newUrl;
 | 
			
		||||
  if (newURI.scheme ~= nil) then 
 | 
			
		||||
    resultURI.scheme = newURI.scheme;
 | 
			
		||||
  else
 | 
			
		||||
    resultURI.scheme = url.scheme;
 | 
			
		||||
  end;
 | 
			
		||||
  if ((newURI.host ~= nil) and (__lua_lib_luautf8_Utf8.len(newURI.host) > 0)) then 
 | 
			
		||||
    resultURI.host = newURI.host;
 | 
			
		||||
    resultURI.port = nil;
 | 
			
		||||
    resultURI.fragment = nil;
 | 
			
		||||
    resultURI.hash = _hx_e();
 | 
			
		||||
    resultURI.XRF = _hx_e();
 | 
			
		||||
    if (newURI.port ~= nil) then 
 | 
			
		||||
      resultURI.port = newURI.port;
 | 
			
		||||
    end;
 | 
			
		||||
  else
 | 
			
		||||
    resultURI.host = url.host;
 | 
			
		||||
  end;
 | 
			
		||||
  local directory = "";
 | 
			
		||||
  if (url.directory ~= nil) then 
 | 
			
		||||
    directory = url.directory;
 | 
			
		||||
  end;
 | 
			
		||||
  if (newURI.directory ~= nil) then 
 | 
			
		||||
    local tmp;
 | 
			
		||||
    if (__lua_lib_luautf8_Utf8.sub(newUrl, 1, 1) ~= "/") then 
 | 
			
		||||
      local startIndex = nil;
 | 
			
		||||
      if (startIndex == nil) then 
 | 
			
		||||
        startIndex = 1;
 | 
			
		||||
      else
 | 
			
		||||
        startIndex = startIndex + 1;
 | 
			
		||||
      end;
 | 
			
		||||
      local r = __lua_lib_luautf8_Utf8.find(newUrl, "://", startIndex, true);
 | 
			
		||||
      tmp = (function() 
 | 
			
		||||
        local _hx_1
 | 
			
		||||
        if ((r ~= nil) and (r > 0)) then 
 | 
			
		||||
        _hx_1 = r - 1; else 
 | 
			
		||||
        _hx_1 = -1; end
 | 
			
		||||
        return _hx_1
 | 
			
		||||
      end )() == -1;
 | 
			
		||||
    else
 | 
			
		||||
      tmp = false;
 | 
			
		||||
    end;
 | 
			
		||||
    if (tmp) then 
 | 
			
		||||
      directory = Std.string(directory) .. Std.string(newURI.directory);
 | 
			
		||||
    else
 | 
			
		||||
      directory = newURI.directory;
 | 
			
		||||
    end;
 | 
			
		||||
  end;
 | 
			
		||||
  resultURI.directory = directory;
 | 
			
		||||
  if (newURI.file ~= nil) then 
 | 
			
		||||
    resultURI.file = newURI.file;
 | 
			
		||||
  end;
 | 
			
		||||
  resultURI.path = Std.string(resultURI.directory) .. Std.string(resultURI.file);
 | 
			
		||||
  if (newURI.query ~= nil) then 
 | 
			
		||||
    resultURI.query = newURI.query;
 | 
			
		||||
  end;
 | 
			
		||||
  if (newURI.fragment ~= nil) then 
 | 
			
		||||
    resultURI.fragment = newURI.fragment;
 | 
			
		||||
  end;
 | 
			
		||||
  resultURI.hash = newURI.hash;
 | 
			
		||||
  resultURI.XRF = newURI.XRF;
 | 
			
		||||
  __xrfragment_URI.computeVars(resultURI);
 | 
			
		||||
  do return resultURI end;
 | 
			
		||||
end
 | 
			
		||||
__xrfragment_URI.cloneURI = function(url) 
 | 
			
		||||
  local clonedURI = __xrfragment_URI.new();
 | 
			
		||||
  clonedURI.url = url.url;
 | 
			
		||||
  clonedURI.source = url.source;
 | 
			
		||||
  clonedURI.scheme = url.scheme;
 | 
			
		||||
  clonedURI.authority = url.authority;
 | 
			
		||||
  clonedURI.userInfo = url.userInfo;
 | 
			
		||||
  clonedURI.password = url.password;
 | 
			
		||||
  clonedURI.host = url.host;
 | 
			
		||||
  clonedURI.port = url.port;
 | 
			
		||||
  clonedURI.relative = url.relative;
 | 
			
		||||
  clonedURI.path = url.path;
 | 
			
		||||
  clonedURI.directory = url.directory;
 | 
			
		||||
  clonedURI.file = url.file;
 | 
			
		||||
  clonedURI.query = url.query;
 | 
			
		||||
  clonedURI.fragment = url.fragment;
 | 
			
		||||
  do return clonedURI end;
 | 
			
		||||
end
 | 
			
		||||
__xrfragment_URI.prototype = _hx_e();
 | 
			
		||||
 | 
			
		||||
__xrfragment_URI.prototype.__class__ =  __xrfragment_URI
 | 
			
		||||
 | 
			
		||||
__xrfragment_XRF.new = function(_fragment,_flags,_index) 
 | 
			
		||||
  local self = _hx_new(__xrfragment_XRF.prototype)
 | 
			
		||||
| 
						 | 
				
			
			@ -3281,6 +3658,8 @@ local _hx_static_init = function()
 | 
			
		|||
  
 | 
			
		||||
  __xrfragment_URI.__meta__ = _hx_o({__fields__={statics=true},statics=_hx_o({__fields__={template=true},template=_hx_o({__fields__={keep=true},keep=nil})})});
 | 
			
		||||
  
 | 
			
		||||
  __xrfragment_URI._parts = _hx_tab_array({[0]="source", "scheme", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "fragment"}, 14);
 | 
			
		||||
  
 | 
			
		||||
  __xrfragment_XRF.IMMUTABLE = 1;
 | 
			
		||||
  
 | 
			
		||||
  __xrfragment_XRF.PROP_BIND = 2;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3385
									
								
								dist/xrfragment.module.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3385
									
								
								dist/xrfragment.module.js
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										32
									
								
								dist/xrfragment.plugin.frontend.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										32
									
								
								dist/xrfragment.plugin.frontend.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -750,7 +750,7 @@ window.frontend = (opts) => new Proxy({
 | 
			
		|||
 | 
			
		||||
    // load original scene and overwrite with updates
 | 
			
		||||
    let url = document.location.search.replace(/\?/,'')
 | 
			
		||||
    let {urlObj,dir,file,hash,ext} = xrf.navigator.origin = xrf.parseUrl(url)
 | 
			
		||||
    let {urlObj,dir,file,hash,ext} = xrf.navigator.origin = xrf.URI.parse(url)
 | 
			
		||||
    const Loader = xrf.loaders[ext]
 | 
			
		||||
    loader = new Loader().setPath( dir )
 | 
			
		||||
    notify('exporting scene<br><br>please wait..')
 | 
			
		||||
| 
						 | 
				
			
			@ -760,29 +760,8 @@ window.frontend = (opts) => new Proxy({
 | 
			
		|||
  },
 | 
			
		||||
 | 
			
		||||
  updateHashPosition(randomize){
 | 
			
		||||
    // *TODO* this should be part of the XRF Threejs framework
 | 
			
		||||
    if( typeof THREE == 'undefined' ) THREE = xrf.THREE
 | 
			
		||||
    let radToDeg  = THREE.MathUtils.radToDeg
 | 
			
		||||
    let toDeg     = (x) => x / (Math.PI / 180)
 | 
			
		||||
    let camera    = document.querySelector('[camera]').object3D.parent // *TODO* fix for threejs
 | 
			
		||||
    camera.position.x += Math.random()/10
 | 
			
		||||
    camera.position.z += Math.random()/10
 | 
			
		||||
 | 
			
		||||
    // *TODO* add camera direction
 | 
			
		||||
    let direction = new xrf.THREE.Vector3()
 | 
			
		||||
    camera.getWorldDirection(direction)
 | 
			
		||||
    const pitch   = Math.asin(direction.y);
 | 
			
		||||
    const yaw     = Math.atan2(direction.x, direction.z);
 | 
			
		||||
    const pitchInDegrees = pitch * 180 / Math.PI;
 | 
			
		||||
    const yawInDegrees = yaw * 180 / Math.PI;
 | 
			
		||||
 | 
			
		||||
    let lastPos = `pos=${camera.position.x.toFixed(2)},${camera.position.y.toFixed(2)},${camera.position.z.toFixed(2)}`
 | 
			
		||||
    let newHash = document.location.hash.replace(/[&]?(pos|rot)=[0-9\.-]+,[0-9\.-]+,[0-9\.-]+/,'')
 | 
			
		||||
    if( lastPos != "pos=" ){
 | 
			
		||||
      newHash += `&${lastPos}`
 | 
			
		||||
      document.location.hash = newHash.replace(/&&/,'&')
 | 
			
		||||
                                      .replace(/#&/,'')
 | 
			
		||||
    }
 | 
			
		||||
    const pos = xrf.frag.pos.get()
 | 
			
		||||
    xrf.navigator.URI.hash.pos = `${pos.x},${pos.y},${pos.z}`
 | 
			
		||||
    this.copyToClipboard( window.location.href );
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -802,8 +781,9 @@ window.frontend = (opts) => new Proxy({
 | 
			
		|||
      document.location.hash += `&meet=${network.meetingLink}`
 | 
			
		||||
    }
 | 
			
		||||
    if( !document.location.hash.match(/pos=/) && (network.posName || network.pos) ){
 | 
			
		||||
      document.location.hash += `&pos=${ network.posName || network.pos }`
 | 
			
		||||
    }
 | 
			
		||||
      xrf.navigator.URI.hash.pos = network.posName || network.pos
 | 
			
		||||
    }else frontend.updateHashPosition()
 | 
			
		||||
 | 
			
		||||
    let url = window.location.href
 | 
			
		||||
    if( opts.linkonly ) return url
 | 
			
		||||
    this.copyToClipboard( url )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								dist/xrfragment.plugin.matrix.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/xrfragment.plugin.matrix.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -316,7 +316,7 @@
 | 
			
		|||
        this.ydoc.scene.set('href',document.location.hash )
 | 
			
		||||
      } 
 | 
			
		||||
    })
 | 
			
		||||
    let hashvars = xrf.URI.parse( document.location.hash )
 | 
			
		||||
    let hashvars = xrf.URI.parse( document.location.hash ).XRF
 | 
			
		||||
    if( hashvars.meet ) this.parseLink(hashvars.meet.string)
 | 
			
		||||
  }
 | 
			
		||||
},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								dist/xrfragment.plugin.network.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/xrfragment.plugin.network.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -489,7 +489,7 @@ chatComponent = {
 | 
			
		|||
        div.classList.add.apply(div.classList, opts.class.concat(["envelope"]))
 | 
			
		||||
      }
 | 
			
		||||
      if( !msg.className.match(/(info|guide|ui)/) ){
 | 
			
		||||
        let frag = xrf.URI.parse(document.location.hash)
 | 
			
		||||
        let frag = xrf.URI.parse(document.location.hash).XRF
 | 
			
		||||
        opts.from = 'you'
 | 
			
		||||
        if( frag.pos ) opts.pos = frag.pos.string
 | 
			
		||||
        msg.classList.add('self')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								dist/xrfragment.plugin.p2p.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/xrfragment.plugin.p2p.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -260,7 +260,7 @@ window.trystero = (opts) => new Proxy({
 | 
			
		|||
      let isTeleport = href.match(/(pos=|http:)/)
 | 
			
		||||
      if( isLocal && !isTeleport && this.href.send ) this.href.send({href})
 | 
			
		||||
    })
 | 
			
		||||
    let hashvars = xrf.URI.parse( document.location.hash )
 | 
			
		||||
    let hashvars = xrf.URI.parse( document.location.hash ).XRF
 | 
			
		||||
    if( hashvars.meet ) this.parseLink(hashvars.meet.string)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										253
									
								
								dist/xrfragment.py
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										253
									
								
								dist/xrfragment.py
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -2303,11 +2303,33 @@ xrfragment_Parser._hx_class = xrfragment_Parser
 | 
			
		|||
 | 
			
		||||
class xrfragment_URI:
 | 
			
		||||
    _hx_class_name = "xrfragment.URI"
 | 
			
		||||
    __slots__ = ()
 | 
			
		||||
    _hx_statics = ["__meta__", "parse", "template"]
 | 
			
		||||
    __slots__ = ("url", "source", "scheme", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "fileExt", "query", "fragment", "hash", "XRF", "URN")
 | 
			
		||||
    _hx_fields = ["url", "source", "scheme", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "fileExt", "query", "fragment", "hash", "XRF", "URN"]
 | 
			
		||||
    _hx_statics = ["__meta__", "_parts", "parseFragment", "template", "parse", "computeVars", "toString", "appendURI", "isRelative", "appendToRelativeURI", "appendToAbsoluteURI", "toAbsolute", "cloneURI"]
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.URN = None
 | 
			
		||||
        self.query = None
 | 
			
		||||
        self.fileExt = None
 | 
			
		||||
        self.file = None
 | 
			
		||||
        self.directory = None
 | 
			
		||||
        self.path = None
 | 
			
		||||
        self.relative = None
 | 
			
		||||
        self.port = None
 | 
			
		||||
        self.host = None
 | 
			
		||||
        self.password = None
 | 
			
		||||
        self.user = None
 | 
			
		||||
        self.userInfo = None
 | 
			
		||||
        self.authority = None
 | 
			
		||||
        self.scheme = None
 | 
			
		||||
        self.source = None
 | 
			
		||||
        self.url = None
 | 
			
		||||
        self.XRF = _hx_AnonObject({})
 | 
			
		||||
        self.hash = _hx_AnonObject({})
 | 
			
		||||
        self.fragment = ""
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def parse(url,_hx_filter):
 | 
			
		||||
    def parseFragment(url,_hx_filter):
 | 
			
		||||
        store = _hx_AnonObject({})
 | 
			
		||||
        tmp = None
 | 
			
		||||
        if (url is not None):
 | 
			
		||||
| 
						 | 
				
			
			@ -2362,6 +2384,230 @@ class xrfragment_URI:
 | 
			
		|||
        frag = StringTools.replace(frag,"null","")
 | 
			
		||||
        python_internal_ArrayImpl._set(parts, 1, frag)
 | 
			
		||||
        return "#".join([python_Boot.toString1(x1,'') for x1 in parts])
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def parse(stringUrl,flags):
 | 
			
		||||
        r = EReg("^(?:(?![^:@]+:[^:@/]*@)([^:/?#.]+):)?(?://)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:/?#]*)(?::(\\d*))?)(((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[?#]|$)))*/?)?([^?#/]*))(?:\\?([^#]*))?(?:#(.*))?)","")
 | 
			
		||||
        startIndex = None
 | 
			
		||||
        if ((((stringUrl.find("://") if ((startIndex is None)) else HxString.indexOfImpl(stringUrl,"://",startIndex))) == -1) and (((("" if ((0 >= len(stringUrl))) else stringUrl[0])) != "/"))):
 | 
			
		||||
            stringUrl = ("/" + ("null" if stringUrl is None else stringUrl))
 | 
			
		||||
        r.matchObj = python_lib_Re.search(r.pattern,stringUrl)
 | 
			
		||||
        url = xrfragment_URI()
 | 
			
		||||
        _g = 0
 | 
			
		||||
        _g1 = len(xrfragment_URI._parts)
 | 
			
		||||
        while (_g < _g1):
 | 
			
		||||
            i = _g
 | 
			
		||||
            _g = (_g + 1)
 | 
			
		||||
            field = python_internal_ArrayImpl._get(xrfragment_URI._parts, i)
 | 
			
		||||
            value = r.matchObj.group(i)
 | 
			
		||||
            setattr(url,(("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field)),value)
 | 
			
		||||
        if (xrfragment_URI.isRelative(url) == True):
 | 
			
		||||
            if ((url.directory is None) and ((url.host is not None))):
 | 
			
		||||
                url.file = url.host
 | 
			
		||||
        url.hash = _hx_AnonObject({})
 | 
			
		||||
        if ((url.fragment is not None) and ((len(url.fragment) > 0))):
 | 
			
		||||
            url.XRF = xrfragment_URI.parseFragment(("#" + HxOverrides.stringOrNull(url.fragment)),flags)
 | 
			
		||||
            key = None
 | 
			
		||||
            _g = 0
 | 
			
		||||
            _g1 = python_Boot.fields(url.XRF)
 | 
			
		||||
            while (_g < len(_g1)):
 | 
			
		||||
                key = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
 | 
			
		||||
                _g = (_g + 1)
 | 
			
		||||
                v = Reflect.field(url.XRF,key)
 | 
			
		||||
                this1 = url.hash
 | 
			
		||||
                value = Reflect.field(v,"string")
 | 
			
		||||
                setattr(this1,(("_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)
 | 
			
		||||
        xrfragment_URI.computeVars(url)
 | 
			
		||||
        return url
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def computeVars(url):
 | 
			
		||||
        r = EReg("//","g")
 | 
			
		||||
        tmp = None
 | 
			
		||||
        if (url.directory is not None):
 | 
			
		||||
            _this = url.directory
 | 
			
		||||
            startIndex = None
 | 
			
		||||
            tmp = (((_this.find("//") if ((startIndex is None)) else HxString.indexOfImpl(_this,"//",startIndex))) != -1)
 | 
			
		||||
        else:
 | 
			
		||||
            tmp = False
 | 
			
		||||
        if tmp:
 | 
			
		||||
            url.directory = r.replace(url.directory,"/")
 | 
			
		||||
        tmp = None
 | 
			
		||||
        if (url.path is not None):
 | 
			
		||||
            _this = url.path
 | 
			
		||||
            startIndex = None
 | 
			
		||||
            tmp = (((_this.find("//") if ((startIndex is None)) else HxString.indexOfImpl(_this,"//",startIndex))) != -1)
 | 
			
		||||
        else:
 | 
			
		||||
            tmp = False
 | 
			
		||||
        if tmp:
 | 
			
		||||
            url.path = r.replace(url.path,"/")
 | 
			
		||||
        tmp = None
 | 
			
		||||
        if (url.file is not None):
 | 
			
		||||
            _this = url.file
 | 
			
		||||
            startIndex = None
 | 
			
		||||
            tmp = (((_this.find("//") if ((startIndex is None)) else HxString.indexOfImpl(_this,"//",startIndex))) != -1)
 | 
			
		||||
        else:
 | 
			
		||||
            tmp = False
 | 
			
		||||
        if tmp:
 | 
			
		||||
            url.file = r.replace(url.file,"/")
 | 
			
		||||
        url.URN = ((HxOverrides.stringOrNull(url.scheme) + "://") + HxOverrides.stringOrNull(url.host))
 | 
			
		||||
        if (url.port is not None):
 | 
			
		||||
            url.URN = (HxOverrides.stringOrNull(url.URN) + HxOverrides.stringOrNull(((":" + HxOverrides.stringOrNull(url.port)))))
 | 
			
		||||
        url.URN = (HxOverrides.stringOrNull(url.URN) + HxOverrides.stringOrNull(url.directory))
 | 
			
		||||
        if (url.file is not None):
 | 
			
		||||
            _this = url.file
 | 
			
		||||
            parts = _this.split(".")
 | 
			
		||||
            if (len(parts) > 1):
 | 
			
		||||
                url.fileExt = (None if ((len(parts) == 0)) else parts.pop())
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def toString(url):
 | 
			
		||||
        result = ""
 | 
			
		||||
        if (url.scheme is not None):
 | 
			
		||||
            result = (("null" if result is None else result) + HxOverrides.stringOrNull(((HxOverrides.stringOrNull(url.scheme) + "://"))))
 | 
			
		||||
        if (url.user is not None):
 | 
			
		||||
            result = (("null" if result is None else result) + HxOverrides.stringOrNull(((HxOverrides.stringOrNull(url.user) + ":"))))
 | 
			
		||||
        if (url.password is not None):
 | 
			
		||||
            result = (("null" if result is None else result) + HxOverrides.stringOrNull(((HxOverrides.stringOrNull(url.password) + "@"))))
 | 
			
		||||
        if (url.host is not None):
 | 
			
		||||
            result = (("null" if result is None else result) + HxOverrides.stringOrNull(url.host))
 | 
			
		||||
        if (url.port is not None):
 | 
			
		||||
            result = (("null" if result is None else result) + HxOverrides.stringOrNull(((":" + HxOverrides.stringOrNull(url.port)))))
 | 
			
		||||
        if (url.directory is not None):
 | 
			
		||||
            result = (("null" if result is None else result) + HxOverrides.stringOrNull(url.directory))
 | 
			
		||||
        if (url.file is not None):
 | 
			
		||||
            result = (("null" if result is None else result) + HxOverrides.stringOrNull(url.file))
 | 
			
		||||
        if (url.query is not None):
 | 
			
		||||
            result = (("null" if result is None else result) + HxOverrides.stringOrNull((("?" + HxOverrides.stringOrNull(url.query)))))
 | 
			
		||||
        if (url.fragment is not None):
 | 
			
		||||
            result = (("null" if result is None else result) + HxOverrides.stringOrNull((("#" + HxOverrides.stringOrNull(url.fragment)))))
 | 
			
		||||
        return result
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def appendURI(url,appendedURI):
 | 
			
		||||
        if (xrfragment_URI.isRelative(url) == True):
 | 
			
		||||
            return xrfragment_URI.appendToRelativeURI(url,appendedURI)
 | 
			
		||||
        else:
 | 
			
		||||
            return xrfragment_URI.appendToAbsoluteURI(url,appendedURI)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def isRelative(url):
 | 
			
		||||
        return (url.scheme is None)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def appendToRelativeURI(url,appendedURI):
 | 
			
		||||
        if ((url.directory is None) or ((url.host is None))):
 | 
			
		||||
            return xrfragment_URI.cloneURI(appendedURI)
 | 
			
		||||
        resultURI = xrfragment_URI()
 | 
			
		||||
        resultURI.host = url.host
 | 
			
		||||
        resultURI.directory = url.directory
 | 
			
		||||
        if (appendedURI.host is not None):
 | 
			
		||||
            resultURI.directory = (HxOverrides.stringOrNull(resultURI.directory) + HxOverrides.stringOrNull(appendedURI.host))
 | 
			
		||||
        if (appendedURI.directory is not None):
 | 
			
		||||
            directory = appendedURI.directory
 | 
			
		||||
            if (appendedURI.host is None):
 | 
			
		||||
                resultURI.directory = (HxOverrides.stringOrNull(resultURI.directory) + HxOverrides.stringOrNull(HxString.substr(directory,1,None)))
 | 
			
		||||
            else:
 | 
			
		||||
                resultURI.directory = (HxOverrides.stringOrNull(resultURI.directory) + ("null" if directory is None else directory))
 | 
			
		||||
        if (appendedURI.file is not None):
 | 
			
		||||
            resultURI.file = appendedURI.file
 | 
			
		||||
        resultURI.path = (HxOverrides.stringOrNull(resultURI.directory) + HxOverrides.stringOrNull(resultURI.file))
 | 
			
		||||
        if (appendedURI.query is not None):
 | 
			
		||||
            resultURI.query = appendedURI.query
 | 
			
		||||
        if (appendedURI.fragment is not None):
 | 
			
		||||
            resultURI.fragment = appendedURI.fragment
 | 
			
		||||
        return resultURI
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def appendToAbsoluteURI(url,appendedURI):
 | 
			
		||||
        resultURI = xrfragment_URI()
 | 
			
		||||
        if (url.scheme is not None):
 | 
			
		||||
            resultURI.scheme = url.scheme
 | 
			
		||||
        if (url.host is not None):
 | 
			
		||||
            resultURI.host = url.host
 | 
			
		||||
        directory = ""
 | 
			
		||||
        if (url.directory is not None):
 | 
			
		||||
            directory = url.directory
 | 
			
		||||
        if (appendedURI.host is not None):
 | 
			
		||||
            appendedURI.directory = (HxOverrides.stringOrNull(appendedURI.directory) + HxOverrides.stringOrNull(appendedURI.host))
 | 
			
		||||
        if (appendedURI.directory is not None):
 | 
			
		||||
            directory = (("null" if directory is None else directory) + HxOverrides.stringOrNull(appendedURI.directory))
 | 
			
		||||
        resultURI.directory = directory
 | 
			
		||||
        if (appendedURI.file is not None):
 | 
			
		||||
            resultURI.file = appendedURI.file
 | 
			
		||||
        resultURI.path = (HxOverrides.stringOrNull(resultURI.directory) + HxOverrides.stringOrNull(resultURI.file))
 | 
			
		||||
        if (appendedURI.query is not None):
 | 
			
		||||
            resultURI.query = appendedURI.query
 | 
			
		||||
        if (appendedURI.fragment is not None):
 | 
			
		||||
            resultURI.fragment = appendedURI.fragment
 | 
			
		||||
        return resultURI
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def toAbsolute(url,newUrl):
 | 
			
		||||
        newURI = xrfragment_URI.parse(newUrl,0)
 | 
			
		||||
        resultURI = xrfragment_URI()
 | 
			
		||||
        resultURI.port = url.port
 | 
			
		||||
        resultURI.source = newUrl
 | 
			
		||||
        if (newURI.scheme is not None):
 | 
			
		||||
            resultURI.scheme = newURI.scheme
 | 
			
		||||
        else:
 | 
			
		||||
            resultURI.scheme = url.scheme
 | 
			
		||||
        if ((newURI.host is not None) and ((len(newURI.host) > 0))):
 | 
			
		||||
            resultURI.host = newURI.host
 | 
			
		||||
            resultURI.port = None
 | 
			
		||||
            resultURI.fragment = None
 | 
			
		||||
            resultURI.hash = _hx_AnonObject({})
 | 
			
		||||
            resultURI.XRF = _hx_AnonObject({})
 | 
			
		||||
            if (newURI.port is not None):
 | 
			
		||||
                resultURI.port = newURI.port
 | 
			
		||||
        else:
 | 
			
		||||
            resultURI.host = url.host
 | 
			
		||||
        directory = ""
 | 
			
		||||
        if (url.directory is not None):
 | 
			
		||||
            directory = url.directory
 | 
			
		||||
        if (newURI.directory is not None):
 | 
			
		||||
            tmp = None
 | 
			
		||||
            if ((("" if ((0 >= len(newUrl))) else newUrl[0])) != "/"):
 | 
			
		||||
                startIndex = None
 | 
			
		||||
                tmp = (((newUrl.find("://") if ((startIndex is None)) else HxString.indexOfImpl(newUrl,"://",startIndex))) == -1)
 | 
			
		||||
            else:
 | 
			
		||||
                tmp = False
 | 
			
		||||
            if tmp:
 | 
			
		||||
                directory = (("null" if directory is None else directory) + HxOverrides.stringOrNull(newURI.directory))
 | 
			
		||||
            else:
 | 
			
		||||
                directory = newURI.directory
 | 
			
		||||
        resultURI.directory = directory
 | 
			
		||||
        if (newURI.file is not None):
 | 
			
		||||
            resultURI.file = newURI.file
 | 
			
		||||
        resultURI.path = (HxOverrides.stringOrNull(resultURI.directory) + HxOverrides.stringOrNull(resultURI.file))
 | 
			
		||||
        if (newURI.query is not None):
 | 
			
		||||
            resultURI.query = newURI.query
 | 
			
		||||
        if (newURI.fragment is not None):
 | 
			
		||||
            resultURI.fragment = newURI.fragment
 | 
			
		||||
        resultURI.hash = newURI.hash
 | 
			
		||||
        resultURI.XRF = newURI.XRF
 | 
			
		||||
        xrfragment_URI.computeVars(resultURI)
 | 
			
		||||
        return resultURI
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def cloneURI(url):
 | 
			
		||||
        clonedURI = xrfragment_URI()
 | 
			
		||||
        clonedURI.url = url.url
 | 
			
		||||
        clonedURI.source = url.source
 | 
			
		||||
        clonedURI.scheme = url.scheme
 | 
			
		||||
        clonedURI.authority = url.authority
 | 
			
		||||
        clonedURI.userInfo = url.userInfo
 | 
			
		||||
        clonedURI.password = url.password
 | 
			
		||||
        clonedURI.host = url.host
 | 
			
		||||
        clonedURI.port = url.port
 | 
			
		||||
        clonedURI.relative = url.relative
 | 
			
		||||
        clonedURI.path = url.path
 | 
			
		||||
        clonedURI.directory = url.directory
 | 
			
		||||
        clonedURI.file = url.file
 | 
			
		||||
        clonedURI.query = url.query
 | 
			
		||||
        clonedURI.fragment = url.fragment
 | 
			
		||||
        return clonedURI
 | 
			
		||||
 | 
			
		||||
xrfragment_URI._hx_class = xrfragment_URI
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2496,6 +2742,7 @@ python_Boot.prefixLength = len("_hx_")
 | 
			
		|||
xrfragment_Parser.error = ""
 | 
			
		||||
xrfragment_Parser.debug = False
 | 
			
		||||
xrfragment_URI.__meta__ = _hx_AnonObject({'statics': _hx_AnonObject({'template': _hx_AnonObject({'keep': None})})})
 | 
			
		||||
xrfragment_URI._parts = ["source", "scheme", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "fragment"]
 | 
			
		||||
xrfragment_XRF.__meta__ = _hx_AnonObject({'statics': _hx_AnonObject({'toDict': _hx_AnonObject({'keep': None})})})
 | 
			
		||||
xrfragment_XRF.IMMUTABLE = 1
 | 
			
		||||
xrfragment_XRF.PROP_BIND = 2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										426
									
								
								dist/xrfragment.three.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										426
									
								
								dist/xrfragment.three.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * v0.5.1 generated at Tue Mar 19 10:04:25 AM UTC 2024
 | 
			
		||||
 * v0.5.1 generated at Tue Apr 16 12:47:01 PM UTC 2024
 | 
			
		||||
 * https://xrfragment.org
 | 
			
		||||
 * SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -1138,9 +1138,13 @@ xrfragment_Parser.getMetaData = function() {
 | 
			
		|||
	var meta = { title : ["title","og:title","dc.title"], description : ["aria-description","og:description","dc.description"], author : ["author","dc.creator"], publisher : ["publisher","dc.publisher"], website : ["og:site_name","og:url","dc.publisher"], license : ["SPDX","dc.rights"]};
 | 
			
		||||
	return meta;
 | 
			
		||||
};
 | 
			
		||||
var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() { };
 | 
			
		||||
var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() {
 | 
			
		||||
	this.XRF = { };
 | 
			
		||||
	this.hash = { };
 | 
			
		||||
	this.fragment = "";
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.__name__ = true;
 | 
			
		||||
xrfragment_URI.parse = function(url,filter) {
 | 
			
		||||
xrfragment_URI.parseFragment = function(url,filter) {
 | 
			
		||||
	var store = { };
 | 
			
		||||
	if(url == null || url.indexOf("#") == -1) {
 | 
			
		||||
		return store;
 | 
			
		||||
| 
						 | 
				
			
			@ -1192,6 +1196,232 @@ xrfragment_URI.template = function(uri,vars) {
 | 
			
		|||
	parts[1] = frag;
 | 
			
		||||
	return parts.join("#");
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.parse = function(stringUrl,flags) {
 | 
			
		||||
	var r = new EReg("^(?:(?![^:@]+:[^:@/]*@)([^:/?#.]+):)?(?://)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:/?#]*)(?::(\\d*))?)(((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[?#]|$)))*/?)?([^?#/]*))(?:\\?([^#]*))?(?:#(.*))?)","");
 | 
			
		||||
	if(stringUrl.indexOf("://") == -1 && stringUrl.charAt(0) != "/") {
 | 
			
		||||
		stringUrl = "/" + stringUrl;
 | 
			
		||||
	}
 | 
			
		||||
	r.match(stringUrl);
 | 
			
		||||
	var url = new xrfragment_URI();
 | 
			
		||||
	var _g = 0;
 | 
			
		||||
	var _g1 = xrfragment_URI._parts.length;
 | 
			
		||||
	while(_g < _g1) {
 | 
			
		||||
		var i = _g++;
 | 
			
		||||
		url[xrfragment_URI._parts[i]] = r.matched(i);
 | 
			
		||||
	}
 | 
			
		||||
	if(xrfragment_URI.isRelative(url) == true) {
 | 
			
		||||
		if(url.directory == null && url.host != null) {
 | 
			
		||||
			url.file = url.host;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	url.hash = { };
 | 
			
		||||
	if(url.fragment != null && url.fragment.length > 0) {
 | 
			
		||||
		url.XRF = xrfragment_URI.parseFragment("#" + url.fragment,flags);
 | 
			
		||||
		var key;
 | 
			
		||||
		var _g = 0;
 | 
			
		||||
		var _g1 = Reflect.fields(url.XRF);
 | 
			
		||||
		while(_g < _g1.length) {
 | 
			
		||||
			var key = _g1[_g];
 | 
			
		||||
			++_g;
 | 
			
		||||
			var v = url.XRF[key];
 | 
			
		||||
			url.hash[key] = v["string"];
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	xrfragment_URI.computeVars(url);
 | 
			
		||||
	return url;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.computeVars = function(url) {
 | 
			
		||||
	var r_r = new RegExp("//","g".split("u").join(""));
 | 
			
		||||
	if(url.directory != null && url.directory.indexOf("//") != -1) {
 | 
			
		||||
		url.directory = url.directory.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	if(url.path != null && url.path.indexOf("//") != -1) {
 | 
			
		||||
		url.path = url.path.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	if(url.file != null && url.file.indexOf("//") != -1) {
 | 
			
		||||
		url.file = url.file.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	url.URN = url.scheme + "://" + url.host;
 | 
			
		||||
	if(url.port != null) {
 | 
			
		||||
		url.URN += ":" + url.port;
 | 
			
		||||
	}
 | 
			
		||||
	url.URN += url.directory;
 | 
			
		||||
	if(url.file != null) {
 | 
			
		||||
		var parts = url.file.split(".");
 | 
			
		||||
		if(parts.length > 1) {
 | 
			
		||||
			url.fileExt = parts.pop();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.toString = function(url) {
 | 
			
		||||
	var result = "";
 | 
			
		||||
	if(url.scheme != null) {
 | 
			
		||||
		result += url.scheme + "://";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.user != null) {
 | 
			
		||||
		result += url.user + ":";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.password != null) {
 | 
			
		||||
		result += url.password + "@";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.host != null) {
 | 
			
		||||
		result += url.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.port != null) {
 | 
			
		||||
		result += ":" + url.port;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		result += url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.file != null) {
 | 
			
		||||
		result += url.file;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.query != null) {
 | 
			
		||||
		result += "?" + url.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.fragment != null) {
 | 
			
		||||
		result += "#" + url.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendURI = function(url,appendedURI) {
 | 
			
		||||
	if(xrfragment_URI.isRelative(url) == true) {
 | 
			
		||||
		return xrfragment_URI.appendToRelativeURI(url,appendedURI);
 | 
			
		||||
	} else {
 | 
			
		||||
		return xrfragment_URI.appendToAbsoluteURI(url,appendedURI);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.isRelative = function(url) {
 | 
			
		||||
	return url.scheme == null;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendToRelativeURI = function(url,appendedURI) {
 | 
			
		||||
	if(url.directory == null || url.host == null) {
 | 
			
		||||
		return xrfragment_URI.cloneURI(appendedURI);
 | 
			
		||||
	}
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	resultURI.host = url.host;
 | 
			
		||||
	resultURI.directory = url.directory;
 | 
			
		||||
	if(appendedURI.host != null) {
 | 
			
		||||
		resultURI.directory += appendedURI.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.directory != null) {
 | 
			
		||||
		var directory = appendedURI.directory;
 | 
			
		||||
		if(appendedURI.host == null) {
 | 
			
		||||
			resultURI.directory += HxOverrides.substr(directory,1,null);
 | 
			
		||||
		} else {
 | 
			
		||||
			resultURI.directory += directory;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.file != null) {
 | 
			
		||||
		resultURI.file = appendedURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(appendedURI.query != null) {
 | 
			
		||||
		resultURI.query = appendedURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = appendedURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendToAbsoluteURI = function(url,appendedURI) {
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	if(url.scheme != null) {
 | 
			
		||||
		resultURI.scheme = url.scheme;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.host != null) {
 | 
			
		||||
		resultURI.host = url.host;
 | 
			
		||||
	}
 | 
			
		||||
	var directory = "";
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		directory = url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.host != null) {
 | 
			
		||||
		appendedURI.directory += appendedURI.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.directory != null) {
 | 
			
		||||
		directory += appendedURI.directory;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.directory = directory;
 | 
			
		||||
	if(appendedURI.file != null) {
 | 
			
		||||
		resultURI.file = appendedURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(appendedURI.query != null) {
 | 
			
		||||
		resultURI.query = appendedURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = appendedURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.toAbsolute = function(url,newUrl) {
 | 
			
		||||
	var newURI = xrfragment_URI.parse(newUrl,0);
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	resultURI.port = url.port;
 | 
			
		||||
	resultURI.source = newUrl;
 | 
			
		||||
	if(newURI.scheme != null) {
 | 
			
		||||
		resultURI.scheme = newURI.scheme;
 | 
			
		||||
	} else {
 | 
			
		||||
		resultURI.scheme = url.scheme;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.host != null && newURI.host.length > 0) {
 | 
			
		||||
		resultURI.host = newURI.host;
 | 
			
		||||
		resultURI.port = null;
 | 
			
		||||
		resultURI.fragment = null;
 | 
			
		||||
		resultURI.hash = { };
 | 
			
		||||
		resultURI.XRF = { };
 | 
			
		||||
		if(newURI.port != null) {
 | 
			
		||||
			resultURI.port = newURI.port;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		resultURI.host = url.host;
 | 
			
		||||
	}
 | 
			
		||||
	var directory = "";
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		directory = url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.directory != null) {
 | 
			
		||||
		if(newUrl.charAt(0) != "/" && newUrl.indexOf("://") == -1) {
 | 
			
		||||
			directory += newURI.directory;
 | 
			
		||||
		} else {
 | 
			
		||||
			directory = newURI.directory;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.directory = directory;
 | 
			
		||||
	if(newURI.file != null) {
 | 
			
		||||
		resultURI.file = newURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(newURI.query != null) {
 | 
			
		||||
		resultURI.query = newURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = newURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.hash = newURI.hash;
 | 
			
		||||
	resultURI.XRF = newURI.XRF;
 | 
			
		||||
	xrfragment_URI.computeVars(resultURI);
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.cloneURI = function(url) {
 | 
			
		||||
	var clonedURI = new xrfragment_URI();
 | 
			
		||||
	clonedURI.url = url.url;
 | 
			
		||||
	clonedURI.source = url.source;
 | 
			
		||||
	clonedURI.scheme = url.scheme;
 | 
			
		||||
	clonedURI.authority = url.authority;
 | 
			
		||||
	clonedURI.userInfo = url.userInfo;
 | 
			
		||||
	clonedURI.password = url.password;
 | 
			
		||||
	clonedURI.host = url.host;
 | 
			
		||||
	clonedURI.port = url.port;
 | 
			
		||||
	clonedURI.relative = url.relative;
 | 
			
		||||
	clonedURI.path = url.path;
 | 
			
		||||
	clonedURI.directory = url.directory;
 | 
			
		||||
	clonedURI.file = url.file;
 | 
			
		||||
	clonedURI.query = url.query;
 | 
			
		||||
	clonedURI.fragment = url.fragment;
 | 
			
		||||
	return clonedURI;
 | 
			
		||||
};
 | 
			
		||||
var xrfragment_XRF = $hx_exports["xrfragment"]["XRF"] = function(_fragment,_flags,_index) {
 | 
			
		||||
	this.floats = [];
 | 
			
		||||
	this.shift = [];
 | 
			
		||||
| 
						 | 
				
			
			@ -1302,6 +1532,7 @@ haxe_Template.hxKeepArrayIterator = new haxe_iterators_ArrayIterator([]);
 | 
			
		|||
xrfragment_Parser.error = "";
 | 
			
		||||
xrfragment_Parser.debug = false;
 | 
			
		||||
xrfragment_URI.__meta__ = { statics : { template : { keep : null}}};
 | 
			
		||||
xrfragment_URI._parts = ["source","scheme","authority","userInfo","user","password","host","port","relative","path","directory","file","query","fragment"];
 | 
			
		||||
xrfragment_XRF.IMMUTABLE = 1;
 | 
			
		||||
xrfragment_XRF.PROP_BIND = 2;
 | 
			
		||||
xrfragment_XRF.QUERY_OPERATOR = 4;
 | 
			
		||||
| 
						 | 
				
			
			@ -1589,7 +1820,7 @@ let pub = function( url, node_or_model, flags ){  // evaluate fragments in url
 | 
			
		|||
  if( !url ) return 
 | 
			
		||||
  if( !url.match(/#/) ) url = `#${url}`
 | 
			
		||||
  let { THREE, camera } = xrf
 | 
			
		||||
  let frag     = xrf.URI.parse( url, flags )
 | 
			
		||||
  let frag     = xrf.URI.parse( url, flags ).XRF
 | 
			
		||||
  let fromNode = node_or_model != xrf.model
 | 
			
		||||
  let isNode   = node_or_model && node_or_model.children
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1756,24 +1987,6 @@ xrf.reset = () => {
 | 
			
		|||
  xrf.layers = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.parseUrl = (url) => {
 | 
			
		||||
  let urlExHash = url.replace(/#.*/,'')
 | 
			
		||||
  let urlObj,file
 | 
			
		||||
  let   store = {}
 | 
			
		||||
  try{
 | 
			
		||||
    urlObj = new URL( urlExHash.match(/:\/\//) ? urlExHash : String(`https://fake.com/${url}`).replace(/\/\//,'/') )
 | 
			
		||||
    file = urlObj.pathname.substring(urlObj.pathname.lastIndexOf('/') + 1);
 | 
			
		||||
    let   search = urlObj.search.substr(1).split("&")
 | 
			
		||||
    for( let i in search )  store[  (search[i].split("=")[0])  ]  = search[i].split("=")[1] || ''
 | 
			
		||||
  }catch(e){ }
 | 
			
		||||
  let   hashmap = url.match("#") ? url.replace(/.*#/,'').split("&") : []
 | 
			
		||||
  for( let i in hashmap ) store[  (hashmap[i].split("=")[0]) ]  = hashmap[i].split("=")[1] || ''
 | 
			
		||||
  let   dir  = url.substring(0, url.lastIndexOf('/') + 1)
 | 
			
		||||
  const hash = url.match(/#/) ? url.replace(/.*#/,'') : ''
 | 
			
		||||
  const ext  = file.split('.').pop()
 | 
			
		||||
  return {urlObj,dir,file,hash,ext,store}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.add = (object) => {
 | 
			
		||||
  object.isXRF = true // mark for easy deletion when replacing scene
 | 
			
		||||
  xrf.scene.add(object)
 | 
			
		||||
| 
						 | 
				
			
			@ -1784,42 +1997,52 @@ xrf.hasNoMaterial = (mesh) => {
 | 
			
		|||
  const hasMaterialName   = mesh.material && mesh.material.name.length > 0 
 | 
			
		||||
  return mesh.geometry && !hasMaterialName && !hasTexture
 | 
			
		||||
}
 | 
			
		||||
xrf.navigator = {}
 | 
			
		||||
xrf.navigator = {URI:{}}
 | 
			
		||||
 | 
			
		||||
xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		||||
  if( !url ) throw 'xrf.navigator.to(..) no url given'
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.navigator.origin = xrf.parseUrl(url)
 | 
			
		||||
  let hashChange = (!file && hash) || !data && xrf.model.file == file
 | 
			
		||||
  let hasPos     = String(hash).match(/pos=/)
 | 
			
		||||
 | 
			
		||||
  let URI = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  URI.hash          = xrf.navigator.reactifyHash(URI.hash)
 | 
			
		||||
  let fileChange    = URI.URN + URI.file != xrf.navigator.URI.URN + xrf.navigator.URI.file 
 | 
			
		||||
  let external      = URI.URN != document.location.origin + document.location.pathname 
 | 
			
		||||
  let hasPos        = URI.hash.pos 
 | 
			
		||||
  let hashChange    = String(xrf.navigator.URI.fragment||"") != String(URI.fragment||"")
 | 
			
		||||
  let hashbus       = xrf.hashbus
 | 
			
		||||
  xrf.navigator.URI = URI
 | 
			
		||||
  let {directory,file,fragment,fileExt} = URI;
 | 
			
		||||
 | 
			
		||||
  let hashbus = xrf.hashbus
 | 
			
		||||
  const evalFragment  = () => {
 | 
			
		||||
    if( URI.fragment ){
 | 
			
		||||
      hashbus.pub( URI.fragment, xrf.model, flags )     // eval local URI XR fragments 
 | 
			
		||||
      xrf.navigator.updateHash(fragment)                // which don't require 
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return new Promise( (resolve,reject) => {
 | 
			
		||||
    xrf
 | 
			
		||||
    .emit('navigate', {url,loader,data})
 | 
			
		||||
    .then( () => {
 | 
			
		||||
 | 
			
		||||
      if( ext && !loader ){  
 | 
			
		||||
        const Loader = xrf.loaders[ext]
 | 
			
		||||
      const Loader = xrf.loaders[fileExt]
 | 
			
		||||
 | 
			
		||||
      if( fileExt && !loader ){  
 | 
			
		||||
        if( !Loader ) return resolve()
 | 
			
		||||
        loader = loader || new Loader().setPath( dir )
 | 
			
		||||
        loader = loader || new Loader().setPath( URI.URN )
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if( !hash && !file && !ext ) return resolve(xrf.model) // nothing we can do here
 | 
			
		||||
      if( !URI.fragment && !URI.file && !URI.fileExt ) return resolve(xrf.model) // nothing we can do here
 | 
			
		||||
 | 
			
		||||
      if( hashChange && !hasPos ){
 | 
			
		||||
        hashbus.pub( url, xrf.model, flags )     // eval local URI XR fragments 
 | 
			
		||||
        xrf.navigator.updateHash(hash)           // which don't require 
 | 
			
		||||
        return resolve(xrf.model)                // positional navigation
 | 
			
		||||
      if( xrf.model && !fileChange && hashChange && !hasPos  ){
 | 
			
		||||
        evalFragment()
 | 
			
		||||
        return resolve(xrf.model)                         // positional navigation
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      xrf
 | 
			
		||||
      .emit('navigateLoading', {url,loader,data})
 | 
			
		||||
      .then( () => {
 | 
			
		||||
        if( hashChange && hasPos ){                 // we're already loaded
 | 
			
		||||
          hashbus.pub( url, xrf.model, flags )     // and eval local URI XR fragments 
 | 
			
		||||
          xrf.navigator.updateHash(hash)
 | 
			
		||||
        if( (!fileChange || !file) && hashChange && hasPos ){                 // we're already loaded
 | 
			
		||||
          evalFragment()
 | 
			
		||||
          xrf.emit('navigateLoaded',{url})
 | 
			
		||||
          return resolve(xrf.model) 
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1829,17 +2052,20 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
        xrf.reset() 
 | 
			
		||||
 | 
			
		||||
        // force relative path for files which dont include protocol or relative path
 | 
			
		||||
        if( dir ) dir = dir[0] == '.' || dir.match("://") ? dir : `.${dir}`
 | 
			
		||||
        url = url.replace(dir,"")
 | 
			
		||||
        loader = loader || new Loader().setPath( dir )
 | 
			
		||||
        if( directory ) directory = directory[0] == '.' || directory.match("://") ? directory : `.${directory}`
 | 
			
		||||
 | 
			
		||||
        loader = loader || new Loader().setPath( URI.URN )
 | 
			
		||||
        const onLoad = (model) => {
 | 
			
		||||
 | 
			
		||||
          model.file = file
 | 
			
		||||
          model.file = URI.file
 | 
			
		||||
          // only change url when loading *another* file
 | 
			
		||||
          if( xrf.model ) xrf.navigator.pushState( `${dir}${file}`, hash )
 | 
			
		||||
          if( xrf.model ){
 | 
			
		||||
            xrf.navigator.pushState( external ? URI.URN + URI.file : URI.file, fragment )
 | 
			
		||||
          }
 | 
			
		||||
          //if( xrf.model ) xrf.navigator.pushState( `${ document.location.pathname != URI.directory ? URI.directory: ''}${URI.file}`, fragment )
 | 
			
		||||
          xrf.model = model 
 | 
			
		||||
 | 
			
		||||
          if( !model.isXRF ) xrf.parseModel(model,url) // this marks the model as an XRF model
 | 
			
		||||
          if( !model.isXRF ) xrf.parseModel(model,url.replace(directory,"")) // this marks the model as an XRF model
 | 
			
		||||
 | 
			
		||||
          if(xrf.debug ) model.animations.map( (a) => console.log("anim: "+a.name) )
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1847,17 +2073,16 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
          xrf.XRWG.generate({model,scene:model.scene})
 | 
			
		||||
 | 
			
		||||
          // spec: 2. init metadata inside model for non-SRC data
 | 
			
		||||
          if( !model.isSRC ){ 
 | 
			
		||||
          if( !model.isSRC ){
 | 
			
		||||
            model.scene.traverse( (mesh) => xrf.parseModel.metadataInMesh(mesh,model) )
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          // spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
 | 
			
		||||
          xrf.frag.defaultPredefinedViews({model,scene:model.scene})
 | 
			
		||||
          // spec: predefined view(s) & objects-of-interest-in-XRWG from URL (https://xrfragment.org/#predefined_view)
 | 
			
		||||
          // spec: predefined view(s) & objects-of-interest-in-XRWG from URI (https://xrfragment.org/#predefined_view)
 | 
			
		||||
          let frag = xrf.hashbus.pub( url, model) // and eval URI XR fragments 
 | 
			
		||||
 | 
			
		||||
          xrf.add( model.scene )
 | 
			
		||||
          if( hash ) xrf.navigator.updateHash(hash)
 | 
			
		||||
          if( fragment ) xrf.navigator.updateHash(fragment)
 | 
			
		||||
          xrf.emit('navigateLoaded',{url,model})
 | 
			
		||||
          resolve(model)
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1866,7 +2091,7 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
          loader.parse(data, "", onLoad )
 | 
			
		||||
        }else{
 | 
			
		||||
          try{
 | 
			
		||||
            loader.load(url, onLoad )
 | 
			
		||||
            loader.load(file, onLoad )
 | 
			
		||||
          }catch(e){ 
 | 
			
		||||
            console.error(e)
 | 
			
		||||
            xrf.emit('navigateError',{url})
 | 
			
		||||
| 
						 | 
				
			
			@ -1880,9 +2105,12 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
xrf.navigator.init = () => {
 | 
			
		||||
  if( xrf.navigator.init.inited ) return
 | 
			
		||||
 | 
			
		||||
  xrf.navigator.URI = xrfragment.URI.parse(document.location.href)
 | 
			
		||||
 | 
			
		||||
  window.addEventListener('popstate', function (event){
 | 
			
		||||
    if( !xrf.navigator.updateHash.active ){ // ignore programmatic hash updates (causes infinite recursion)
 | 
			
		||||
      xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
 | 
			
		||||
      //xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
 | 
			
		||||
      xrf.navigator.to( document.location.href.replace(/\?/,'') )
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  
 | 
			
		||||
| 
						 | 
				
			
			@ -1908,10 +2136,10 @@ xrf.navigator.setupNavigateFallbacks = () => {
 | 
			
		|||
 | 
			
		||||
  xrf.addEventListener('navigate', (opts) => {
 | 
			
		||||
    let {url} = opts
 | 
			
		||||
    let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
    let {fileExt} = xrfragment.URI.parse(url)
 | 
			
		||||
 | 
			
		||||
    // handle http links
 | 
			
		||||
    if( url.match(/^http/) && !xrf.loaders[ext] ){
 | 
			
		||||
    if( url.match(/^http/) && !xrf.loaders[fileExt] ){
 | 
			
		||||
      let inIframe
 | 
			
		||||
      try { inIframe = window.self !== window.top; } catch (e) { inIframe = true; }
 | 
			
		||||
      return inIframe ? window.parent.postMessage({ url }, '*') : window.open( url, '_blank')
 | 
			
		||||
| 
						 | 
				
			
			@ -1931,7 +2159,7 @@ xrf.navigator.setupNavigateFallbacks = () => {
 | 
			
		|||
 | 
			
		||||
xrf.navigator.updateHash = (hash,opts) => {
 | 
			
		||||
  if( hash.replace(/^#/,'') == document.location.hash.substr(1) || hash.match(/\|/) ) return  // skip unnecesary pushState triggers
 | 
			
		||||
  console.log(`URL: ${document.location.search.substr(1)}#${hash}`)
 | 
			
		||||
  console.log(`URI: ${document.location.search.substr(1)}#${hash}`)
 | 
			
		||||
  xrf.navigator.updateHash.active = true  // important to prevent recursion
 | 
			
		||||
  document.location.hash = hash
 | 
			
		||||
  xrf.navigator.updateHash.active = false
 | 
			
		||||
| 
						 | 
				
			
			@ -1942,6 +2170,23 @@ xrf.navigator.pushState = (file,hash) => {
 | 
			
		|||
  window.history.pushState({},`${file}#${hash}`, document.location.pathname + `?${file}#${hash}` )
 | 
			
		||||
  xrf.emit('pushState', {file, hash} )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.navigator.reactifyHash = ( obj ) => {
 | 
			
		||||
  return new Proxy(obj,{
 | 
			
		||||
    get(me,k)  { return me[k] },
 | 
			
		||||
    set(me,k,v){ 
 | 
			
		||||
      me[k] = v 
 | 
			
		||||
      xrf.navigator.to( "#" + this.toString(me) )
 | 
			
		||||
    },
 | 
			
		||||
    toString(me){
 | 
			
		||||
      let parts = []
 | 
			
		||||
      Object.keys(me).map( (k) => {
 | 
			
		||||
        parts.push( me[k] ? `${k}=${encodeURIComponent(me[k])}` : k ) 
 | 
			
		||||
      })
 | 
			
		||||
      return parts.join('&')
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * navigation, portals & mutations
 | 
			
		||||
| 
						 | 
				
			
			@ -1993,7 +2238,6 @@ xrf.frag.href = function(v, opts){
 | 
			
		|||
    .emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
 | 
			
		||||
    .then( () => {
 | 
			
		||||
 | 
			
		||||
      let {urlObj,dir,file,hash,ext} = xrf.parseUrl(v.string)
 | 
			
		||||
      const isLocal = v.string[0] == '#'
 | 
			
		||||
      const hasPos  = isLocal && v.string.match(/pos=/)
 | 
			
		||||
      const flags   = isLocal ? xrf.XRF.PV_OVERRIDE : undefined
 | 
			
		||||
| 
						 | 
				
			
			@ -2153,6 +2397,32 @@ xrf.frag.pos = function(v, opts){
 | 
			
		|||
  camera.updateMatrixWorld()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.frag.pos.get = function(precision,randomize){
 | 
			
		||||
    if( !precision ) precision = 2;
 | 
			
		||||
    if( typeof THREE == 'undefined' ) THREE = xrf.THREE
 | 
			
		||||
    let radToDeg  = THREE.MathUtils.radToDeg
 | 
			
		||||
    let toDeg     = (x) => x / (Math.PI / 180)
 | 
			
		||||
    let camera    = xrf.camera 
 | 
			
		||||
    if( randomize ){
 | 
			
		||||
      camera.position.x += Math.random()/10
 | 
			
		||||
      camera.position.z += Math.random()/10
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // *TODO* add camera direction
 | 
			
		||||
    let direction = new xrf.THREE.Vector3()
 | 
			
		||||
    camera.getWorldDirection(direction)
 | 
			
		||||
    const pitch   = Math.asin(direction.y);
 | 
			
		||||
    const yaw     = Math.atan2(direction.x, direction.z);
 | 
			
		||||
    const pitchInDegrees = pitch * 180 / Math.PI;
 | 
			
		||||
    const yawInDegrees = yaw * 180 / Math.PI;
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      x: String(camera.position.x.toFixed(2)),
 | 
			
		||||
      y: String(camera.position.y.toFixed(2)),
 | 
			
		||||
      z: String(camera.position.z.toFixed(2)),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.addEventListener('reset', (opts) => {
 | 
			
		||||
  // set the player to position 0,0,0
 | 
			
		||||
  xrf.camera.position.set(0,0,0)
 | 
			
		||||
| 
						 | 
				
			
			@ -2207,7 +2477,7 @@ xrf.frag.src = function(v, opts){
 | 
			
		|||
  if( mesh.isSRC ) return // only embed src once 
 | 
			
		||||
 | 
			
		||||
  let url       = xrf.frag.src.expandURI( mesh, v.string )
 | 
			
		||||
  let srcFrag   = opts.srcFrag = xrfragment.URI.parse(url)
 | 
			
		||||
  let srcFrag   = opts.srcFrag = xrfragment.URI.parse(url).XRF
 | 
			
		||||
  opts.isLocal  = v.string[0] == '#'
 | 
			
		||||
  opts.isPortal = xrf.frag.src.renderAsPortal(mesh)
 | 
			
		||||
  opts.isSRC    = mesh.isSRC = true 
 | 
			
		||||
| 
						 | 
				
			
			@ -2294,7 +2564,7 @@ xrf.frag.src.externalSRC = (url,frag,opts) => {
 | 
			
		|||
  fetch(url, { method: 'HEAD' })
 | 
			
		||||
  .then( (res) => {
 | 
			
		||||
    let mimetype = res.headers.get('Content-type')
 | 
			
		||||
    if(xrf.debug != undefined ) console.log("HEAD "+url+" => "+mimetype)
 | 
			
		||||
    if(xrf.debug > 0 ) console.log("HEAD "+url+" => "+mimetype)
 | 
			
		||||
    if( url.replace(/#.*/,'').match(/\.(gltf|glb)$/)     ) mimetype = 'gltf'
 | 
			
		||||
    if( url.replace(/#.*/,'').match(/\.(frag|fs|glsl)$/) ) mimetype = 'x-shader/x-fragment'
 | 
			
		||||
    if( url.replace(/#.*/,'').match(/\.(vert|vs)$/)      ) mimetype = 'x-shader/x-fragment'
 | 
			
		||||
| 
						 | 
				
			
			@ -3195,8 +3465,8 @@ xrf.addEventListener('render', (opts) => {
 | 
			
		|||
 | 
			
		||||
let loadAudio = (mimetype) => function(url,opts){
 | 
			
		||||
  let {mesh,src,camera,THREE} = opts
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
  let frag = xrf.URI.parse( url )
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  xrf.init.audio()
 | 
			
		||||
  let isPositionalAudio = !(mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -3207,8 +3477,8 @@ let loadAudio = (mimetype) => function(url,opts){
 | 
			
		|||
  mesh.media = mesh.media || {}
 | 
			
		||||
  mesh.media.audio = { set: (mediafragment,v) => mesh.media.audio[mediafragment] = v }
 | 
			
		||||
 | 
			
		||||
  let finalUrl = url.replace(/#.*/,'')
 | 
			
		||||
  if( xrf.debug != undefined ) console.log("GET "+finalUrl)
 | 
			
		||||
  let finalUrl = URL.URN + URL.file 
 | 
			
		||||
  if( xrf.debug > 0 ) console.log("GET "+finalUrl)
 | 
			
		||||
  audioLoader.load( finalUrl, function( buffer ) {
 | 
			
		||||
 | 
			
		||||
    sound.setBuffer( buffer );
 | 
			
		||||
| 
						 | 
				
			
			@ -3318,7 +3588,8 @@ audioMimeTypes.map( (mimetype) =>  xrf.frag.src.type[ mimetype ] = loadAudio(mim
 | 
			
		|||
xrf.frag.src.type['fbx'] = function( url, opts ){
 | 
			
		||||
  return new Promise( async (resolve,reject) => {
 | 
			
		||||
    let {mesh,src} = opts
 | 
			
		||||
    let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
    let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
    let frag = URL.XRF 
 | 
			
		||||
    let loader
 | 
			
		||||
 | 
			
		||||
    let {THREE}        = await import('https://unpkg.com/three@0.161.0/build/three.module.js')
 | 
			
		||||
| 
						 | 
				
			
			@ -3346,14 +3617,17 @@ xrf.frag.src.type['fbx'] = function( url, opts ){
 | 
			
		|||
xrf.frag.src.type['x-shader/x-fragment'] = function(url,opts){
 | 
			
		||||
  let {mesh,THREE} = opts
 | 
			
		||||
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  let isFragmentShader = /\.(fs|frag|glsl)$/
 | 
			
		||||
  let isVertexShader   = /\.(vs|vert)$/
 | 
			
		||||
 | 
			
		||||
  let shaderReqs = []
 | 
			
		||||
  let shaderCode = {}
 | 
			
		||||
  let shader   = {
 | 
			
		||||
    fragment: { code: '', url: url.match( isFragmentShader ) ? url : '' },
 | 
			
		||||
    vertex:   { code: '', url: url.match( isVertexShader   ) ? url : '' }
 | 
			
		||||
    fragment: { code: '', url: url.match( isFragmentShader ) ? URL.URN + URL.file : '' },
 | 
			
		||||
    vertex:   { code: '', url: url.match( isVertexShader   ) ? URL.URN + URL.file : '' }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  var onShaderLoaded = ((args) => (type, status, code) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -3412,19 +3686,15 @@ xrf.frag.src.type['x-shader/x-vertex']   = xrf.frag.src.type['x-shader/x-fragmen
 | 
			
		|||
xrf.frag.src.type['gltf'] = function( url, opts ){
 | 
			
		||||
  return new Promise( (resolve,reject) => {
 | 
			
		||||
    let {mesh,src} = opts
 | 
			
		||||
    let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
    let URL = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
    let {directory,file,fileExt,URN} = URL;
 | 
			
		||||
    let loader
 | 
			
		||||
 | 
			
		||||
    const Loader = xrf.loaders[ext]
 | 
			
		||||
    const Loader = xrf.loaders[fileExt]
 | 
			
		||||
    if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext 
 | 
			
		||||
    if( !dir.match("://") ){ // force relative path 
 | 
			
		||||
      dir = dir.substr(0,2) == './' ? dir : `./${dir}`
 | 
			
		||||
      loader = new Loader().setPath( dir )
 | 
			
		||||
    }else{
 | 
			
		||||
      loader = new Loader() 
 | 
			
		||||
    }
 | 
			
		||||
    loader = new Loader().setPath( URN )
 | 
			
		||||
 | 
			
		||||
    loader.load(url, (model) => {
 | 
			
		||||
    loader.load(file, (model) => {
 | 
			
		||||
      model.isSRC = true
 | 
			
		||||
      resolve(model)
 | 
			
		||||
    })
 | 
			
		||||
| 
						 | 
				
			
			@ -3435,7 +3705,7 @@ xrf.frag.src.type['gltf'] = function( url, opts ){
 | 
			
		|||
let loadHTML = (mimetype) => function(url,opts){
 | 
			
		||||
  let {mesh,src,camera} = opts
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
  let frag = xrf.URI.parse( url )
 | 
			
		||||
  let frag = xrf.URI.parse( url ).XRF
 | 
			
		||||
  console.warn("todo: html viewer for src not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3452,6 +3722,8 @@ htmlMimeTypes.map( (mimetype) =>  xrf.frag.src.type[ mimetype ] = loadHTML(mimet
 | 
			
		|||
xrf.frag.src.type['image/png'] = function(url,opts){
 | 
			
		||||
  let {mesh,THREE} = opts
 | 
			
		||||
  let restrictTo3DBoundingBox = mesh.geometry
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  mesh.material = new xrf.THREE.MeshBasicMaterial({ 
 | 
			
		||||
    map: null, 
 | 
			
		||||
| 
						 | 
				
			
			@ -3495,7 +3767,7 @@ xrf.frag.src.type['image/png'] = function(url,opts){
 | 
			
		|||
    renderImage(texture)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  new THREE.TextureLoader().load( url, onLoad, null, console.error );
 | 
			
		||||
  new THREE.TextureLoader().load( URL.URN + URL.file, onLoad, null, console.error );
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3701,9 +3973,9 @@ xrf.portalNonEuclidian.stencilRef = 1
 | 
			
		|||
 | 
			
		||||
let loadVideo = (mimetype) => function(url,opts){
 | 
			
		||||
  let {mesh,src,camera} = opts
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
  const THREE = xrf.THREE
 | 
			
		||||
  let frag = xrf.URI.parse( url )
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  mesh.media = mesh.media || {}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3725,7 +3997,7 @@ let loadVideo = (mimetype) => function(url,opts){
 | 
			
		|||
    },false)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  video.src = url
 | 
			
		||||
  video.src = URL.URN + URL.file 
 | 
			
		||||
  video.speed = 1.0
 | 
			
		||||
  video.looping = false
 | 
			
		||||
  video.set = (mediafragment,v) => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										426
									
								
								dist/xrfragment.three.module.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										426
									
								
								dist/xrfragment.three.module.js
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * v0.5.1 generated at Tue Mar 19 10:04:25 AM UTC 2024
 | 
			
		||||
 * v0.5.1 generated at Tue Apr 16 12:47:01 PM UTC 2024
 | 
			
		||||
 * https://xrfragment.org
 | 
			
		||||
 * SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -1138,9 +1138,13 @@ xrfragment_Parser.getMetaData = function() {
 | 
			
		|||
	var meta = { title : ["title","og:title","dc.title"], description : ["aria-description","og:description","dc.description"], author : ["author","dc.creator"], publisher : ["publisher","dc.publisher"], website : ["og:site_name","og:url","dc.publisher"], license : ["SPDX","dc.rights"]};
 | 
			
		||||
	return meta;
 | 
			
		||||
};
 | 
			
		||||
var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() { };
 | 
			
		||||
var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() {
 | 
			
		||||
	this.XRF = { };
 | 
			
		||||
	this.hash = { };
 | 
			
		||||
	this.fragment = "";
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.__name__ = true;
 | 
			
		||||
xrfragment_URI.parse = function(url,filter) {
 | 
			
		||||
xrfragment_URI.parseFragment = function(url,filter) {
 | 
			
		||||
	var store = { };
 | 
			
		||||
	if(url == null || url.indexOf("#") == -1) {
 | 
			
		||||
		return store;
 | 
			
		||||
| 
						 | 
				
			
			@ -1192,6 +1196,232 @@ xrfragment_URI.template = function(uri,vars) {
 | 
			
		|||
	parts[1] = frag;
 | 
			
		||||
	return parts.join("#");
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.parse = function(stringUrl,flags) {
 | 
			
		||||
	var r = new EReg("^(?:(?![^:@]+:[^:@/]*@)([^:/?#.]+):)?(?://)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:/?#]*)(?::(\\d*))?)(((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[?#]|$)))*/?)?([^?#/]*))(?:\\?([^#]*))?(?:#(.*))?)","");
 | 
			
		||||
	if(stringUrl.indexOf("://") == -1 && stringUrl.charAt(0) != "/") {
 | 
			
		||||
		stringUrl = "/" + stringUrl;
 | 
			
		||||
	}
 | 
			
		||||
	r.match(stringUrl);
 | 
			
		||||
	var url = new xrfragment_URI();
 | 
			
		||||
	var _g = 0;
 | 
			
		||||
	var _g1 = xrfragment_URI._parts.length;
 | 
			
		||||
	while(_g < _g1) {
 | 
			
		||||
		var i = _g++;
 | 
			
		||||
		url[xrfragment_URI._parts[i]] = r.matched(i);
 | 
			
		||||
	}
 | 
			
		||||
	if(xrfragment_URI.isRelative(url) == true) {
 | 
			
		||||
		if(url.directory == null && url.host != null) {
 | 
			
		||||
			url.file = url.host;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	url.hash = { };
 | 
			
		||||
	if(url.fragment != null && url.fragment.length > 0) {
 | 
			
		||||
		url.XRF = xrfragment_URI.parseFragment("#" + url.fragment,flags);
 | 
			
		||||
		var key;
 | 
			
		||||
		var _g = 0;
 | 
			
		||||
		var _g1 = Reflect.fields(url.XRF);
 | 
			
		||||
		while(_g < _g1.length) {
 | 
			
		||||
			var key = _g1[_g];
 | 
			
		||||
			++_g;
 | 
			
		||||
			var v = url.XRF[key];
 | 
			
		||||
			url.hash[key] = v["string"];
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	xrfragment_URI.computeVars(url);
 | 
			
		||||
	return url;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.computeVars = function(url) {
 | 
			
		||||
	var r_r = new RegExp("//","g".split("u").join(""));
 | 
			
		||||
	if(url.directory != null && url.directory.indexOf("//") != -1) {
 | 
			
		||||
		url.directory = url.directory.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	if(url.path != null && url.path.indexOf("//") != -1) {
 | 
			
		||||
		url.path = url.path.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	if(url.file != null && url.file.indexOf("//") != -1) {
 | 
			
		||||
		url.file = url.file.replace(r_r,"/");
 | 
			
		||||
	}
 | 
			
		||||
	url.URN = url.scheme + "://" + url.host;
 | 
			
		||||
	if(url.port != null) {
 | 
			
		||||
		url.URN += ":" + url.port;
 | 
			
		||||
	}
 | 
			
		||||
	url.URN += url.directory;
 | 
			
		||||
	if(url.file != null) {
 | 
			
		||||
		var parts = url.file.split(".");
 | 
			
		||||
		if(parts.length > 1) {
 | 
			
		||||
			url.fileExt = parts.pop();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.toString = function(url) {
 | 
			
		||||
	var result = "";
 | 
			
		||||
	if(url.scheme != null) {
 | 
			
		||||
		result += url.scheme + "://";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.user != null) {
 | 
			
		||||
		result += url.user + ":";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.password != null) {
 | 
			
		||||
		result += url.password + "@";
 | 
			
		||||
	}
 | 
			
		||||
	if(url.host != null) {
 | 
			
		||||
		result += url.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.port != null) {
 | 
			
		||||
		result += ":" + url.port;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		result += url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.file != null) {
 | 
			
		||||
		result += url.file;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.query != null) {
 | 
			
		||||
		result += "?" + url.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.fragment != null) {
 | 
			
		||||
		result += "#" + url.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendURI = function(url,appendedURI) {
 | 
			
		||||
	if(xrfragment_URI.isRelative(url) == true) {
 | 
			
		||||
		return xrfragment_URI.appendToRelativeURI(url,appendedURI);
 | 
			
		||||
	} else {
 | 
			
		||||
		return xrfragment_URI.appendToAbsoluteURI(url,appendedURI);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.isRelative = function(url) {
 | 
			
		||||
	return url.scheme == null;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendToRelativeURI = function(url,appendedURI) {
 | 
			
		||||
	if(url.directory == null || url.host == null) {
 | 
			
		||||
		return xrfragment_URI.cloneURI(appendedURI);
 | 
			
		||||
	}
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	resultURI.host = url.host;
 | 
			
		||||
	resultURI.directory = url.directory;
 | 
			
		||||
	if(appendedURI.host != null) {
 | 
			
		||||
		resultURI.directory += appendedURI.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.directory != null) {
 | 
			
		||||
		var directory = appendedURI.directory;
 | 
			
		||||
		if(appendedURI.host == null) {
 | 
			
		||||
			resultURI.directory += HxOverrides.substr(directory,1,null);
 | 
			
		||||
		} else {
 | 
			
		||||
			resultURI.directory += directory;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.file != null) {
 | 
			
		||||
		resultURI.file = appendedURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(appendedURI.query != null) {
 | 
			
		||||
		resultURI.query = appendedURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = appendedURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.appendToAbsoluteURI = function(url,appendedURI) {
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	if(url.scheme != null) {
 | 
			
		||||
		resultURI.scheme = url.scheme;
 | 
			
		||||
	}
 | 
			
		||||
	if(url.host != null) {
 | 
			
		||||
		resultURI.host = url.host;
 | 
			
		||||
	}
 | 
			
		||||
	var directory = "";
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		directory = url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.host != null) {
 | 
			
		||||
		appendedURI.directory += appendedURI.host;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.directory != null) {
 | 
			
		||||
		directory += appendedURI.directory;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.directory = directory;
 | 
			
		||||
	if(appendedURI.file != null) {
 | 
			
		||||
		resultURI.file = appendedURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(appendedURI.query != null) {
 | 
			
		||||
		resultURI.query = appendedURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(appendedURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = appendedURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.toAbsolute = function(url,newUrl) {
 | 
			
		||||
	var newURI = xrfragment_URI.parse(newUrl,0);
 | 
			
		||||
	var resultURI = new xrfragment_URI();
 | 
			
		||||
	resultURI.port = url.port;
 | 
			
		||||
	resultURI.source = newUrl;
 | 
			
		||||
	if(newURI.scheme != null) {
 | 
			
		||||
		resultURI.scheme = newURI.scheme;
 | 
			
		||||
	} else {
 | 
			
		||||
		resultURI.scheme = url.scheme;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.host != null && newURI.host.length > 0) {
 | 
			
		||||
		resultURI.host = newURI.host;
 | 
			
		||||
		resultURI.port = null;
 | 
			
		||||
		resultURI.fragment = null;
 | 
			
		||||
		resultURI.hash = { };
 | 
			
		||||
		resultURI.XRF = { };
 | 
			
		||||
		if(newURI.port != null) {
 | 
			
		||||
			resultURI.port = newURI.port;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		resultURI.host = url.host;
 | 
			
		||||
	}
 | 
			
		||||
	var directory = "";
 | 
			
		||||
	if(url.directory != null) {
 | 
			
		||||
		directory = url.directory;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.directory != null) {
 | 
			
		||||
		if(newUrl.charAt(0) != "/" && newUrl.indexOf("://") == -1) {
 | 
			
		||||
			directory += newURI.directory;
 | 
			
		||||
		} else {
 | 
			
		||||
			directory = newURI.directory;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.directory = directory;
 | 
			
		||||
	if(newURI.file != null) {
 | 
			
		||||
		resultURI.file = newURI.file;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.path = resultURI.directory + resultURI.file;
 | 
			
		||||
	if(newURI.query != null) {
 | 
			
		||||
		resultURI.query = newURI.query;
 | 
			
		||||
	}
 | 
			
		||||
	if(newURI.fragment != null) {
 | 
			
		||||
		resultURI.fragment = newURI.fragment;
 | 
			
		||||
	}
 | 
			
		||||
	resultURI.hash = newURI.hash;
 | 
			
		||||
	resultURI.XRF = newURI.XRF;
 | 
			
		||||
	xrfragment_URI.computeVars(resultURI);
 | 
			
		||||
	return resultURI;
 | 
			
		||||
};
 | 
			
		||||
xrfragment_URI.cloneURI = function(url) {
 | 
			
		||||
	var clonedURI = new xrfragment_URI();
 | 
			
		||||
	clonedURI.url = url.url;
 | 
			
		||||
	clonedURI.source = url.source;
 | 
			
		||||
	clonedURI.scheme = url.scheme;
 | 
			
		||||
	clonedURI.authority = url.authority;
 | 
			
		||||
	clonedURI.userInfo = url.userInfo;
 | 
			
		||||
	clonedURI.password = url.password;
 | 
			
		||||
	clonedURI.host = url.host;
 | 
			
		||||
	clonedURI.port = url.port;
 | 
			
		||||
	clonedURI.relative = url.relative;
 | 
			
		||||
	clonedURI.path = url.path;
 | 
			
		||||
	clonedURI.directory = url.directory;
 | 
			
		||||
	clonedURI.file = url.file;
 | 
			
		||||
	clonedURI.query = url.query;
 | 
			
		||||
	clonedURI.fragment = url.fragment;
 | 
			
		||||
	return clonedURI;
 | 
			
		||||
};
 | 
			
		||||
var xrfragment_XRF = $hx_exports["xrfragment"]["XRF"] = function(_fragment,_flags,_index) {
 | 
			
		||||
	this.floats = [];
 | 
			
		||||
	this.shift = [];
 | 
			
		||||
| 
						 | 
				
			
			@ -1302,6 +1532,7 @@ haxe_Template.hxKeepArrayIterator = new haxe_iterators_ArrayIterator([]);
 | 
			
		|||
xrfragment_Parser.error = "";
 | 
			
		||||
xrfragment_Parser.debug = false;
 | 
			
		||||
xrfragment_URI.__meta__ = { statics : { template : { keep : null}}};
 | 
			
		||||
xrfragment_URI._parts = ["source","scheme","authority","userInfo","user","password","host","port","relative","path","directory","file","query","fragment"];
 | 
			
		||||
xrfragment_XRF.IMMUTABLE = 1;
 | 
			
		||||
xrfragment_XRF.PROP_BIND = 2;
 | 
			
		||||
xrfragment_XRF.QUERY_OPERATOR = 4;
 | 
			
		||||
| 
						 | 
				
			
			@ -1589,7 +1820,7 @@ let pub = function( url, node_or_model, flags ){  // evaluate fragments in url
 | 
			
		|||
  if( !url ) return 
 | 
			
		||||
  if( !url.match(/#/) ) url = `#${url}`
 | 
			
		||||
  let { THREE, camera } = xrf
 | 
			
		||||
  let frag     = xrf.URI.parse( url, flags )
 | 
			
		||||
  let frag     = xrf.URI.parse( url, flags ).XRF
 | 
			
		||||
  let fromNode = node_or_model != xrf.model
 | 
			
		||||
  let isNode   = node_or_model && node_or_model.children
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1756,24 +1987,6 @@ xrf.reset = () => {
 | 
			
		|||
  xrf.layers = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.parseUrl = (url) => {
 | 
			
		||||
  let urlExHash = url.replace(/#.*/,'')
 | 
			
		||||
  let urlObj,file
 | 
			
		||||
  let   store = {}
 | 
			
		||||
  try{
 | 
			
		||||
    urlObj = new URL( urlExHash.match(/:\/\//) ? urlExHash : String(`https://fake.com/${url}`).replace(/\/\//,'/') )
 | 
			
		||||
    file = urlObj.pathname.substring(urlObj.pathname.lastIndexOf('/') + 1);
 | 
			
		||||
    let   search = urlObj.search.substr(1).split("&")
 | 
			
		||||
    for( let i in search )  store[  (search[i].split("=")[0])  ]  = search[i].split("=")[1] || ''
 | 
			
		||||
  }catch(e){ }
 | 
			
		||||
  let   hashmap = url.match("#") ? url.replace(/.*#/,'').split("&") : []
 | 
			
		||||
  for( let i in hashmap ) store[  (hashmap[i].split("=")[0]) ]  = hashmap[i].split("=")[1] || ''
 | 
			
		||||
  let   dir  = url.substring(0, url.lastIndexOf('/') + 1)
 | 
			
		||||
  const hash = url.match(/#/) ? url.replace(/.*#/,'') : ''
 | 
			
		||||
  const ext  = file.split('.').pop()
 | 
			
		||||
  return {urlObj,dir,file,hash,ext,store}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.add = (object) => {
 | 
			
		||||
  object.isXRF = true // mark for easy deletion when replacing scene
 | 
			
		||||
  xrf.scene.add(object)
 | 
			
		||||
| 
						 | 
				
			
			@ -1784,42 +1997,52 @@ xrf.hasNoMaterial = (mesh) => {
 | 
			
		|||
  const hasMaterialName   = mesh.material && mesh.material.name.length > 0 
 | 
			
		||||
  return mesh.geometry && !hasMaterialName && !hasTexture
 | 
			
		||||
}
 | 
			
		||||
xrf.navigator = {}
 | 
			
		||||
xrf.navigator = {URI:{}}
 | 
			
		||||
 | 
			
		||||
xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		||||
  if( !url ) throw 'xrf.navigator.to(..) no url given'
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.navigator.origin = xrf.parseUrl(url)
 | 
			
		||||
  let hashChange = (!file && hash) || !data && xrf.model.file == file
 | 
			
		||||
  let hasPos     = String(hash).match(/pos=/)
 | 
			
		||||
 | 
			
		||||
  let URI = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  URI.hash          = xrf.navigator.reactifyHash(URI.hash)
 | 
			
		||||
  let fileChange    = URI.URN + URI.file != xrf.navigator.URI.URN + xrf.navigator.URI.file 
 | 
			
		||||
  let external      = URI.URN != document.location.origin + document.location.pathname 
 | 
			
		||||
  let hasPos        = URI.hash.pos 
 | 
			
		||||
  let hashChange    = String(xrf.navigator.URI.fragment||"") != String(URI.fragment||"")
 | 
			
		||||
  let hashbus       = xrf.hashbus
 | 
			
		||||
  xrf.navigator.URI = URI
 | 
			
		||||
  let {directory,file,fragment,fileExt} = URI;
 | 
			
		||||
 | 
			
		||||
  let hashbus = xrf.hashbus
 | 
			
		||||
  const evalFragment  = () => {
 | 
			
		||||
    if( URI.fragment ){
 | 
			
		||||
      hashbus.pub( URI.fragment, xrf.model, flags )     // eval local URI XR fragments 
 | 
			
		||||
      xrf.navigator.updateHash(fragment)                // which don't require 
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return new Promise( (resolve,reject) => {
 | 
			
		||||
    xrf
 | 
			
		||||
    .emit('navigate', {url,loader,data})
 | 
			
		||||
    .then( () => {
 | 
			
		||||
 | 
			
		||||
      if( ext && !loader ){  
 | 
			
		||||
        const Loader = xrf.loaders[ext]
 | 
			
		||||
      const Loader = xrf.loaders[fileExt]
 | 
			
		||||
 | 
			
		||||
      if( fileExt && !loader ){  
 | 
			
		||||
        if( !Loader ) return resolve()
 | 
			
		||||
        loader = loader || new Loader().setPath( dir )
 | 
			
		||||
        loader = loader || new Loader().setPath( URI.URN )
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if( !hash && !file && !ext ) return resolve(xrf.model) // nothing we can do here
 | 
			
		||||
      if( !URI.fragment && !URI.file && !URI.fileExt ) return resolve(xrf.model) // nothing we can do here
 | 
			
		||||
 | 
			
		||||
      if( hashChange && !hasPos ){
 | 
			
		||||
        hashbus.pub( url, xrf.model, flags )     // eval local URI XR fragments 
 | 
			
		||||
        xrf.navigator.updateHash(hash)           // which don't require 
 | 
			
		||||
        return resolve(xrf.model)                // positional navigation
 | 
			
		||||
      if( xrf.model && !fileChange && hashChange && !hasPos  ){
 | 
			
		||||
        evalFragment()
 | 
			
		||||
        return resolve(xrf.model)                         // positional navigation
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      xrf
 | 
			
		||||
      .emit('navigateLoading', {url,loader,data})
 | 
			
		||||
      .then( () => {
 | 
			
		||||
        if( hashChange && hasPos ){                 // we're already loaded
 | 
			
		||||
          hashbus.pub( url, xrf.model, flags )     // and eval local URI XR fragments 
 | 
			
		||||
          xrf.navigator.updateHash(hash)
 | 
			
		||||
        if( (!fileChange || !file) && hashChange && hasPos ){                 // we're already loaded
 | 
			
		||||
          evalFragment()
 | 
			
		||||
          xrf.emit('navigateLoaded',{url})
 | 
			
		||||
          return resolve(xrf.model) 
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1829,17 +2052,20 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
        xrf.reset() 
 | 
			
		||||
 | 
			
		||||
        // force relative path for files which dont include protocol or relative path
 | 
			
		||||
        if( dir ) dir = dir[0] == '.' || dir.match("://") ? dir : `.${dir}`
 | 
			
		||||
        url = url.replace(dir,"")
 | 
			
		||||
        loader = loader || new Loader().setPath( dir )
 | 
			
		||||
        if( directory ) directory = directory[0] == '.' || directory.match("://") ? directory : `.${directory}`
 | 
			
		||||
 | 
			
		||||
        loader = loader || new Loader().setPath( URI.URN )
 | 
			
		||||
        const onLoad = (model) => {
 | 
			
		||||
 | 
			
		||||
          model.file = file
 | 
			
		||||
          model.file = URI.file
 | 
			
		||||
          // only change url when loading *another* file
 | 
			
		||||
          if( xrf.model ) xrf.navigator.pushState( `${dir}${file}`, hash )
 | 
			
		||||
          if( xrf.model ){
 | 
			
		||||
            xrf.navigator.pushState( external ? URI.URN + URI.file : URI.file, fragment )
 | 
			
		||||
          }
 | 
			
		||||
          //if( xrf.model ) xrf.navigator.pushState( `${ document.location.pathname != URI.directory ? URI.directory: ''}${URI.file}`, fragment )
 | 
			
		||||
          xrf.model = model 
 | 
			
		||||
 | 
			
		||||
          if( !model.isXRF ) xrf.parseModel(model,url) // this marks the model as an XRF model
 | 
			
		||||
          if( !model.isXRF ) xrf.parseModel(model,url.replace(directory,"")) // this marks the model as an XRF model
 | 
			
		||||
 | 
			
		||||
          if(xrf.debug ) model.animations.map( (a) => console.log("anim: "+a.name) )
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1847,17 +2073,16 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
          xrf.XRWG.generate({model,scene:model.scene})
 | 
			
		||||
 | 
			
		||||
          // spec: 2. init metadata inside model for non-SRC data
 | 
			
		||||
          if( !model.isSRC ){ 
 | 
			
		||||
          if( !model.isSRC ){
 | 
			
		||||
            model.scene.traverse( (mesh) => xrf.parseModel.metadataInMesh(mesh,model) )
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          // spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
 | 
			
		||||
          xrf.frag.defaultPredefinedViews({model,scene:model.scene})
 | 
			
		||||
          // spec: predefined view(s) & objects-of-interest-in-XRWG from URL (https://xrfragment.org/#predefined_view)
 | 
			
		||||
          // spec: predefined view(s) & objects-of-interest-in-XRWG from URI (https://xrfragment.org/#predefined_view)
 | 
			
		||||
          let frag = xrf.hashbus.pub( url, model) // and eval URI XR fragments 
 | 
			
		||||
 | 
			
		||||
          xrf.add( model.scene )
 | 
			
		||||
          if( hash ) xrf.navigator.updateHash(hash)
 | 
			
		||||
          if( fragment ) xrf.navigator.updateHash(fragment)
 | 
			
		||||
          xrf.emit('navigateLoaded',{url,model})
 | 
			
		||||
          resolve(model)
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1866,7 +2091,7 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
          loader.parse(data, "", onLoad )
 | 
			
		||||
        }else{
 | 
			
		||||
          try{
 | 
			
		||||
            loader.load(url, onLoad )
 | 
			
		||||
            loader.load(file, onLoad )
 | 
			
		||||
          }catch(e){ 
 | 
			
		||||
            console.error(e)
 | 
			
		||||
            xrf.emit('navigateError',{url})
 | 
			
		||||
| 
						 | 
				
			
			@ -1880,9 +2105,12 @@ xrf.navigator.to = (url,flags,loader,data) => {
 | 
			
		|||
xrf.navigator.init = () => {
 | 
			
		||||
  if( xrf.navigator.init.inited ) return
 | 
			
		||||
 | 
			
		||||
  xrf.navigator.URI = xrfragment.URI.parse(document.location.href)
 | 
			
		||||
 | 
			
		||||
  window.addEventListener('popstate', function (event){
 | 
			
		||||
    if( !xrf.navigator.updateHash.active ){ // ignore programmatic hash updates (causes infinite recursion)
 | 
			
		||||
      xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
 | 
			
		||||
      //xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
 | 
			
		||||
      xrf.navigator.to( document.location.href.replace(/\?/,'') )
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  
 | 
			
		||||
| 
						 | 
				
			
			@ -1908,10 +2136,10 @@ xrf.navigator.setupNavigateFallbacks = () => {
 | 
			
		|||
 | 
			
		||||
  xrf.addEventListener('navigate', (opts) => {
 | 
			
		||||
    let {url} = opts
 | 
			
		||||
    let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
    let {fileExt} = xrfragment.URI.parse(url)
 | 
			
		||||
 | 
			
		||||
    // handle http links
 | 
			
		||||
    if( url.match(/^http/) && !xrf.loaders[ext] ){
 | 
			
		||||
    if( url.match(/^http/) && !xrf.loaders[fileExt] ){
 | 
			
		||||
      let inIframe
 | 
			
		||||
      try { inIframe = window.self !== window.top; } catch (e) { inIframe = true; }
 | 
			
		||||
      return inIframe ? window.parent.postMessage({ url }, '*') : window.open( url, '_blank')
 | 
			
		||||
| 
						 | 
				
			
			@ -1931,7 +2159,7 @@ xrf.navigator.setupNavigateFallbacks = () => {
 | 
			
		|||
 | 
			
		||||
xrf.navigator.updateHash = (hash,opts) => {
 | 
			
		||||
  if( hash.replace(/^#/,'') == document.location.hash.substr(1) || hash.match(/\|/) ) return  // skip unnecesary pushState triggers
 | 
			
		||||
  console.log(`URL: ${document.location.search.substr(1)}#${hash}`)
 | 
			
		||||
  console.log(`URI: ${document.location.search.substr(1)}#${hash}`)
 | 
			
		||||
  xrf.navigator.updateHash.active = true  // important to prevent recursion
 | 
			
		||||
  document.location.hash = hash
 | 
			
		||||
  xrf.navigator.updateHash.active = false
 | 
			
		||||
| 
						 | 
				
			
			@ -1942,6 +2170,23 @@ xrf.navigator.pushState = (file,hash) => {
 | 
			
		|||
  window.history.pushState({},`${file}#${hash}`, document.location.pathname + `?${file}#${hash}` )
 | 
			
		||||
  xrf.emit('pushState', {file, hash} )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.navigator.reactifyHash = ( obj ) => {
 | 
			
		||||
  return new Proxy(obj,{
 | 
			
		||||
    get(me,k)  { return me[k] },
 | 
			
		||||
    set(me,k,v){ 
 | 
			
		||||
      me[k] = v 
 | 
			
		||||
      xrf.navigator.to( "#" + this.toString(me) )
 | 
			
		||||
    },
 | 
			
		||||
    toString(me){
 | 
			
		||||
      let parts = []
 | 
			
		||||
      Object.keys(me).map( (k) => {
 | 
			
		||||
        parts.push( me[k] ? `${k}=${encodeURIComponent(me[k])}` : k ) 
 | 
			
		||||
      })
 | 
			
		||||
      return parts.join('&')
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * navigation, portals & mutations
 | 
			
		||||
| 
						 | 
				
			
			@ -1993,7 +2238,6 @@ xrf.frag.href = function(v, opts){
 | 
			
		|||
    .emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
 | 
			
		||||
    .then( () => {
 | 
			
		||||
 | 
			
		||||
      let {urlObj,dir,file,hash,ext} = xrf.parseUrl(v.string)
 | 
			
		||||
      const isLocal = v.string[0] == '#'
 | 
			
		||||
      const hasPos  = isLocal && v.string.match(/pos=/)
 | 
			
		||||
      const flags   = isLocal ? xrf.XRF.PV_OVERRIDE : undefined
 | 
			
		||||
| 
						 | 
				
			
			@ -2153,6 +2397,32 @@ xrf.frag.pos = function(v, opts){
 | 
			
		|||
  camera.updateMatrixWorld()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.frag.pos.get = function(precision,randomize){
 | 
			
		||||
    if( !precision ) precision = 2;
 | 
			
		||||
    if( typeof THREE == 'undefined' ) THREE = xrf.THREE
 | 
			
		||||
    let radToDeg  = THREE.MathUtils.radToDeg
 | 
			
		||||
    let toDeg     = (x) => x / (Math.PI / 180)
 | 
			
		||||
    let camera    = xrf.camera 
 | 
			
		||||
    if( randomize ){
 | 
			
		||||
      camera.position.x += Math.random()/10
 | 
			
		||||
      camera.position.z += Math.random()/10
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // *TODO* add camera direction
 | 
			
		||||
    let direction = new xrf.THREE.Vector3()
 | 
			
		||||
    camera.getWorldDirection(direction)
 | 
			
		||||
    const pitch   = Math.asin(direction.y);
 | 
			
		||||
    const yaw     = Math.atan2(direction.x, direction.z);
 | 
			
		||||
    const pitchInDegrees = pitch * 180 / Math.PI;
 | 
			
		||||
    const yawInDegrees = yaw * 180 / Math.PI;
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      x: String(camera.position.x.toFixed(2)),
 | 
			
		||||
      y: String(camera.position.y.toFixed(2)),
 | 
			
		||||
      z: String(camera.position.z.toFixed(2)),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
xrf.addEventListener('reset', (opts) => {
 | 
			
		||||
  // set the player to position 0,0,0
 | 
			
		||||
  xrf.camera.position.set(0,0,0)
 | 
			
		||||
| 
						 | 
				
			
			@ -2207,7 +2477,7 @@ xrf.frag.src = function(v, opts){
 | 
			
		|||
  if( mesh.isSRC ) return // only embed src once 
 | 
			
		||||
 | 
			
		||||
  let url       = xrf.frag.src.expandURI( mesh, v.string )
 | 
			
		||||
  let srcFrag   = opts.srcFrag = xrfragment.URI.parse(url)
 | 
			
		||||
  let srcFrag   = opts.srcFrag = xrfragment.URI.parse(url).XRF
 | 
			
		||||
  opts.isLocal  = v.string[0] == '#'
 | 
			
		||||
  opts.isPortal = xrf.frag.src.renderAsPortal(mesh)
 | 
			
		||||
  opts.isSRC    = mesh.isSRC = true 
 | 
			
		||||
| 
						 | 
				
			
			@ -2294,7 +2564,7 @@ xrf.frag.src.externalSRC = (url,frag,opts) => {
 | 
			
		|||
  fetch(url, { method: 'HEAD' })
 | 
			
		||||
  .then( (res) => {
 | 
			
		||||
    let mimetype = res.headers.get('Content-type')
 | 
			
		||||
    if(xrf.debug != undefined ) console.log("HEAD "+url+" => "+mimetype)
 | 
			
		||||
    if(xrf.debug > 0 ) console.log("HEAD "+url+" => "+mimetype)
 | 
			
		||||
    if( url.replace(/#.*/,'').match(/\.(gltf|glb)$/)     ) mimetype = 'gltf'
 | 
			
		||||
    if( url.replace(/#.*/,'').match(/\.(frag|fs|glsl)$/) ) mimetype = 'x-shader/x-fragment'
 | 
			
		||||
    if( url.replace(/#.*/,'').match(/\.(vert|vs)$/)      ) mimetype = 'x-shader/x-fragment'
 | 
			
		||||
| 
						 | 
				
			
			@ -3195,8 +3465,8 @@ xrf.addEventListener('render', (opts) => {
 | 
			
		|||
 | 
			
		||||
let loadAudio = (mimetype) => function(url,opts){
 | 
			
		||||
  let {mesh,src,camera,THREE} = opts
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
  let frag = xrf.URI.parse( url )
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  xrf.init.audio()
 | 
			
		||||
  let isPositionalAudio = !(mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -3207,8 +3477,8 @@ let loadAudio = (mimetype) => function(url,opts){
 | 
			
		|||
  mesh.media = mesh.media || {}
 | 
			
		||||
  mesh.media.audio = { set: (mediafragment,v) => mesh.media.audio[mediafragment] = v }
 | 
			
		||||
 | 
			
		||||
  let finalUrl = url.replace(/#.*/,'')
 | 
			
		||||
  if( xrf.debug != undefined ) console.log("GET "+finalUrl)
 | 
			
		||||
  let finalUrl = URL.URN + URL.file 
 | 
			
		||||
  if( xrf.debug > 0 ) console.log("GET "+finalUrl)
 | 
			
		||||
  audioLoader.load( finalUrl, function( buffer ) {
 | 
			
		||||
 | 
			
		||||
    sound.setBuffer( buffer );
 | 
			
		||||
| 
						 | 
				
			
			@ -3318,7 +3588,8 @@ audioMimeTypes.map( (mimetype) =>  xrf.frag.src.type[ mimetype ] = loadAudio(mim
 | 
			
		|||
xrf.frag.src.type['fbx'] = function( url, opts ){
 | 
			
		||||
  return new Promise( async (resolve,reject) => {
 | 
			
		||||
    let {mesh,src} = opts
 | 
			
		||||
    let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
    let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
    let frag = URL.XRF 
 | 
			
		||||
    let loader
 | 
			
		||||
 | 
			
		||||
    let {THREE}        = await import('https://unpkg.com/three@0.161.0/build/three.module.js')
 | 
			
		||||
| 
						 | 
				
			
			@ -3346,14 +3617,17 @@ xrf.frag.src.type['fbx'] = function( url, opts ){
 | 
			
		|||
xrf.frag.src.type['x-shader/x-fragment'] = function(url,opts){
 | 
			
		||||
  let {mesh,THREE} = opts
 | 
			
		||||
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  let isFragmentShader = /\.(fs|frag|glsl)$/
 | 
			
		||||
  let isVertexShader   = /\.(vs|vert)$/
 | 
			
		||||
 | 
			
		||||
  let shaderReqs = []
 | 
			
		||||
  let shaderCode = {}
 | 
			
		||||
  let shader   = {
 | 
			
		||||
    fragment: { code: '', url: url.match( isFragmentShader ) ? url : '' },
 | 
			
		||||
    vertex:   { code: '', url: url.match( isVertexShader   ) ? url : '' }
 | 
			
		||||
    fragment: { code: '', url: url.match( isFragmentShader ) ? URL.URN + URL.file : '' },
 | 
			
		||||
    vertex:   { code: '', url: url.match( isVertexShader   ) ? URL.URN + URL.file : '' }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  var onShaderLoaded = ((args) => (type, status, code) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -3412,19 +3686,15 @@ xrf.frag.src.type['x-shader/x-vertex']   = xrf.frag.src.type['x-shader/x-fragmen
 | 
			
		|||
xrf.frag.src.type['gltf'] = function( url, opts ){
 | 
			
		||||
  return new Promise( (resolve,reject) => {
 | 
			
		||||
    let {mesh,src} = opts
 | 
			
		||||
    let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
    let URL = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
    let {directory,file,fileExt,URN} = URL;
 | 
			
		||||
    let loader
 | 
			
		||||
 | 
			
		||||
    const Loader = xrf.loaders[ext]
 | 
			
		||||
    const Loader = xrf.loaders[fileExt]
 | 
			
		||||
    if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext 
 | 
			
		||||
    if( !dir.match("://") ){ // force relative path 
 | 
			
		||||
      dir = dir.substr(0,2) == './' ? dir : `./${dir}`
 | 
			
		||||
      loader = new Loader().setPath( dir )
 | 
			
		||||
    }else{
 | 
			
		||||
      loader = new Loader() 
 | 
			
		||||
    }
 | 
			
		||||
    loader = new Loader().setPath( URN )
 | 
			
		||||
 | 
			
		||||
    loader.load(url, (model) => {
 | 
			
		||||
    loader.load(file, (model) => {
 | 
			
		||||
      model.isSRC = true
 | 
			
		||||
      resolve(model)
 | 
			
		||||
    })
 | 
			
		||||
| 
						 | 
				
			
			@ -3435,7 +3705,7 @@ xrf.frag.src.type['gltf'] = function( url, opts ){
 | 
			
		|||
let loadHTML = (mimetype) => function(url,opts){
 | 
			
		||||
  let {mesh,src,camera} = opts
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
  let frag = xrf.URI.parse( url )
 | 
			
		||||
  let frag = xrf.URI.parse( url ).XRF
 | 
			
		||||
  console.warn("todo: html viewer for src not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3452,6 +3722,8 @@ htmlMimeTypes.map( (mimetype) =>  xrf.frag.src.type[ mimetype ] = loadHTML(mimet
 | 
			
		|||
xrf.frag.src.type['image/png'] = function(url,opts){
 | 
			
		||||
  let {mesh,THREE} = opts
 | 
			
		||||
  let restrictTo3DBoundingBox = mesh.geometry
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  mesh.material = new xrf.THREE.MeshBasicMaterial({ 
 | 
			
		||||
    map: null, 
 | 
			
		||||
| 
						 | 
				
			
			@ -3495,7 +3767,7 @@ xrf.frag.src.type['image/png'] = function(url,opts){
 | 
			
		|||
    renderImage(texture)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  new THREE.TextureLoader().load( url, onLoad, null, console.error );
 | 
			
		||||
  new THREE.TextureLoader().load( URL.URN + URL.file, onLoad, null, console.error );
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3701,9 +3973,9 @@ xrf.portalNonEuclidian.stencilRef = 1
 | 
			
		|||
 | 
			
		||||
let loadVideo = (mimetype) => function(url,opts){
 | 
			
		||||
  let {mesh,src,camera} = opts
 | 
			
		||||
  let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
 | 
			
		||||
  const THREE = xrf.THREE
 | 
			
		||||
  let frag = xrf.URI.parse( url )
 | 
			
		||||
  let URL  = xrfragment.URI.toAbsolute( xrf.navigator.URI, url )
 | 
			
		||||
  let frag = URL.XRF 
 | 
			
		||||
 | 
			
		||||
  mesh.media = mesh.media || {}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3725,7 +3997,7 @@ let loadVideo = (mimetype) => function(url,opts){
 | 
			
		|||
    },false)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  video.src = url
 | 
			
		||||
  video.src = URL.URN + URL.file 
 | 
			
		||||
  video.speed = 1.0
 | 
			
		||||
  video.looping = false
 | 
			
		||||
  video.set = (mediafragment,v) => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								index.html
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								index.html
									
										
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -10,6 +10,8 @@ window.AFRAME.registerComponent('xrf-get', {
 | 
			
		|||
    var el = this.el;
 | 
			
		||||
    var meshname = this.data.name || this.data;
 | 
			
		||||
 | 
			
		||||
    if( !meshname || typeof meshname != 'string' ) return
 | 
			
		||||
 | 
			
		||||
    this.el.addEventListener('update', (evt) => {
 | 
			
		||||
 | 
			
		||||
      setTimeout( () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +48,8 @@ window.AFRAME.registerComponent('xrf-get', {
 | 
			
		|||
          this.el.object3D.child = mesh    // keep reference (because .children will be empty)
 | 
			
		||||
 | 
			
		||||
          if( !this.el.id ) this.el.setAttribute("id",`xrf-${mesh.name}`)
 | 
			
		||||
        }else console.warn("xrf-get ignore: "+JSON.stringify(this.data))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      }, evt && evt.timeout ? evt.timeout: 500)
 | 
			
		||||
 | 
			
		||||
    })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -110,7 +110,7 @@ xrf.navigator.init = () => {
 | 
			
		|||
 | 
			
		||||
  window.addEventListener('popstate', function (event){
 | 
			
		||||
    if( !xrf.navigator.updateHash.active ){ // ignore programmatic hash updates (causes infinite recursion)
 | 
			
		||||
      xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
 | 
			
		||||
      xrf.navigator.to( document.location.href.replace(/\?/,'') )
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ let loadAudio = (mimetype) => function(url,opts){
 | 
			
		|||
  mesh.media.audio = { set: (mediafragment,v) => mesh.media.audio[mediafragment] = v }
 | 
			
		||||
 | 
			
		||||
  let finalUrl = URL.URN + URL.file 
 | 
			
		||||
  if( xrf.debug != undefined ) console.log("GET "+finalUrl)
 | 
			
		||||
  if( xrf.debug > 0 ) console.log("GET "+finalUrl)
 | 
			
		||||
  audioLoader.load( finalUrl, function( buffer ) {
 | 
			
		||||
 | 
			
		||||
    sound.setBuffer( buffer );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -401,6 +401,8 @@ class URI {
 | 
			
		|||
        
 | 
			
		||||
        resultURI.port = url.port;
 | 
			
		||||
 | 
			
		||||
        resultURI.source = newUrl;
 | 
			
		||||
 | 
			
		||||
        if (newURI.scheme != null)
 | 
			
		||||
        {
 | 
			
		||||
            resultURI.scheme = newURI.scheme;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,7 @@ createScene = (noadd) => {
 | 
			
		|||
 | 
			
		||||
filterScene = (URI,opts) => {
 | 
			
		||||
  opts = opts || {}
 | 
			
		||||
  frag = xrf.URI.parse(URI)
 | 
			
		||||
  frag = xrf.URI.parse(URI).XRF
 | 
			
		||||
  var {a,b,c,d,extembed,scene} = createScene()
 | 
			
		||||
  xrf.filter.scene({...opts,scene,frag})
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,9 +15,9 @@ console.assert = ((assert) => (a,b) => {
 | 
			
		|||
/* 
 | 
			
		||||
 * parser checks
 | 
			
		||||
 */
 | 
			
		||||
let frags = xrf.URI.parse('://foo.com/1.gltf#pos=1.0,2.0,3.0&t=0,100')
 | 
			
		||||
let frags = xrf.URI.parse('://foo.com/1.gltf#pos=1.0,2.0,3.0&t=0,100').XRF
 | 
			
		||||
console.assert( frags.t, {frags, reason:'URI.parse(): t needs to be set'})
 | 
			
		||||
 | 
			
		||||
let frag = xrf.URI.parse("#foo=1")
 | 
			
		||||
let frag = xrf.URI.parse("#foo=1").XRF
 | 
			
		||||
console.assert( frag, {reason: 'xrf.URI.parse() should be available'})
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue