From 2a9b97e7bb59c3d2b86d0fdd299dd10bde6fd041 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Sun, 15 Oct 2023 13:35:54 +0200 Subject: [PATCH] ui fixes + build fixes --- dist/utils.js | 296 +++++++++++++++++++++++++++++ dist/xrfragment.aframe.js | 3 +- dist/xrfragment.three.js | 3 +- dist/xrfragment.three.module.js | 3 +- example/aframe/sandbox/index.html | 14 +- example/assets/css/style.css | 6 +- example/assets/js/utils.js | 14 ++ example/threejs/sandbox/index.html | 2 +- make | 2 + src/3rd/js/three/navigator.js | 3 +- 10 files changed, 328 insertions(+), 18 deletions(-) create mode 100644 dist/utils.js diff --git a/dist/utils.js b/dist/utils.js new file mode 100644 index 0000000..3e17af8 --- /dev/null +++ b/dist/utils.js @@ -0,0 +1,296 @@ + +// contentLoaders = {".gltf" : () => .....} and so on + +function loadFile(contentLoaders, multiple){ + return () => { + window.notify("if you're on Meta browser, file-uploads might be disabled") + let input = document.createElement('input'); + input.type = 'file'; + input.multiple = multiple; + input.accept = Object.keys(contentLoaders).join(","); + input.onchange = () => { + let files = Array.from(input.files); + let file = files.slice ? files[0] : files + for( var i in contentLoaders ){ + let r = new RegExp('\\'+i+'$') + if( file.name.match(r) ) return contentLoaders[i](file) + } + alert(file.name+" is not supported") + }; + input.click(); + } +} + +function setupConsole(el){ + if( !el ) return setTimeout( () => setupConsole( $('.lil-gui') ),200 ) + let $console = document.createElement('textarea') + $console.style.position = 'absolute' + $console.style.display = 'block' + $console.style.zIndex = 2000; + $console.style.background = "transparent !important" + $console.style.pointerEvents = 'none' + $console.style.top = '70px' + $console.style.padding = '10px' + $console.style.margin = '10px' + $console.style.background = '#000' + $console.style.left = $console.style.right = $console.style.bottom = 0; + $console.style.color = '#A6F'; + $console.style.fontSize = '10px'; + $console.style.fontFamily = 'Courier' + $console.style.border = '0' + $console.innerHTML = "XRFRAGMENT CONSOLE OUTPUT:\n" + + el.appendChild($console) + + console.log = ( (log) => function(){ + let str = ([...arguments]).join(" ") + let s = str; + log(s) + let lines = String($console.innerHTML + "\n"+s).split("\n") + while( lines.length > 200 ) lines.shift() + $console.innerHTML = lines.join("\n") + $console.scrollTop = $console.scrollHeight; + })(console.log.bind(console)) +} + +function setupUrlBar(el,XRF){ + let inIframe = window.location !== window.parent.location + let ids = ['#overlay','a#embed','a#source','a#model','#qrcode'] + let showButtons = () => { + ids.map( (i) => $(i).style.display = 'block' ) + $('a#more').style.display = 'none' + if( inIframe ) $('#uri').style.display = 'block' + } + $('a#more').addEventListener('click', () => showButtons() ) + + XRF.addEventListener('hash', () => reflectUrl() ) + const reflectUrl = window.reflectUrl = (url) => { + el.value = url || document.location.search.substr(1) + document.location.hash + let QR = window.QR + QR.canvas = document.getElementById('qrcode') + QR.draw( document.location.href, QR.canvas ) + } + reflectUrl() +} + +function SnackBar(userOptions) { + var snackbar = this || (window.snackbar = {}); + var _Interval; + var _Message; + var _Element; + var _Container; + + var _OptionDefaults = { + message: "Operation performed successfully.", + dismissible: true, + timeout: 7000, + status: "" + } + var _Options = _OptionDefaults; + + function _Create() { + let _Containers = [ ...document.querySelectorAll(".js-snackbar-container") ] + _Containers.map( (c) => c.remove() ) + _Container = null + + if (!_Container) { + // need to create a new container for notifications + _Container = document.createElement("div"); + _Container.classList.add("js-snackbar-container"); + + document.body.appendChild(_Container); + } + _Container.innerHTML = '' + _Element = document.createElement("div"); + _Element.classList.add("js-snackbar__wrapper"); + + let innerSnack = document.createElement("div"); + innerSnack.classList.add("js-snackbar", "js-snackbar--show"); + + if (_Options.status) { + _Options.status = _Options.status.toLowerCase().trim(); + + let status = document.createElement("span"); + status.classList.add("js-snackbar__status"); + + + if (_Options.status === "success" || _Options.status === "green") { + status.classList.add("js-snackbar--success"); + } + else if (_Options.status === "warning" || _Options.status === "alert" || _Options.status === "orange") { + status.classList.add("js-snackbar--warning"); + } + else if (_Options.status === "danger" || _Options.status === "error" || _Options.status === "red") { + status.classList.add("js-snackbar--danger"); + } + else { + status.classList.add("js-snackbar--info"); + } + + innerSnack.appendChild(status); + } + + _Message = document.createElement("span"); + _Message.classList.add("js-snackbar__message"); + _Message.innerHTML = _Options.message; + + innerSnack.appendChild(_Message); + + if (_Options.dismissible) { + let closeBtn = document.createElement("span"); + closeBtn.classList.add("js-snackbar__close"); + closeBtn.innerText = "\u00D7"; + + closeBtn.onclick = snackbar.Close; + + innerSnack.appendChild(closeBtn); + } + + _Element.style.height = "0px"; + _Element.style.opacity = "0"; + _Element.style.marginTop = "0px"; + _Element.style.marginBottom = "0px"; + + _Element.appendChild(innerSnack); + _Container.appendChild(_Element); + + if (_Options.timeout !== false) { + _Interval = setTimeout(snackbar.Close, _Options.timeout); + } + } + + var _ConfigureDefaults = function() { + // if no options given, revert to default + if (userOptions === undefined) { + return; + } + + if (userOptions.message !== undefined) { + _Options.message = userOptions.message; + } + + if (userOptions.dismissible !== undefined) { + if (typeof (userOptions.dismissible) === "string") { + _Options.dismissible = (userOptions.dismissible === "true"); + } + else if (typeof (userOptions.dismissible) === "boolean") { + _Options.dismissible = userOptions.dismissible; + } + else { + console.debug("Invalid option provided for 'dismissable' [" + userOptions.dismissible + "] is of type " + (typeof userOptions.dismissible)); + } + } + + + if (userOptions.timeout !== undefined) { + if (typeof (userOptions.timeout) === "boolean" && userOptions.timeout === false) { + _Options.timeout = false; + } + else if (typeof (userOptions.timeout) === "string") { + _Options.timeout = parseInt(userOptions.timeout); + } + + + if (typeof (userOptions.timeout) === "number") { + if (userOptions.timeout === Infinity) { + _Options.timeout = false; + } + else if (userOptions.timeout >= 0) { + _Options.timeout = userOptions.timeout; + } + else { + console.debug("Invalid timeout entered. Must be greater than or equal to 0."); + } + + _Options.timeout = userOptions.timeout; + } + + + } + + if (userOptions.status !== undefined) { + _Options.status = userOptions.status; + } + } + + snackbar.Open = function() { + let contentHeight = _Element.firstElementChild.scrollHeight; // get the height of the content + + _Element.style.height = contentHeight + "px"; + _Element.style.opacity = 1; + _Element.style.marginTop = "5px"; + _Element.style.marginBottom = "5px"; + + _Element.addEventListener("transitioned", function() { + _Element.removeEventListener("transitioned", arguments.callee); + _Element.style.height = null; + }) + } + + snackbar.Close = function () { + if (_Interval) + clearInterval(_Interval); + + let snackbarHeight = _Element.scrollHeight; // get the auto height as a px value + let snackbarTransitions = _Element.style.transition; + _Element.style.transition = ""; + + requestAnimationFrame(function() { + _Element.style.height = snackbarHeight + "px"; // set the auto height to the px height + _Element.style.opacity = 1; + _Element.style.marginTop = "0px"; + _Element.style.marginBottom = "0px"; + _Element.style.transition = snackbarTransitions + + requestAnimationFrame(function() { + _Element.style.height = "0px"; + _Element.style.opacity = 0; + }) + }); + + setTimeout(function() { + try { _Container.removeChild(_Element); } catch (e) { } + }, 1000); + }; + + _ConfigureDefaults(); + _Create(); + snackbar.Open(); +} + +function notify(scope){ + return function notify(str,opts){ + str = String(str) + opts = opts || {} + if( !opts.status ){ + opts.status = "info" + if( str.match(/error/g) ) opts.status = "danger" + if( str.match(/warning/g) ) opts.status = "warning" + } + opts = Object.assign({ message: str , status, timeout:2000 },opts) + SnackBar( opts ) + } +} + +function download(){ + function fetchAndDownload(dataurl, filename) { + var a = document.createElement("a"); + a.href = dataurl; + a.setAttribute("download", filename); + a.click(); + return false; + } + let file = document.location.search.replace(/\?/,'') + fetchAndDownload( file, file ) +} + +function embed(){ + // *TODO* this should be part of the XRF framework + let camera = document.querySelector('[camera]').object3D.parent // *TODO* fix for threejs + 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=[0-9\.-]+,[0-9\.-]+,[0-9\.-]+/,'') + newHash += `&${lastPos}` + document.location.hash = newHash.replace(/&&/,'&') + // End of *TODO* + window.notify(`Link copied to clipboard! ❤️
ps. to embed this experience in your website,
copy/paste the following into your HTML:
`,{timeout:10000}) +} diff --git a/dist/xrfragment.aframe.js b/dist/xrfragment.aframe.js index 3224cf2..bc17a7d 100644 --- a/dist/xrfragment.aframe.js +++ b/dist/xrfragment.aframe.js @@ -1060,8 +1060,7 @@ xrf.navigator.to = (url,flags,loader,data) => { return new Promise( (resolve,reject) => { let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url) - - if( !file || xrf.model.file == file ){ // we're already loaded + if( !file || (!data && xrf.model.file == file) ){ // we're already loaded hashbus.pub( url, xrf.model, flags ) // and eval local URI XR fragments xrf.navigator.updateHash(hash) return resolve(xrf.model) diff --git a/dist/xrfragment.three.js b/dist/xrfragment.three.js index ac09f3f..98a643b 100644 --- a/dist/xrfragment.three.js +++ b/dist/xrfragment.three.js @@ -1060,8 +1060,7 @@ xrf.navigator.to = (url,flags,loader,data) => { return new Promise( (resolve,reject) => { let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url) - - if( !file || xrf.model.file == file ){ // we're already loaded + if( !file || (!data && xrf.model.file == file) ){ // we're already loaded hashbus.pub( url, xrf.model, flags ) // and eval local URI XR fragments xrf.navigator.updateHash(hash) return resolve(xrf.model) diff --git a/dist/xrfragment.three.module.js b/dist/xrfragment.three.module.js index 13e782a..641dc93 100644 --- a/dist/xrfragment.three.module.js +++ b/dist/xrfragment.three.module.js @@ -1060,8 +1060,7 @@ xrf.navigator.to = (url,flags,loader,data) => { return new Promise( (resolve,reject) => { let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url) - - if( !file || xrf.model.file == file ){ // we're already loaded + if( !file || (!data && xrf.model.file == file) ){ // we're already loaded hashbus.pub( url, xrf.model, flags ) // and eval local URI XR fragments xrf.navigator.updateHash(hash) return resolve(xrf.model) diff --git a/example/aframe/sandbox/index.html b/example/aframe/sandbox/index.html index f9aa17f..62ef081 100644 --- a/example/aframe/sandbox/index.html +++ b/example/aframe/sandbox/index.html @@ -11,6 +11,7 @@ + - ➕ clone project - 🔗 share - ⬇️ scene + ➕ host + 🔗 share + ⬇️ scene XRF @@ -32,7 +33,7 @@ - + @@ -45,8 +46,7 @@ -