feeles-ide
Version:
The hackable and serializable IDE to make learning material
1,318 lines (1,064 loc) • 223 kB
JavaScript
/*!
* matter-tools 0.9.1 by Liam Brummitt 2017-01-26
* https://github.com/liabru/matter-tools
* License MIT
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("Matter"), require("MatterTools"), require("jQuery"));
else if(typeof define === 'function' && define.amd)
define(["Matter", "MatterTools", "jQuery"], factory);
else if(typeof exports === 'object')
exports["Inspector"] = factory(require("Matter"), require("MatterTools"), require("jQuery"));
else
root["MatterTools"] = root["MatterTools"] || {}, root["MatterTools"]["Inspector"] = factory(root["Matter"], root["MatterTools"], root["jQuery"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_2__, __WEBPACK_EXTERNAL_MODULE_7__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/demo/lib";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
/**
* A tool for inspecting worlds.
* @module Inspector
*/
var Inspector = module.exports = {};
var $ = __webpack_require__(7);
__webpack_require__(8);
var ToolsCommon = __webpack_require__(3);
var Serializer = __webpack_require__(2).Serializer;
var km = __webpack_require__(9);
var Matter = __webpack_require__(1);
var Body = Matter.Body;
var Bounds = Matter.Bounds;
var Composite = Matter.Composite;
var Common = Matter.Common;
var Events = Matter.Events;
var Mouse = Matter.Mouse;
var Query = Matter.Query;
var Vertices = Matter.Vertices;
var Vector = Matter.Vector;
var MouseConstraint = Matter.MouseConstraint;
var $body;
/**
* Creates an inspector
* @function Gui.create
* @param {engine} engine
* @param {render} [render]
* @param {object} options
* @return {inspector} The created inspector instance.
*/
Inspector.create = function (engine, render, options) {
if (!$) {
console.log('Could not create inspector, missing jQuery.');
return;
}
var inspector = {
engine: null,
render: null,
isPaused: false,
selected: [],
selectStart: null,
selectEnd: null,
selectBounds: Bounds.create(),
mousePrevPosition: { x: 0, y: 0 },
offset: { x: 0, y: 0 },
autoHide: true,
autoRewind: true,
bodyClass: '',
exportIndent: 0,
clipboard: [],
controls: {
container: null,
worldTree: null
},
root: Composite.create({
label: 'Root'
}),
keyBindings: []
};
inspector = Common.extend(inspector, options);
Inspector.instance = inspector;
inspector.engine = engine;
inspector.render = render;
if (inspector.render) {
inspector.mouse = Mouse.create(inspector.render.canvas);
inspector.mouseConstraint = MouseConstraint.create(engine, { mouse: inspector.mouse });
} else {
inspector.mouse = {
position: {
x: 0,
y: 0
}
};
}
if (Serializer) {
inspector.serializer = Serializer.create();
localStorage.removeItem('pauseState');
}
$body = $('body');
Composite.add(inspector.root, engine.world);
engine.world.isModified = true;
engine.world.parent = null;
var styles = __webpack_require__(10);
ToolsCommon.injectStyles(styles, 'js-tree-style');
styles = __webpack_require__(11);
ToolsCommon.injectStyles(styles, 'matter-inspector-style');
inspector.keyBind = Common.chain(km, function (key) {
inspector.keyBindings.push(key);
});
_initControls(inspector);
_initEngineEvents(inspector);
_initTree(inspector);
_initKeybinds(inspector);
return inspector;
};
/**
* Destroys the inspector
* @function Gui.destroy
* @param {Inspector} inspector
*/
Inspector.destroy = function (inspector) {
inspector.controls.worldTree.data('jstree').destroy();
var inspectorElements = [].slice.call(document.body.querySelectorAll('.ins-container', '.vakata-context', '.jstree-marker'));
inspectorElements.forEach(ToolsCommon.domRemove);
inspector.keyBindings.forEach(function (key) {
km.unbind(key);
});
Events.off(inspector.engine, 'beforeUpdate', inspector.beforeEngineUpdate);
if (inspector.render) {
Events.off(inspector.render, 'afterRender', inspector.afterRender);
Events.off(inspector.mouseConstraint);
}
};
var _initControls = function _initControls(inspector) {
var controls = inspector.controls;
var $inspectorContainer = $('<div class="ins-container">'),
$buttonGroup = $('<div class="ins-control-group">'),
$searchBox = $('<input class="ins-search-box" type="search" placeholder="search">'),
$importButton = $('<button class="ins-import-button ins-button">Import</button>'),
$exportButton = $('<button class="ins-export-button ins-button">Export</button>'),
$pauseButton = $('<button class="ins-pause-button ins-button">Pause</button>'),
$helpButton = $('<button class="ins-help-button ins-button">Help</button>'),
$addCompositeButton = $('<button class="ins-add-button ins-button">+</button>');
if (Serializer) {
$buttonGroup.append($pauseButton, $importButton, $exportButton, $helpButton);
} else {
$buttonGroup.append($pauseButton, $helpButton);
}
$inspectorContainer.prepend($searchBox, $addCompositeButton);
$body.prepend($inspectorContainer);
controls.pauseButton = $pauseButton;
controls.importButton = $importButton;
controls.exportButton = $exportButton;
controls.helpButton = $helpButton;
controls.searchBox = $searchBox;
controls.container = $inspectorContainer;
controls.addCompositeButton = $addCompositeButton;
controls.pauseButton.click(function () {
_setPaused(inspector, !inspector.isPaused);
});
controls.exportButton.click(function () {
_exportFile(inspector);
});
controls.importButton.click(function () {
_importFile(inspector);
});
controls.helpButton.click(function () {
_showHelp(inspector);
});
controls.addCompositeButton.click(function () {
_addNewComposite(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 _showHelp() {
var help = "Matter Tools\n\n";
help += "Drag nodes in the tree to move them between composites.\n";
help += "Use browser's developer console to inspect selected objects.\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 on empty space to select a region.\n";
help += "[right click] and drag on an object to move it.\n";
help += "[right click + shift] and drag to move whole selection.\n\n";
help += "[ctrl-c] to copy selected world objects.\n";
help += "[ctrl-v] to paste copied world objects to mouse position.\n";
help += "[del] or [backspace] delete selected objects.\n\n";
help += "[shift + s] scale-xy selected objects with mouse or arrows.\n";
help += "[shift + s + d] scale-x selected objects with mouse or arrows.\n";
help += "[shift + s + f] scale-y selected objects with mouse or arrows.\n";
help += "[shift + r] rotate selected objects with mouse or arrows.\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";
help += "[shift + r] toggle auto-rewind on play/pause.\n\n";
help += "[shift + j] show this help message.";
alert(help);
};
var _initKeybinds = function _initKeybinds(inspector) {
inspector.keyBind('shift+space', function () {
_setPaused(inspector, !inspector.isPaused);
});
if (inspector.serializer) {
inspector.keyBind('shift+o', function () {
_exportFile(inspector);
});
inspector.keyBind('shift+i', function () {
_importFile(inspector);
});
}
inspector.keyBind('shift+j', function () {
_showHelp(inspector);
});
inspector.keyBind('shift+y', function () {
inspector.autoHide = !inspector.autoHide;
$body.toggleClass('ins-auto-hide gui-auto-hide', inspector.autoHide);
});
inspector.keyBind('shift+r', function () {
inspector.autoRewind = !inspector.autoRewind;
if (!inspector.autoRewind) localStorage.removeItem('pauseState');
});
inspector.keyBind('shift+q', function () {
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);
}
});
inspector.keyBind('del', function () {
_deleteSelectedObjects(inspector);
});
inspector.keyBind('backspace', function () {
_deleteSelectedObjects(inspector);
});
if (inspector.serializer) {
inspector.keyBind('ctrl+c', function () {
_copySelectedObjects(inspector);
});
inspector.keyBind('ctrl+v', function () {
_pasteSelectedObjects(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.type.toUpperCase() === 'SEARCH') || d.tagName.toUpperCase() === 'TEXTAREA') {
doPrevent = d.readOnly || d.disabled;
} else {
doPrevent = true;
}
}
if (doPrevent) {
event.preventDefault();
}
});
};
var _initTree = function _initTree(inspector) {
var engine = inspector.engine,
controls = inspector.controls,
deferTimeout;
var worldTreeOptions = {
'core': {
'check_callback': true
},
'dnd': {
'copy': false
},
'search': {
'show_only_matches': true,
'fuzzy': false
},
'types': {
'#': {
'valid_children': []
},
'body': {
'valid_children': []
},
'constraint': {
'valid_children': []
},
'composite': {
'valid_children': []
},
'bodies': {
'valid_children': ['body']
},
'constraints': {
'valid_children': ['constraint']
},
'composites': {
'valid_children': ['composite']
}
},
'plugins': ['dnd', 'types', 'unique', 'search']
};
controls.worldTree = $('<div class="ins-world-tree">').jstree(worldTreeOptions);
controls.container.append(controls.worldTree);
controls.worldTree.on('changed.jstree', function (event, data) {
var selected = [],
worldTree = controls.worldTree.data('jstree');
if (data.action !== 'select_node') return;
// defer selection update until selection has finished propagating
clearTimeout(deferTimeout);
deferTimeout = setTimeout(function () {
data.selected = worldTree.get_selected();
for (var i = 0; i < data.selected.length; i++) {
var nodeId = data.selected[i],
objectType = nodeId.split('_')[0],
objectId = nodeId.split('_')[1],
worldObject = Composite.get(engine.world, objectId, objectType);
switch (objectType) {
case 'body':
case 'constraint':
case 'composite':
selected.push(worldObject);
break;
}
}
_setSelectedObjects(inspector, selected);
}, 1);
});
$(document).on('dnd_stop.vakata', function (event, data) {
var worldTree = controls.worldTree.data('jstree'),
nodes = data.data.nodes;
// handle drag and drop
// move items between composites
for (var i = 0; i < nodes.length; i++) {
var node = worldTree.get_node(nodes[i]),
parentNode = worldTree.get_node(worldTree.get_parent(nodes[i])),
prevCompositeId = node.data.compositeId,
newCompositeId = parentNode.data.compositeId;
if (prevCompositeId === newCompositeId) continue;
var nodeId = nodes[i],
objectType = nodeId.split('_')[0],
objectId = nodeId.split('_')[1],
worldObject = Composite.get(inspector.root, objectId, objectType),
prevComposite = Composite.get(inspector.root, prevCompositeId, 'composite'),
newComposite = Composite.get(inspector.root, newCompositeId, 'composite');
Composite.move(prevComposite, worldObject, newComposite);
}
});
controls.worldTree.on('dblclick.jstree', function () {
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];
switch (objectType) {
case 'composite':
case 'composites':
case 'bodies':
case 'constraints':
var children = worldTree.get_node(nodeId).children;
for (var j = 0; j < children.length; j++) {
worldTree.select_node(children[j], false);
}break;
}
}
});
};
var _addBodyClass = function _addBodyClass(inspector, classNames) {
// only apply changes to prevent DOM lag
if (inspector.bodyClass.indexOf(' ' + classNames) === -1) {
$body.addClass(classNames);
inspector.bodyClass = ' ' + $body.attr('class');
}
};
var _removeBodyClass = function _removeBodyClass(inspector, classNames) {
// only apply changes to prevent DOM lag
var updateRequired = false,
classes = classNames.split(' ');
for (var i = 0; i < classes.length; i++) {
updateRequired = inspector.bodyClass.indexOf(' ' + classes[i]) !== -1;
if (updateRequired) break;
}
if (updateRequired) {
$body.removeClass(classNames);
inspector.bodyClass = ' ' + $body.attr('class');
}
};
var _getMousePosition = function _getMousePosition(inspector) {
return Vector.add(inspector.mouse.position, inspector.offset);
};
var _initEngineEvents = function _initEngineEvents(inspector) {
var engine = inspector.engine,
mouse = inspector.mouse,
mousePosition = _getMousePosition(inspector),
controls = inspector.controls;
inspector.beforeEngineUpdate = function () {
// update mouse position reference
mousePosition = _getMousePosition(inspector);
var mouseDelta = mousePosition.x - inspector.mousePrevPosition.x,
keyDelta = km.isPressed('up') + km.isPressed('right') - km.isPressed('down') - km.isPressed('left'),
delta = mouseDelta + keyDelta;
// update interface when world changes
if (engine.world.isModified) {
var data = _generateCompositeTreeNode(inspector.root, null, true);
_updateTree(controls.worldTree.data('jstree'), data);
_setSelectedObjects(inspector, []);
}
// update region selection
if (inspector.selectStart !== null) {
inspector.selectEnd.x = mousePosition.x;
inspector.selectEnd.y = mousePosition.y;
Bounds.update(inspector.selectBounds, [inspector.selectStart, inspector.selectEnd]);
}
// rotate mode
if (km.shift && km.isPressed('r')) {
var rotateSpeed = 0.03,
angle = Math.max(-2, Math.min(2, delta)) * rotateSpeed;
_addBodyClass(inspector, 'ins-cursor-rotate');
_rotateSelectedObjects(inspector, angle);
} else {
_removeBodyClass(inspector, 'ins-cursor-rotate');
}
// scale mode
if (km.shift && km.isPressed('s')) {
var scaleSpeed = 0.02,
scale = 1 + Math.max(-2, Math.min(2, delta)) * scaleSpeed;
_addBodyClass(inspector, 'ins-cursor-scale');
var scaleX, scaleY;
if (km.isPressed('d')) {
scaleX = scale;
scaleY = 1;
} else if (km.isPressed('f')) {
scaleX = 1;
scaleY = scale;
} else {
scaleX = scaleY = scale;
}
_scaleSelectedObjects(inspector, scaleX, scaleY);
} else {
_removeBodyClass(inspector, 'ins-cursor-scale');
}
// translate mode
if (mouse.button === 2) {
_addBodyClass(inspector, 'ins-cursor-move');
_moveSelectedObjects(inspector, mousePosition.x, mousePosition.y);
} else {
_removeBodyClass(inspector, 'ins-cursor-move');
}
inspector.mousePrevPosition = Common.clone(mousePosition);
};
Events.on(inspector.engine, 'beforeUpdate', inspector.beforeEngineUpdate);
if (inspector.mouseConstraint) {
Events.on(inspector.mouseConstraint, 'mouseup', function () {
// select objects in region if making a region selection
if (inspector.selectStart !== null) {
var selected = Query.region(Composite.allBodies(engine.world), inspector.selectBounds);
_setSelectedObjects(inspector, selected);
}
// clear selection region
inspector.selectStart = null;
inspector.selectEnd = null;
Events.trigger(inspector, 'selectEnd');
});
Events.on(inspector.mouseConstraint, 'mousedown', function () {
var bodies = Composite.allBodies(engine.world),
constraints = Composite.allConstraints(engine.world),
isUnionSelect = km.shift || km.control,
worldTree = inspector.controls.worldTree.data('jstree'),
i;
if (mouse.button === 2) {
var hasSelected = false;
for (i = 0; i < bodies.length; i++) {
var body = bodies[i];
if (Bounds.contains(body.bounds, mousePosition) && Vertices.contains(body.vertices, mousePosition)) {
if (isUnionSelect) {
_addSelectedObject(inspector, body);
} else {
_setSelectedObjects(inspector, [body]);
}
hasSelected = true;
break;
}
}
if (!hasSelected) {
for (i = 0; i < constraints.length; i++) {
var constraint = constraints[i],
bodyA = constraint.bodyA,
bodyB = constraint.bodyB;
if (constraint.label.indexOf('Mouse Constraint') !== -1) continue;
var pointAWorld = constraint.pointA,
pointBWorld = constraint.pointB;
if (bodyA) pointAWorld = Vector.add(bodyA.position, constraint.pointA);
if (bodyB) pointBWorld = Vector.add(bodyB.position, constraint.pointB);
if (!pointAWorld || !pointBWorld) continue;
var distA = Vector.magnitudeSquared(Vector.sub(mousePosition, pointAWorld)),
distB = Vector.magnitudeSquared(Vector.sub(mousePosition, pointBWorld));
if (distA < 100 || distB < 100) {
if (isUnionSelect) {
_addSelectedObject(inspector, constraint);
} else {
_setSelectedObjects(inspector, [constraint]);
}
hasSelected = true;
break;
}
}
if (!hasSelected) {
worldTree.deselect_all(true);
_setSelectedObjects(inspector, []);
inspector.selectStart = Common.clone(mousePosition);
inspector.selectEnd = Common.clone(mousePosition);
Bounds.update(inspector.selectBounds, [inspector.selectStart, inspector.selectEnd]);
Events.trigger(inspector, 'selectStart');
} else {
inspector.selectStart = null;
inspector.selectEnd = null;
}
}
}
if (mouse.button === 2 && inspector.selected.length > 0) {
_addBodyClass(inspector, 'ins-cursor-move');
_updateSelectedMouseDownOffset(inspector);
}
});
}
if (inspector.render) {
inspector.afterRender = function () {
var renderController = inspector.render.controller,
context = inspector.render.context;
if (renderController.inspector) renderController.inspector(inspector, context);
};
Events.on(inspector.render, 'afterRender', inspector.afterRender);
}
};
var _deleteSelectedObjects = function _deleteSelectedObjects(inspector) {
var objects = [],
object,
worldTree = inspector.controls.worldTree.data('jstree'),
i;
// delete objects in world
for (i = 0; i < inspector.selected.length; i++) {
object = inspector.selected[i].data;
if (object !== inspector.engine.world) objects.push(object);
}
// also delete non-world composites (selected only in the UI tree)
var selectedNodes = worldTree.get_selected();
for (i = 0; i < selectedNodes.length; i++) {
var node = worldTree.get_node(selectedNodes[i]);
if (node.type === 'composite') {
node = worldTree.get_node(node.children[0]);
if (node.data) {
var compositeId = node.data.compositeId;
object = Composite.get(inspector.root, compositeId, 'composite');
if (object && object !== inspector.engine.world) {
objects.push(object);
worldTree.delete_node(selectedNodes[i]);
}
}
}
}
Composite.remove(inspector.root, objects, true);
_setSelectedObjects(inspector, []);
};
var _copySelectedObjects = function _copySelectedObjects(inspector) {
inspector.clipboard.length = 0;
// put selected objects into clipboard
for (var i = 0; i < inspector.selected.length; i++) {
var object = inspector.selected[i].data;
if (object.type !== 'body') continue;
inspector.clipboard.push(object);
}
};
var _pasteSelectedObjects = function _pasteSelectedObjects(inspector) {
if (!inspector.serializer) {
return;
}
var objects = [],
worldTree = inspector.controls.worldTree.data('jstree');
// copy objects in world
for (var i = 0; i < inspector.clipboard.length; i++) {
var object = inspector.clipboard[i],
clone = Serializer.clone(inspector.serializer, object);
Body.translate(clone, { x: 50, y: 50 });
// add the clone to the same composite as original
var node = worldTree.get_node(object.type + '_' + object.id, false),
compositeId = node.data.compositeId,
composite = Composite.get(inspector.engine.world, compositeId, 'composite');
Composite.add(composite, clone);
objects.push(clone);
}
// select clones after waiting for tree to update
setTimeout(function () {
_setSelectedObjects(inspector, objects);
}, 200);
};
var _updateSelectedMouseDownOffset = function _updateSelectedMouseDownOffset(inspector) {
var selected = inspector.selected,
mousePosition = _getMousePosition(inspector),
item,
data;
for (var i = 0; i < selected.length; i++) {
item = selected[i];
data = item.data;
if (data.position) {
item.mousedownOffset = {
x: mousePosition.x - data.position.x,
y: mousePosition.y - data.position.y
};
} else if (data.pointA && !data.bodyA) {
item.mousedownOffset = {
x: mousePosition.x - data.pointA.x,
y: mousePosition.y - data.pointA.y
};
} else if (data.pointB && !data.bodyB) {
item.mousedownOffset = {
x: mousePosition.x - data.pointB.x,
y: mousePosition.y - data.pointB.y
};
}
}
};
var _moveSelectedObjects = function _moveSelectedObjects(inspector, x, y) {
var selected = inspector.selected,
item,
data;
for (var i = 0; i < selected.length; i++) {
item = selected[i];
data = item.data;
if (!item.mousedownOffset) continue;
switch (data.type) {
case 'body':
var delta = {
x: x - data.position.x - item.mousedownOffset.x,
y: y - data.position.y - item.mousedownOffset.y
};
Body.translate(data, delta);
data.positionPrev.x = data.position.x;
data.positionPrev.y = data.position.y;
break;
case 'constraint':
var point = data.pointA;
if (data.bodyA) point = data.pointB;
point.x = x - item.mousedownOffset.x;
point.y = y - item.mousedownOffset.y;
var initialPointA = data.bodyA ? Vector.add(data.bodyA.position, data.pointA) : data.pointA,
initialPointB = data.bodyB ? Vector.add(data.bodyB.position, data.pointB) : data.pointB;
data.length = Vector.magnitude(Vector.sub(initialPointA, initialPointB));
break;
}
}
};
var _scaleSelectedObjects = function _scaleSelectedObjects(inspector, scaleX, scaleY) {
var selected = inspector.selected,
item,
data;
for (var i = 0; i < selected.length; i++) {
item = selected[i];
data = item.data;
switch (data.type) {
case 'body':
Body.scale(data, scaleX, scaleY, data.position);
if (data.circleRadius) data.circleRadius *= scaleX;
break;
}
}
};
var _rotateSelectedObjects = function _rotateSelectedObjects(inspector, angle) {
var selected = inspector.selected,
item,
data;
for (var i = 0; i < selected.length; i++) {
item = selected[i];
data = item.data;
switch (data.type) {
case 'body':
Body.rotate(data, angle);
break;
}
}
};
var _setPaused = function _setPaused(inspector, isPaused) {
if (isPaused) {
if (inspector.autoRewind && inspector.serializer) {
_setSelectedObjects(inspector, []);
Serializer.loadState(inspector.serializer, inspector.engine, 'pauseState');
}
inspector.engine.timing.timeScale = 0;
inspector.isPaused = true;
inspector.controls.pauseButton.text('Play');
Events.trigger(inspector, 'paused');
} else {
if (inspector.autoRewind && inspector.serializer) {
Serializer.saveState(inspector.serializer, inspector.engine, 'pauseState');
}
inspector.engine.timing.timeScale = 1;
inspector.isPaused = false;
inspector.controls.pauseButton.text('Pause');
Events.trigger(inspector, 'play');
}
};
var _setSelectedObjects = function _setSelectedObjects(inspector, objects) {
var worldTree = inspector.controls.worldTree.data('jstree'),
data,
i;
for (i = 0; i < inspector.selected.length; i++) {
data = inspector.selected[i].data;
worldTree.deselect_node(data.type + '_' + data.id, true);
}
inspector.selected = [];
if (objects.length > 0) {
console.clear();
}
for (i = 0; i < objects.length; i++) {
data = objects[i];
if (data) {
// add the object to the selection
_addSelectedObject(inspector, data);
// log selected objects to console for property inspection
if (i < 5) {
console.log(data.label + ' ' + data.id + ': %O', data);
} else if (i === 6) {
console.warn('Omitted inspecting ' + (objects.length - 5) + ' more objects');
}
}
}
};
var _addSelectedObject = function _addSelectedObject(inspector, object) {
if (!object) return;
var worldTree = inspector.controls.worldTree.data('jstree');
inspector.selected.push({ data: object });
worldTree.select_node(object.type + '_' + object.id, true);
};
var _updateTree = function _updateTree(tree, data) {
data[0].state = data[0].state || { opened: true };
tree.settings.core.data = data;
tree.refresh(-1);
};
var _generateCompositeTreeNode = function _generateCompositeTreeNode(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 = _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;
children.push(childNode);
childNode = _generateConstraintsTreeNode(composite.constraints, composite.id);
childNode.id = 'constraints_' + composite.id;
children.push(childNode);
node.children = children;
return node;
};
var _generateCompositesTreeNode = function _generateCompositesTreeNode(composites, compositeId) {
var node = {
type: 'composites',
text: 'Composites',
data: {
compositeId: compositeId
},
children: [],
'li_attr': {
'class': 'jstree-node-type-composites'
}
};
for (var i = 0; i < composites.length; i++) {
var composite = composites[i];
node.children.push(_generateCompositeTreeNode(composite, compositeId));
}
return node;
};
var _generateBodiesTreeNode = function _generateBodiesTreeNode(bodies, compositeId) {
var node = {
type: 'bodies',
text: 'Bodies',
data: {
compositeId: compositeId
},
children: [],
'li_attr': {
'class': 'jstree-node-type-bodies'
}
};
for (var i = 0; i < bodies.length; i++) {
var body = bodies[i];
node.children.push({
type: 'body',
id: 'body_' + body.id,
data: {
compositeId: compositeId
},
text: (body.label ? body.label : 'Body') + ' ' + body.id,
'li_attr': {
'class': 'jstree-node-type-body'
}
});
}
return node;
};
var _generateConstraintsTreeNode = function _generateConstraintsTreeNode(constraints, compositeId) {
var node = {
type: 'constraints',
text: 'Constraints',
data: {
compositeId: compositeId
},
children: [],
'li_attr': {
'class': 'jstree-node-type-constraints'
}
};
for (var i = 0; i < constraints.length; i++) {
var constraint = constraints[i];
node.children.push({
type: 'constraint',
id: 'constraint_' + constraint.id,
data: {
compositeId: compositeId
},
text: (constraint.label ? constraint.label : 'Constraint') + ' ' + constraint.id,
'li_attr': {
'class': 'jstree-node-type-constraint'
}
});
}
return node;
};
var _addNewComposite = function _addNewComposite(inspector) {
var newComposite = Composite.create();
Composite.add(inspector.root, newComposite);
// move new 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(newComposite);
Composite.setModified(inspector.engine.world, true, true, false);
};
var _exportFile = function _exportFile(inspector) {
if (!inspector.serializer) {
alert('No serializer.');
return;
}
if (inspector.selected.length === 0) {
alert('No objects were selected, so export could not be created. Can only export objects that are in the World composite.');
return;
}
var fileName = 'export-objects',
exportComposite = Composite.create({
label: 'Exported Objects'
});
// add everything else, must be in top-down order
for (var i = 0; i < inspector.selected.length; i++) {
var object = inspector.selected[i].data;
// skip if it's already in the composite tree
// this means orphans will be added in the root
if (Composite.get(exportComposite, object.id, object.type)) 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';
// serialise
var json = Serializer.serialise(inspector.serializer, exportComposite, inspector.exportIndent);
// launch export download
var _isWebkit = 'WebkitAppearance' in document.documentElement.style;
if (_isWebkit) {
var blob = new Blob([json], { type: 'application/json' }),
anchor = document.createElement('a');
anchor.download = fileName;
anchor.href = (window.webkitURL || window.URL).createObjectURL(blob);
anchor.dataset.downloadurl = ['application/json', anchor.download, anchor.href].join(':');
anchor.click();
} else {
window.open('data:application/json;charset=utf-8,' + escape(json));
}
Events.trigger(inspector, 'export');
};
var _importFile = function _importFile(inspector) {
if (!inspector.serializer) {
alert('No serializer.');
return;
}
var element = document.createElement('div'),
fileInput;
element.innerHTML = '<input type="file">';
fileInput = element.firstChild;
fileInput.addEventListener('change', function () {
var file = fileInput.files[0];
if (file.name.match(/\.(txt|json)$/)) {
var reader = new FileReader();
reader.onload = function () {
var importedComposite = inspector.serializer.parse(reader.result);
if (importedComposite) {
importedComposite.label = 'Imported Objects';
Composite.rebase(importedComposite);
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);
}
};
reader.readAsText(file);
} else {
alert('File not supported, .json or .txt JSON files only');
}
});
fileInput.click();
};
/*
*
* Events Documentation
*
*/
/**
* Fired after the inspector's import button pressed
*
* @event export
* @param {} event An event object
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
*/
/**
* Fired after the inspector's export button pressed
*
* @event import
* @param {} event An event object
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
*/
/**
* Fired after the inspector user starts making a selection
*
* @event selectStart
* @param {} event An event object
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
*/
/**
* Fired after the inspector user ends making a selection
*
* @event selectEnd
* @param {} event An event object
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
*/
/**
* Fired after the inspector is paused
*
* @event pause
* @param {} event An event object
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
*/
/**
* Fired after the inspector is played
*
* @event play
* @param {} event An event object
* @param {} event.source The source object of the event
* @param {} event.name The name of the event
*/
/*** EXPORTS FROM exports-loader ***/
/***/ },
/* 1 */
/***/ function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
/***/ },
/* 2 */
/***/ function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_2__;
/***/ },
/* 3 */
/***/ function(module, exports) {
"use strict";
/**
* @class Common
*/
var Common = module.exports = {};
Common.injectStyles = function (styles, id) {
if (document.getElementById(id)) {
return;
}
var root = document.createElement('div');
root.innerHTML = '<style id="' + id + '" type="text/css">' + styles + '</style>';
var lastStyle = document.head.querySelector('style:last-of-type');
Common.domInsertBefore(root.firstElementChild, lastStyle);
};
Common.injectScript = function (url, id, callback) {
if (document.getElementById(id)) {
return;
}
var script = document.createElement('script');
script.id = id;
script.src = url;
script.onload = callback;
document.body.appendChild(script);
};
Common.domRemove = function (element) {
return element.parentElement.removeChild(element);
};
Common.domInsertBefore = function (element, before) {
return before.parentNode.insertBefore(element, before.previousElementSibling);
};
/*** EXPORTS FROM exports-loader ***/
/***/ },
/* 4 */,
/* 5 */,
/* 6 */,
/* 7 */
/***/ function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_7__;
/***/ },
/* 8 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! jsTree - v3.3.3 - 2016-10-31 - (MIT) */
!function(a){"use strict"; true?!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(7)], __WEBPACK_AMD_DEFINE_FACTORY__ = (a), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)):"undefined"!=typeof module&&module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a,b){"use strict";if(!a.jstree){var c=0,d=!1,e=!1,f=!1,g=[],h=a("script:last").attr("src"),i=window.document;a.jstree={version:"3.3.3",defaults:{plugins:[]},plugins:{},path:h&&-1!==h.indexOf("/")?h.replace(/\/[^\/]+$/,""):"",idregex:/[\\:&!^|()\[\]<>@*'+~#";.,=\- \/${}%?`]/g,root:"#"},a.jstree.create=function(b,d){var e=new a.jstree.core(++c),f=d;return d=a.extend(!0,{},a.jstree.defaults,d),f&&f.plugins&&(d.plugins=f.plugins),a.each(d.plugins,function(a,b){"core"!==a&&(e=e.plugin(b,d[b]))}),a(b).data("jstree",e),e.init(b,d),e},a.jstree.destroy=function(){a(".jstree:jstree").jstree("destroy"),a(i).off(".jstree")},a.jstree.core=function(a){this._id=a,this._cnt=0,this._wrk=null,this._data={core:{themes:{name:!1,dots:!1,icons:!1,ellipsis:!1},selected:[],last_error:{},working:!1,worker_queue:[],focused:null}}},a.jstree.reference=function(b){var c=null,d=null;if(!b||!b.id||b.tagName&&b.nodeType||(b=b.id),!d||!d.length)try{d=a(b)}catch(e){}if(!d||!d.length)try{d=a("#"+b.replace(a.jstree.idregex,"\\$&"))}catch(e){}return d&&d.length&&(d=d.closest(".jstree")).length&&(d=d.data("jstree"))?c=d:a(".jstree").each(function(){var d=a(this).data("jstree");return d&&d._model.data[b]?(c=d,!1):void 0}),c},a.fn.jstree=function(c){var d="string"==typeof c,e=Array.prototype.slice.call(arguments,1),f=null;return c!==!0||this.length?(this.each(function(){var g=a.jstree.reference(this),h=d&&g?g[c]:null;return f=d&&h?h.apply(g,e):null,g||d||c!==b&&!a.isPlainObject(c)||a.jstree.create(this,c),(g&&!d||c===!0)&&(f=g||!1),null!==f&&f!==b?!1:void 0}),null!==f&&f!==b?f:this):!1},a.expr.pseudos.jstree=a.expr.createPseudo(function(c){return function(c){return a(c).hasClass("jstree")&&a(c).data("jstree")!==b}}),a.jstree.defaults.core={data:!1,strings:!1,check_callback:!1,error:a.noop,animation:200,multiple:!0,themes:{name:!1,url:!1,dir:!1,dots:!0,icons:!0,ellipsis:!1,stripes:!1,variant:!1,responsive:!1},expand_selected_onload:!0,worker:!0,force_text:!1,dblclick_toggle:!0},a.jstree.core.prototype={plugin:function(b,c){var d=a.jstree.plugins[b];return d?(this._data[b]={},d.prototype=this,new d(c,this)):this},init:function(b,c){this._model={data:{},changed:[],force_full_redraw:!1,redraw_timeout:!1,default_state:{loaded:!0,opened:!1,selected:!1,disabled:!1}},this._model.data[a.jstree.root]={id:a.jstree.root,parent:null,parents:[],children:[],children_d:[],state:{loaded:!1}},this.element=a(b).addClass("jstree jstree-"+this._id),this.settings=c,this._data.core.ready=!1,this._data.core.loaded=!1,this._data.core.rtl="rtl"===this.element.css("direction"),this.element[this._data.core.rtl?"addClass":"removeClass"]("jstree-rtl"),this.element.attr("role","tree"),this.settings.core.multiple&&this.element.attr("aria-multiselectable",!0),this.element.attr("tabindex")||this.element.attr("tabindex","0"),this.bind(),this.trigger("init"),this._data.core.original_container_html=this.element.find(" > ul > li").clone(!0),this._data.core.original_container_html.find("li").addBack().contents().filter(function(){return 3===this.nodeType&&(!this.nodeValue||/^\s+$/.test(this.nodeValue))}).remove(),this.element.html("<ul class='jstree-container-ul jstree-children' role='group'><li id='j"+this._id+"_loading' class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='tree-item'><i class='jstree-icon jstree-ocl'></i><a class='jstree-anchor' href='#'><i class='jstree-icon jstree-themeicon-hidden'></i>"+this.get_string("Loading ...")+"</a></li></ul>"),this.element.attr("aria-activedescendant","j"+this._id+"_loading"),this._data.core.li_height=this.get_container_ul().children("li").first().height()||24,this._data.core.node=this._create_prototype_node(),this.trigger("loading"),this.load_node(a.jstree.root)},destroy:function(a){if(this._wrk)try{window.URL.revokeObjectURL(this._wrk),this._wrk=null}catch(b){}a||this.element.empty(),this.teardown()},_create_prototype_node:function(){var a=i.createElement("LI"),b,c;return a.setAttribute("role","treeitem"),b=i.createElement("I"),b.className="jstree-icon jstree-ocl",b.setAttribute("role","presentation"),a.appendChild(b),b=i.createElement("A"),b.className="jstree-anchor",b.setAttribute("href","#"),b.setAttribute("tabindex","-1"),c=i.createElement("I"),c.className="jstree-icon jstree-themeicon",c.setAttribute("role","presentation"),b.appendChild(c),a.appendChild(b),b=c=null,a},teardown:function(){this.unbind(),this.element.removeClass("jstree").removeData("jstree").find("[class^='jstree']").addBack().attr("class",function(){return this.className.replace(/jstree[^ ]*|$/gi,"")}),this.element=null},bind:function(){var b="",c=null,d=0;this.element.on("dblclick.jstree",function(a){if(a.target.tagName&&"input"===a.target.tagName.toLowerCase())return!0;if(i.selection&&i.selection.empty)i.selection.empty();else if(window.getSelection){var b=window.getSelection();try{b.removeAllRanges(),b.collapse()}catch(c){}}}).on("mousedown.jstree",a.proxy(function(a){a.target===this.element[0]&&(a.preventDefault(),d=+new Date)},this)).on("mousedown.jstree",".jstree-ocl",function(a){a.preventDefault()}).on("click.jstree",".jstree-ocl",a.proxy(function(a){this.toggle_node(a.target)},this)).on("dblclick.jstree",".jstree-anchor",a.proxy(function(a){return a.target.tagName&&"input"===a.target.tagName.toLowerCase()?!0:void(this.settings.core.dblclick_toggle&&this.toggle_node(a.target))},this)).on("click.jstree",".jstree-anchor",a.proxy(function(b){b.preventDefault(),b.currentTarget!==i.activeElement&&a(b.currentTarget).focus(),this.activate_node(b.currentTarget,b)},this)).on("keydown.jstree",".jstree-anchor",a.proxy(function(b){if(b.target.tagName&&"input"===b.target.tagName.toLowerCase())return!0;if(32!==b.which&&13!==b.which&&(b.shiftKey||b.ctrlKey||b.altKey||b.metaKey))return!0;var c=null;switch(this._data.core.rtl&&(37===b.which?b.which=39:39===b.which&&(b.which=37)),b.which){case 32:b.ctrlKey&&(b.type="click",a(b.currentTarget).trigger(b));break;case 13:b.type="click",a(b.currentTarget).trigger(b);break;case 37:b.preventDefault(),this.is_open(b.currentTarget)?this.close_node(b.currentTarget):(c=this.get_parent(b.currentTarget),c&&c.id!==a.jstree.root&&this.get_node(c,!0).children(".jstree-anchor").focus());break;case 38:b.preventDefault(),c=this.get_prev_dom(b.currentTarget),c&&c.length&&c.children(".jstree-anchor").focus();break;case 39:b.preventDefault(),this.is_closed(b.currentTarget)?this.open_node(b.currentTarget,function(a){this.get_node(a,!0).children(".jstree-anchor").focus()}):this.is_open(b.currentTarget)&&(c=this.get_node(b.currentTarget,!0).children(".jstree-children")[0],c&&a(this._firstChild(c)).children(".jstree-anchor").focus());break;case 40:b.preventDefault(),c=this.get_next_dom(b.currentTarget),c&&c.length&&c.children(".jstree-anchor").focus();break;case 106:this.open_all();break;case 36:b.preventDefault(),c=this._firstChild(this.get_container_ul()[0]),c&&a(c).children(".jstree-anchor").filter(":visible").focus();break;case 35:b.preventDefault(),this.element.find(".jstree-anchor").filter(":visible").last().focus();break;case 113:b.preventDefault(),this.edit(b.currentTarget)}},this)).on("load_node.jstree",a.proxy(function(b,c){c.status&&(c.node.id!==a.jstree.root||this._data.core.loaded||(this._data.core.loaded=!0,this._firstChild(this.get_container_ul()[0])&&this.element.attr("aria-activedescendant",this._firstChild(this.get_container_ul()[0]).id),this.trigger("loaded")),this._data.core.ready||setTimeout(a.proxy(function(){if(this.element&&!this.get_container_ul().find(".jstree-loading").length){if(this._data.core.ready=!0,this._data.core.selected.length){if(this.settings.core.expand_selected_onload){var b=[],c,d;for(c=0,d=this._data.core.selected.length;d>c;c++)b=b.concat(this._model.data[this._data.core.selected[c]].parents);for(b=a.vakata.array_unique(b),c=0,d=b.length;d>c;c++)this.open_node(b[c],!1,0)}this.trigger("changed",{action:"ready",selected:this._data.core.selected})}this.trigger("ready")}},this),0))},this)).on("keypress.jstree",a.proxy(function(d){if(d.target.tagName&&"input"===d.target.tagName.toLowerCase())return!0;c&&clearTimeout(c),c=setTimeout(function(){b=""},500);var e=String.fromCharCode(d.which).toLowerCase(),f=this.element.find(".jstree-anchor").filter(":visible"),g=f.index(i.activeElement)||0,h=!1;if(b+=e,b.length>1){if(f.slice(g).each(a.proxy(function(c,d){return 0===a(d).text().toLowerCase().indexOf(b)?(a(d).focus(),h=!0,!1):void 0},this)),h)return;if(f.slice(0,g).each(a.proxy(function(c,d){return 0===a(d).text().toLowerCase().indexOf(b)?(a(d).focus(),h=!0,!1):void 0},this)),h)return}if(new RegExp("^"+e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")+"+$").test(b)){if(f.slice(g+1).each(a.proxy(function(b,c){return a(c).text().toLowerCase().charAt(0)===e?(a(c).focus(),h=!0,!1):void 0},this)),h)return;if(f.slice(0,g+1).each(a.proxy(function(b,c){return a(c).text().toLowerCase().charAt(0)===e?(a(c).focus(),h=!0,!1):void 0},this)),h)return}},this)).on("init.jstree",a.proxy(function(){var a=this.settings.core.themes;this._data.core.themes.dots=a.dots,this._data.core.themes.stripes=a.stripes,this._data.core.themes.icons=a.icons,this._data.core.themes.ellipsis=a.ellipsis,this.set_theme(a.name||"default",a.url),this.set_theme_variant(a.variant)},this)).on("loading.jstree",a.proxy(function(){this[this._data.core.themes.dots?"show_dots":"hide_dots"](),this[this._data.core.themes.icons?"show_icons":"hide_icons"](),this[this._data.core.themes.stripes?"show_stripes":"hide_stripes"](),this[this._data.core.themes.ellipsis?"show_ellipsis":"hide_ellipsis"]()},this)).on("blur.jstree",".jstree-anchor",a.proxy(function(b){this._data.core.focused=null,a(b.currentTarget).filter(".jstree-hovered").mouseleave(),this.element.attr("tabindex","0")},this)).on("focus.jstree",".jstree-anchor",a.proxy(function(b){var c=this.get_node(b.currentTarget);c&&c.id&&(this._data.core.focused=c.id),this.element.find(".jstree-hovered").not(b.currentTarget).mouseleave(),a(b.currentTarget).mouseenter(),this.element.attr("tabindex","-1")},this)).on("focus.jstree",a.proxy(function(){if(+new Date-d>500&&!this._data.core.focused){d=0;var a=this.get_node(this.element.attr("aria-activedescendant"),!0);a&&a.find("> .jstree-anchor").focus()}},this)).on("mouseenter.jstree",".jstree-anchor",a.proxy(function(a){this.hover_node(a.currentTarget)},this)).on("mouseleave.jstree",".jstree-anchor",a.proxy(function(a){this.dehover_node(a.currentTarget)},this))},unbind:function(){this.element.off(".jstree"),a(i).off(".jstree-"+this._id)},trigger:function(a,b){b||(b={}),b.instance=this,this.element.triggerHandler(a.replace(".jstree","")+".jstree",b)},get_cont