editor improvements

This commit is contained in:
Leon van Kammen 2024-03-15 10:32:11 +00:00
parent 85d25386c7
commit 24f1336c41
4 changed files with 84 additions and 44 deletions

View file

@ -2,6 +2,7 @@ AFRAME.registerComponent('vconsole', {
init: function () { init: function () {
//AFRAME.XRF.navigator.to("https://coderofsalvation.github.io/xrsh-media/assets/background.glb") //AFRAME.XRF.navigator.to("https://coderofsalvation.github.io/xrsh-media/assets/background.glb")
let aScene = AFRAME.scenes[0] let aScene = AFRAME.scenes[0]
return
// return // return
document.head.innerHTML += ` document.head.innerHTML += `

View file

@ -11,6 +11,7 @@ $editorPopup = (el) => new Proxy({
<td><b class="badge">href</a></td> <td><b class="badge">href</a></td>
<td> <td>
<input type="text" id="href" placeholder="https://foo.com" maxlength="255" <input type="text" id="href" placeholder="https://foo.com" maxlength="255"
onkeydown="document.querySelector('#editActions').classList.add('show')"
onkeyup="$editor.selected.edited = $editor.selected.userData.href = this.value" onkeyup="$editor.selected.edited = $editor.selected.userData.href = this.value"
value="${$editor.selected.userData.href||''}" /> value="${$editor.selected.userData.href||''}" />
</td> </td>
@ -19,6 +20,7 @@ $editorPopup = (el) => new Proxy({
<td><b class="badge">src</a></td> <td><b class="badge">src</a></td>
<td> <td>
<input type="text" id="src" placeholder="https://foo.com" maxlength="255" <input type="text" id="src" placeholder="https://foo.com" maxlength="255"
onkeydown="document.querySelector('#editActions').classList.add('show')"
onkeyup="$editor.selected.edited = $editor.selected.userData.src = this.value" onkeyup="$editor.selected.edited = $editor.selected.userData.src = this.value"
value="${$editor.selected.userData.src||''}" /> value="${$editor.selected.userData.src||''}" />
</td> </td>
@ -27,23 +29,38 @@ $editorPopup = (el) => new Proxy({
<td><b class="badge">tag</a></td> <td><b class="badge">tag</a></td>
<td> <td>
<input type="text" id="tag" placeholder="foo bar" maxlength="255" <input type="text" id="tag" placeholder="foo bar" maxlength="255"
onkeydown="document.querySelector('#editActions').classList.add('show')"
onkeyup="$editor.selected.edited = $editor.selected.userData.tag = this.value" onkeyup="$editor.selected.edited = $editor.selected.userData.tag = this.value"
value="${$editor.selected.userData.tag||''}" /> value="${$editor.selected.userData.tag||''}" />
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<br>
<div id="editActions">
<button class="download" onclick="$editor.export()"><i class="gg-software-download"></i> &nbsp;&nbsp;&nbsp;download scene file</button>
<br>
</div>
</div> </div>
<style type="text/css"> <style type="text/css">
table.editorPopup input{ table.editorPopup input{
min-width:200px; min-width:200px;
} }
table.editorPopup tr td:nth-child(1){
text-align:left;
}
#editActions{
visibility:hidden;
}
#editActions.show{
visibility:visible;
}
</style> </style>
`, `,
init(opts){ init(opts){
el.innerHTML = this.html(opts) el.innerHTML = this.html(opts)
return el return (this.el = el)
}, },
},{ },{
@ -84,52 +101,76 @@ $editor = (el,opts) => new Proxy({
</style> </style>
`, `,
enabled: false, selecting: false,
editing: false,
helper: null, helper: null,
selected: null, selected: null,
init(opts){ init(opts){
el.innerHTML = this.html el.innerHTML = this.html
window.frontend.el.querySelector('#topbar').appendChild(el); window.frontend.el.querySelector('#topbar').appendChild(el);
el.querySelector('.edit-btn').addEventListener('click', () => $editor.enabled = true ) el.querySelector('.edit-btn').addEventListener('click', () => {
if( $editor.selecting || $editor.editing ) this.reset()
else{
$editor.selecting = true
$editor.editing = false
}
})
document.addEventListener('download', (e) => this.updateOriginalScene(e.detail) ) document.addEventListener('frontend.export', (e) => this.updateOriginalScene(e.detail) )
xrf.addEventListener('href', (opts) => {
if( this.selecting || this.editing ) return opts.promise().reject("$editor should block hrefs while editing") // never resolve (block hrefs from interfering)
})
return this return this
}, },
reset(){
if( this.helper) xrf.scene.remove(this.helper)
this.selecting = false
this.editing = false
},
export(){
window.frontend.download()
this.reset()
},
editNode(){ editNode(){
if( !this.enabled ) return console.log("not editing") if( !this.selecting ) return console.log("not editing")
$editor.enabled = false // disable selections $editor.editing = true
this.enableHref(this.selected,true) // re-enable hrefs
//`<b>XR Fragment:</b> #${this.selected.name}<br><br>${this.getMetaData(this.selected)}`),{ //`<b>XR Fragment:</b> #${this.selected.name}<br><br>${this.getMetaData(this.selected)}`),{
setTimeout( () => this.reset(), 4000 )
notify( $editorPopup( document.createElement('div') ).init(this) , { notify( $editorPopup( document.createElement('div') ).init(this) , {
timeout:false, timeout:false,
onclose: () => xrf.scene.remove( this.helper ) onclose: () => this.reset()
}) })
}, },
initEdit(scene){ initEdit(scene){
if( !this.listenersInstalled ){
AFRAME.scenes[0].addEventListener('click', () => this.editNode() ) AFRAME.scenes[0].addEventListener('click', () => this.editNode() )
this.listenersInstalled = true
}
scene.traverse( (n) => { scene.traverse( (n) => {
let highlight = (n) => (e) => { let highlight = (n) => (e) => {
if( this.selected ) this.enableHref(this.selected,true) // re-enable href of previous selection if( !this.selecting || this.editing ) return // do nothing
if( this.helper){ if( this.helper){
if( this.helper.selected == n.uuid ) return // already selected if( this.helper.selected == n.uuid ) return // already selected
xrf.scene.remove(this.helper) xrf.scene.remove(this.helper)
} }
if( !this.enabled ) return // do nothing
this.selected = n this.selected = n
this.helper = new THREE.BoxHelper( n, 0xFF00FF ) this.helper = new THREE.BoxHelper( n, 0xFF00FF )
this.helper.material.linewidth = 5 this.helper.material.linewidth = 4
this.helper.material.color = xrf.focusLine.material.color this.helper.material.color = xrf.focusLine.material.color
this.helper.material.dashSize = xrf.focusLine.material.dashSize
this.helper.material.gapSize = xrf.focusLine.material.gapSize
this.helper.selected = n.uuid this.helper.selected = n.uuid
xrf.scene.add(this.helper) xrf.scene.add(this.helper)
let div = document.createElement('div') let div = document.createElement('div')
notify(`<b>#${n.name}</b><br>${this.getMetaData(this.selected)}`) notify(`<b>#${n.name}</b><br>${this.getMetaData(this.selected)}`)
this.enableHref(n,false) // prevent clicks from doing their usual teleporting/executions
} }
if( n.material ) n.addEventListener('mousemove', n.highlightOnMouseMove = highlight(n) ) if( n.material ) n.addEventListener('mousemove', n.highlightOnMouseMove = highlight(n) )
}) })
@ -143,24 +184,15 @@ $editor = (el,opts) => new Proxy({
return html return html
}, },
enableHref(n, state){ updateOriginalScene(e){
if( n.userData.XRF && n.userData.XRF.href && n.userData.XRF.href.exec ){ const {scene,ext} = e
let exec = n.userData.XRF.href.exec scene.traverse( (n) => {
if( !state && !exec.bak ){ if( !n.name ) return
exec.bak = exec // overwrite node with modified userData from scene
n.userData.XRF.href.exec = function(){} let o = xrf.scene.getObjectByName(n.name)
} if( o && o.edited ){
if( state && exec.bak ){ for( let i in o.userData ) n.userData[i] = o.userData[i]
n.userData.XRF.href.exec = exec.bak console.log("updating export")
}
}
},
updateOriginalScene(opts){
let {scene,ext} = opts
xrf.scene.traverse( (n) => {
if( n.edited && scene.getObjectByName(n.name) ){
scene.getObjectByName(n.name).userData = n.userData
} }
}) })
} }
@ -174,20 +206,18 @@ $editor = (el,opts) => new Proxy({
me[k] = v me[k] = v
switch( k ){ switch( k ){
case "enabled":{ case "selecting":{
lookctl = $('[look-controls]').components['look-controls'] lookctl = $('[look-controls]').components['look-controls']
if( v ){ if( v ){
lookctl.pause() // prevent click-conflict lookctl.pause() // prevent click-conflict
notify("click an object to reveal XR Fragment metadata") notify("click an object to reveal XR Fragment metadata")
xrf.interactive.raycastAll = true xrf.interactive.raycastAll = true
if( !xrf.scene.initEdit ) me.initEdit(xrf.scene) me.initEdit(xrf.scene)
lookctl.pause() // prevent click-conflict lookctl.pause() // prevent click-conflict
el.querySelector('.edit-btn').classList.add(['enabled']) el.querySelector('.edit-btn').classList.add(['enabled'])
}else{ }else{
lookctl.pause() // prevent click-conflict lookctl.pause() // prevent click-conflict
xrf.scene.traverse( (n) => { xrf.scene.traverse( (n) => {
me.enableHref(n,true)
if( n.highlightOnMouseMove ){ if( n.highlightOnMouseMove ){
n.removeEventListener( 'mousemove', n.highlightOnMouseMove ) n.removeEventListener( 'mousemove', n.highlightOnMouseMove )
} }

View file

@ -252,14 +252,20 @@ window.frontend = (opts) => new Proxy({
return false; return false;
} }
function exportScene(scene,ext){ function exportScene(model,ext){
const exporter = new (xrf.loaders[ext].exporter || defaultExporter) const exporter = new (xrf.loaders[ext].exporter || defaultExporter)
document.dispatchEvent( new CustomEvent('download',{detail:{scene,ext}}) ) document.dispatchEvent( new CustomEvent('frontend.export',{detail:{ scene: model.scene,ext}}) )
exporter.parse( exporter.parse(
scene, model.scene,
function ( glb ) { download(glb, `${file}.${ext}`) }, // ready function ( glb ) { download(glb, `${file}`) }, // ready
function ( error ) { console.error(error) }, // error function ( error ) { console.error(error) }, // error
{binary:true} {
binary:true,
onlyVisible: false,
animations: model.animations,
includeCustomExtensions: true,
trs:true
}
); );
} }
@ -268,8 +274,9 @@ window.frontend = (opts) => new Proxy({
let {urlObj,dir,file,hash,ext} = xrf.navigator.origin = xrf.parseUrl(url) let {urlObj,dir,file,hash,ext} = xrf.navigator.origin = xrf.parseUrl(url)
const Loader = xrf.loaders[ext] const Loader = xrf.loaders[ext]
loader = new Loader().setPath( dir ) loader = new Loader().setPath( dir )
notify('exporting scene<br><br>please wait..')
loader.load(url, (model) => { loader.load(url, (model) => {
exportScene(model.scene,ext,file) exportScene(model,ext,file)
}) })
}, },
@ -315,7 +322,7 @@ window.frontend = (opts) => new Proxy({
if( network.meetingLink && !document.location.hash.match(/meet=/) ){ if( network.meetingLink && !document.location.hash.match(/meet=/) ){
document.location.hash += `&meet=${network.meetingLink}` document.location.hash += `&meet=${network.meetingLink}`
} }
if( !document.location.hash.match(/pos=/) ){ if( !document.location.hash.match(/pos=/) && (network.posName || network.pos) ){
document.location.hash += `&pos=${ network.posName || network.pos }` document.location.hash += `&pos=${ network.posName || network.pos }`
} }
let url = window.location.href let url = window.location.href

View file

@ -4,7 +4,9 @@ xrf.frag.defaultPredefinedViews = (opts) => {
let {scene,model} = opts; let {scene,model} = opts;
scene.traverse( (n) => { scene.traverse( (n) => {
if( n.userData && n.userData['#'] ){ if( n.userData && n.userData['#'] ){
xrf.hashbus.pub( n.userData['#'], n ) // evaluate default XR fragments without affecting URL if( !n.parent ){
xrf.navigator.to( n.userData['#'] )
}else xrf.hashbus.pub( n.userData['#'], n ) // evaluate default XR fragments without affecting URL
} }
}) })
} }