diff --git a/demo/css/matter-tools.css b/demo/css/matter-tools.css index 4870ff0..958da6e 100644 --- a/demo/css/matter-tools.css +++ b/demo/css/matter-tools.css @@ -8,40 +8,44 @@ body .dg.main { body.gui-auto-hide .dg.ac { right: -233px; - - -webkit-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - -moz-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - -o-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); /* custom */ - - -webkit-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - -moz-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - -o-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); /* custom */ - - transition-delay: 3s; - -webkit-transition-delay: 3s; } body .dg.ac:hover, body.gui-show .dg.ac { right: 0px; +} +body.gui-auto-hide.gui-transitions .dg.ac { + -webkit-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); + -moz-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); + -o-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); + transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); + + -webkit-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); + -moz-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); + -o-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); + transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); + + transition-delay: 3s; + -webkit-transition-delay: 3s; +} + +body.gui-transitions .dg.ac:hover, +body.gui-show.gui-transitions .dg.ac { -webkit-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); -moz-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); -o-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); - transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); /* custom */ + transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); -webkit-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); -moz-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); -o-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); - transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); /* custom */ + transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); transition-delay: 0; -webkit-transition-delay: 0; } - body .dg.main.taller-than-window .close-button { border-top: 1px solid #444; border-right: 4px solid #444; @@ -89,6 +93,7 @@ body .dg li.save-row .button { body .dg li.title { padding-left: 22px; + border-bottom: 1px solid #555; background: #444 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 10px 10px no-repeat; } @@ -166,12 +171,12 @@ body .dg.a { .ins-container { position: fixed; overflow: auto; - width: 220px; + width: 260px; bottom: 0; top: 0; left: 0; background: #3d3d3d; - padding: 1% 20px; + padding: 0; font-family: Arial; font-size: 12px; color: #aaa; @@ -182,46 +187,106 @@ body .dg.a { .ins-auto-hide .ins-container { left: -245px; border-right: 1px dotted #888; - - -webkit-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - -moz-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - -o-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); /* custom */ - - -webkit-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - -moz-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - -o-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); /* custom */ - - transition-delay: 3s; - -webkit-transition-delay: 3s; } .ins-container:hover, .ins-show .ins-container { left: 0px; border-right: 0px dotted #888; +} +.ins-transitions .ins-container { + -webkit-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); + -moz-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); + -o-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); + transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); + + -webkit-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); + -moz-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); + -o-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); + transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); + + transition-delay: 3s; + -webkit-transition-delay: 3s; +} + +.ins-transitions .ins-container:hover, +.ins-transitions.ins-show .ins-container { -webkit-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); -moz-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); -o-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); - transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); /* custom */ + transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); -webkit-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); -moz-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); -o-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); - transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); /* custom */ + transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); transition-delay: 0; -webkit-transition-delay: 0; } +.ins-search-box { + margin: 14px 23px; + border: 0; + padding: 7px 8px; + font-size: 12px; + width: 80%; + box-sizing: border-box; + border-radius: 3px; + background: #444; + border: 1px solid #444; + color: #999; +} + +.ins-search-box:focus { + background: #484848; + color: #aaa; + border: 1px solid rgba(255,255,255,0.1); + outline: 0; +} + +.ins-search-box::-webkit-search-cancel-button { + -webkit-appearance: none; + height: 15px; + width: 8px; + cursor: pointer; +} + +.ins-search-box::-webkit-search-cancel-button:before { + height: 10px; + width: 10px; + content: 'x'; + font-family: Arial; + line-height: 0; + font-size: 13px; + color: #999; + font-weight: bold; + cursor: pointer; +} + +.ins-search-box::-webkit-input-placeholder { + color: #777; +} + +.ins-search-box:-moz-placeholder { + color: #777; +} + +.ins-search-box::-moz-placeholder { + color: #777; +} + +.ins-search-box:-ms-input-placeholder { + color: #777; +} + .ins-world-tree { overflow: auto; position: absolute; left: -24px; right: 0px; - top: 60px; + top: 110px; bottom: 8px; } @@ -229,7 +294,9 @@ body .dg.a { display: block; clear: both; overflow: hidden; - margin: 8px 0; + padding: 14px 20px 12px 20px; + background: #444; + border-bottom: 1px solid #555; } .ins-button { @@ -237,14 +304,16 @@ body .dg.a { float: left; margin: 0 2px; font-size: 11px; + line-height: 1; padding: 6px 8px; - min-width: 51px; + min-width: 49px; text-align: center; background: #333; border: 0; color: #aaa; border-radius: 2px; border-bottom: 2px solid #2e2e2e; + box-sizing: border-box; } .ins-button:hover { @@ -252,6 +321,12 @@ body .dg.a { border-bottom: 2px solid #2fa1d6; } +.jstree-default .jstree-search { + font-style: italic; + color: #aaa; + font-weight: normal; +} + .jstree-default .jstree-wholerow-hovered, .jstree-default .jstree-hovered { background: transparent; @@ -271,11 +346,19 @@ body .dg.a { transition: none; } +.jstree-default .jstree-leaf .jstree-clicked { + color: #bbb !important; + + -webkit-transition: color 100ms linear; + -moz-transition: color 100ms linear; + -o-transition: color 100ms linear; + transition: color 100ms linear; +} + .jstree-default .jstree-open > .jstree-children > .jstree-node > .jstree-anchor:before { content: ''; display: block; position: absolute; - z-index: -1; left: 0; right: 1px; height: 26px; @@ -283,10 +366,22 @@ body .dg.a { border-radius: 0; box-shadow: none; border-right: none; + pointer-events: none; + background: rgba(0,0,0,0); + + -webkit-transition: background 100ms linear; + -moz-transition: background 100ms linear; + -o-transition: background 100ms linear; + transition: background 100ms linear; } .jstree-default .jstree-anchor.jstree-clicked:before { - background: #373737 !important; + background: rgba(0,0,0,0.1) !important; + + -webkit-transition: background 100ms linear; + -moz-transition: background 100ms linear; + -o-transition: background 100ms linear; + transition: background 100ms linear; } .jstree-default .jstree-node-type-body > .jstree-anchor:before { diff --git a/src/render/Render.js b/src/render/Render.js index cbae199..de09876 100644 --- a/src/render/Render.js +++ b/src/render/Render.js @@ -707,7 +707,8 @@ var Render = {}; context.translate(0.5, 0.5); context.lineWidth = 1; - context.strokeStyle = 'rgba(255,165,0,0.8)'; + context.strokeStyle = 'rgba(255,165,0,0.9)'; + context.setLineDash([1,2]); switch (item.type) { @@ -738,6 +739,7 @@ var Render = {}; } + context.setLineDash([0]); context.translate(-0.5, -0.5); } @@ -745,15 +747,15 @@ var Render = {}; if (inspector.selectStart !== null) { context.translate(0.5, 0.5); context.lineWidth = 1; - context.setLineDash([1,2]); - context.strokeStyle = 'rgba(255,165,0,0.5)'; + context.strokeStyle = 'rgba(255,165,0,0.6)'; + context.fillStyle = 'rgba(255,165,0,0.1)'; bounds = inspector.selectBounds; context.beginPath(); context.rect(Math.floor(bounds.min.x), Math.floor(bounds.min.y), Math.floor(bounds.max.x - bounds.min.x), Math.floor(bounds.max.y - bounds.min.y)); context.closePath(); context.stroke(); - context.setLineDash([0]); + context.fill(); context.translate(-0.5, -0.5); } }; diff --git a/src/tools/Inspector.js b/src/tools/Inspector.js index 5873201..acff43f 100644 --- a/src/tools/Inspector.js +++ b/src/tools/Inspector.js @@ -10,6 +10,7 @@ var Inspector = {}; (function() { var _key, + _isWebkit = 'WebkitAppearance' in document.documentElement.style, $body; /** @@ -36,13 +37,17 @@ var Inspector = {}; selectStart: null, selectEnd: null, selectBounds: Bounds.create(), - root: Composite.create() + autoHide: true, + hasTransitions: _isWebkit ? true : false, + root: Composite.create({ + label: 'Root' + }) }; inspector = Common.extend(inspector, options); if (Resurrect) { - inspector.serializer = new Resurrect({ prefix: '$' }); + inspector.serializer = new Resurrect({ prefix: '$', cleanup: true }); inspector.serializer.parse = inspector.serializer.resurrect; } else { inspector.serializer = JSON; @@ -52,7 +57,8 @@ var Inspector = {}; _key = window.key || {}; Inspector.instance = inspector; - $body.addClass('ins-auto-hide gui-auto-hide'); + $body.toggleClass('ins-auto-hide gui-auto-hide', inspector.autoHide); + $body.toggleClass('ins-transitions gui-transitions', inspector.hasTransitions); Composite.add(inspector.root, engine.world); engine.world.parent = null; @@ -71,19 +77,21 @@ var Inspector = {}; var $inspectorContainer = $('
'), $buttonGroup = $('
'), + $searchBox = $(''), $importButton = $(''), $exportButton = $(''), $pauseButton = $(''), $helpButton = $(''); $buttonGroup.append($pauseButton, $importButton, $exportButton, $helpButton); - $inspectorContainer.prepend($buttonGroup); + $inspectorContainer.prepend($buttonGroup, $searchBox); $body.prepend($inspectorContainer); controls.pauseButton = $pauseButton; controls.importButton = $importButton; controls.exportButton = $exportButton; controls.helpButton = $helpButton; + controls.searchBox = $searchBox; controls.container = $inspectorContainer; controls.pauseButton.click(function() { @@ -99,22 +107,46 @@ var Inspector = {}; }); controls.helpButton.click(function() { - var help = "matter-inspector quick help \n\n"; - - help += "drag nodes in the tree to move them between composites \n\n"; - help += "[shift + space] to pause or play simulation \n"; - help += "[right click] and drag to select objects \n"; - help += "[del] or [backspace] to delete selected objects \n"; - help += "[shift + s] to scale-xy selected objects with mouse \n"; - help += "[shift + s + d] to scale-x selected objects with mouse \n"; - help += "[shift + s + f] to scale-y selected objects with mouse \n"; - help += "[shift + r] to rotate selected objects with mouse \n"; - help += "[shift + i] to import objects \n"; - help += "[shift + o] to export selected objects\n"; - help += "\nnote: inspector will only render if the renderer in use supports it"; - - alert(help); + _showHelp(inspector); }); + + var searchTimeout; + + controls.searchBox.keyup(function () { + clearTimeout(searchTimeout); + searchTimeout = setTimeout(function () { + var value = controls.searchBox.val(), + worldTree = controls.worldTree.data('jstree'); + worldTree.search(value); + }, 250); + }); + }; + + var _showHelp = function(inspector) { + var help = "Matter Tools \n\n"; + + help += "Drag nodes in the tree to move them between composites. \n\n"; + help += "Use browser's developer console to inspect selected objects. \n\n"; + help += "Note: selections only render if renderer supports it. \n\n"; + + help += "[shift + space] pause or play simulation. \n"; + help += "[right click] and drag to select objects. \n"; + help += "[del] or [backspace] delete selected objects. \n\n"; + + help += "[shift + s] scale-xy selected objects with mouse. \n"; + help += "[shift + s + d] scale-x selected objects with mouse. \n"; + help += "[shift + s + f] scale-y selected objects with mouse. \n"; + help += "[shift + r] rotate selected objects with mouse. \n\n"; + + help += "[shift + q] set selected objects as static (can't be undone). \n"; + help += "[shift + i] import objects. \n"; + help += "[shift + o] export selected objects. \n"; + help += "[shift + h] toggle Matter.Gui. \n"; + help += "[shift + y] toggle auto-hide. \n\n"; + + help += "[shift + j] show this help message."; + + alert(help); }; var _initKeybinds = function(inspector) { @@ -133,13 +165,39 @@ var Inspector = {}; _importFile(inspector); }); + _key('shift+j', function() { + _showHelp(inspector); + }); + + _key('shift+y', function() { + inspector.autoHide = !inspector.autoHide; + $body.toggleClass('ins-auto-hide gui-auto-hide', inspector.autoHide); + }); + + _key('shift+q', function() { + var worldTree = inspector.controls.worldTree.data('jstree'); + for (var i = 0; i < inspector.selected.length; i++) { + var object = inspector.selected[i].data; + if (object.type === 'body' && !object.isStatic) + Body.setStatic(object, true); + } + }); + + _key('del', function() { + _deleteSelectedObjects(inspector); + }); + + _key('backspace', function() { + _deleteSelectedObjects(inspector); + }); + // prevent the backspace key from navigating back // http://stackoverflow.com/questions/1495219/how-can-i-prevent-the-backspace-key-from-navigating-back $(document).unbind('keydown').bind('keydown', function (event) { var doPrevent = false; if (event.keyCode === 8) { var d = event.srcElement || event.target; - if ((d.tagName.toUpperCase() === 'INPUT' && (d.type.toUpperCase() === 'TEXT' || d.type.toUpperCase() === 'PASSWORD' || d.type.toUpperCase() === 'FILE' || d.type.toUpperCase() === 'EMAIL' )) || d.tagName.toUpperCase() === 'TEXTAREA') { + if ((d.tagName.toUpperCase() === 'INPUT' && (d.type.toUpperCase() === 'TEXT' || d.type.toUpperCase() === 'PASSWORD' || d.type.toUpperCase() === 'FILE' || d.type.toUpperCase() === 'EMAIL' || d.type.toUpperCase() === 'SEARCH')) || d.tagName.toUpperCase() === 'TEXTAREA') { doPrevent = d.readOnly || d.disabled; } else { @@ -165,7 +223,14 @@ var Inspector = {}; 'dnd': { 'copy': false }, + 'search': { + 'show_only_matches': true, + 'fuzzy': false + }, 'types': { + '#': { + 'valid_children': [] + }, 'body': { 'valid_children': [] }, @@ -185,7 +250,7 @@ var Inspector = {}; 'valid_children': ['composite'] } }, - 'plugins' : ['dnd', 'types', 'unique'] + 'plugins' : ['dnd', 'types', 'unique', 'search'] }; controls.worldTree = $('
').jstree(worldTreeOptions); @@ -215,17 +280,6 @@ var Inspector = {}; case 'composite': selected.push(worldObject); break; - - case 'composites': - case 'bodies': - case 'constraints': - var node = worldTree.get_node(nodeId), - children = worldTree.get_node(nodeId).children; - - for (var j = 0; j < children.length; j++) - worldTree.select_node(children[j], false); - - break; } } @@ -257,21 +311,34 @@ var Inspector = {}; newComposite = Composite.get(inspector.root, newCompositeId, 'composite'); Composite.move(prevComposite, worldObject, newComposite); - node.data.compositeId = newCompositeId; - - /*if (newComposite === engine.world) { - // if moved to the world, remove old tree node - // it will be regenerated automatically - worldTree.set_id(nodeId, nodeId + "-dupe"); - //setTimeout(function() { - // worldTree.delete_node(nodeId); - //}, 1); - }*/ } }); controls.worldTree.on('dblclick.jstree', function(event, data) { - _setPaused(inspector, true); + var worldTree = controls.worldTree.data('jstree'), + selected = worldTree.get_selected(); + + // select all children of double clicked node + for (var i = 0; i < selected.length; i++) { + var nodeId = selected[i], + objectType = nodeId.split('_')[0], + objectId = nodeId.split('_')[1], + worldObject = Composite.get(engine.world, objectId, objectType); + + switch (objectType) { + case 'composite': + case 'composites': + case 'bodies': + case 'constraints': + var node = worldTree.get_node(nodeId), + children = worldTree.get_node(nodeId).children; + + for (var j = 0; j < children.length; j++) + worldTree.select_node(children[j], false); + + break; + } + } }); }; @@ -281,28 +348,10 @@ var Inspector = {}; Events.on(engine, 'tick', function() { if (engine.world.isModified) { - var data = _generateCompositeTreeNode(engine.world); + var data = _generateCompositeTreeNode(inspector.root, null, true); _updateTree(controls.worldTree.data('jstree'), data); _setSelectedObjects(inspector, []); } - - if (key.isPressed('del') || key.isPressed('backspace')) { - var objects = [], - worldTree = inspector.controls.worldTree.data('jstree'); - - for (var i = 0; i < inspector.selected.length; i++) { - var object = inspector.selected[i].data; - - if (object === inspector.engine.world) - continue; - - objects.push(object); - worldTree.delete_node(object.type + '_' + object.id); - } - - Composite.remove(inspector.root, objects, true); - _setSelectedObjects(inspector, []); - } }); Events.on(engine, 'mouseup', function(event) { @@ -561,6 +610,24 @@ var Inspector = {}; }); }; + var _deleteSelectedObjects = function(inspector) { + var objects = [], + worldTree = inspector.controls.worldTree.data('jstree'); + + for (var i = 0; i < inspector.selected.length; i++) { + var object = inspector.selected[i].data; + + if (object === inspector.engine.world) + continue; + + objects.push(object); + worldTree.delete_node(object.type + '_' + object.id); + } + + Composite.remove(inspector.root, objects, true); + _setSelectedObjects(inspector, []); + }; + var _setPaused = function(inspector, isPaused) { if (isPaused) { inspector.engine.timing.timeScale = 0; @@ -618,37 +685,41 @@ var Inspector = {}; }; var _updateTree = function(tree, data) { - data.state = data.state || { opened: true }; - tree.settings.core.data = tree.settings.core.data || [data]; - tree.settings.core.data[tree.settings.core.data.length - 1] = data; + data[0].state = data[0].state || { opened: true }; + tree.settings.core.data = data; tree.refresh(-1); }; - var _generateCompositeTreeNode = function(composite, compositeId) { - var node = { - id: 'composite_' + composite.id, - data: { - compositeId: compositeId, - }, - type: 'composite', - text: (composite.label ? composite.label : 'Composite') + ' ' + composite.id, - children: [], - 'li_attr': { - 'class': 'jstree-node-type-composite' - } - }; + var _generateCompositeTreeNode = function(composite, compositeId, isRoot) { + var children = [], + node = { + id: 'composite_' + composite.id, + data: { + compositeId: compositeId, + }, + type: 'composite', + text: (composite.label ? composite.label : 'Composite') + ' ' + composite.id, + 'li_attr': { + 'class': 'jstree-node-type-composite' + } + }; - var childNode = _generateBodiesTreeNode(composite.bodies, composite.id); + var childNode = _generateCompositesTreeNode(composite.composites, composite.id); + childNode.id = 'composites_' + composite.id; + children.push(childNode); + + if (isRoot) + return childNode.children; + + childNode = _generateBodiesTreeNode(composite.bodies, composite.id); childNode.id = 'bodies_' + composite.id; - node.children.push(childNode); + children.push(childNode); childNode = _generateConstraintsTreeNode(composite.constraints, composite.id); childNode.id = 'constraints_' + composite.id; - node.children.push(childNode); + children.push(childNode); - childNode = _generateCompositesTreeNode(composite.composites, composite.id); - childNode.id = 'composites_' + composite.id; - node.children.push(childNode); + node.children = children; return node; }; @@ -741,11 +812,17 @@ var Inspector = {}; toExport = []; if (inspector.serializer) { - var exportComposite = Composite.create({ + if (inspector.selected.length === 0) { + alert('No objects were selected, so export could not be created.'); + return; + } + + var fileName = "export-objects", + exportComposite = Composite.create({ label: 'Exported Objects' }); - // add everything else + // add everything else, must be in top-down order for (var i = 0; i < inspector.selected.length; i++) { var object = inspector.selected[i].data; @@ -755,8 +832,15 @@ var Inspector = {}; continue; Composite.add(exportComposite, object); + + // better filename for small exports + if (inspector.selected.length === 1) + fileName = 'export-' + object.label + '-' + object.id; } + // santise filename + fileName = fileName.toLowerCase().replace(/[^\w\-]/g, '') + '.json'; + var json = inspector.serializer.stringify(exportComposite, function(key, value) { // skip non-required values if (key === 'path') @@ -764,15 +848,23 @@ var Inspector = {}; // limit precision of floats if (!/^#/.exec(key) && typeof value === 'number') { - return parseFloat(value.toFixed(2)); + var fixed = parseFloat(value.toFixed(3)); + + // do not limit if limiting will cause value to zero + // TODO: this should ideally dynamically find the SF precision required + if (fixed === 0 && value !== 0) + return value; + + return fixed; } + return value; - }, 4); + }); var blob = new Blob([json], { type: 'application/json' }), anchor = document.createElement('a'); - anchor.download = 'world.json'; + anchor.download = fileName; anchor.href = (window.webkitURL || window.URL).createObjectURL(blob); anchor.dataset.downloadurl = ['application/json', anchor.download, anchor.href].join(':'); anchor.click(); @@ -804,13 +896,17 @@ var Inspector = {}; Composite.rebase(importedComposite); importedComposite.label = 'Imported Objects'; - var worldTree = inspector.controls.worldTree.data('jstree'), - data = _generateCompositeTreeNode(importedComposite), - coreData = worldTree.settings.core.data; - - coreData.unshift(data); - worldTree.refresh(-1); Composite.add(inspector.root, importedComposite); + + // move imported composite to the start + // so that it appears top of tree + inspector.root.composites.splice(inspector.root.composites.length - 1, 1); + inspector.root.composites.unshift(importedComposite); + + var worldTree = inspector.controls.worldTree.data('jstree'), + data = _generateCompositeTreeNode(inspector.root, null, true); + + _updateTree(worldTree, data); } };