webgme-hfsm
Version:
WebGME Domain for creating Executable Heirarchical Finite State Machines (HFSMs). Contains metamodel, visualization, simulation, and code generation for Heirarchical Finite State Machines (HFSMs) following the UML State Machine specification.
261 lines (224 loc) • 10.5 kB
JavaScript
/**
* @author William Emfinger https://github.com/finger563
*/
define(['js/util',
'bower/mustache.js/mustache.min',
'text!./Dialog.html',
'text!./Type.html',
'css!./Dialog.css'],
function(Util,
mustache,
DialogTemplate,
TypeTemplate){
'use strict';
var Dialog;
var ignoreTypes = ['Documentation']
const typeMap = {
'boolean': 'checkbox',
'float': 'number'
};
const valueMap = {
'checkbox': function(el) { return el[0].checked; }
};
var attrToID = function(attr) {
return attr.replace(/ /gm, '_');
};
var attrForm = ['<div class="form-group" id="p{{id}}">',
'<label class="col-sm-4 control-label">{{attr}}</label>',
'<div class="col-sm-8 controls">' ,
'<input type="{{type}}" id="{{id}}" placeholder="">',
'</div>',
'</div>'].join('\n');
/**
* Dialog Constructor
* Insert dialog modal into body and initialize editor with
* customized options
*/
Dialog = function () {
// Get Modal Template node for Editor Dialog and append it to body
this._dialog = $(DialogTemplate);
this._dialog.appendTo($(document.body))
// Get element nodes
this._el = this._dialog.find('.modal-body').first();
// forms
this._attrForm = this._dialog.find('#attrForm').first();
this._childSelector = this._dialog.find('#childTypeSelector').first();
// buttons
this._btnSave = this._dialog.find('.btn-save').first();
this._btnClose = this._dialog.find('.close').first();
this._btnCancel = this._dialog.find('.btn-cancel').first();
};
/**
* Initialize Dialog
* @param {Object} nodeDesc Descriptor for the node that will be the parent
* @param {Object} client Client object for creating nodes and setting attributes
* @return {void}
*/
Dialog.prototype.initialize = function ( desc, client, position) {
var self = this;
self.client = client;
// Initialize Modal and append it to main DOM
this._dialog.modal({ show: false});
// add children types to selector
this._childSelector.on('change', this.selectChild.bind(this));
this._childTypes = {};
this._childTypes = self.getValidChildrenTypes( desc, client );
var typeNames = Object.keys(this._childTypes).sort().reverse();
typeNames.map(function(t) {
$(self._childSelector).append(new Option(t, t));
});
$(this._childSelector).val( typeNames[0] );
this.renderChildForm();
// Event listener on click for SAVE button
this._btnSave.on('click', function (event) {
// Invoke callback to deal with modified text, like save it in client.
var attr = self.getAttributesFromForm();
client.startTransaction();
var type = self.getSelectedChildType();
var childCreationParams = {
parentId: desc.id,
baseId: self.getSelectedChildMetaId(),
position: position,
};
var msg = 'Creating new child of type ' + type + ' with parent ' + desc.id;
var newChildPath = client.createChild( childCreationParams, msg );
// save node data here dependent on the type of node
Object.keys(attr).map(function( attrName ) {
var attrVal = attr[attrName];
var currentAttr = client.getNode(newChildPath).getAttribute(attrName);
if (attrVal != currentAttr) {
msg = 'Setting "'+attrName+'" to "'+attrVal+'"';
client.setAttribute( newChildPath, attrName, attrVal, msg );
}
});
client.completeTransaction('', function(err, result) {
if (err) {
} else {
WebGMEGlobal.State.registerActiveSelection([newChildPath], {invoker: this});
}
});
// Close dialog
self._dialog.modal({ show: false});
self._dialog.modal('hide');
event.stopPropagation();
event.preventDefault();
});
// Event listener on click for CLOSE button
this._btnClose.on('click', function (event) {
// Close dialog
self._dialog.modal({ show: false});
self._dialog.modal('hide');
event.stopPropagation();
event.preventDefault();
});
// Event listener on click for CANCEL button
this._btnCancel.on('click', function (event) {
// Close dialog
self._dialog.modal({ show: false});
self._dialog.modal('hide');
event.stopPropagation();
event.preventDefault();
});
// Listener on event when dialog is shown
// Use callback to show editor after Modal window is shown.
this._dialog.on('shown.bs.modal', function () {
// Render text from params into Editor and store it in local storage
});
// Listener on event when dialog is hidden
this._dialog.on('hidden.bs.modal', function () {
self._dialog.empty();
self._dialog.remove();
});
};
// CHILD RELATED FUNCTIONS
Dialog.prototype.getSelectedChildType = function () {
var self = this;
return $(self._childSelector).val();
};
Dialog.prototype.getSelectedChildMetaId = function () {
var self = this;
return self._childTypes[ self.getSelectedChildType() ];
};
Dialog.prototype.getCurrentMetaNode = function() {
var self = this;
return self.client.getNode( self.getSelectedChildMetaId() );
};
Dialog.prototype.selectChild = function (event) {
var self = this;
//var childSelect = event.target;
//var newChildType = childSelect.options[ childSelect.selectedIndex ].textContent;
self.renderChildForm();
};
Dialog.prototype.renderChildForm = function() {
var self = this;
self._attrForm.empty();
self._attrForm.append( self.getForm() );
};
Dialog.prototype.getValidChildrenTypes = function( desc, client ) {
var node = client.getNode( desc.id );
var validChildTypes = {};
// figure out what the allowable range is
var validChildren = node.getValidChildrenTypesDetailed( );
Object.keys( validChildren ).map(function( metaId ) {
var child = client.getNode( metaId );
var childType = child.getAttribute('name');
var canCreateMore = validChildren[ metaId ];
if ( canCreateMore &&
!child.isAbstract() &&
!child.isConnection() &&
ignoreTypes.indexOf( childType ) == -1 )
validChildTypes[ childType ] = metaId;
});
return validChildTypes;
};
// ATTRIBUTE RELATED FUNCTIONS
Dialog.prototype.getCurrentAttributeNames = function () {
var self = this;
return self.getCurrentMetaNode().getAttributeNames().sort();
};
Dialog.prototype.getForm = function ( ) {
var self = this;
var form = '';
var node = self.getCurrentMetaNode();
self.getCurrentAttributeNames().map( function(a) {
form += self.renderAttributeForm( a, node.getAttributeMeta(a).type );
});
return form;
};
Dialog.prototype.renderAttributeForm = function ( attr, type ) {
return mustache.render( attrForm, {
attr: attr,
id: attrToID(attr),
type: (typeMap[type] || type)
} );
};
Dialog.prototype.getAttributesFromForm = function () {
var self = this;
var attr = {};
self.getCurrentAttributeNames().map(function(a) {
var el = $(self._dialog).find('#'+attrToID(a)).first();
var type = el.type || (el[0] && el[0].type);
var val = valueMap[type] ? valueMap[type](el) : el.val();
attr[a] = val;
});
return attr;
};
/**
* Update text in editor area
* @param {String} newtext [new text to replace old one]
*/
Dialog.prototype.updateText = function (newtext) {
this.text = newtext;
};
/**
* Show actual text editor in its container by loading EpicEditor, this method
* must be put into listener's callback function because its container is not appended
* into DOM at this point and load() cannot access other DOM elements.
* @return {void}
*/
Dialog.prototype.show = function () {
var self = this;
self._dialog.modal('show');
};
return Dialog;
});