293 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			293 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/*
 | 
						|
 * v0.5.1 generated at Thu May 22 07:30:49 PM CEST 2025
 | 
						|
 * https://xrfragment.org
 | 
						|
 * SPDX-License-Identifier: AGPL-3.0-or-later
 | 
						|
 */
 | 
						|
(function(){
 | 
						|
// this demonstrates the remotestorage aframe component 
 | 
						|
 | 
						|
// reactive component for displaying the menu 
 | 
						|
remoteStorageComponent = (el) => new Proxy({
 | 
						|
 | 
						|
  html: (data) => (`
 | 
						|
    <style type="text/css">
 | 
						|
      body #files .rs-button-big{
 | 
						|
        background: #FFF;
 | 
						|
        box-shadow: none;
 | 
						|
        border: 1px solid #CCC;
 | 
						|
        padding: 10px 0px 49px 10px;
 | 
						|
      }
 | 
						|
      #files .rs-button{
 | 
						|
        background:#CCC;
 | 
						|
      }
 | 
						|
      #files input {
 | 
						|
        min-width:345px;
 | 
						|
      }
 | 
						|
      #files #buttons select,
 | 
						|
      #files #buttons button{
 | 
						|
        width:255px;
 | 
						|
        max-width:unset;
 | 
						|
      }
 | 
						|
      #files #listing{
 | 
						|
        margin-bottom:15px;
 | 
						|
      }
 | 
						|
      #files #delete{
 | 
						|
        display: none;
 | 
						|
        transform: translate(10px, 5px);
 | 
						|
      }
 | 
						|
      #links{
 | 
						|
        display:none
 | 
						|
      }
 | 
						|
    </style> 
 | 
						|
 | 
						|
    <div id="remoteFilesTab">
 | 
						|
      <div id="rswidget"></div>
 | 
						|
      <br>
 | 
						|
      <div id="buttons" style="display:none">
 | 
						|
        <select id="listing" alt="your files"></select> 
 | 
						|
        <i class="gg-close-o" id="delete" alt="delete" onclick="$remotestorage.remove()"></i>
 | 
						|
        <a href="https://inspektor.5apps.com/?path=%2Fwebxr%2F" target="_blank" style="margin-left:15px">manage files</a>
 | 
						|
        <br>
 | 
						|
        <button onclick="$remotestorage.savePrivate()"><i class="gg-software-download"></i> save experience</button>
 | 
						|
        <br>
 | 
						|
        <button onclick="$remotestorage.savePublic()" ><i class="gg-globe-alt"></i> publish online</button>
 | 
						|
        <br>
 | 
						|
        <div id="links">
 | 
						|
          <br>
 | 
						|
          <div><i class="gg-link"></i>   3D file</div>
 | 
						|
          <input type="text" value='' id="file">
 | 
						|
          <br>
 | 
						|
          <div><i class="gg-link"></i>   3D file in webviewer</div>
 | 
						|
          <input type="text" value='' id="webviewer">
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
  `),
 | 
						|
 | 
						|
  connected: false,
 | 
						|
  $listing: false,
 | 
						|
  $links: false,
 | 
						|
 | 
						|
  init(opts){
 | 
						|
    // create HTML element
 | 
						|
    $files.tabs = $files.tabs.concat({id:"remoteFiles", name: "remote storage"})
 | 
						|
    el.innerHTML = this.html(this)
 | 
						|
    el.className = "tab"
 | 
						|
    document.querySelector("#files .tab-frame").appendChild(el);
 | 
						|
 | 
						|
    // setup references
 | 
						|
    this.$listing = document.querySelector('#files .tab-frame select#listing');
 | 
						|
    this.$links   = document.querySelector('#files .tab-frame #links');
 | 
						|
 | 
						|
    // setup input listeners
 | 
						|
    (['click']).map( (e) => el.addEventListener(e, (ev) => typeof this[e] == 'function' && this[e](ev.target.id,ev) ) )
 | 
						|
    
 | 
						|
    // signal ready 
 | 
						|
    setTimeout( () => {
 | 
						|
      document.dispatchEvent( new CustomEvent("remotestorage:ready", {detail: {$files:this,xrf}}) )
 | 
						|
    },100)
 | 
						|
 | 
						|
    this.loadScript( () => this.initRemoteStorage() )
 | 
						|
 | 
						|
    return this
 | 
						|
  },
 | 
						|
 | 
						|
  loadScript(cb){
 | 
						|
    let el = document.createElement("script")
 | 
						|
    el.setAttribute("defer","")
 | 
						|
    el.src = "https://unpkg.com/remotestoragejs@2.0.0-beta.7/release/remotestorage.js"
 | 
						|
    document.head.appendChild(el)
 | 
						|
 | 
						|
    el = document.createElement("script")
 | 
						|
    el.src = "https://unpkg.com/remotestorage-widget@1.6.0/build/widget.js"
 | 
						|
    el.addEventListener('load', () => setTimeout(cb,2000) )
 | 
						|
    document.head.appendChild(el)
 | 
						|
  },
 | 
						|
 | 
						|
  initRemoteStorage(){
 | 
						|
    let apis = {
 | 
						|
      dropbox: "4jc8nx1lbarp472"
 | 
						|
    }
 | 
						|
    const modules = []
 | 
						|
    if( typeof WebXR != undefined ){
 | 
						|
      modules.push(WebXR) // defined in remotestorage-module-webXRF.js
 | 
						|
    }
 | 
						|
    window.remoteStorage = new RemoteStorage({logging: true, modules })
 | 
						|
    if( Object.keys(apis).length ) remoteStorage.setApiKeys(apis)
 | 
						|
 | 
						|
    remoteStorage.on('not-connected',   (e) => { this.connected = false })
 | 
						|
    remoteStorage.on('ready',           (e) => { })
 | 
						|
    remoteStorage.on('connected',       (e) => { 
 | 
						|
      this.connected = true 
 | 
						|
      // force open dialog and click remote-tab
 | 
						|
      frontend.$topbar.toggle(true)
 | 
						|
      $files.toggle(true)
 | 
						|
      document.querySelector("#files input#remoteFiles").click()
 | 
						|
 | 
						|
      this.updateFiles()
 | 
						|
    })
 | 
						|
 | 
						|
    remoteStorage.access.claim( `webxr`, 'rw');           // our data dir
 | 
						|
    remoteStorage.caching.enable( `/webxr/` )             // local-first, remotestorage-second
 | 
						|
    remoteStorage.caching.enable( `/public/webxr/` )      // local-first, remotestorage-second
 | 
						|
 | 
						|
    // create widget
 | 
						|
    let opts = {}
 | 
						|
    opts.modalBackdrop = false
 | 
						|
    opts.leaveOpen     = true
 | 
						|
    widget = new window.Widget(window.remoteStorage, opts)
 | 
						|
    widget.attach( "rswidget" );
 | 
						|
 | 
						|
  },
 | 
						|
 | 
						|
  savePrivate(){
 | 
						|
    frontend.download( (data,filename) => {
 | 
						|
      filename = prompt('save-as filename', filename)
 | 
						|
      remoteStorage.webxr.add(data,{public:false,filename,mimetype: 'model/glb-binary'})    
 | 
						|
      .then( () => window.notify(`saved webxr/${filename} to remote storage`) )
 | 
						|
      .catch( (e) => {
 | 
						|
        console.error(e)
 | 
						|
        window.notify(`failed to save webxr/${filename} to remote storage`,{status:'error'})
 | 
						|
      })
 | 
						|
    })
 | 
						|
  },
 | 
						|
 | 
						|
  savePublic(){
 | 
						|
    frontend.download( (data,filename) => {
 | 
						|
      filename = prompt('save-as filename', filename)
 | 
						|
      opts = {public:true,filename,mimetype: 'model/glb-binary'}
 | 
						|
      remoteStorage.webxr.add(data,opts)
 | 
						|
      .then( (res) => {
 | 
						|
        window.notify(`saved webxr/${filename} to remote storage`) 
 | 
						|
        const link = opts.client.storage.remote.href + opts.client.base + filename 
 | 
						|
        const linkWebView = document.location.href.replace(/(\?|#).*/,'') + `?${link}` 
 | 
						|
        this.$links.querySelector("#file").value = link
 | 
						|
        this.$links.querySelector("#webviewer").value = linkWebView 
 | 
						|
        this.$links.style.display = 'block'
 | 
						|
      })
 | 
						|
      .catch( (e) => {
 | 
						|
        console.error(e)
 | 
						|
        window.notify(`failed to save webxr/${filename} to remote storage`,{status:'error'})
 | 
						|
      })
 | 
						|
    })
 | 
						|
  },
 | 
						|
 | 
						|
  openPrivate(file){
 | 
						|
    if( !confirm(`teleport to ${file} on your remotestorage?`) ) return
 | 
						|
    remoteStorage.webxr.getFile(file)
 | 
						|
    .then( (res) => {
 | 
						|
      for( var i in xrf.loaders ){
 | 
						|
        if( file.replace(/.*\./).match(i) ){
 | 
						|
          xrf.navigator.URI.file = '' // bypass cached file (easy refresh same file for testing)
 | 
						|
          xrf.navigator.to(file,null, (new xrf.loaders[i]()), res.data)
 | 
						|
          return
 | 
						|
        }
 | 
						|
      }
 | 
						|
      throw 'unknown filetype: '+file
 | 
						|
    })
 | 
						|
    .catch( (e) => {
 | 
						|
      console.error(e)
 | 
						|
      window.notify("could not load webxr/"+file)
 | 
						|
    })
 | 
						|
  },
 | 
						|
 | 
						|
  remove(){
 | 
						|
    const currentFile = el.querySelector('select#listing').value
 | 
						|
    if( confirm("remove "+currentFile+" from remote storage?") ){
 | 
						|
      remoteStorage.webxr.remove(currentFile)
 | 
						|
      .then( () => {
 | 
						|
        window.notify(`removed webxr/${filename} from remote storage`) 
 | 
						|
        this.updateFiles()
 | 
						|
      })
 | 
						|
      .catch( (e) => {
 | 
						|
        console.error(e)
 | 
						|
        window.notify(`could not webxr/${filename} from remote storage`,{status:'error'}) 
 | 
						|
      })
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  updateFiles(){
 | 
						|
    remoteStorage.webxr.getListing()
 | 
						|
    .then( (listing) => {
 | 
						|
 | 
						|
      this.$listing.innerHTML = '' // empty
 | 
						|
 | 
						|
      const addOption = (value,text) => {
 | 
						|
        let opt = document.createElement("option")
 | 
						|
        opt.text = text
 | 
						|
        opt.value = value
 | 
						|
        this.$listing.appendChild(opt)
 | 
						|
      }
 | 
						|
 | 
						|
      addOption("","--- your experiences ---")
 | 
						|
      for( let file in listing ){
 | 
						|
        if( file.match(/\.(glb|gltf|usd|obj|col|fbx)$/) ) addOption(file,file)
 | 
						|
      }
 | 
						|
 | 
						|
      // autoload selection 
 | 
						|
      if( !this.updateFiles.autoload ){ // run once
 | 
						|
        this.$listing.addEventListener('change', () => {
 | 
						|
          if( this.$listing.options.selectedIndex > 0 ) this.openPrivate(this.$listing.value) 
 | 
						|
          document.querySelector("#delete").style.display = this.$listing.options.selectedIndex == 0 ? "none" : "inline-block"
 | 
						|
          this.$links.style.display = 'none'
 | 
						|
        })
 | 
						|
        this.updateFiles.autoload = true
 | 
						|
      }
 | 
						|
    })
 | 
						|
 | 
						|
  },
 | 
						|
 | 
						|
  click(id,e){
 | 
						|
    //switch(id){
 | 
						|
    //  case "more": return this.toggle(); break;
 | 
						|
    //}
 | 
						|
  }
 | 
						|
},
 | 
						|
{
 | 
						|
 | 
						|
  get(me,k,v){ return me[k] },
 | 
						|
 | 
						|
  set(me,k,v){ 
 | 
						|
    me[k] = v    
 | 
						|
    switch( k ){
 | 
						|
        case 'connected': el.querySelector("#buttons").style.display = v ? 'block' : 'none'; break;
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
})
 | 
						|
 | 
						|
// reactify component!
 | 
						|
document.addEventListener('$files:ready', (e) => {
 | 
						|
  window.$remotestorage = remoteStorageComponent( document.createElement('div') ).init(e.detail)
 | 
						|
})
 | 
						|
const WebXR = { name: 'webxr', builder: function(privateClient, publicClient) {
 | 
						|
  return {
 | 
						|
    exports: {
 | 
						|
      add: function(data,opts) {
 | 
						|
        if( !data || !opts.filename || !opts.mimetype) throw 'webxr.add() needs filedata + filename + mimetype'
 | 
						|
        const client = opts.client = opts.public ? publicClient : privateClient;
 | 
						|
        return client.storeFile(opts.mimetype, opts.filename,data)
 | 
						|
      },
 | 
						|
 | 
						|
      getListing: function(a,opts){
 | 
						|
        opts = opts || {}
 | 
						|
        const client = opts.public ? publicClient : privateClient;
 | 
						|
        return client.getListing(a)
 | 
						|
      },
 | 
						|
 | 
						|
      getFile: function(file,opts){
 | 
						|
        opts = opts || {}
 | 
						|
        const client = opts.public ? publicClient : privateClient;
 | 
						|
        return client.getFile(file)
 | 
						|
      },
 | 
						|
 | 
						|
      remove: function(file,opts){
 | 
						|
        opts = opts || {}
 | 
						|
        const client = opts.public ? publicClient : privateClient;
 | 
						|
        return client.remove(file)
 | 
						|
      }
 | 
						|
 | 
						|
    }
 | 
						|
  }
 | 
						|
}};
 | 
						|
}).apply({})
 |