wip: remotestorage
This commit is contained in:
parent
ac2989df40
commit
5dd7f6a764
9 changed files with 512 additions and 72 deletions
293
dist/xrfragment.plugin.remotestorage.js
vendored
Normal file
293
dist/xrfragment.plugin.remotestorage.js
vendored
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* v0.5.1 generated at Thu May 15 04:48:16 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({})
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
import * as SUPER_THREE from 'super-three';
|
||||
import { DRACOLoader } from 'super-three/examples/jsm/loaders/DRACOLoader';
|
||||
import { GLTFLoader } from 'super-three/examples/jsm/loaders/GLTFLoader';
|
||||
import { KTX2Loader } from 'super-three/examples/jsm/loaders/KTX2Loader';
|
||||
import { OBB } from 'super-three/addons/math/OBB.js';
|
||||
import { OBJLoader } from 'super-three/examples/jsm/loaders/OBJLoader';
|
||||
import { FBXLoader } from 'super-three/examples/jsm/loaders/FBXLoader';
|
||||
import { USDZLoader } from 'super-three/examples/jsm/loaders/USDZLoader';
|
||||
import { ColladaLoader } from 'super-three/examples/jsm/loaders/ColladaLoader';
|
||||
import { MTLLoader } from 'super-three/examples/jsm/loaders/MTLLoader';
|
||||
import * as BufferGeometryUtils from 'super-three/examples/jsm/utils/BufferGeometryUtils';
|
||||
import { LightProbeGenerator } from 'super-three/examples/jsm/lights/LightProbeGenerator';
|
||||
import { TransformControls } from 'super-three/examples/jsm/controls/TransformControls.js';
|
||||
import { GLTFExporter } from 'super-three/examples/jsm/exporters/GLTFExporter.js';
|
||||
|
||||
var THREE = window.THREE = SUPER_THREE;
|
||||
|
||||
// TODO: Eventually include these only if they are needed by a component.
|
||||
require('../../vendor/DeviceOrientationControls'); // THREE.DeviceOrientationControls
|
||||
THREE.DRACOLoader = DRACOLoader;
|
||||
THREE.GLTFLoader = GLTFLoader;
|
||||
THREE.KTX2Loader = KTX2Loader;
|
||||
THREE.OBJLoader = OBJLoader;
|
||||
THREE.MTLLoader = MTLLoader;
|
||||
THREE.FBXLoader = FBXLoader;
|
||||
THREE.USDZLoader = USDZLoader;
|
||||
THREE.ColladaLoader = ColladaLoader;
|
||||
THREE.OBB = OBB;
|
||||
THREE.BufferGeometryUtils = BufferGeometryUtils;
|
||||
THREE.LightProbeGenerator = LightProbeGenerator;
|
||||
THREE.TransformControls = TransformControls;
|
||||
THREE.GLTFExporter = GLTFExporter || console.error("GLTFExporter not found");
|
||||
//THREE.Text = Text
|
||||
|
||||
export default THREE;
|
||||
|
|
@ -434,6 +434,7 @@ chatComponent.css = `
|
|||
margin-right:15px;
|
||||
width:100%;
|
||||
max-width:40%;
|
||||
margin-bottom:7px;
|
||||
}
|
||||
|
||||
.envelope,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ filesComponent = (el) => new Proxy({
|
|||
<div class="msg ui">
|
||||
<div>
|
||||
<div id="files">
|
||||
<i class="gg-close-o" id="close" onclick="$files.remove()"></i>
|
||||
<a onclick="$files.toggle(false)"><i class="gg-close-o" id="close"></i></a>
|
||||
<br>
|
||||
<div class="tab-frame">
|
||||
${data.tabs.map( (t) =>
|
||||
|
|
@ -29,8 +29,8 @@ filesComponent = (el) => new Proxy({
|
|||
`
|
||||
).join('')
|
||||
}
|
||||
<br><br><br>
|
||||
<div class="tab">
|
||||
<br><br>
|
||||
<div class="tab" style="margin-top:15px;">
|
||||
<div id="localFilesTab">
|
||||
<button id="localOpen" onclick="$files.fileLoaders()" ><i class="gg-software-upload"></i> open experience</button>
|
||||
<br>
|
||||
|
|
|
|||
|
|
@ -364,8 +364,9 @@ document.head.innerHTML += `
|
|||
opacity:0.5
|
||||
}
|
||||
|
||||
body.menu .js-snackbar__wrapper {
|
||||
top: 64px;
|
||||
body.menu .js-snackbar__wrapper,
|
||||
body.topbar .js-snackbar__wrapper {
|
||||
transform: translateY(40px);
|
||||
}
|
||||
|
||||
.transcript{
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@ window.frontend = (opts) => new Proxy({
|
|||
.setupCapture()
|
||||
.setupUserHints()
|
||||
.setupNetworkListeners()
|
||||
.hidetopbarWhenMenuCollapse()
|
||||
.setupTopbar()
|
||||
.hideTopbarWhenMenuCollapse()
|
||||
.hideUIWhenNavigating()
|
||||
|
||||
window.notify = this.notify
|
||||
|
|
@ -68,6 +69,16 @@ window.frontend = (opts) => new Proxy({
|
|||
return this
|
||||
},
|
||||
|
||||
setupTopbar(){
|
||||
// setup topbar handle
|
||||
this.$topbar = this.el.querySelector("#topbar")
|
||||
this.$topbar.toggle = (state) => {
|
||||
this.$topbar.style.display = state ? 'block' : 'none'
|
||||
document.body.classList[ state ? 'add' : 'remove' ](['topbar'])
|
||||
}
|
||||
return this
|
||||
},
|
||||
|
||||
setupIframeUrlHandler(){
|
||||
// allow iframe to open url
|
||||
window.addEventListener('message', (event) => {
|
||||
|
|
@ -175,9 +186,9 @@ window.frontend = (opts) => new Proxy({
|
|||
return this
|
||||
},
|
||||
|
||||
hidetopbarWhenMenuCollapse(){
|
||||
hideTopbarWhenMenuCollapse(){
|
||||
// hide topbar when menu collapse button is pressed
|
||||
document.addEventListener('$menu:collapse', (e) => this.el.querySelector("#topbar").style.display = e.detail === true ? 'block' : 'none')
|
||||
document.addEventListener('$menu:collapse', (e) => this.$topbar.toggle( e.detail === true ) )
|
||||
return this
|
||||
},
|
||||
|
||||
|
|
@ -250,9 +261,9 @@ window.frontend = (opts) => new Proxy({
|
|||
window.frontend.emit("notify",opts)
|
||||
},
|
||||
|
||||
download(){
|
||||
download(cb){
|
||||
|
||||
function exportScene(model,ext,file){
|
||||
function exportScene(model,ext,file,cb){
|
||||
|
||||
document.dispatchEvent( new CustomEvent('frontend.export',{detail:{ scene: model.scene,ext}}) )
|
||||
xrf.emit('export', {scene: model.scene, ext})
|
||||
|
|
@ -266,15 +277,17 @@ window.frontend = (opts) => new Proxy({
|
|||
return false;
|
||||
}
|
||||
|
||||
if( !cb ) cb = download
|
||||
|
||||
// setup exporters
|
||||
let defaultExporter = THREE.GLTFExporter
|
||||
if( !xrf.loaders['gltf'].exporter ) xrf.loaders['gltf'].exporter = defaultExporter
|
||||
if( !xrf.loaders['glb'].exporter ) xrf.loaders['glb'].exporter = defaultExporter
|
||||
const exporter = new xrf.loaders[ext].exporter()
|
||||
debugger
|
||||
|
||||
exporter.parse(
|
||||
model.scene,
|
||||
function ( glb ) { download(glb, `${file}`) }, // ready
|
||||
function ( glb ) { cb(glb, `${file}`) }, // ready
|
||||
function ( error ) { console.error(error) }, // error
|
||||
{
|
||||
binary:true,
|
||||
|
|
@ -293,9 +306,15 @@ window.frontend = (opts) => new Proxy({
|
|||
const Loader = xrf.loaders[fileExt]
|
||||
loader = new Loader().setPath( dir )
|
||||
notify('exporting scene<br><br>please wait..')
|
||||
loader.load(url, (model) => {
|
||||
exportScene(model,fileExt,file)
|
||||
}, console.error )
|
||||
|
||||
fetch(url, { method: 'HEAD' })
|
||||
.then( (res) => { // url exists
|
||||
if( res.ok ){
|
||||
loader.load( url, (model) => exportScene(model,fileExt,file,cb), console.error )
|
||||
}else{
|
||||
exportScene(xrf.model,fileExt,file,cb)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
updateHashPosition(randomize){
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
const WebXRF = { name: 'webxr', builder: function(privateClient, publicClient) {
|
||||
return {
|
||||
exports: {
|
||||
addScene: function() {}
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
|
@ -14,33 +14,68 @@ remoteStorageComponent = (el) => new Proxy({
|
|||
#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">
|
||||
<button id="remoteOpen" ><i class="gg-software-upload"></i> open experience</button>
|
||||
<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 id="remoteSave"><i class="gg-software-download"></i> save private experience</button>
|
||||
<button onclick="$remotestorage.savePrivate()"><i class="gg-software-download"></i> save experience</button>
|
||||
<br>
|
||||
<button id="remoteSave"><i class="gg-globe-alt"></i> save public experience</button>
|
||||
<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: "online"})
|
||||
$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}}) )
|
||||
|
|
@ -68,21 +103,27 @@ remoteStorageComponent = (el) => new Proxy({
|
|||
dropbox: "4jc8nx1lbarp472"
|
||||
}
|
||||
const modules = []
|
||||
if( typeof WebXRF != undefined ){
|
||||
modules.push(WebXRF) // defined in remotestorage-module-webXRF.js
|
||||
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('connected', (e) => { this.connected = true })
|
||||
//remoteStorage.on('network-offline', (e) => this.el.sceneEl.emit('remoteStorage.network-offline',e) )
|
||||
//remoteStorage.on('network-online', (e) => this.el.sceneEl.emit('remoteStorage.network-online',e) )
|
||||
//remoteStorage.on('error', (e) => this.el.sceneEl.emit('remoteStorage.error',e) )
|
||||
remoteStorage.on('ready', (e) => { } )
|
||||
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()
|
||||
|
||||
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
|
||||
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 = {}
|
||||
|
|
@ -93,6 +134,103 @@ remoteStorageComponent = (el) => new Proxy({
|
|||
|
||||
},
|
||||
|
||||
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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue