sandbox/grouping/js/GroupFormContainer.js
(function() {
/**
* Class used to build a container with inputEx forms
* @class FormContainer
* @extends Container
* @constructor
* @param {Object} options Configuration object (see properties)
* @param {Layer} layer The Y.Layer (or subclass) instance that contains this container
*/
Y.GroupFormContainer = function(options, layer) {
/*var fieldConfigs = Y.GroupUtils.fieldConfigsFromModules(options.groupConfig.modules, options.getBaseConfigFunction);
var intermediate = Y.GroupUtils.generateFields(fieldConfigs, {fields: {}, terminals: {}}, {fields: {"0email" : true}, terminals: {}}); //TODO: wrong arguments
options.fields = intermediate.fields;
var terminalConfigs = Y.GroupUtils.terminalConfigsFromModules(options.groupConfig.modules, options.getBaseConfigFunction);
options.terminals = Y.GroupUtils.generateTerminals(terminalConfigs , {fields: {}, terminals: {}}, {fields: {}, terminals: {}}, intermediate.usedTerminalNames);
*/
Y.GroupFormContainer.superclass.constructor.call(this, options, layer);
this.getBaseConfig = this.options.getBaseConfigFunction;
this.positionTerminals();
};
Y.extend(Y.GroupFormContainer, Y.FormContainer, {
/**
* @method setOptions
*/
setOptions: function(options) {
Y.GroupFormContainer.superclass.setOptions.call(this, options);
this.options.getBaseConfigFunction = options.getBaseConfigFunction
this.options.groupConfig = options.groupConfig;
},
/**
* The render method is overrided to call renderForm
* @method render
*/
render: function() {
Y.GroupFormContainer.superclass.render.call(this);
this.renderExpand();
},
positionTerminals: function()
{
var terminals = {};
for (var i in this.options.terminals)
{
var elem = this.options.terminals[i];
var side = elem.side;
if (!Y.Lang.isValue(side))
side = "top";
if (!Y.Lang.isArray(terminals[side]))
terminals[side] = [];
terminals[side].push(elem);
}
var terminal_width = 30;
var getRange = function(N) { return terminal_width * (N-1); };
var positionByNumber = function(n,N, size) {
// n is expected to run from 0 to N-1, where N is the number of terminals on an edge
var range = getRange(N);
var half_range = range / 2;
var pos = size / 2;
pos -= half_range - n*terminal_width;
var offset = terminal_width / 2;
return pos-offset; // position in centre of terminal
};
var height = this.el.offsetHeight;
var width = this.el.offsetWidth;
var horizontalMax = Math.max(Y.GroupUtils.valueOr(terminals["top"], []).length, Y.GroupUtils.valueOr(terminals["bottom"], []).length);
var verticalMax = Math.max(Y.GroupUtils.valueOr(terminals["left"], []).length, Y.GroupUtils.valueOr(terminals["right"], []).length);
if (height < getRange(verticalMax))
{
this.bodyEl.style.minHeight = new String(getRange(verticalMax)) + "px";
height = this.el.offsetHeight;
}
if (width < getRange(horizontalMax))
{
this.bodyEl.style.minWidth = new String(getRange(horizontalMax)) + "px";
width = this.el.offsetWidth;
}
for (var side in terminals)
{
var sTerminals = terminals[side];
var count = sTerminals.length;
var variable, fixed, size;
if (side == "left" || side == "right")
{
variable = "top";
size = height;
} else
{
variable = "left";
size = width;
}
fixed = side;
for (var i = 0; i < count; i++)
{
var terminal = this.getTerminal(sTerminals[i].name);
var pos = new Object();
pos[fixed] = -15;
pos[variable] = new String(positionByNumber(i, count, size));
terminal.setPosition(pos);
}
}
},
renderExpand: function() {
this.unGroupButton = Y.WireIt.cn('div', {className: 'WireIt-Container-ungroupbutton'} );
Y.one(this.unGroupButton).on("click", this.expand, this, true);
this.ddHandle.appendChild(this.unGroupButton)
},
expand: function()
{
//For each module add it to the layer
//For each wire wire up the new containers
//For each internal group add to layer groups, remap from serialised
//For each wire on group container make wire to new containers
//Remove group container
//var expandedContainers = Y.GroupUtils.expand(this.options.groupConfig, this, this.layer);
var mapModuleId = function(offset, moduleId)
{
return parseInt(offset)+parseInt(moduleId);
};
var offset = this.layer.containers.length;
var thisConfig = this.getConfig();
var position = [thisConfig.position[0], thisConfig.position[1]];
var expandedContainers = [];
for (var mI in this.options.groupConfig.modules)
{
var m = this.options.groupConfig.modules[mI];
var baseContainerConfig = this.getBaseConfig(m.name);
var newConfig = Y.JSON.parse( Y.JSON.stringify( m.config ) ) //TODO: nasty deep clone, probably breaks if you have DOM elements in your config or something
Y.mix(newConfig , baseContainerConfig);
newConfig.title = m.name;
var newPos = this.translatePosition(newConfig.position, position);
newConfig.position = newPos;
var container = this.layer.addContainer(newConfig);
//Y.one(container.el).addClass("WiringEditor-module-"+m.name);
container.setValue(m.value);
expandedContainers.push(container);
}
var deserialise = function(sGroup, groupToSet)
{
var group = groupToSet;
if (!Y.Lang.isValue(group))
group = new Y.Group(this.group.grouper, this.layer)
group.properties = sGroup.properties; //TODO: copy rather than reference?
if (Y.Lang.isValue(sGroup.groupContainer))
{
group.groupContainer = expandedContainers[sGroup.groupContainer];
group.groupContainer.group = group;
}
else
{
group.containers = [];
group.groups = [];
for (var cI in sGroup.containers)
{
var co = sGroup.containers[cI];
var c = expandedContainers[co.container];
group.containers.push({"container" : c, "overrides" : co.overrides});
c.group = this.group;
}
for (var gI in sGroup.groups)
{
var go = sGroup.groups[gI]
var g = deserialise.call(this, go.group);
group.groups.push({"group" : g, "overrides" : go.overrides});
g.group = this.group;
}
}
return group;
}
var group = deserialise.call(this, this.options.groupConfig.group, this.group);
/*
for (var cI in expandedContainers)
{
var c = expandedContainers[cI]
c.group = this.innerGroup;
}*/
var getTerminalByName = function (terminals, name)
{
for (var tI in terminals)
{
var t = terminals[tI];
if (t.options.name == name)
return t;
}
};
var self = this;
var reconnectTerminal = function(terminal, internalId, internalName)
{
for (var wI in terminal.wires)
{
var w = terminal.wires[wI];
var wire = {}
var thisC = {"moduleId" : mapModuleId(offset, internalId), "terminal" : internalName}
if (w.terminal1 == terminal)
{
wire.src = thisC
wire.tgt = {"moduleId" : self.layer.containers.indexOf(w.terminal2.container), "terminal" : w.terminal2.options.name}
}
else
{
wire.tgt = thisC
wire.src = {"moduleId" : self.layer.containers.indexOf(w.terminal1.container), "terminal" : w.terminal1.options.name}
}
self.layer.addWire(wire);
}
};
var reconnect = function (tfMap, getInternalConfig, offset)
{
for (var fName in tfMap.fields)
{
var fMap = tfMap.fields[fName];
var f = self.form.inputsNames[fName];
var internal = getInternalConfig(fMap.containerId, fMap.name);
internal.setValue(f.getValue());
if (Y.Lang.isObject(f.terminal))
reconnectTerminal(f.terminal, mapModuleId(offset, fMap.containerId), fMap.name);
}
for (var tName in tfMap.terminals)
{
var tMap = tfMap.terminals[tName];
var t = getTerminalByName(self.terminals, tName);
reconnectTerminal(t, mapModuleId(offset, tMap.containerId), tMap.name);
}
}
reconnect(this.options.groupConfig.map.containerMap, function(id, name) { return group.containers[id].container.form.inputsNames[name]; }, 0);
reconnect(this.options.groupConfig.map.groupMap, function(id, name) { return group.groups[id].group.groupContainer.form.inputsNames[name] }, group.containers.length);
//Deserialise groups
//Set Field values
/*
for (var fName in this.form.inputsNames)
{
var f = this.form.inputsNames[fName];
var internal = Y.GroupUtils.getInternalField(this.options.groupConfig, fName);
var container = expandedContainers[internal.moduleId];
container.form.inputsNames[internal.name].setValue(f.getValue());
}
*/
for (var wI in this.options.groupConfig.wires)
{
var w = this.options.groupConfig.wires[wI]
this.layer.addWire(
{
"src":{
"moduleId": mapModuleId(offset, w.src.moduleId),
"terminal": w.src.terminal
},
"tgt":{
"moduleId": mapModuleId(offset, w.tgt.moduleId),
"terminal": w.tgt.terminal
}
}
);
}
//Remap current external wires to their corresponding internal containers
/*
for (var tI in this.terminals)
{
var t = this.terminals[tI]
for (var wI in t.wires)
{
var w = t.wires[wI]
var internal = Y.GroupUtils.getInternalTerminal(this.options.groupConfig, t.options.name);
var wire = {}
var thisC = {"moduleId" : mapModuleId(offset, internal.moduleId), "terminal" : internal.name}
if (w.terminal1 == t)
{
wire.src = thisC
wire.tgt = {"moduleId" : this.layer.containers.indexOf(w.terminal2.container), "terminal" : w.terminal2.options.name}
}
else
{
wire.tgt = thisC
wire.src = {"moduleId" : this.layer.containers.indexOf(w.terminal1.container), "terminal" : w.terminal1.options.name}
}
this.layer.addWire(wire);
}
}
*/
this.layer.removeContainer(this);
this.group.groupContainer = null;
var POPIgI = 0;
for (POPIgI = 0; POPIgI < group.groups.length; POPIgI++)
{
var g = group.groups[POPIgI].group;
if (g.properties.expanded && Y.Lang.isValue(g.groupContainer))
g.groupContainer.expand();
}
this.group.grouper.showGroup.call(this.group.grouper, this.group);
},
translatePosition: function(modulePosition, position)
{
return [ Math.max(0, modulePosition[0]+position[0]), Math.max(0, modulePosition[1]+position[1]) ];
},
getConfig : function()
{
var config = Y.GroupFormContainer.superclass.getConfig.call(this);
Y.mix(config, {"fields" : this.options.fields, "terminals" : this.options.terminals, "groupConfig" : this.options.groupConfig});
return config;
}
/**
* @method getValue
*/
/* getValue: function() {
return this.group;
},
*/
/**
* @method setValue
*/
/*setValue: function(val) {
this.group = val;
//Terminals
this.removeAllTerminals();
this.initTerminals(val.terminals);
this.dd.setTerminals(this.terminals);
//Fields - have to go after terminal stuff since fields create their own terminals and above stuff would destroy them
this.options.fields = val.fields;
this.form.destroy();
this.renderForm();
}*/
});
})();