diff --git a/src/3rd/js/plugin/frontend/$chat.js b/src/3rd/js/plugin/frontend/$chat.js
index 2bd87ad..296eac8 100644
--- a/src/3rd/js/plugin/frontend/$chat.js
+++ b/src/3rd/js/plugin/frontend/$chat.js
@@ -106,7 +106,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')
diff --git a/src/3rd/js/plugin/frontend/frontend.js b/src/3rd/js/plugin/frontend/frontend.js
index 0c158d6..9dcd75b 100644
--- a/src/3rd/js/plugin/frontend/frontend.js
+++ b/src/3rd/js/plugin/frontend/frontend.js
@@ -274,7 +274,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
please wait..')
diff --git a/src/3rd/js/plugin/matrix/matrix.js b/src/3rd/js/plugin/matrix/matrix.js
index 4022afa..487f492 100644
--- a/src/3rd/js/plugin/matrix/matrix.js
+++ b/src/3rd/js/plugin/matrix/matrix.js
@@ -314,7 +314,7 @@ window.matrix = (opts) => new Proxy({
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)
}
},
diff --git a/src/3rd/js/plugin/p2p/trystero.js b/src/3rd/js/plugin/p2p/trystero.js
index 21dd921..36c3baf 100644
--- a/src/3rd/js/plugin/p2p/trystero.js
+++ b/src/3rd/js/plugin/p2p/trystero.js
@@ -258,7 +258,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)
}
diff --git a/src/3rd/js/three/hashbus.js b/src/3rd/js/three/hashbus.js
index 12f376e..e83b1ae 100644
--- a/src/3rd/js/three/hashbus.js
+++ b/src/3rd/js/three/hashbus.js
@@ -7,7 +7,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
diff --git a/src/3rd/js/three/index.js b/src/3rd/js/three/index.js
index 8899511..344a920 100644
--- a/src/3rd/js/three/index.js
+++ b/src/3rd/js/three/index.js
@@ -88,24 +88,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)
diff --git a/src/3rd/js/three/navigator.js b/src/3rd/js/three/navigator.js
index c9339b1..8fd3e93 100644
--- a/src/3rd/js/three/navigator.js
+++ b/src/3rd/js/three/navigator.js
@@ -1,21 +1,22 @@
-xrf.navigator = {URL:{}}
+xrf.navigator = {URI:{}}
xrf.navigator.to = (url,flags,loader,data) => {
if( !url ) throw 'xrf.navigator.to(..) no url given'
- 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 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.URL = URL
- let {directory,file,fragment,fileExt} = URL;
+ xrf.navigator.URI = URI
+ let {directory,file,fragment,fileExt} = URI;
+ console.dir({URI, nav: xrf.navigator.URI})
- debugger
const evalFragment = () => {
- if( URL.fragment ){
- hashbus.pub( URL.fragment, xrf.model, flags ) // eval local URI XR fragments
+ if( URI.fragment ){
+ hashbus.pub( URI.fragment, xrf.model, flags ) // eval local URI XR fragments
xrf.navigator.updateHash(fragment) // which don't require
}
}
@@ -25,16 +26,16 @@ xrf.navigator.to = (url,flags,loader,data) => {
.emit('navigate', {url,loader,data})
.then( () => {
- console.log("URN: "+URL.URN)
+ const Loader = xrf.loaders[fileExt]
+
if( fileExt && !loader ){
- const Loader = xrf.loaders[fileExt]
if( !Loader ) return resolve()
- loader = loader || new Loader().setPath( URL.URN )
+ loader = loader || new Loader().setPath( URI.URN )
}
- if( !URL.fragment && !URL.file && !URL.fileExt ) 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( xrf.model && hashChange && !hasPos ){
+ if( xrf.model && !fileChange && hashChange && !hasPos ){
evalFragment()
return resolve(xrf.model) // positional navigation
}
@@ -42,7 +43,7 @@ xrf.navigator.to = (url,flags,loader,data) => {
xrf
.emit('navigateLoading', {url,loader,data})
.then( () => {
- if( !fileChange && hashChange && hasPos ){ // we're already loaded
+ if( (!fileChange || !file) && hashChange && hasPos ){ // we're already loaded
evalFragment()
xrf.emit('navigateLoaded',{url})
return resolve(xrf.model)
@@ -55,16 +56,15 @@ xrf.navigator.to = (url,flags,loader,data) => {
// force relative path for files which dont include protocol or relative path
if( directory ) directory = directory[0] == '.' || directory.match("://") ? directory : `.${directory}`
- loader = loader || new Loader().setPath( URL.URN )
+ loader = loader || new Loader().setPath( URI.URN )
const onLoad = (model) => {
- model.file = URL.file
+ model.file = URI.file
// only change url when loading *another* file
if( xrf.model ){
- let path = URL.directory != document.location.pathname ? URL.directory : '';
- xrf.navigator.pushState( `${path}${URL.file}`, fragment )
+ xrf.navigator.pushState( external ? URI.URN + URI.file : URI.file, fragment )
}
- //if( xrf.model ) xrf.navigator.pushState( `${ document.location.pathname != URL.directory ? URL.directory: ''}${URL.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.replace(directory,"")) // this marks the model as an XRF model
@@ -75,13 +75,12 @@ 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 )
@@ -108,7 +107,7 @@ 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)
+ 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)
@@ -138,10 +137,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')
@@ -161,7 +160,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
@@ -172,3 +171,20 @@ 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('&')
+ }
+ })
+}
diff --git a/src/3rd/js/three/xrf/href.js b/src/3rd/js/three/xrf/href.js
index 3f83494..dd1c618 100644
--- a/src/3rd/js/three/xrf/href.js
+++ b/src/3rd/js/three/xrf/href.js
@@ -49,7 +49,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
diff --git a/src/3rd/js/three/xrf/src.js b/src/3rd/js/three/xrf/src.js
index ab8aa5d..f26780e 100644
--- a/src/3rd/js/three/xrf/src.js
+++ b/src/3rd/js/three/xrf/src.js
@@ -7,7 +7,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
diff --git a/src/3rd/js/three/xrf/src/audio.js b/src/3rd/js/three/xrf/src/audio.js
index 563b6be..645e581 100644
--- a/src/3rd/js/three/xrf/src/audio.js
+++ b/src/3rd/js/three/xrf/src/audio.js
@@ -8,8 +8,8 @@
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)
@@ -20,7 +20,7 @@ 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(/#.*/,'')
+ let finalUrl = URL.URN + URL.file
if( xrf.debug != undefined ) console.log("GET "+finalUrl)
audioLoader.load( finalUrl, function( buffer ) {
diff --git a/src/3rd/js/three/xrf/src/fbx.js b/src/3rd/js/three/xrf/src/fbx.js
index 42516f5..e636d51 100644
--- a/src/3rd/js/three/xrf/src/fbx.js
+++ b/src/3rd/js/three/xrf/src/fbx.js
@@ -5,7 +5,8 @@
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')
diff --git a/src/3rd/js/three/xrf/src/glsl.js b/src/3rd/js/three/xrf/src/glsl.js
index 885d755..52c6940 100644
--- a/src/3rd/js/three/xrf/src/glsl.js
+++ b/src/3rd/js/three/xrf/src/glsl.js
@@ -5,14 +5,17 @@
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) => {
diff --git a/src/3rd/js/three/xrf/src/gltf.js b/src/3rd/js/three/xrf/src/gltf.js
index 83ba3d5..9a6e728 100644
--- a/src/3rd/js/three/xrf/src/gltf.js
+++ b/src/3rd/js/three/xrf/src/gltf.js
@@ -5,19 +5,15 @@
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)
})
diff --git a/src/3rd/js/three/xrf/src/html.js b/src/3rd/js/three/xrf/src/html.js
index 08d3800..c37d066 100644
--- a/src/3rd/js/three/xrf/src/html.js
+++ b/src/3rd/js/three/xrf/src/html.js
@@ -2,7 +2,7 @@
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")
}
diff --git a/src/3rd/js/three/xrf/src/image.js b/src/3rd/js/three/xrf/src/image.js
index a87e135..92e3931 100644
--- a/src/3rd/js/three/xrf/src/image.js
+++ b/src/3rd/js/three/xrf/src/image.js
@@ -7,6 +7,8 @@
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,
@@ -50,7 +52,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 );
}
diff --git a/src/3rd/js/three/xrf/src/video.js b/src/3rd/js/three/xrf/src/video.js
index 14cfdb1..6a99ed1 100644
--- a/src/3rd/js/three/xrf/src/video.js
+++ b/src/3rd/js/three/xrf/src/video.js
@@ -1,9 +1,9 @@
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 || {}
@@ -25,7 +25,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) => {
diff --git a/src/Test.hx b/src/Test.hx
index 59990fd..996f0b2 100644
--- a/src/Test.hx
+++ b/src/Test.hx
@@ -1,6 +1,5 @@
import xrfragment.Filter;
import xrfragment.URI;
-import xrfragment.URL;
import xrfragment.XRF;
class Spec {
@@ -14,7 +13,7 @@ class Spec {
class Test {
static var errors:Int = 0;
- static var browser : xrfragment.URL = null;
+ static var browser : xrfragment.URI = null;
static public function main():Void {
test( "url.json", Spec.load("src/spec/url.json") );
@@ -36,7 +35,7 @@ class Test {
var valid:Bool = false;
var item:Dynamic = spec[i];
f = new Filter(item.data);
- res = URI.parse(item.data,null);
+ res = URI.parseFragment(item.data,null);
if( item.expect.fn == "test" ) valid = item.expect.out == f.test( item.expect.input[0] );
if( item.expect.fn == "testProperty" ) valid = item.expect.out == f.testProperty( item.expect.input[0], item.expect.input[1] );
if( item.expect.fn == "testPropertyInt" ) valid = item.expect.out == f.testProperty( item.expect.input[0], item.expect.input[1] );
@@ -44,8 +43,8 @@ class Test {
if( item.expect.fn == "testParsed" ) valid = item.expect.out == res.exists(item.expect.input);
if( item.expect.fn == "testPredefinedView" ) valid = res.exists(item.expect.input) && item.expect.out == res.get(item.expect.input).is( XRF.PV_EXECUTE) ;
if( item.expect.fn == "testPropertyAssign" ) valid = res.exists(item.expect.input) && item.expect.out == res.get(item.expect.input).is( XRF.PROP_BIND) ;
- if( item.expect.fn == "testBrowserOverride" ) valid = item.expect.out == (URI.parse(item.data,XRF.NAVIGATOR)).exists(item.expect.input);
- if( item.expect.fn == "testEmbedOverride" ) valid = item.expect.out == (URI.parse(item.data,XRF.METADATA)).exists(item.expect.input);
+ if( item.expect.fn == "testBrowserOverride" ) valid = item.expect.out == (URI.parseFragment(item.data,XRF.NAVIGATOR)).exists(item.expect.input);
+ if( item.expect.fn == "testEmbedOverride" ) valid = item.expect.out == (URI.parseFragment(item.data,XRF.METADATA)).exists(item.expect.input);
if( item.expect.fn == "testURL" ) valid = testURL( item.data, item.expect.input, item.expect.out, false );
if( item.expect.fn == "testURLHash" ) valid = testURL( item.data, item.expect.input, item.expect.out, false );
if( item.expect.fn == "testURLBrowse" ) valid = testURL( item.data, item.expect.input, item.expect.out, true );
@@ -87,11 +86,11 @@ 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);
+ var URI = xrfragment.URI;
+ var url:URI = URI.parse(_url,0);
if( browserMode ){
if( browser == null ) browser = url;
- url = browser = URL.toAbsolute( browser, _url );
+ url = browser = URI.toAbsolute( browser, _url );
}
var parts:Array = attr.split(".");
if( parts.length > 1 && parts[0] == "hash" && url.hash.exists( parts[1]) ){
diff --git a/src/xrfragment/URI.hx b/src/xrfragment/URI.hx
index d251ea2..cfbc706 100644
--- a/src/xrfragment/URI.hx
+++ b/src/xrfragment/URI.hx
@@ -1,5 +1,13 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 Leon van Kammen/NLNET
+
+/*
+ * various snippets originate from:
+ *
+ * http://haxe.org/doc/snip/uri_parser,
+ * https://github.com/haxecocktail/cocktail-url/blob/master/cocktail/url/URI.hx
+ */
+
package xrfragment;
import xrfragment.Parser;
@@ -27,10 +35,44 @@ import xrfragment.XRF;
@:keep // <- avoids accidental removal by dead code elimination
class URI {
- public static var fragment:haxe.DynamicAccess;
+ /**
+ * URI parts names
+ */
+ private static var _parts : Array = ["source", "scheme", "authority", "userInfo", "user",
+ "password","host","port","relative","path","directory","file","query","fragment"];
+
+ /**
+ * URI parts
+ */
+ public var url : String;
+ public var source : String;
+ public var scheme : String;
+ public var authority : String;
+ public var userInfo : String;
+ public var user : String;
+ public var password : String;
+ public var host : String;
+ public var port : String;
+ public var relative : String;
+ 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 = {};
+ public var XRF : haxe.DynamicAccess = {};
+ public var URN : String;
+
+ /**
+ * class constructor
+ */
+ public function new( )
+ {
+ }
@:keep
- public static function parse(url:String,filter:Int):haxe.DynamicAccess {
+ public static function parseFragment(url:String,filter:Int):haxe.DynamicAccess {
var store:haxe.DynamicAccess = {}; // 1. store key/values into a associative array or dynamic object
if( url == null || url.indexOf("#") == -1 ) return store;
var fragment:Array = url.split("#"); // 1. fragment URI starts with `#`
@@ -71,6 +113,381 @@ class URI {
return parts.join("#");
}
+ /**
+ * Parse a string url and return a typed
+ * object from it.
+ *
+ * note : implementation originate from here :
+ * http://haxe.org/doc/snip/uri_parser
+ */
+ public static function parse(stringUrl:String, flags:Int ):URI
+ {
+ // 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);
+
+ var url:URI = new URI();
+
+ // Use reflection to set each part
+ for (i in 0..._parts.length)
+ {
+ Reflect.setField(url, _parts[i], r.matched(i));
+ }
+
+ //hack for relative url with only a file
+ if (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:String;
+ for( key in url.XRF.keys() ){
+ var v:haxe.DynamicAccess = url.XRF.get(key);
+ url.hash[key] = v.get("string");
+ }
+ }
+
+ computeVars(url);
+
+ return url;
+ }
+
+ private static function computeVars( url:URI ) {
+ // 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 = url.file.split(".");
+ if( parts.length > 1 ){
+ url.fileExt = parts.pop();
+ }
+ }
+
+ }
+
+ /**
+ * Serialize an URl OBJect into an
+ * URI string
+ */
+ public static function toString(url:URI):String
+ {
+ var result:String = "";
+
+ 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;
+ }
+
+ /**
+ * takes 2 urls and return a new url which is the result
+ * of appending the second url to the first.
+ *
+ * if the first url points to a file, the file is removed
+ * and the appended url is added after the last directory
+ *
+ * only the query string and fragment of the appended url are used
+ */
+ public static function appendURI(url:URI, appendedURI:URI):URI
+ {
+ if (isRelative(url) == true)
+ {
+ return appendToRelativeURI(url, appendedURI);
+ }
+ else
+ {
+ return appendToAbsoluteURI(url, appendedURI);
+ }
+ }
+
+ /**
+ * return wether the url is relative (true)
+ * or absolute (false)
+ */
+ public static function isRelative(url:URI):Bool
+ {
+ return url.scheme == null;
+ }
+
+ /**
+ * append the appended url to a relative url
+ */
+ public static function appendToRelativeURI(url:URI, appendedURI:URI):URI
+ {
+ //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
+ //then only the appended url content is returned, as this method replace the file
+ //part of the base url anyway
+ if (url.directory == null || url.host == null)
+ {
+ return cloneURI(appendedURI);
+ }
+
+ var resultURI:URI = new 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)
+ {
+ //remove the initial '/' char if no host, as already present
+ //in base url
+ resultURI.directory += directory.substr(1);
+ }
+ 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;
+ }
+
+ /**
+ * append the appended url to an absolute url
+ */
+ public static function appendToAbsoluteURI(url:URI, appendedURI:URI):URI
+ {
+ var resultURI:URI = new URI();
+
+ if (url.scheme != null)
+ {
+ resultURI.scheme = url.scheme;
+ }
+
+ if (url.host != null)
+ {
+ resultURI.host = url.host;
+ }
+
+ var directory:String = "";
+ 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;
+ }
+
+ /**
+ * append the appended url to an absolute url
+ */
+ public static function toAbsolute(url:URI, newUrl:String ):URI
+ {
+ var newURI:URI = parse(newUrl,0);
+ var resultURI:URI = new URI();
+
+ resultURI.port = url.port;
+
+ if (newURI.scheme != null)
+ {
+ resultURI.scheme = newURI.scheme;
+ }else{
+ resultURI.scheme = url.scheme;
+ }
+
+ if (newURI.host != null && newURI.host.length > 0 )
+ {
+ trace("host: "+newURI.host);
+ 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:String = "";
+ 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;
+ computeVars(resultURI);
+
+ return resultURI;
+ }
+
+ /**
+ * clone the provided url
+ */
+ private static function cloneURI(url:URI):URI
+ {
+ var clonedURI:URI = new 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;
+ }
+
}
/**
diff --git a/src/xrfragment/URL.hx b/src/xrfragment/URL.hx
deleted file mode 100644
index 5772f0e..0000000
--- a/src/xrfragment/URL.hx
+++ /dev/null
@@ -1,436 +0,0 @@
-package xrfragment;
-
-import xrfragment.URI;
-
-/*
- * Cocktail, HTML rendering engine
- * http://haxe.org/com/libs/cocktail
- *
- * Copyright (c) Silex Labs
- * Cocktail is available under the MIT license
- * http://www.silexlabs.org/labs/cocktail-licensing/
- * https://github.com/haxecocktail/cocktail-url/blob/master/cocktail/url/URL.hx
- */
-
-/**
- * Parse and serialize an URL.
- *
- * note : parts of the implementation originate from
- * here : http://haxe.org/doc/snip/uri_parser,
- * some part of the URL have been renamed to match
- * w3c spec
- *
- * @author Yannick Dominguez
- */
-@:expose // <- makes the class reachable from plain JavaScript
-@:keep // <- avoids accidental removal by dead code elimination
-class URL
-{
- /**
- * URL parts names
- */
- private static var _parts : Array = ["source", "scheme", "authority", "userInfo", "user",
- "password","host","port","relative","path","directory","file","query","fragment"];
-
- /**
- * URL parts
- */
- public var url : String;
- public var source : String;
- public var scheme : String;
- public var authority : String;
- public var userInfo : String;
- public var user : String;
- public var password : String;
- public var host : String;
- public var port : String;
- public var relative : String;
- 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 = {};
- public var XRF : haxe.DynamicAccess = {};
- public var URN : String;
-
- /**
- * class constructor
- */
- public function new( )
- {
- }
-
- /**
- * Parse a string url and return a typed
- * object from it.
- *
- * note : implementation originate from here :
- * http://haxe.org/doc/snip/uri_parser
- */
- public static function parse(stringUrl:String ):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);
-
- var url:URL = new URL();
-
- // Use reflection to set each part
- for (i in 0..._parts.length)
- {
- Reflect.setField(url, _parts[i], r.matched(i));
- }
-
- //hack for relative url with only a file
- if (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.parse( "#"+url.fragment, 0 );
- var key:String;
- for( key in url.XRF.keys() ){
- var v:haxe.DynamicAccess = url.XRF.get(key);
- url.hash[key] = v.get("string");
- }
- }
-
- 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 = url.file.split(".");
- if( parts.length > 1 ){
- url.fileExt = parts.pop();
- }
- }
-
- }
-
- /**
- * Serialize an URl OBJect into an
- * URL string
- */
- public static function toString(url:URL):String
- {
- var result:String = "";
-
- 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;
- }
-
- /**
- * takes 2 urls and return a new url which is the result
- * of appending the second url to the first.
- *
- * if the first url points to a file, the file is removed
- * and the appended url is added after the last directory
- *
- * only the query string and fragment of the appended url are used
- */
- public static function appendURL(url:URL, appendedURL:URL):URL
- {
- if (isRelative(url) == true)
- {
- return appendToRelativeURL(url, appendedURL);
- }
- else
- {
- return appendToAbsoluteURL(url, appendedURL);
- }
- }
-
- /**
- * return wether the url is relative (true)
- * or absolute (false)
- */
- public static function isRelative(url:URL):Bool
- {
- return url.scheme == null;
- }
-
- /**
- * append the appended url to a relative 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
- //then only the appended url content is returned, as this method replace the file
- //part of the base url anyway
- if (url.directory == null || url.host == null)
- {
- return cloneURL(appendedURL);
- }
-
- var resultURL:URL = new URL();
- resultURL.host = url.host;
- resultURL.directory = url.directory;
-
- if (appendedURL.host != null)
- {
- resultURL.directory += appendedURL.host;
- }
-
- if (appendedURL.directory != null)
- {
- var directory = appendedURL.directory;
- if (appendedURL.host == null)
- {
- //remove the initial '/' char if no host, as already present
- //in base url
- resultURL.directory += directory.substr(1);
- }
- else
- {
- resultURL.directory += directory;
- }
-
- }
-
- if (appendedURL.file != null)
- {
- resultURL.file = appendedURL.file;
- }
-
- resultURL.path = resultURL.directory + resultURL.file;
-
- if (appendedURL.query != null)
- {
- resultURL.query = appendedURL.query;
- }
-
- if (appendedURL.fragment != null)
- {
- resultURL.fragment = appendedURL.fragment;
- }
-
- return resultURL;
- }
-
- /**
- * append the appended url to an absolute url
- */
- public static function appendToAbsoluteURL(url:URL, appendedURL:URL):URL
- {
- var resultURL:URL = new URL();
-
- if (url.scheme != null)
- {
- resultURL.scheme = url.scheme;
- }
-
- if (url.host != null)
- {
- resultURL.host = url.host;
- }
-
- var directory:String = "";
- if (url.directory != null)
- {
- directory = url.directory;
- }
-
- if (appendedURL.host != null)
- {
- appendedURL.directory += appendedURL.host;
- }
-
- if (appendedURL.directory != null)
- {
- directory += appendedURL.directory;
- }
-
- resultURL.directory = directory;
-
- if (appendedURL.file != null)
- {
- resultURL.file = appendedURL.file;
- }
-
- resultURL.path = resultURL.directory + resultURL.file;
-
- if (appendedURL.query != null)
- {
- resultURL.query = appendedURL.query;
- }
-
- if (appendedURL.fragment != null)
- {
- resultURL.fragment = appendedURL.fragment;
- }
-
- 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
- */
- private static function cloneURL(url:URL):URL
- {
- var clonedURL:URL = new URL();
-
- clonedURL.url = url.url;
- clonedURL.source = url.source;
- clonedURL.scheme = url.scheme;
- clonedURL.authority = url.authority;
- clonedURL.userInfo = url.userInfo;
- clonedURL.password = url.password;
- clonedURL.host = url.host;
- clonedURL.port = url.port;
- clonedURL.relative = url.relative;
- clonedURL.path = url.path;
- clonedURL.directory = url.directory;
- clonedURL.file = url.file;
- clonedURL.query = url.query;
- clonedURL.fragment = url.fragment;
-
- return clonedURL;
- }
-}