Skip to content

Commit 80da443

Browse files
committed
Added clone and remove icons on scenegraph
1 parent d8dc74d commit 80da443

File tree

5 files changed

+75
-21
lines changed

5 files changed

+75
-21
lines changed

‎example/index.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<script src="js/aframe.min.js"></script>
77
</head>
88
<body>
9-
<a-scene debug stats>
9+
<a-scene debug="true" stats>
1010
<a-assets>
1111
<a-mixin id="blue" material="color: #4CC3D9"></a-mixin>
1212
<a-mixin id="blueBox" geometry="primitive: box; depth: 2; height: 5; width: 1" material="color: #4CC3D9"></a-mixin>

‎src/actions/entity.js‎

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,38 @@ export function updateEntity (entity, componentName, propertyName, value) {
4747
export function removeEntity (entity, force) {
4848
if (entity) {
4949
if (force === true || confirm('Do you really want to remove the entity: `' + (entity.id || entity.tagName) + '`')) {
50+
var closest = findClosestEntity(entity);
5051
entity.parentNode.removeChild(entity);
51-
// @todo Select the next entity in the scenegraph
52-
editor.selectEntity(null);
52+
editor.selectEntity(closest);
5353
}
5454
}
5555
}
5656

57+
function findClosestEntity(entity) {
58+
// First we try to find the after the entity
59+
var nextEntity = entity.nextElementSibling;
60+
while (nextEntity && (!nextEntity.isEntity || nextEntity.isEditor)) {
61+
nextEntity = nextEntity.nextElementSibling;
62+
}
63+
64+
// Return if we found it
65+
if (nextEntity && nextEntity.isEntity && !nextEntity.isEditor) {
66+
return nextEntity;
67+
}
68+
// Otherwise try to find before the entity
69+
var prevEntity = entity.previousElementSibling;
70+
while (prevEntity && (!prevEntity.isEntity || prevEntity.isEditor)) {
71+
prevEntity = prevEntity.previousElementSibling;
72+
}
73+
74+
// Return if we found it
75+
if (prevEntity && prevEntity.isEntity && !prevEntity.isEditor) {
76+
return prevEntity;
77+
}
78+
79+
return null;
80+
}
81+
5782
/**
5883
* Remove the selected entity
5984
* @param {boolean} force (Optional) If true it won't ask for confirmation
@@ -62,6 +87,16 @@ export function removeSelectedEntity (force) {
6287
removeEntity(editor.selectedEntity);
6388
}
6489

90+
91+
/**
92+
* Insert an node after a referenced node.
93+
* @param {Element} newNode Node to insert.
94+
* @param {Element} referenceNode Node used as reference to insert after it.
95+
*/
96+
function insertAfter (newNode, referenceNode) {
97+
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
98+
}
99+
65100
/**
66101
* Clone an entity, inserting it after the cloned one.
67102
* @param {Element} entity Entity to clone
@@ -73,9 +108,14 @@ export function cloneEntity (entity) {
73108
});
74109

75110
// Get a valid unique ID for the entity
76-
copy.id = getUniqueId(entity.id);
77-
//insertAfter(copy, entity);
78-
entity.insertAdjacentHTML('afterend', copy.outerHTML);
111+
if (entity.id) {
112+
copy.id = getUniqueId(entity.id);
113+
}
114+
copy.addEventListener('loaded', function() {
115+
Events.emit('sceneModified');
116+
editor.selectEntity(copy);
117+
});
118+
insertAfter(copy, entity);
79119
}
80120

81121
/**
@@ -85,15 +125,6 @@ export function cloneSelectedEntity () {
85125
cloneEntity(editor.selectedEntity);
86126
}
87127

88-
/**
89-
* Insert an node after a referenced node.
90-
* @param {Element} newNode Node to insert.
91-
* @param {Element} referenceNode Node used as reference to insert after it.
92-
*/
93-
function insertAfter (newNode, referenceNode) {
94-
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
95-
}
96-
97128
/**
98129
* Detect element's Id collision and returns a valid one
99130
* @param {string} baseId Proposed Id

‎src/components/Main.js‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
/* global editor */
22
require('../lib/vendor/ga');
3-
const Events = require('../lib/Events.js');
4-
const Editor = require('../lib/editor');
53

64
import React from 'react';
75
import ReactDOM from 'react-dom';

‎src/components/SceneGraph.js‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import debounce from 'lodash.debounce';
33

4+
import {removeEntity, cloneEntity} from '../actions/entity';
45
const Events = require('../lib/Events.js');
56

67
const ICONS = {
@@ -109,11 +110,12 @@ export default class SceneGraph extends React.Component {
109110

110111
const pad = '&nbsp;&nbsp;&nbsp;'.repeat(depth);
111112
const label = child.id ? child.id : '&lt;' + child.tagName.toLowerCase() + '&gt;';
113+
const html = pad + label + extra;
112114

113115
options.push({
114116
static: true,
115117
value: child,
116-
html: pad + label + extra
118+
html: html
117119
});
118120

119121
if (child.tagName.toLowerCase() !== 'a-entity') {
@@ -176,8 +178,15 @@ export default class SceneGraph extends React.Component {
176178
let className = 'option' + (option.value === this.state.value ? ' active' : '');
177179
return (
178180
<div key={idx} className={className} value={option.value}
179-
dangerouslySetInnerHTML={{__html: option.html}}
180-
onClick={() => {this.handleEntityClick(option.value)}}/>
181+
onClick={this.setValue.bind(this, option.value)}>
182+
<span dangerouslySetInnerHTML={{__html: option.html}}></span>
183+
<span className="icons">
184+
<a href="#" onClick={() => cloneEntity(option.value)}
185+
title="Clone entity" className="button fa fa-clone"></a>
186+
<a href="#" onClick={(e) => {e.stopPropagation(); removeEntity(option.value)}}
187+
title="Remove entity" className="button fa fa-trash-o"></a>
188+
</span>
189+
</div>
181190
);
182191
});
183192
}

‎src/css/main.css‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ input.number:focus {
275275
left: 0;
276276
top: 33px;
277277
bottom: 0;
278-
width: 180px;
278+
width: 200px;
279279
overflow: auto;
280280
background: #2b2b2b;
281281
display: flex;
@@ -924,13 +924,29 @@ code, pre {
924924
.outliner .option {
925925
padding: 4px;
926926
white-space: nowrap;
927+
display: flex;
928+
justify-content: space-between;
927929
}
928930

929931
.outliner .option.active {
930932
background-color: #1faaf2;
931933
color: #fff;
932934
}
933935

936+
.outliner .option .icons {
937+
display: none;
938+
margin: 0 3px 0 10px;
939+
}
940+
941+
.outliner .option .icons .button {
942+
font-size: 12px;
943+
color: #fff;
944+
}
945+
946+
.outliner .option.active .icons {
947+
display: inline;
948+
}
949+
934950
.outliner .fa {
935951
color: #aaa;
936952
}

0 commit comments

Comments
 (0)