build/wireit-all/wireit-all.js
/* This file is auto-generated by src/loader/scripts/meta_join.js */
YUI().use(function(Y) {
var CONFIG = {
groups: {
'wireit': {
base: 'wireit/src/',
combine: false,
modules: {
"arrow-wire": {
"requires": [
"wire-base"
]
},
"bezier-wire": {
"requires": [
"wire-base"
]
},
"bidirectional-arrow-wire": {
"requires": [
"arrow-wire"
]
},
"container": {
"requires": [
"widget-stdmod",
"widget-stack",
"widget-parent",
"widget-child",
"dd",
"resize",
"wires-delegate",
"widget-terminals",
"widget-icons"
],
"skinnable": true
},
"image-container": {
"requires": [
"container"
],
"skinnable": true
},
"inout-container": {
"requires": [
"container",
"terminal-input",
"terminal-output"
],
"skinnable": true
},
"layer": {
"requires": [
"widget-parent",
"container",
"wires-delegate"
],
"skinnable": true
},
"straight-wire": {
"requires": [
"wire-base"
]
},
"terminal": {
"requires": [
"widget",
"widget-child",
"widget-position",
"widget-position-align",
"wire-base",
"wires-delegate",
"terminal-dragedit",
"terminal-scissors",
"terminal-ddgroups"
],
"skinnable": true
},
"terminal-ddgroups": {
"requires": [
"terminal-dragedit"
]
},
"terminal-dragedit": {
"requires": [
"bezier-wire",
"dd-drop",
"dd-drag",
"dd-proxy"
]
},
"terminal-input": {
"requires": [
"terminal"
]
},
"terminal-output": {
"requires": [
"terminal"
]
},
"terminal-scissors": {
"requires": [
"overlay"
],
"skinnable": true
},
"textarea-container": {
"requires": [
"container"
]
},
"widget-icons": {
"requires": [],
"skinnable": true
},
"widget-terminals": {
"requires": [
"terminal"
]
},
"wire-base": {
"requires": [
"graphics"
],
"skinnable": true
},
"wireit-app": {
"requires": [
"app",
"handlebars",
"model",
"model-list",
"json",
"view",
"layer",
"bezier-wire",
"anim"
]
},
"wires-delegate": {
"requires": [
"wire-base"
]
}
}
}
}
};
if(typeof YUI_config === 'undefined') {
YUI_config = {groups: {}};
}
Y.mix(YUI_config.groups, CONFIG.groups);
});
YUI.add('arrow-wire', function (Y, NAME) {
'use strict';
/**
* @module arrow-wire
*/
/**
* Extend CanvasWire to draw an arrow wire
* @class ArrowWire
* @extends WireBase
* @constructor
* @param {Object} config the configuration for the ArrowWire attributes
*/
Y.ArrowWire = function (config) {
Y.ArrowWire.superclass.constructor.apply(this, arguments);
};
Y.ArrowWire.NAME = 'arrowwire';
Y.extend(Y.ArrowWire, Y.WireBase, {
_drawArrow: function(src, tgt) {
var d = 7, // arrow width/2
distance = Math.sqrt(Math.pow(src[0]-tgt[0],2) + Math.pow(src[1]-tgt[1],2)),
dlug = 20, //arrow length
t = (distance === 0) ? 0 : 1 - (dlug/distance),
//point on the wire with constant distance (dlug) from terminal2
z = [
Math.abs( src[0] + t * (tgt[0] - src[0]) ),
Math.abs( src[1] + t * (tgt[1] - src[1]) )
],
// start drawing arrows
// line which connects the terminals: y=ax+b
W = src[0] - tgt[0],
Wa = src[1] - tgt[1],
Wb = src[0] * tgt[1] - src[1] * tgt[0],
a, b, aProst, bProst,
A,B,C,
delta,
x1,x2,y1,y2,
o;
if (W !== 0) {
a = Wa / W;
b = Wb / W;
}
else {
a = 0;
}
// line perpendicular to the main line: y = aProst*x + b
if (a === 0) {
aProst = 0;
}
else {
aProst = -1 / a;
}
bProst = z[1] - aProst * z[0]; //point z lays on this line
// we have to calculate coordinates of 2 points, which lay on perpendicular line and have the same distance (d) from point z
A = 1 + Math.pow(aProst, 2);
B = 2 * aProst * bProst - 2 * z[0] - 2 * z[1] * aProst;
C = -2 * z[1] * bProst + Math.pow(z[0], 2) + Math.pow(z[1], 2) - Math.pow(d, 2) + Math.pow(bProst, 2);
delta = Math.pow(B, 2) - 4 * A * C;
if (delta < 0) { return; }
x1 = (-B + Math.sqrt(delta)) / (2 * A);
x2 = (-B - Math.sqrt(delta)) / (2 * A);
y1 = aProst * x1 + bProst;
y2 = aProst * x2 + bProst;
if (src[1] === tgt[1]) {
o = (src[0] > tgt[0]) ? 1 : -1;
x1 = tgt[0] + o * dlug;
x2 = x1;
y1 -= d;
y2 += d;
}
// triangle border
this.moveTo(tgt[0] + 6, tgt[1] + 6);
this.lineTo(x1 + 6, y1 + 6);
this.moveTo(tgt[0] + 6, tgt[1] + 6);
this.lineTo(x2 + 6, y2 + 6);
},
/**
* @method _draw
* @private
*/
_draw: function () {
this.clear();
var src = this.get('src').getXY(),
tgt = this.get('tgt').getXY();
this.moveTo((src[0] + 6), (src[1] + 6));
this.lineTo((tgt[0] + 6), (tgt[1] + 6));
this._drawArrow(src, tgt);
this.end();
}
});
Y.ArrowWire.ATTRS = Y.merge(Y.WireBase.ATTRS, {});
}, '@VERSION@', {"requires": ["wire-base"]});
YUI.add('bezier-wire', function (Y, NAME) {
/**
* @module bezier-wire
*/
/**
* Extend WireBase to draw a bezier curve
* @class BezierWire
* @extends WireBase
* @constructor
* @param {Object} config the configuration for the BezierWire attributes
*/
Y.BezierWire = function (cfg) {
Y.BezierWire.superclass.constructor.apply(this, arguments);
};
Y.BezierWire.NAME = "bezierwire";
Y.extend(Y.BezierWire, Y.WireBase, {
/**
* Draw the bezier curve.
* The canvas is made bigger to contain the curls
* @method _draw
* @method private
*/
_draw: function () {
this.clear();
var src = this.get('src').getXY(),
tgt = this.get('tgt').getXY(),
srcDir = this.get('srcDir'),
tgtDir = this.get('tgtDir'),
bezierTangentNorm = this.get('bezierTangentNorm'),
terminalSize = 14/2;
this.moveTo(src[0]+terminalSize,src[1]+terminalSize);
this.curveTo(src[0]+terminalSize+srcDir[0]*bezierTangentNorm,
src[1]+terminalSize+srcDir[1]*bezierTangentNorm,
tgt[0]+terminalSize+tgtDir[0]*bezierTangentNorm,
tgt[1]+terminalSize+tgtDir[1]*bezierTangentNorm,
tgt[0]+terminalSize,
tgt[1]+terminalSize);
this.end();
},
SERIALIZABLE_ATTRS: function() {
return ["color","width","bezierTangentNorm"];
}
});
Y.BezierWire.ATTRS = Y.merge(Y.WireBase.ATTRS, {
/**
* Norm of the tangeant vector at the endpoints.
* @attribute bezierTangentNorm
* @default 100
* @type Integer
*/
bezierTangentNorm: {
setter: function (val) {
return parseInt(val, 10);
},
value: 100
}
});
}, '@VERSION@', {"requires": ["wire-base"]});
YUI.add('bidirectional-arrow-wire', function (Y, NAME) {
/**
* @module bidirectional-arrow-wire
*/
/**
* BidirectionalArrowWire
* @class BidirectionalArrowWire
* @extends ArrowWire
* @constructor
* @param {Object} config the configuration for the BezierWire attributes
*/
Y.BidirectionalArrowWire = function (config) {
Y.BidirectionalArrowWire.superclass.constructor.apply(this, arguments);
};
Y.BidirectionalArrowWire.NAME = 'bidirectionalarrowwire';
Y.extend(Y.BidirectionalArrowWire, Y.ArrowWire, {
_draw: function () {
this.clear();
var src = this.get('src').getXY(),
tgt = this.get('tgt').getXY();
this.moveTo((src[0] + 6), (src[1] + 6));
this.lineTo((tgt[0] + 6), (tgt[1] + 6));
this._drawArrow(src, tgt);
this._drawArrow(tgt, src);
this.end();
}
});
Y.BidirectionalArrowWire.ATTRS = Y.merge(Y.ArrowWire.ATTRS, {});
}, '@VERSION@', {"requires": ["arrow-wire"]});
YUI.add('container', function (Y, NAME) {
'use strict';
/**
* @module container
*/
/**
* Container is an Overlay (XY positioning)
* It is a WidgetChild (belongs to Layer)
* It is also a WidgetParent (has many terminals)
* @class Container
* @extends Widget
* @uses WidgetStdMod
* @uses WidgetStack
* @uses WidgetParent
* @uses WidgetChild
* @uses WiresDelegate
* @uses WidgetTerminals
* @uses WidgetIcons
* @constructor
*/
Y.Container = Y.Base.create("container", Y.Widget, [
Y.WidgetStdMod,
Y.WidgetStack,
Y.WidgetParent,
Y.WidgetChild,
Y.WiresDelegate,
Y.WidgetTerminals,
Y.WidgetIcons
], {
/**
* @method renderUI
*/
renderUI: function () {
this._renderDrag();
this._renderResize();
},
bindUI: function() {
if(this.resize) {
this.resize.on('resize:resize', this._onResize, this);
}
this.drag.on('drag:drag', function () {
this.redrawAllWires();
}, this);
},
syncUI: function() {
// waiting for the next tick to align the terminals
Y.later(0, this, function() {
this.alignTerminals();
});
},
_renderDrag: function() {
// make the overlay draggable
this.drag = new Y.DD.Drag({
node: this.get('boundingBox'),
handles : [ this._findStdModSection(Y.WidgetStdMod.HEADER) ]
});
},
_renderResize: function() {
// Make the overlay resizable
if(!this.get('resizable')) {
return;
}
this.resize = new Y.Resize({
node: this.get('contentBox'),
handles: 'br' // bottom-right
});
},
_onResize: function(e) {
// On resize, fillHeight, & align terminals & wires
this._fillHeight();
this.alignTerminals();
// Set width & height
var region = this.get('boundingBox').get('region');
this.set('width', e.details[0].info.offsetWidth);
this.set('height', e.details[0].info.offsetHeight);
},
/**
* Click handler for the close icon
* @method _onCloseClick
* @private
*/
_onCloseClick: function () {
this.destroy();
},
SERIALIZABLE_ATTRS: function() {
var attrs = ['x', 'y'];
if(this.get('resizable')) {
attrs.push('width');
attrs.push('height');
}
return attrs;
},
toJSON: function () {
var o = {},
a = this;
Y.Array.each(this.SERIALIZABLE_ATTRS(), function (attr) {
o[attr] = a.get(attr);
});
return o;
},
destructor: function () {
this.drag.destroy();
if(this.resize) {
this.resize.destroy();
}
}
}, {
ATTRS: {
/**
* Relative left position (in the layer referential)
* @attribute x
*/
x: {
lazyAdd: false,
getter: function() {
return parseInt(this.get('boundingBox').getStyle('left'),10);
},
setter: function(val) {
this.get('boundingBox').setStyle('left', val);
},
validator: function(val) {
return Y.Lang.isNumber(val);
}
},
/**
* Relative top position (in the layer referential)
* @attribute y
*/
y: {
lazyAdd: false,
getter: function() {
return parseInt(this.get('boundingBox').getStyle('top'),10);
},
setter: function(val) {
this.get('boundingBox').setStyle('top', val);
},
validator: function(val) {
return Y.Lang.isNumber(val);
}
},
/**
* @attribute zIndex
*/
zIndex: {
value: 5
},
/**
* @attribute resizable
*/
resizable: {
value: true
},
/**
* @attribute fillHeight
*/
fillHeight: {
value: true
},
preventSelfWiring: {
value: true
},
/**
* Override the default value of WidgetIcons to add the close button
* @attribute icons
*/
icons: {
value: [
{title: 'close', click: '_onCloseClick', className: 'ui-silk ui-silk-cancel'}
]
}
}
});
}, '@VERSION@', {
"requires": [
"widget-stdmod",
"widget-stack",
"widget-parent",
"widget-child",
"dd",
"resize",
"wires-delegate",
"widget-terminals",
"widget-icons"
],
"skinnable": true
});
YUI.add('image-container', function (Y, NAME) {
/**
* @module image-container
*/
/**
* ImageContainer is an Overlay (XY positioning)
* It is a WidgetChild (belongs to Layer)
* It is also a WidgetParent (has many terminals)
* @class ImageContainer
* @extends Container
* @constructor
*/
Y.ImageContainer = Y.Base.create("image-container", Y.Container, [], {
/**
* @method renderUI
*/
renderUI: function () {
this.image = Y.Node.create('<img src="'+this.get('imageUrl')+'" width="'+this.get('width')+'" height="'+this.get('height')+'"/>');
this.image.appendTo( this.get('contentBox') );
Y.ImageContainer.superclass.renderUI.apply(this);
if(this.resize && this.get('resizePreserveRatio') ) {
this.resize.plug(Y.Plugin.ResizeConstrained, {
preserveRatio: true
});
}
},
/**
* @method bindUI
*/
bindUI: function() {
this.image.after('load', this.alignTerminals, this);
if(this.resize) {
this.resize.after('resize:resize', this._onResizeImage, this);
}
this.drag.set('handles', [this.image]);
Y.ImageContainer.superclass.bindUI.apply(this);
},
_onResizeImage: function(e) {
var p = e.details[0].info;
this.image.set('width', p.right-p.left);
this.image.set('height', p.bottom-p.top);
}
}, {
ATTRS: {
/**
* Url of the image you want to render (relative to the script's page)
* @attribute imageUrl
*/
imageUrl: {
value: '',
setter: function(url) {
if(this.image) {
this.image.set('src', url);
}
}
},
/**
* Preserve ratio when resized (only if resizable)
* @attribute resizePreserveRatio
*/
resizePreserveRatio: {
value: true
}
}
});
}, '@VERSION@', {"requires": ["container"], "skinnable": true});
YUI.add('inout-container', function (Y, NAME) {
/**
* @module inout-container
*/
/**
* Container with left inputs and right outputs
* @class InOutContainer
* @extends Container
* @constructor
* @param {Object} options
*/
Y.InOutContainer = Y.Base.create("inout-container", Y.Container, [], {
/**
* @method renderUI
*/
renderUI: function () {
Y.InOutContainer.superclass.renderUI.call(this);
this._renderInputsOutputs();
},
/**
* @method _renderInputsOutputs
*/
_renderInputsOutputs: function () {
this.setStdModContent(Y.WidgetStdMod.BODY, "<ul class='inputs'></ul><ul class='outputs'></ul>");
var bb = this.get('boundingBox'),
inputsUl = bb.one('ul.inputs'),
outputsUl = bb.one('ul.outputs'),
inputs = this.get('inputs'),
outputs = this.get('outputs'),
i, n;
for(i = 0, n = inputs.length ; i < n ; i++) {
Y.Node.create('<li>'+inputs[i].label+'</li>').appendTo(inputsUl);
this.add({
type: 'TerminalInput',
name: inputs[i].name,
dir: [-0.3, 0]
});
}
for(i = 0, n = outputs.length; i < n ; i++) {
Y.Node.create('<li>'+outputs[i].label+'</li>').appendTo(outputsUl);
this.add({
type: 'TerminalOutput',
name: outputs[i].name,
dir: [0.3, 0]
});
}
Y.later(100, this, function() {
var i, term;
for(i = 0 ; i < inputs.length ; i++) {
this.item(i).align( inputsUl.all('li').item(i) , [Y.WidgetPositionAlign.TC, Y.WidgetPositionAlign.LC] );
}
for(i = 0 ; i < outputs.length ; i++) {
term = this.item(inputs.length + i);
term.align( outputsUl.all('li').item(i) , [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.RC] );
term.set('x', term.get('x')+11);
}
});
}
}, {
ATTRS: {
resizable: {
value: false
},
/**
* @attribute inputs
* @description Array of strings for which an Input terminal will be created.
* @default []
* @type Array
*/
inputs: [],
/**
* @attribute outputs
* @description Array of strings for which an Output terminal will be created.
* @default []
* @type Array
*/
outputs: []
}
});
}, '@VERSION@', {"requires": ["container", "terminal-input", "terminal-output"], "skinnable": true});
YUI.add('layer', function (Y, NAME) {
/**
* @module layer
*/
/**
* Layer : Widget to manage collections of wires (through WiresDelegate) and containers (trough WidgetParent)
* @class Layer
* @extends Widget
* @uses WidgetParent
* @uses WiresDelegate
*/
Y.Layer = Y.Base.create("layer", Y.Widget, [Y.WidgetParent, Y.WiresDelegate], {
initializer: function () {
this.graphic = new Y.Graphic({render: this.get('contentBox') });
},
/**
* Alias method for WidgetParent.removeAll
* @method clear
*/
clear: function () {
this.removeAll();
}
}, {
ATTRS: {
defaultChildType: {
value: 'Container'
}
}
});
}, '@VERSION@', {"requires": ["widget-parent", "container", "wires-delegate"], "skinnable": true});
YUI.add('straight-wire', function (Y, NAME) {
/**
* @module straight-wire
*/
/**
* Straight Wire
* @class StraightWire
* @extends WireBase
* @constructor
* @param {Object} cfg the configuration for the StraightWire attributes
*/
Y.StraightWire = function (cfg) {
Y.StraightWire.superclass.constructor.apply(this, arguments);
};
Y.StraightWire.NAME = "straightwire";
Y.extend(Y.StraightWire, Y.WireBase, {
/**
* @method _draw
* @private
*/
_draw: function () {
this.clear();
var src = this.get('src').getXY(),
tgt = this.get('tgt').getXY();
this.moveTo((src[0]+6), (src[1]+6));
this.lineTo((tgt[0]+6), (tgt[1]+6));
this.end();
}
});
Y.StraightWire.ATTRS = Y.merge(Y.WireBase.ATTRS, {});
}, '@VERSION@', {"requires": ["wire-base"]});
YUI.add('terminal', function (Y, NAME) {
/**
* @module terminal
*/
'use strict';
/**
* Terminal is responsible for wire edition
*
* @class Terminal
* @extends Widget
* @uses WidgetChild
* @uses WidgetPosition
* @uses WidgetPositionAlign
* @uses WiresDelegate
* @uses TerminalDragEdit
* @uses TerminalScissors
* @uses TerminalDDGroups
* @constructor
* @param {Object} oConfigs The user configuration for the instance.
*/
Y.Terminal = Y.Base.create("terminal", Y.Widget, [
Y.WidgetChild,
Y.WidgetPosition,
Y.WidgetPositionAlign,
Y.WiresDelegate,
Y.TerminalDragEdit,
Y.TerminalScissors,
Y.TerminalDDGroups
], {
syncUI: function () {
this._syncOffset();
},
_syncOffset: function() {
var offset = this.get('offset');
if(offset) {
this._posNode.setStyle('left', offset[0]);
this._posNode.setStyle('top', offset[1]);
this.syncXY();
}
},
bindUI: function() {
var bb = this.get('boundingBox');
bb.on('mouseover', this._onMouseOver, this);
bb.on('mouseout', this._onMouseOut, this);
},
_onMouseOver: function() {
Y.later(300, this, this._showOverlay);
},
_showOverlay: function() {
this.get('boundingBox').addClass( this.getClassName("show-overlay") );
},
_onMouseOut: function() {
Y.later(300, this, this._hideOverlay);
},
_hideOverlay: function() {
var bb = this.get('boundingBox');
// because of the timer, the widget may have been destroyed
if(bb) {
bb.removeClass( this.getClassName("show-overlay") );
}
},
// override the WiresDelegate behavior which re-fires the event
// add the connected class
_onAddWire: function (e) {
this.get('boundingBox').addClass( this.getClassName("connected") );
},
// override the WiresDelegate behavior which re-fires the event
// Remove the connected class if it has no more wires:
_onRemoveWire: function (e) {
if(this._wires.length === 0) {
this.get('boundingBox').removeClass( this.getClassName("connected") );
}
},
/**
* This function is a temporary test. I added the border width while traversing the DOM and
* I calculated the offset to center the wire in the terminal just after its creation
* @method getXY
*/
getXY: function () {
var container = this.get('parent'),
layer = container.get('parent'),
layerXY = layer.get('boundingBox').getXY(),
absXY = this.get('contentBox').getXY();
return [absXY[0]-layerXY[0] + 15/2 , absXY[1]-layerXY[1] + 15/2];
}
}, {
ATTRS: {
/**
* @attribute name
*/
name: {
value: null
},
/**
* Vector direction at the terminal
* (used by BezierWire ou Scissors)
* @attribute dir
*/
dir: {
value: [0,1]
},
alignNode: {
value: null
},
/**
* @attribute offset
*/
offset: {
value: null,
validator: function(val) {
return this._validateXY(val);
}
}
}
});
}, '@VERSION@', {
"requires": [
"widget",
"widget-child",
"widget-position",
"widget-position-align",
"wire-base",
"wires-delegate",
"terminal-dragedit",
"terminal-scissors",
"terminal-ddgroups"
],
"skinnable": true
});
YUI.add('terminal-ddgroups', function (Y, NAME) {
/**
* @module terminal-ddgroups
*/
/**
* Extension to add "groups" labels when hovering the terminal
* @class TerminalDDGroups
* @constructor
* @param {Object} config configuration object
*/
Y.TerminalDDGroups = function (config) {
Y.after(this._renderUIgroups, this, "renderUI");
Y.after(this._showOverlayDDGroups, this, "_showOverlay");
};
Y.TerminalDDGroups.ATTRS = {
showGroups: {
value: true
}
};
Y.TerminalDDGroups.prototype = {
_renderUIgroups: function () {
if( this.get('editable') ) {
this._renderTooltip();
}
},
/**
* create a persisting tooltip with the dd-groups class
* @method _renderTooltip
*/
_renderTooltip: function () {
if(this.get('showGroups')) {
this._ddGroupsOverlay = new Y.Overlay({
render: this.get('boundingBox'),
bodyContent: this.get('ddGroupsDrag').join(',')
});
this._ddGroupsOverlay.get('contentBox').addClass( this.getClassName("dd-groups") );
}
},
_showOverlayDDGroups: function() {
this._ddGroupsOverlay.align( this.get('contentBox'), [Y.WidgetPositionAlign.TC, Y.WidgetPositionAlign.BC] );
}
};
}, '@VERSION@', {"requires": ["terminal-dragedit"]});
YUI.add('terminal-dragedit', function (Y, NAME) {
/**
* @module terminal-dragedit
*/
/**
* Extension which makes the wires editable
* @class TerminalDragEdit
* @constructor
* @param {Object} config configuration object
*/
Y.TerminalDragEdit = function (config) {
Y.after(this._renderUIdragedit, this, "renderUI");
Y.after(this._bindUIdragedit, this, "bindUI");
var attrs = {
"color":{value:"rgb(173,216,230)"},
"weight":{value:4},
"opacity":{value:1},
"dashstyle":{value:"none"},
"fill":{value:"rgb(255,255,255)"},
"editwire-class": {value: Y.BezierWire}
};
this.addAttrs(attrs, config);
};
Y.TerminalDragEdit.ATTRS = {
/**
* Sets the terminal editable
* @attribute editable
*/
editable: {
value: true
},
/**
* @attribute graphic
*/
graphic: {
value: null
},
/**
* @attribute alwaysSrc
*/
alwaysSrc: {
value: false
},
ddGroupsDrag: {
value: ['terminal']
},
ddGroupsDrop: {
value: ['terminal']
}
};
Y.TerminalDragEdit.prototype = {
/**
* @method _renderUIdragedit
*/
_renderUIdragedit: function () {
if( this.get('editable') ) {
this.get('contentBox').addClass( this.getClassName("editable") );
// Make the contentBox draggable with a DDProxy
var drag = new Y.DD.Drag({
node: this.get('contentBox'),
groups: this.get('ddGroupsDrag') //this.get('groups')
}).plug(Y.Plugin.DDProxy, {
cloneNode: true,
moveOnEnd: false
});
this.drag = drag;
// Create the Drop object
var drop = new Y.DD.Drop({
node: this.get('contentBox'),
groups: this.get('ddGroupsDrop') //this.get('groups')
});
drop.terminal = this;
this.drop = drop;
}
},
/**
* @method _bindUIdragedit
*/
_bindUIdragedit: function () {
var drag = this.drag;
if(drag) {
drag.on('drag:start', this._onDragEditStart, this);
drag.on('drag:drag', this._onDragEditDrag, this);
drag.on('drag:drophit', this._onDragEditDrophit, this);
drag.on('drag:dropmiss', this._onDragEditDropmiss, this);
drag.on('drag:enter', this._onDragEditEnter, this);
drag.on('drag:exit', this._onDragEditExit, this);
}
},
/**
* on drag start, create the wire between 2 fake terminals
* @method _onDragEditStart
*/
_onDragEditStart: function (ev) {
// save the position
this._editwireX = ev.pageX;
this._editwireY = ev.pageY;
var dir = this.get('dir');
var that = this;
if(!this.get('graphic')) {
this.set('graphic', this.get('root').graphic);
}
var container = this.get('parent');
var layer = container.get('parent');
var offset = layer.get('boundingBox').getXY();
this.drag.wire = this.get('graphic').addShape({
type: this.get('editwire-class'),
// TODO: customizable
stroke: {
weight: this.get('weight'),
color: this.get('color'),
opacity:this.get('opacity'),
dashstyle:this.get('dashstyle'),
fill:this.get('fill')
},
src: {
getXY: function () { return [ev.pageX - offset[0] + 15 / 2, ev.pageY - offset[1] + 15 / 2]; }
},
tgt: {
getXY: function () { return [that._magnetX || (that._editwireX - offset[0] + 15 / 2),
that._magnetY || (that._editwireY - offset[1] + 15 / 2)]; }
},
srcDir: dir,
tgtDir: [-dir[0],-dir[1]]
});
},
/**
* Update the position of the fake target and redraw the wire
* @method _onDragEditDrag
* @private
*/
_onDragEditDrag: function (ev) {
this._editwireX = ev.pageX;
this._editwireY = ev.pageY;
this.drag.wire._draw();
},
/**
* on drop hit, set the wire src and tgt terminals
* @method _onDragEditDrophit
* @private
*/
_onDragEditDrophit: function (ev) {
if( this.isValidWireTerminal(ev.drop.terminal) ) {
if(ev.drop.terminal.alwaysSrc) {
this.drag.wire.set('src', ev.drop.terminal);
this.drag.wire.set('tgt', this);
} else {
this.drag.wire.set('src', this);
this.drag.wire.set('tgt', ev.drop.terminal);
}
// Remove the reference to this wire
this.drag.wire = null;
// Reset the magnet position
this._magnetX = null;
this._magnetY = null;
} else {
this.drag.wire.destroy();
}
},
/**
* on drop miss, destroy the wire
* @method _onDragEditDropmiss
*/
_onDragEditDropmiss: function (ev) {
this.drag.wire.destroy();
this.drag.wire = null;
},
/**
* @method _onDragEditEnter
*/
_onDragEditEnter: function (ev) {
var pos = ev.drop.terminal.getXY();
this._magnetX = pos[0];
this._magnetY = pos[1];
// TODO: this only works for Bezier...
this.drag.wire.set('tgtDir', ev.drop.terminal.get('dir'));
},
/**
* @method _onDragEditExit
*/
_onDragEditExit: function (ev) {
this._magnetX = null;
this._magnetY = null;
},
/**
* @method isValidWireTerminal
*/
isValidWireTerminal: function (DDterminal) {
if(this.get('parent') !== undefined && (this.get('parent').get('preventSelfWiring'))){
if (DDterminal._parentNode._node == this._parentNode._node) {
return false;
}
}
return true;
},
/**
* @method destructor
*/
destructor: function () {
if(this.drag) {
this.drag.destroy();
}
if(this.drop) {
this.drop.destroy();
}
}
};
}, '@VERSION@', {"requires": ["bezier-wire", "dd-drop", "dd-drag", "dd-proxy"]});
YUI.add('terminal-input', function (Y, NAME) {
/**
* @module terminal-input
*/
'use strict';
/**
* Class that extends Terminal to differenciate Input/Output terminals
* @class TerminalInput
* @extends Terminal
* @constructor
* @param {Object} oConfigs The user configuration for the instance.
*/
Y.TerminalInput = Y.Base.create("terminal-input", Y.Terminal, [], {
getClassName: function(n) {
return "yui3-terminal-"+n;
}
}, {
ATTRS: {
dir: {
value: [-0.3, 0]
},
ddGroupsDrag: {
value: ['input']
},
ddGroupsDrop: {
value: ['output']
}
// TODO
// nMaxWires: 1,
}
});
}, '@VERSION@', {"requires": ["terminal"]});
YUI.add('terminal-output', function (Y, NAME) {
/**
* @module terminal-output
*/
'use strict';
/**
* Class that extends Terminal to differenciate Input/Output terminals
* @class TerminalOutput
* @extends Terminal
* @constructor
* @param {Object} oConfigs The user configuration for the instance.
*/
Y.TerminalOutput = Y.Base.create("terminal-output", Y.Terminal, [], {
getClassName: function(n) {
return "yui3-terminal-"+n;
}
}, {
ATTRS: {
dir: {
value: [0.3, 0]
},
ddGroupsDrag: {
value: ['output']
},
ddGroupsDrop: {
value: ['input']
}
// TODO
// alwaysSrc: true
}
});
}, '@VERSION@', {"requires": ["terminal"]});
YUI.add('terminal-scissors', function (Y, NAME) {
/**
* @module terminal-scissors
*/
/**
* @class TerminalScissors
* @constructor
* @param {Object} config configuration object
*/
Y.TerminalScissors = function (config) {
Y.after(this._renderUIScissors, this, "renderUI");
Y.after(this._bindUIScissors, this, "bindUI");
};
Y.TerminalScissors.ATTRS = {
/**
* @attribute dirNormed
*/
dirNormed: {
getter: function() {
var dir = this.get('dir'),
a = dir[0],
b = dir[1],
norm = Math.sqrt(a*a+b*b);
return [dir[0]/norm, dir[1]/norm];
}
},
/**
* @attribute scissorsDistance
*/
scissorsDistance: {
value: 30
}
};
Y.TerminalScissors.prototype = {
/**
* @method _renderUIScissors
* @private
*/
_renderUIScissors: function () {
if( this.get('editable') ) {
this._renderScissors();
}
},
/**
* @method _bindUIScissors
* @private
*/
_bindUIScissors: function () {
if( this.get('editable') ) {
this._scissorsOverlay.get('boundingBox').on('click', this.destroyWires, this);
}
},
/**
* @method _renderScissors
* @private
*/
_renderScissors: function () {
this._scissorsOverlay = new Y.Overlay({});
this._scissorsOverlay.get('contentBox').addClass( this.getClassName("scissors") );
var refXY = this.get('xy'),
normed_dir = this.get('dirNormed'),
distance = this.get('scissorsDistance');
this._scissorsOverlay.set('x', refXY[0]+normed_dir[0]*distance-8);
this._scissorsOverlay.set('y', refXY[1]+normed_dir[1]*distance-8);
this._scissorsOverlay.render( this.get('boundingBox') );
}
};
}, '@VERSION@', {"requires": ["overlay"], "skinnable": true});
YUI.add('textarea-container', function (Y, NAME) {
/**
* @module textarea-container
*/
/**
* Form container for a single textarea field which is resizeable.
* You still need to specify the "fields".
* @class TextareaContainer
* @extends Container
* @constructor
* @param {Object} options Configuration object (see properties)
*/
Y.TextareaContainer = Y.Base.create("textarea-container", Y.Container, [], {
SERIALIZABLE_ATTRS: function() {
return Y.TextareaContainer.superclass.SERIALIZABLE_ATTRS.call(this).concat(['value']);
},
renderUI: function() {
Y.TextareaContainer.superclass.renderUI.call(this);
this.setStdModContent(Y.WidgetStdMod.BODY, "<textarea></textarea>");
this._bodyNode = this.getStdModNode(Y.WidgetStdMod.BODY);
this._textarea = this._bodyNode.one('textarea');
},
bindUI: function() {
Y.TextareaContainer.superclass.bindUI.call(this);
if(this.resize) {
this.resize.after('resize:resize', this._afterResizeTextarea, this);
}
},
_fillTextareaSize: function() {
this.fillHeight(this._bodyNode);
var region = this._bodyNode.get('region');
this._textarea.setStyle('height', region.height);
this._textarea.setStyle('width', region.width);
},
_afterResizeTextarea: function(e) {
this._fillTextareaSize();
},
syncUI: function() {
Y.TextareaContainer.superclass.syncUI.call(this);
this.getStdModNode(Y.WidgetStdMod.BODY).one('textarea').set( this.get('value') );
Y.later(0, this, function() {
this._fillTextareaSize();
});
}
}, {
ATTRS: {
/**
* Value of the textarea
* @attribute value
*/
value: {
getter: function () {
return this.getStdModNode(Y.WidgetStdMod.BODY).one('textarea').get('value');
},
setter: function (value) {
this.getStdModNode(Y.WidgetStdMod.BODY).one('textarea').set('value', value);
}
}
}
});
}, '@VERSION@', {"requires": ["container"]});
YUI.add('widget-icons', function (Y, NAME) {
/**
* @module widget-icons
*/
/**
* @class WidgetIcons
* @constructor
* @param {Object} config configuration object
*/
Y.WidgetIcons = function (config) {
Y.after(this._renderUIicons, this, "renderUI");
};
Y.WidgetIcons.ATTRS = {
/**
* Set of icons
* @attribute icons
*/
icons: {
value: []
}
};
Y.WidgetIcons.prototype = {
_renderUIicons: function () {
/*var p = this.get('contentBox'),
that = this;*/
Y.Array.each( this.get('icons'), Y.bind(this._renderUIicon, this));
},
_renderUIicon: function(icon) {
var i = Y.Node.create('<span class="yui3-widget-icons-icon '+this.getClassName('icon')+' '+icon.className+'" title="'+icon.title+'"></span>');
i.on('click', Y.bind(this[icon.click], this) );
i.appendTo( this.get('contentBox') );
}
};
}, '@VERSION@', {"requires": [], "skinnable": true});
YUI.add('wire-base', function (Y, NAME) {
/**
* @module wire-base
*/
/**
* The wire widget
* The wire is drawn between "src" and "tgt" (so they might be directional).
*
* "src" and "tgt" MUST have a "getXY" function
*
* "src" and "tgt" MAY additionnaly have the "addWire", "removeWire" methods.
* Those methods are designed to be used through the Y.WiringsDelegate extension,
* which provide basic list-handling on wires.
*
* @class WireBase
* @extends Path
* @param {Object} oConfigs The user configuration for the instance.
*/
Y.WireBase = function (config) {
Y.WireBase.superclass.constructor.apply(this, arguments);
};
Y.WireBase.NAME = "wirebase";
Y.extend(Y.WireBase, Y.Path, {
/**
* Notify the WiresDeletates through addWire
* @method initializer
*/
initializer: function () {
Y.WireBase.superclass.initializer.apply(this, arguments);
var src = this.get('src'), tgt = this.get('tgt');
if(src && src.get) {
this.set('srcDir', src.get('dir') );
}
if(tgt && tgt.get) {
this.set('tgtDir', tgt.get('dir') );
}
if(src && Y.Lang.isFunction (src.addWire) ) {
src.addWire(this);
}
if(tgt && Y.Lang.isFunction (tgt.addWire) ) {
tgt.addWire(this);
}
},
/**
* @method bindUI
*/
bindUI: function () {
Y.ArrowWire.superclass.bindUI.call(this);
//this.after("bezierTangentNormChange", this._afterChangeRedraw, this);
this.on('srcChange', function (e) {
this.set('srcDir', e.newVal.get('dir') );
}, this);
this.on('tgtChange', function (e) {
this.set('tgtDir', e.newVal.get('dir') );
}, this);
},
/**
* call removeWire on WiringsDelegate
* @method destroy
*/
destroy: function () {
Y.WireBase.superclass.destroy.apply(this, arguments);
var src = this.get('src'), tgt = this.get('tgt');
if(src && Y.Lang.isFunction (src.removeWire) ) {
src.removeWire(this);
}
if(tgt && Y.Lang.isFunction (tgt.removeWire) ) {
tgt.removeWire(this);
}
},
/**
* Drawing method. Meant to be overriden by a plugin
* @method _draw
* @private
*/
_draw: function () {
//throw new Error("Y.Wire has no draw method. Consider using a plugin such as 'bezier-wire' in your YUI.use statement");
},
getOtherTerminal: function (term) {
return (term === this.get('src')) ? this.get('tgt') : this.get('src');
},
// TODO:
//SERIALIZABLE_ATTRS: ["src","tgt"],
toJSON: function () {
return {};
}
});
Y.WireBase.ATTRS = Y.merge(Y.Path.ATTRS, {
/**
* @attribute src
*/
src: {
value: null,
setter: function (val) {
//console.log("src setter", val, this);
// remove this wire from the list of the previous src/tgt item
// TODO: prev value
/*if(e.prevVal && Y.Lang.isFunction (e.prevVal.removeWire) ) {
e.prevVal.removeWire(this);
}*/
if(val && Y.Lang.isFunction (val.addWire) ) {
val.addWire(this);
}
return val;
}
},
/**
* @attribute tgt
*/
tgt: {
value: null,
setter: function (val) {
//console.log("tgt setter", val, this);
// remove this wire from the list of the previous src/tgt item
// TODO: prev value
/*if(e.prevVal && Y.Lang.isFunction (e.prevVal.removeWire) ) {
e.prevVal.removeWire(this);
}*/
if(val && Y.Lang.isFunction (val.addWire) ) {
val.addWire(this);
}
return val;
}
},
/**
* @attribute srcDir
* @type Array
* @default [1,0]
*/
srcDir: {
validator: Y.Lang.isArray,
value: [1,0]
},
/**
* @attribute tgtDir
* @type Array
* @default -srcDir
*/
tgtDir: {
validator: Y.Lang.isArray,
valueFn: function () {
var d = this.get('srcDir');
return [-d[0],-d[1]];
}
}
});
}, '@VERSION@', {"requires": ["graphics"], "skinnable": true});
YUI.add('wireit-app', function (Y, NAME) {
// -- LocalStorageSync ---------------------------------------------------------------------
// Saves WiringModel
function LocalStorageSync(key) {
var localStorage;
if (!key) {
Y.error('No storage key specified.');
}
if (Y.config.win.localStorage) {
localStorage = Y.config.win.localStorage;
}
// Try to retrieve existing data from localStorage, if there is any.
// Otherwise, initialize `data` to an empty object.
var data = Y.JSON.parse((localStorage && localStorage.getItem(key)) || '{}');
// Delete a model with the specified id.
function destroy(id) {
var modelHash;
if ((modelHash = data[id])) {
delete data[id];
save();
}
return modelHash;
}
// Generate a unique id to assign to a newly-created model.
function generateId() {
var id = '',
i = 4;
while (i--) {
id += (((1 + Math.random()) * 0x10000) | 0)
.toString(16).substring(1);
}
return id;
}
// Loads a model with the specified id. This method is a little tricky,
// since it handles loading for both individual models and for an entire
// model list.
//
// If an id is specified, then it loads a single model. If no id is
// specified then it loads an array of all models. This allows the same sync
// layer to be used for both the TodoModel and TodoList classes.
function get(id) {
return id ? data[id] : Y.Object.values(data);
}
// Saves the entire `data` object to localStorage.
function save() {
localStorage && localStorage.setItem(key, Y.JSON.stringify(data));
}
// Sets the id attribute of the specified model (generating a new id if
// necessary), then saves it to localStorage.
function set(model) {
var hash = model.toJSON(),
idAttribute = model.idAttribute;
if (!Y.Lang.isValue(hash[idAttribute])) {
hash[idAttribute] = generateId();
}
data[hash[idAttribute]] = hash;
save();
return hash;
}
// Returns a `sync()` function that can be used with either a Model or a
// ModelList instance.
return function (action, options, callback) {
// `this` refers to the Model or ModelList instance to which this sync
// method is attached.
var isModel = Y.Model && this instanceof Y.Model;
switch (action) {
case 'create': // intentional fallthru
case 'update':
callback(null, set(this));
return;
case 'read':
callback(null, get(isModel && this.get('id')));
return;
case 'delete':
callback(null, destroy(isModel && this.get('id')));
return;
}
};
}
// -- WiringModel ---------------------------------------------------------------------
Y.WiringModel = Y.Base.create('wiringModel', Y.Model, [], {
sync: LocalStorageSync('wireit-app')
}, {
ATTRS: {
id: {value: null},
name : {value: ''},
containers : {value: []},
description: {value: ''},
wires : {value: []}
}
});
// -- WiringModelList ---------------------------------------------------------------------
Y.WiringModelList = Y.Base.create('wiringModelList', Y.ModelList, [], {
sync: LocalStorageSync('wireit-app'),
model : Y.WiringModel
});
Y.WiringListView = Y.Base.create('wiringListView', Y.View, [], {
template: Y.Handlebars.compile(Y.one('#t-wiring-list').getContent()),
/*initializer: function () {
},*/
render: function () {
var content = this.template({wirings: this.get('modelList').toJSON() });
this.get('container').setContent(content);
return this;
}
});
// -- ContainerType ---------------------------------------------------------------------
Y.ContainerType = Y.Base.create('containerModel', Y.Model, [], {
// The `id` attribute for this Model will be an alias for `name`.
idAttribute: 'name'
}, {
ATTRS: {
name : {value: null},
description: {value: null},
config : {value: null}
}
});
// -- ContainerTypeList -----------------------------------------------------------------
Y.ContainerTypeList = Y.Base.create('containerTypeList', Y.ModelList, [], {
model: Y.ContainerType
});
// -- Editor View ------------------------------------------------------------
Y.EditorView = Y.Base.create('editorView', Y.View, [], {
template: Y.Handlebars.compile(Y.one('#t-editor').getContent()),
events: {
'#wiring-save-btn': {click: 'saveWiring'}
},
render: function () {
var content = this.template({
containerTypes: this.get('containerTypes').toJSON()
});
this.get('container').setContent(content);
// Make items draggable to the layer
var that = this;
this.get('container').all('.containerType-name').each(function (node) {
var drag = new Y.DD.Drag({
node: node,
groups: ['containerType']
}).plug(Y.Plugin.DDProxy, {
cloneNode: true,
moveOnEnd: false
});
drag._containerTypeName = node._node.attributes["app-container-name"].value; //node._node.innerHTML;
// On drom, add it to the layer
drag.on('drag:drophit', function (ev) {
var p = that.layer.get('boundingBox').getXY();
that._addContainerFromName(ev.drag._containerTypeName, {
x: ev.drag.lastXY[0] - p[0],
y: ev.drag.lastXY[1] - p[1]
});
}, this);
});
this._renderLayer();
return this;
},
_renderLayer: function () {
this.layer = new Y.Layer({
height: 500
});
// Create the Drop object
var drop = new Y.DD.Drop({
node: this.layer.get('contentBox'),
groups: ['containerType']
});
this.layer.render( this.get('container').one('#layer-container') );
var wiring = this.get('model');
if(wiring) {
this.setWiring( wiring );
}
},
saveWiring: function (e) {
var o = {
name: Y.one('#wiring-name').get('value') || 'Unnamed'
};
// Children are containers
o.containers = [];
Y.Array.each(this.layer._items, function (item) {
o.containers.push({
containerType: item.containerTypeName,
config: item.toJSON()
});
});
// Wires:
o.wires = [];
var layer = this.layer;
Y.Array.each(this.layer._wires, function (wire) {
var src = wire.get('src');
var tgt = wire.get('tgt');
o.wires.push( {
src: { container: layer._items.indexOf( src.get('parent') ), terminal: src.get('name') },
tgt: { container: layer._items.indexOf( tgt.get('parent') ), terminal: tgt.get('name') },
config: wire.toJSON()
});
});
if( this.get('model') ) {
this.get('model').setAttrs(o);
}
else {
this.set('model', new Y.WiringModel(o) );
}
this.get('model').save();
// TODO: add only one message
var s = Y.Node.create('<div class="alert-message bg-warning" style="width: 300px; z-index: 10001;"><p>Saved !</p></div>').appendTo(document.body);
var anim = new Y.Anim({
node: s,
duration: 0.5,
easing: Y.Easing.easeOut,
from: { xy: [400, -50] },
to: { xy: [400, 2] }
});
anim.on('end', function () {
Y.later(1000, this, function () {
(new Y.Anim({
node: s,
duration: 0.5,
easing: Y.Easing.easeOut,
to: { xy: [400, -50] }
})).run();
});
});
anim.run();
},
setWiring: function (wiring) {
var that = this,
layer = this.layer;
Y.Array.each( wiring.get('containers'), function (container) {
that._addContainerFromName(container.containerType, container.config);
Y.on('available', function (el) {
Y.one('#wiring-name').set('value', wiring.get('name') );
}, '#wiring-name');
});
Y.Array.each( wiring.get('wires'), function (wire) {
// prevent bad configs...
if(!wire.src || !wire.tgt) return;
var srcContainer = layer.item(wire.src.container),
srcTerminal = srcContainer.getTerminal(wire.src.terminal),
tgtContainer = layer.item(wire.tgt.container),
tgtTerminal = tgtContainer.getTerminal(wire.tgt.terminal);
// TODO: wire.config;
var w = layer.graphic.addShape({
type: Y.BezierWire,
stroke: {
weight: 4,
color: "rgb(173,216,230)"
},
src: srcTerminal,
tgt: tgtTerminal
});
});
// TODO: this is awful ! But we need to wait for everything to render & position
Y.later(200, this, function () {
layer.redrawAllWires();
});
},
_addContainerFromName: function (containerTypeName, containerConfig) {
var containerType = this.get('containerTypes').getById(containerTypeName);
var containerConf = Y.mix({}, containerType.get('config'));
containerConf = Y.mix(containerConf, containerConfig);
this.layer.add(containerConf);
var container = this.layer.item(this.layer.size()-1);
container.containerTypeName = containerTypeName;
}
}, {
ATTRS: {
containerTypes: {
value: null
}
}
});
/**
* @module wireit-app
*/
// -- WireIt App ---------------------------------------------------------
Y.WireItApp = new Y.Base.create('contributorsApp', Y.App, [], {
views: {
editorPage: {
type: Y.EditorView
},
wiringListPage: {
type: Y.WiringListView
}
},
initializer: function () {
// show indication that the app is busy loading data.
this.on('navigate', this.indicateLoading);
this.once('ready', function (e) {
if (this.hasRoute(this.getPath())) {
this.dispatch();
} else {
this.showWiringListPage();
}
});
},
// -- Event Handlers -------------------------------------------------------
indicateLoading: function (e) {
this.get('activeView').get('container').addClass('loading');
},
// -- Route Handlers -------------------------------------------------------
handleWiring: function (req, res, next) {
var wiringId = req.params.wiring,
wirings = this.get('modelList'),
wiring = wirings.getById(wiringId);
this.set('wiring', wiring);
next();
},
showEditorPage: function () {
this.showView('editorPage', {
containerTypes: this.get('containerTypes'),
wirings: this.get('modelList'),
model: this.get('wiring')
});
},
blankEditorPage: function () {
this.showView('editorPage', {
containerTypes: this.get('containerTypes'),
wirings: this.get('modelList'),
model: null
});
},
showWiringListPage: function () {
//this.get('modelList').load();
var wirings = new Y.WiringModelList();
wirings.load();
this.set('modelList', wirings);
this.showView('wiringListPage', {
modelList: this.get('modelList')
});
}
}, {
ATTRS: {
containerTypes: {
value: new Y.ContainerTypeList()
},
modelList: {
value: new Y.WiringModelList()
},
wiring: {
value: null
},
routes: {
value: [
{path: '/', callback: 'showWiringListPage'},
{path: '/wirings/:wiring/*', callback: 'handleWiring'},
{path: '/wirings/:wiring/edit', callback: 'showEditorPage'},
{path: '/wirings/new', callback: 'blankEditorPage'}
]
}
}
});
}, '@VERSION@', {"requires": ["app", "handlebars", "model", "model-list", "json", "view", "layer", "bezier-wire", "anim"]});
YUI.add('wires-delegate', function (Y, NAME) {
/**
* @module wires-delegate
*/
/**
* WiresDelegate is an extension for Widgets to manipulate a list of wires.
*
* The WidgetParent/WidgetChild relationship isn't sufficient
* because wires have 2 parents, so we use this extension instead of WidgetParent
*
* @class WiresDelegate
* @constructor
* @param {Object} config configuration object
*/
Y.WiresDelegate = function () {
this._wires = [];
this.publish('addWire');
this.publish('removeWire');
// Bubble events from terminals
this.on('*:addWire', this._onAddWire, this);
this.on('*:removeWire', this._onRemoveWire, this);
};
Y.WiresDelegate.ATTRS = {};
Y.WiresDelegate.prototype = {
_wireFromEvent: function(e) {
var w = e;
while(!!w._event) { w = w.details[0]; }
return w;
},
_onAddWire: function (e) {
this.addWire( this._wireFromEvent(e) );
},
_onRemoveWire: function (e) {
this.removeWire( this._wireFromEvent(e) );
},
/**
* Add a wire to this terminal.
* @method addWire
* @param {Wire} wire Wire instance to add
*/
addWire: function (wire) {
var index = Y.Array.indexOf(this._wires, wire);
if(index === -1) {
this._wires.push(wire);
this.fire('addWire', wire);
}
},
/**
* When a wire is destroyed
* @method removeWire
*/
removeWire: function (wire) {
var index = Y.Array.indexOf(this._wires, wire),
w, v;
if( index !== -1 ) {
// Compact the array
w = this._wires;
this._wires = [];
v = this._wires;
Y.Array.each(w,function (i) { if(i !== wire){ v.push(i); } });
// Fire the event
this.fire('removeWire', wire);
}
},
/**
* Remove all wires
* @method destroyWires
*/
destroyWires: function () {
if(this._wires) {
Y.Array.each(this._wires, function (w) {
w.destroy();
});
}
},
/**
* Returns a list of all the terminals connected to this terminal through its wires.
* @method getConnected
* @return {Array} List of all connected terminals
*/
getConnected: function () {
var list = [], i, n;
if(this._wires) {
for(i = 0, n = this._wires.length ; i < n ; i++) {
list.push(this._wires[i].getOtherTerminal(this));
}
}
return list;
},
/**
* Redraw all the wires connected to this terminal
* @method redrawAllWires
*/
redrawAllWires: function () {
if(this._wires) {
Y.Array.each(this._wires, function (w) {
w._draw();
});
}
},
destructor: function () {
this.destroyWires();
}
};
}, '@VERSION@', {"requires": ["wire-base"]});
YUI.add('wireit-all', function (Y, NAME) {}, '@VERSION@');