work in progress [might break]

This commit is contained in:
Leon van Kammen 2024-04-10 10:54:24 +00:00
parent cd69dcd006
commit 184eae64b0
4 changed files with 163 additions and 56 deletions

View File

@ -1,39 +1,49 @@
xrf.navigator = {}
xrf.navigator = {URL:{}}
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 URL = xrfragment.URL.toAbsolute( xrf.navigator.URL, url )
console.dir({URL, nav: xrf.navigator.URL})
let fileChange = URL.file && URL.file != xrf.navigator.URL.file
let hasPos = URL.hash.pos
let hashChange = String(xrf.navigator.URL.fragment||"") != String(URL.fragment||"")
let hashbus = xrf.hashbus
xrf.navigator.URL = URL
let {directory,file,fragment,fileExt} = URL;
let hashbus = xrf.hashbus
debugger
const evalFragment = () => {
if( URL.fragment ){
hashbus.pub( URL.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]
console.log("URN: "+URL.URN)
if( fileExt && !loader ){
const Loader = xrf.loaders[fileExt]
if( !Loader ) return resolve()
loader = loader || new Loader().setPath( dir )
loader = loader || new Loader().setPath( URL.URN )
}
if( !hash && !file && !ext ) return resolve(xrf.model) // nothing we can do here
if( !URL.fragment && !URL.file && !URL.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 && 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 && hashChange && hasPos ){ // we're already loaded
evalFragment()
xrf.emit('navigateLoaded',{url})
return resolve(xrf.model)
}
@ -43,17 +53,21 @@ 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( URL.URN )
const onLoad = (model) => {
model.file = file
model.file = URL.file
// only change url when loading *another* file
if( xrf.model ) xrf.navigator.pushState( `${dir}${file}`, hash )
if( xrf.model ){
let path = URL.directory != document.location.pathname ? URL.directory : '';
xrf.navigator.pushState( `${path}${URL.file}`, fragment )
}
//if( xrf.model ) xrf.navigator.pushState( `${ document.location.pathname != URL.directory ? URL.directory: ''}${URL.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) )
@ -71,7 +85,7 @@ xrf.navigator.to = (url,flags,loader,data) => {
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)
}
@ -80,7 +94,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})
@ -94,6 +108,8 @@ xrf.navigator.to = (url,flags,loader,data) => {
xrf.navigator.init = () => {
if( xrf.navigator.init.inited ) return
xrf.navigator.URL = xrfragment.URL.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 )

View File

@ -88,10 +88,10 @@ class Test {
static public function testURL( _url:String, attr:String, output:String, browserMode: Bool = false): Bool {
var URL = xrfragment.URL;
var url:URL = URL.parse(_url,true);
var url:URL = URL.parse(_url);
if( browserMode ){
if( browser == null ) browser = url;
url = URL.toAbsolute( browser, _url );
url = browser = URL.toAbsolute( browser, _url );
}
var parts:Array<String> = attr.split(".");
if( parts.length > 1 && parts[0] == "hash" && url.hash.exists( parts[1]) ){

View File

@ -6,5 +6,15 @@
{"fn":"url","data":"http://foo.com?foo=1#mycustom=foo", "expect":{ "fn":"testURL", "input":"scheme","out":"http"},"label":"test URL scheme http"},
{"fn":"url","data":"http://foo.com/a/b?foo=1#mycustom=foo", "expect":{ "fn":"testURL", "input":"path","out":"/a/b"},"label":"test URL path /a/b"},
{"fn":"url","data":"http://foo.com/a/b?foo=1#mycustom=foo", "expect":{ "fn":"testURL", "input":"hash.mycustom","out":"foo"},"label":"test URL hash #mycustom == foo"},
{"fn":"url","data":"http://foo.com/a/b?foo=1#mycustom=foo", "expect":{ "fn":"testURLBrowse", "input":"host","out":"foo.com"},"label":"test URLBrowser"}
{"fn":"url","data":"http://foo.com/a/b", "expect":{ "fn":"testURL", "input":"path","out":"/a/b"},"label":"test URL path /a/b/"},
{"fn":"url","data":"http://foo.com/a/b?foo=1#mycustom=foo", "expect":{ "fn":"testURLBrowse", "input":"host","out":"foo.com"},"label":"test URLBrowser"},
{"fn":"url","data":"http://foo.com/a/b?https://foo.com/abc#mycustom=foo", "expect":{ "fn":"testURL", "input":"path","out":"/a/b"},"label":"test URL url-in-query"},
{"fn":"url","data":"http://foo.com/a/b?https://foo.com/abc#mycustom=foo", "expect":{ "fn":"testURLBrowse", "input":"path","out":"/a/b"},"label":"test URLBrowser url-in-query"},
{"fn":"url","data":"/bar/flop#mycustom=foo", "expect":{ "fn":"testURLBrowse", "input":"host","out":"foo.com"},"label":"test URLBrowser (maintain host)"},
{"fn":"url","data":"/bar/flop?foo=1#mycustom=foo", "expect":{ "fn":"testURLBrowse", "input":"query","out":"foo=1"},"label":"test URLBrowser (parse query)"},
{"fn":"url","data":"/flop/flap#mycustom=foo", "expect":{ "fn":"testURLBrowse", "input":"path","out":"/flop/flap"},"label":"test URLBrowser (overwrite path)"},
{"fn":"url","data":"/bar/flop#mycustom=foo", "expect":{ "fn":"testURLBrowse", "input":"path","out":"/bar/flop"},"label":"test URLBrowser (overwrite path 2)"},
{"fn":"url","data":"/bar/flop#mycustom=foo", "expect":{ "fn":"testURLBrowse", "input":"host","out":"foo.com"},"label":"test URLBrowser (maintain host)"},
{"fn":"url","data":"c/d?foo=1#mycustom=foo", "expect":{ "fn":"testURLBrowse", "input":"path","out":"/bar/flop/c/d"},"label":"test URLBrowser (append path+query)"},
{"fn":"url","data":"a/b#foo=bar", "expect":{ "fn":"testURL", "input":"hash.foo","out":"bar"},"label":"test URL hash #mycustom == foo"}
]

View File

@ -48,10 +48,12 @@ class URL
public var path : String;
public var directory : String;
public var file : String;
public var fileExt : String;
public var query : String;
public var fragment : String;
public var hash : haxe.DynamicAccess<Dynamic>;
public var XRF : haxe.DynamicAccess<Dynamic>;
public var hash : haxe.DynamicAccess<Dynamic> = {};
public var XRF : haxe.DynamicAccess<Dynamic> = {};
public var URN : String;
/**
* class constructor
@ -71,6 +73,10 @@ class URL
{
// The almighty regexp (courtesy of http://blog.stevenlevithan.com/archives/parseuri)
var r : EReg = ~/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
if( stringUrl.indexOf("://") == -1 && stringUrl.charAt(0) != '/' ){
stringUrl = "/" + stringUrl; // workaround for relative urls
}
// Match the regexp to the url
r.match(stringUrl);
@ -93,7 +99,7 @@ class URL
}
url.hash = {};
if( url.fragment.length > 0 ){
if( url.fragment != null && url.fragment.length > 0 ){
url.XRF = xrfragment.URI.parse( "#"+url.fragment, 0 );
var key:String;
for( key in url.XRF.keys() ){
@ -101,24 +107,38 @@ class URL
url.hash[key] = v.get("string");
}
}
trace("host:"+url.host);
trace("path:"+url.path);
trace("frag:"+url.fragment);
trace("source:"+url.source);
trace("scheme:"+url.scheme);
trace("authority:"+url.authority);
trace("userInfo:"+url.userInfo);
trace("user:"+url.user);
trace("password:"+url.password);
trace("host:"+url.host);
trace("port:"+url.port);
trace("relative:"+url.relative);
trace("path:"+url.path);
trace("directory:"+url.directory);
trace("file:"+url.file);
trace("query:"+url.query);
computeVars(url);
return url;
}
private static function computeVars( url:URL ) {
// clean up url
var r = ~/\/\//g;
if( url.directory != null && url.directory.indexOf("//") != -1 ){
url.directory = r.replace(url.directory,"/");
}
if( url.path != null && url.path.indexOf("//") != -1 ){
url.path = r.replace(url.path,"/");
}
if( url.file != null && url.file.indexOf("//") != -1 ){
url.file = r.replace(url.file,"/");
}
// generate URN
url.URN = url.scheme + "://" + url.host;
if( url.port != null ) url.URN += ":"+url.port;
url.URN += url.directory;
// extract file extension if any
if( url.file != null){
var parts:Array<String> = url.file.split(".");
if( parts.length > 1 ){
url.fileExt = parts.pop();
}
}
}
/**
* Serialize an URl OBJect into an
@ -205,19 +225,11 @@ class URL
{
return url.scheme == null;
}
/*
*
*/
public static function toAbsolute( oldUrl:URL, newUrl:String ) : URL {
var newURL:URL = new URL(newUrl);
return appendURL( oldUrl, newURL );
}
/**
* append the appended url to a relative url
*/
private static function appendToRelativeURL(url:URL, appendedURL:URL):URL
public static function appendToRelativeURL(url:URL, appendedURL:URL):URL
{
//when relative url parsed, if it contains only a file (ex : "style.css")
//then it will store it in the host attribute. So if the url has no directory
@ -276,7 +288,7 @@ class URL
/**
* append the appended url to an absolute url
*/
private static function appendToAbsoluteURL(url:URL, appendedURL:URL):URL
public static function appendToAbsoluteURL(url:URL, appendedURL:URL):URL
{
var resultURL:URL = new URL();
@ -327,6 +339,75 @@ class URL
return resultURL;
}
/**
* append the appended url to an absolute url
*/
public static function toAbsolute(url:URL, newUrl:String ):URL
{
var newURL:URL = parse(newUrl);
var resultURL:URL = new URL();
resultURL.port = url.port;
if (newURL.scheme != null)
{
resultURL.scheme = newURL.scheme;
}else{
resultURL.scheme = url.scheme;
}
if (newURL.host != null && newURL.host.length > 0 )
{
trace("host: "+newURL.host);
resultURL.host = newURL.host;
resultURL.port = null;
if( newURL.port != null ){
resultURL.port = newURL.port;
}
}else{
resultURL.host = url.host;
}
var directory:String = "";
if (url.directory != null)
{
directory = url.directory;
}
if (newURL.directory != null)
{
if( newUrl.charAt(0) != '/' && newUrl.indexOf("://") == -1 ){
directory += newURL.directory;
}else{
directory = newURL.directory;
}
}
resultURL.directory = directory;
if (newURL.file != null)
{
resultURL.file = newURL.file;
}
resultURL.path = resultURL.directory + resultURL.file;
if (newURL.query != null)
{
resultURL.query = newURL.query;
}
if (newURL.fragment != null)
{
resultURL.fragment = newURL.fragment;
}
resultURL.hash = newURL.hash;
resultURL.XRF = newURL.XRF;
computeVars(resultURL);
return resultURL;
}
/**
* clone the provided url