/**
* The Diagram Builder Component
*
* @module aui-diagram-builder
*/
var Lang = A.Lang,
isBoolean = Lang.isBoolean,
isObject = Lang.isObject,
isString = Lang.isString,
AArray = A.Array,
aGetClassName = A.getClassName,
CSS_PROPERTY_BUILDER_FIELD = aGetClassName('property', 'builder', 'field'),
CSS_DIAGRAM_NODE = aGetClassName('diagram', 'node'),
CSS_DIAGRAM_NODE_CONTENT = aGetClassName('diagram', 'node', 'content'),
CSS_DIAGRAM_NODE_EDITING = aGetClassName('diagram', 'node', 'editing'),
CSS_DIAGRAM_SUGGEST_CONNECTOR = aGetClassName('diagram', 'node', 'suggest', 'connector'),
isConnector = function(val) {
return A.instanceOf(val, A.Connector);
},
isDiagramNode = function(val) {
return A.instanceOf(val, A.DiagramNode);
};
/**
* A base class for Diagram Builder.
*
* Check the [live demo](http://alloyui.com/examples/diagram-builder/).
*
* @class A.DiagramBuilder
* @extends A.PropertyBuilder
* @param {Object} config Object literal specifying widget configuration
* properties.
* @constructor
* @example
```
<div id="diagram-builder-bb">
<div id="diagram-builder-sn"></div>
</div>
```
* @example
```
YUI().use(
'aui-diagram-builder',
function(Y) {
var availableFields = [
{
iconClass: 'diagram-node-task-icon',
label: 'Task',
type: 'task'
}
];
var diagramBuilder = new Y.DiagramBuilder (
{
availableFields: availableFields,
boundingBox: '#diagram-builder-bb',
fields: [
{
name: 'StartNode',
type: 'start',
xy: [10, 10]
},
{
name: 'EndNode',
type: 'end',
xy: [300, 400]
}
],
render: true,
srcNode: '#diagram-builder-sn'
}
);
diagramBuilder.connectAll(
[
{
connector: {
name: 'TaskConnector'
},
source: 'StartNode',
target: 'EndNode'
}
]
);
}
);
```
*/
var DiagramBuilder = A.Component.create({
/**
* Static property provides a string to identify the class.
*
* @property NAME
* @type String
* @static
*/
NAME: 'diagram-builder',
/**
* Static property used to define the default attribute
* configuration for the `A.DiagramBuilder`.
*
* @property ATTRS
* @type Object
* @static
*/
ATTRS: {
/**
* Stores an instance of `A.Connector`.
*
* @attribute connector
* @default null
*/
connector: {
setter: '_setConnector',
value: null
},
/**
* Configuration object for draggable fields.
*
* @attribute fieldsDragConfig
* @default null
* @type Object
*/
fieldsDragConfig: {
value: null,
setter: '_setFieldsDragConfig',
validator: isObject
},
/**
* Stores an instance of `A.Graphic`.
*
* @attribute graphic
* @type Object
*/
graphic: {
valueFn: function() {
return new A.Graphic();
},
validator: isObject
},
/**
* Checks if the drop zones should be highlighted or not.
*
* @attribute highlightDropZones
* @default true
* @type Boolean
*/
highlightDropZones: {
validator: isBoolean,
value: true
},
/**
* Collection of strings used to label elements of the UI.
*
* @attribute strings
* @type Object
*/
strings: {
value: {
addNode: 'Add node',
cancel: 'Cancel',
close: 'Close',
deleteConnectorsMessage: 'Are you sure you want to delete the selected connector(s)?',
deleteNodesMessage: 'Are you sure you want to delete the selected node(s)?',
propertyName: 'Property Name',
save: 'Save',
settings: 'Settings',
value: 'Value'
}
},
/**
* Checks if a connector suggestion is visible or not.
*
* @attribute showSuggestConnector
* @default true
* @type Boolean
*/
showSuggestConnector: {
validator: isBoolean,
value: true
},
/**
* Stores an instance of `A.Overlay` used in the connector suggestion.
*
* @attribute suggestConnectorOverlay
* @default null
*/
suggestConnectorOverlay: {
value: null,
setter: '_setSuggestConnectorOverlay'
},
/**
* Boolean indicating if use of the WAI-ARIA Roles and States should be enabled..
*
* @attribute useARIA
* @default true
* @type {Boolean}
*/
useARIA: {
validator: isBoolean,
value: true,
writeOnce: 'initOnly'
}
},
/**
* Static property used to define the augmented classes.
*
* @property AUGMENTS
* @type Array
* @static
*/
AUGMENTS: [A.PropertyBuilderSettings],
/**
* Static property used to define which component it extends.
*
* @property EXTENDS
* @type String
* @static
*/
EXTENDS: A.PropertyBuilder,
/**
* The index of the fields tab.
*
* @property FIELDS_TAB
* @default 0
* @type Number
* @static
*/
FIELDS_TAB: 0,
/**
* The index of the settings tab.
*
* @property SETTINGS_TAB
* @default 1
* @type Number
* @static
*/
SETTINGS_TAB: 1,
prototype: {
editingConnector: null,
editingNode: null,
publishedSource: null,
publishedTarget: null,
selectedConnector: null,
selectedNode: null,
/**
* Construction logic executed during `A.DiagramBuilder` instantiation.
* Lifecycle.
*
* @method initializer
* @protected
*/
initializer: function() {
var instance = this,
canvas = instance.get('canvas');
instance.on({
cancel: instance._onCancel,
'drag:drag': instance._onDrag,
'drag:end': instance._onDragEnd,
'drop:hit': instance._onDropHit,
save: instance._onSave
});
A.DiagramNodeManager.on({
publishedSource: function(event) {
instance.publishedTarget = null;
instance.publishedSource = event.publishedSource;
}
});
canvas.on('mousedown', A.bind(instance._onCanvasMouseDown, instance));
canvas.on('mouseenter', A.bind(instance._onCanvasMouseEnter, instance));
instance.handlerKeyDown = A.getDoc().on('keydown', A.bind(instance._afterKeyEvent, instance));
instance.dropContainer.delegate(
'click', A.bind(instance._onNodeClick, instance), '.' + CSS_DIAGRAM_NODE);
instance.dropContainer.delegate(
'mousedown', A.bind(instance._onCloseButtonMouseDown, instance),
'.diagram-builder-controls button'
);
instance.dropContainer.delegate(
'mouseenter', A.bind(instance._onNodeMouseEnter, instance), '.' + CSS_DIAGRAM_NODE);
instance.dropContainer.delegate(
'mouseleave', A.bind(instance._onNodeMouseLeave, instance), '.' + CSS_DIAGRAM_NODE);
},
/**
* Render the `A.DiagramBuilder` component instance. Lifecycle.
*
* @method renderUI
* @protected
*/
renderUI: function() {
var instance = this;
A.DiagramBuilder.superclass.renderUI.apply(this, arguments);
instance._setupFieldsDrag();
instance._renderGraphic();
},
/**
* Sync the `A.DiagramBuilder` UI. Lifecycle.
*
* @method syncUI
* @protected
*/
syncUI: function() {
var instance = this;
A.DiagramBuilder.superclass.syncUI.apply(this, arguments);
instance.syncConnectionsUI();
instance.connector = instance.get('connector');
if (instance.get('useARIA')) {
instance.plug(A.Plugin.Aria);
}
},
/**
* Syncs the connections in the UI.
*
* @method syncConnectionsUI
*/
syncConnectionsUI: function() {
var instance = this;
instance.get('fields').each(function(diagramNode) {
diagramNode.syncConnectionsUI();
});
},
/**
* Fetches all fields and destroys each instance of it.
*
* @method clearFields
*/
clearFields: function() {
var instance = this;
var fields = [];
instance.get('fields').each(function(diagramNode) {
fields.push(diagramNode);
});
AArray.each(fields, function(diagramNode) {
diagramNode.destroy();
});
fields = instance.editingConnector = instance.editingNode = instance.selectedNode = null;
},
/**
* Disables the settings tab and selects the field tab.
*
* @method closeEditProperties
*/
closeEditProperties: function() {
var instance = this;
var editingNode = instance.editingNode;
var tabView = instance.tabView;
tabView.selectChild(A.DiagramBuilder.FIELDS_TAB);
tabView.disableTab(A.DiagramBuilder.SETTINGS_TAB);
if (editingNode) {
editingNode.get('boundingBox').removeClass(CSS_DIAGRAM_NODE_EDITING);
}
instance.editingConnector = instance.editingNode = null;
},
/**
* Gets two `A.DiagramNode` instances and connect them.
*
* @method connect
* @param diagramNode1
* @param diagramNode2
* @param optConnector
*/
connect: function(diagramNode1, diagramNode2, optConnector) {
var instance = this;
if (isString(diagramNode1)) {
diagramNode1 = A.DiagramNode.getNodeByName(diagramNode1);
}
if (isString(diagramNode2)) {
diagramNode2 = A.DiagramNode.getNodeByName(diagramNode2);
}
if (diagramNode1 && diagramNode2) {
diagramNode1.connect(diagramNode2.get('name'), optConnector);
}
return instance;
},
/**
* Creates a connector for each node that has source and target
* properties.
*
* @method connectAll
* @param nodes
*/
connectAll: function(nodes) {
var instance = this;
AArray.each(nodes, function(node) {
if (node.hasOwnProperty('source') && node.hasOwnProperty('target')) {
instance.connect(node.source, node.target, node.connector);
}
});
return instance;
},
/**
* Creates a new field based on the field class type.
*
* @method createField
* @param val
*/
createField: function(val) {
var instance = this;
if (!isDiagramNode(val)) {
val.builder = instance;
val.bubbleTargets = instance;
val = new(instance.getFieldClass(val.type || 'node'))(val);
}
return val;
},
/**
* Fetches all selected connectors and disconnect them.
*
* @method deleteSelectedConnectors
*/
deleteSelectedConnectors: function() {
var instance = this;
var strings = instance.getStrings();
var selectedConnectors = instance.getSelectedConnectors();
if (selectedConnectors.length && window.confirm(strings.deleteConnectorsMessage)) {
AArray.each(selectedConnectors, function(connector) {
var transition = connector.get('transition');
A.DiagramNode.getNodeByName(transition.source).disconnect(transition);
});
instance.stopEditing();
}
},
/**
* Fetches the selected node and delete it.
*
* @method deleteSelectedNode
*/
deleteSelectedNode: function() {
var instance = this;
var strings = instance.getStrings();
var selectedNode = instance.selectedNode;
if (selectedNode && !selectedNode.get('required') && window.confirm(strings.deleteNodesMessage)) {
selectedNode.close();
instance.editingNode = instance.selectedNode = null;
instance.stopEditing();
}
},
/**
* Destructor lifecycle implementation for the `A.DiagramBuilder` class.
*
* @method destructor
* @param attribute
* @protected
*/
destructor: function() {
var instance = this;
instance.get('suggestConnectorOverlay').destroy();
},
/**
* An utility function to loop through all connectors.
*
* @method eachConnector
* @param fn
*/
eachConnector: function(fn) {
var instance = this;
instance.get('fields').each(function(diagramNode) {
var transitions = diagramNode.get('transitions');
AArray.each(transitions.values(), function(transition) {
fn.call(instance, diagramNode.getConnector(transition), transition, diagramNode);
});
});
},
/**
* Enables the settings tab, sets the connector properties in the
* property list, and stores the connector in the `editingConnector` and
* `selectedConnector` attributes.
*
* @method editConnector
* @param connector
*/
editConnector: function(connector) {
var instance = this;
if (connector) {
var tabView = instance.tabView;
instance.closeEditProperties();
tabView.enableTab(A.DiagramBuilder.SETTINGS_TAB);
tabView.selectChild(A.DiagramBuilder.SETTINGS_TAB);
instance.propertyList.set('data', connector.getProperties());
instance.editingConnector = instance.selectedConnector = connector;
}
},
/**
* Enables the settings tab, sets the node properties in the property
* list, and stores the node in the `editingNode` and `selectedNode`
* attributes.
*
* @method editNode
* @param diagramNode
*/
editNode: function(diagramNode) {
var instance = this;
if (diagramNode) {
var tabView = instance.tabView;
instance.closeEditProperties();
tabView.enableTab(A.DiagramBuilder.SETTINGS_TAB);
tabView.selectChild(A.DiagramBuilder.SETTINGS_TAB);
instance.propertyList.set('data', diagramNode.getProperties());
diagramNode.get('boundingBox').addClass(CSS_DIAGRAM_NODE_EDITING);
instance.editingNode = instance.selectedNode = diagramNode;
}
},
/**
* Gets the field class based on the `A.DiagramBuilder` type. If the type
* doesn't exist, logs an error message.
*
* @method getFieldClass
* @param type
*/
getFieldClass: function(type) {
var clazz = A.DiagramBuilder.types[type];
if (clazz) {
return clazz;
}
else {
A.log('The field type: [' + type + '] couldn\'t be found.');
return null;
}
},
/**
* Returns a collection of nodes by its transition property.
*
* @method getNodesByTransitionProperty
* @param property
* @param value
*/
getNodesByTransitionProperty: function(property, value) {
var instance = this,
nodes = [],
transitions;
instance.get('fields').each(function(diagramNode) {
transitions = diagramNode.get('transitions');
AArray.each(transitions.values(), function(transition) {
if (transition[property] === value) {
nodes.push(diagramNode);
return false;
}
});
});
return nodes;
},
/**
* Returns a collection of selected connectors.
*
* @method getSelectedConnectors
*/
getSelectedConnectors: function() {
var instance = this;
var selected = [];
instance.eachConnector(function(connector) {
if (connector.get('selected')) {
selected.push(connector);
}
});
return selected;
},
/**
* Returns a collection of source nodes.
*
* @method getSourceNodes
* @param diagramNode
*/
getSourceNodes: function(diagramNode) {
var instance = this;
return instance.getNodesByTransitionProperty('target', diagramNode.get('name'));
},
/**
* Hides the suggest connector overlay.
*
* @method hideSuggestConnectorOverlay
* @param diagramNode
* @param drag
*/
hideSuggestConnectorOverlay: function() {
var instance = this;
instance.connector.hide();
instance.get('suggestConnectorOverlay').hide();
try {
instance.fieldsDrag.dd.set('lock', false);
}
catch (e) {}
},
/**
* Checks if a node is able to connect with another.
*
* @method isAbleToConnect
*/
isAbleToConnect: function() {
var instance = this;
return !!(instance.publishedSource && instance.publishedTarget);
},
/**
* Checks if the field is draggable.
*
* @method isFieldsDrag
* @param drag
*/
isFieldsDrag: function(drag) {
var instance = this;
return (drag === instance.fieldsDrag.dd);
},
/**
* Renders a field in the `dropContainer`.
*
* @method plotField
* @param field
*/
plotField: function(field) {
var instance = this;
if (!field.get('rendered')) {
field.render(instance.dropContainer);
}
},
/**
* Selects and focus a certain node.
*
* @method select
* @param diagramNode
*/
select: function(diagramNode) {
var instance = this;
instance.unselectNodes();
instance.selectedNode = diagramNode.set('selected', true).focus();
},
/**
* Shows the suggest connector overlay in a certain X and Y position.
*
* @method showSuggestConnectorOverlay
* @param xy
*/
showSuggestConnectorOverlay: function(xy) {
var instance = this,
showSuggestConnectorOverlay = instance.get('suggestConnectorOverlay');
showSuggestConnectorOverlay.get('boundingBox').addClass(CSS_DIAGRAM_SUGGEST_CONNECTOR);
showSuggestConnectorOverlay.set(
'xy', xy || instance.connector.get('p2')).show();
try {
instance.fieldsDrag.dd.set('lock', true);
}
catch (e) {}
},
/**
* Clears node/connectors selections and close edit properties.
*
* @method stopEditing
*/
stopEditing: function() {
var instance = this;
instance.unselectConnectors();
instance.unselectNodes();
instance.closeEditProperties();
},
/**
* Converts fields to JSON format.
*
* @method toJSON
* @return {Object}
*/
toJSON: function() {
var instance = this;
var output = {
nodes: []
};
instance.get('fields').each(function(diagramNode) {
var node = {
transitions: []
},
transitions = diagramNode.get('transitions');
// serialize node attributes
AArray.each(diagramNode.SERIALIZABLE_ATTRS, function(attributeName) {
node[attributeName] = diagramNode.get(attributeName);
});
// serialize node transitions
AArray.each(transitions.values(), function(transition) {
var connector = diagramNode.getConnector(transition);
transition.connector = connector.toJSON();
node.transitions.push(transition);
});
output.nodes.push(node);
});
return output;
},
/**
* Clears connectors selection.
*
* @method unselectConnectors
*/
unselectConnectors: function() {
var instance = this;
AArray.each(instance.getSelectedConnectors(), function(connector) {
connector.set('selected', false);
});
},
/**
* Clears nodes selection.
*
* @method unselectNodes
*/
unselectNodes: function() {
var instance = this;
var selectedNode = instance.selectedNode;
if (selectedNode) {
selectedNode.set('selected', false);
}
instance.selectedNode = null;
},
/**
* Fires after a key event is dispatched.
*
* @method _afterKeyEvent
* @param event
* @protected
*/
_afterKeyEvent: function(event) {
var instance = this;
if (event.hasModifier() || A.getDoc().get('activeElement').test(':input,td')) {
return;
}
if (event.isKey('esc')) {
instance._onEscKey(event);
}
else if (event.isKey('backspace') || event.isKey('delete')) {
instance._onDeleteKey(event);
}
},
/**
* Deletes the Selected `diagramNode` and any connectors attached to it.
*
* @method _deleteSelectedNode
* @param event {Event.Facade} Event Facade object
* @protected
*/
_deleteSelectedNode: function(event) {
var instance = this;
instance.deleteSelectedConnectors();
instance.deleteSelectedNode();
event.halt();
},
/**
* Fires on cancel event.
*
* @method _onCancel
* @param event
* @protected
*/
_onCancel: function() {
var instance = this;
instance.closeEditProperties();
},
/**
* Sync UI after entering mouse in the canvas node.
*
* @method _onCanvasMouseEnter
* @param event
* @protected
*/
_onCanvasMouseEnter: function() {
var instance = this;
instance.syncUI();
},
/**
* Handles `mousedown` events on the diagram close button.
*
* @method _onCloseButtonMouseDown
* @param event
* @protected
*/
_onCloseButtonMouseDown: function(event) {
var instance = this;
var diagramNode = event.currentTarget.ancestor('.' + 'diagram-node');
if (isDiagramNode(A.Widget.getByNode(diagramNode))) {
instance._deleteSelectedNode(event);
}
},
/**
* Fires when delete key is pressed.
*
* @method _onDeleteKey
* @param event
* @protected
*/
_onDeleteKey: function(event) {
var instance = this,
selectedConnectors = instance.getSelectedConnectors();
if (isDiagramNode(A.Widget.getByNode(event.target))) {
instance._deleteSelectedNode(event);
}
else if (selectedConnectors.length > 0) {
instance.deleteSelectedConnectors();
event.halt();
}
},
/**
* Triggers when the drag occurs.
*
* @method _onDrag
* @param event
* @protected
*/
_onDrag: function(event) {
var instance = this;
var drag = event.target;
if (instance.isFieldsDrag(drag)) {
var diagramNode = A.Widget.getByNode(drag.get('dragNode'));
if (diagramNode) {
diagramNode.alignTransitions();
AArray.each(instance.getSourceNodes(diagramNode), function(sourceNode) {
sourceNode.alignTransitions();
});
if (instance.get('useARIA')) {
instance.aria.setAttributes(
[
{
name: 'grabbed',
node: diagramNode.get('boundingBox'),
value: 'true'
},
{
name: 'dropeffect',
node: instance.get('canvas'),
value: 'move'
}
]
);
}
}
}
},
/**
* Triggers when the drag ends.
*
* @method _onDragEnd
* @param event
* @protected
*/
_onDragEnd: function(event) {
var instance = this;
var drag = event.target;
var diagramNode = A.Widget.getByNode(drag.get('dragNode'));
if (diagramNode && instance.isFieldsDrag(drag)) {
diagramNode.set('xy', diagramNode.getNodeCoordinates());
if (instance.get('useARIA')) {
instance.aria.setAttributes(
[
{
name: 'grabbed',
node: diagramNode.get('boundingBox'),
value: 'false'
},
{
name: 'dropeffect',
node: instance.get('canvas'),
value: 'none'
}
]
);
}
}
},
/**
* Triggers when drop is hit.
*
* @method _onDropHit
* @param event
* @protected
*/
_onDropHit: function(event) {
var instance = this;
var drag = event.drag;
if (instance.isAvailableFieldsDrag(drag)) {
var availableField = drag.get('node').getData('availableField');
var newField = instance.addField({
xy: A.DiagramNode.getNodeCoordinates(drag.lastXY, instance.dropContainer),
type: availableField.get('type')
});
instance.select(newField);
}
},
/**
* Fires when the esc key is pressed.
*
* @method _onEscKey
* @param event
* @protected
*/
_onEscKey: function(event) {
var instance = this;
instance.hideSuggestConnectorOverlay();
instance.stopEditing();
event.halt();
},
/**
* Stops editing after mouse down in the canvas node.
*
* @method _onCanvasMouseDown
* @param event
* @protected
*/
_onCanvasMouseDown: function() {
var instance = this;
instance.stopEditing();
instance.hideSuggestConnectorOverlay();
},
/**
* Fires when the node gets clicked.
*
* @method _onNodeClick
* @param event
* @protected
*/
_onNodeClick: function(event) {
var instance = this;
var diagramNode = A.Widget.getByNode(event.currentTarget);
instance.select(diagramNode);
instance._onNodeEdit(event);
event.stopPropagation();
},
/**
* Fires when the node is edited.
*
* @method _onNodeEdit
* @param event
* @protected
*/
_onNodeEdit: function(event) {
var instance = this;
// Only enable editing if the double clicked node is inside the node
// contentBox.
if (!event.target.ancestor('.' + CSS_DIAGRAM_NODE_CONTENT, true)) {
return;
}
var diagramNode = A.Widget.getByNode(event.currentTarget);
if (diagramNode) {
instance.editNode(diagramNode);
}
},
/**
* Fires when mouse enters the node.
*
* @method _onNodeMouseEnter
* @param event
* @protected
*/
_onNodeMouseEnter: function(event) {
var diagramNode = A.Widget.getByNode(event.currentTarget);
diagramNode.set('highlighted', true);
},
/**
* Fires when mouse leaves the node.
*
* @method _onNodeMouseLeave
* @param event
* @protected
*/
_onNodeMouseLeave: function(event) {
var instance = this;
var publishedSource = instance.publishedSource;
var diagramNode = A.Widget.getByNode(event.currentTarget);
if (!publishedSource || !publishedSource.boundaryDragDelegate.dd.get('dragging')) {
diagramNode.set('highlighted', false);
}
},
/**
* Handles save event for editing node and connector.
*
* @method _onSave
* @param event
* @protected
*/
_onSave: function() {
var instance = this;
var editingNode = instance.editingNode;
var editingConnector = instance.editingConnector;
var modelList = instance.propertyList.get('data');
if (editingNode) {
modelList.each(function(model) {
editingNode.set(model.get('attributeName'), model.get('value'));
});
}
else if (editingConnector) {
modelList.each(function(model) {
editingConnector.set(model.get('attributeName'), model.get('value'));
});
}
},
/**
* Fires when suggest connector node is clicked.
*
* @method _onSuggestConnectorNodeClick
* @param event
* @protected
*/
_onSuggestConnectorNodeClick: function(event) {
var instance = this;
var availableField = event.currentTarget.getData('availableField');
var connector = instance.connector;
var node = instance.addField({
type: availableField.get('type'),
xy: connector.toCoordinate(connector.get('p2'))
});
instance.hideSuggestConnectorOverlay();
instance.publishedSource.connectNode(node);
},
/**
* Renders the `graphic` attribute.
*
* @method _renderGraphic
* @protected
*/
_renderGraphic: function() {
var instance = this;
instance.get('graphic').render(instance.dropContainer);
},
/**
* Set the `connector` attribute.
*
* @method _setConnector
* @param val
* @protected
*/
_setConnector: function(val) {
var instance = this;
if (!isConnector(val)) {
var xy = instance.get('canvas').getXY();
val = new A.Connector(
A.merge({
builder: instance,
graphic: instance.get('graphic'),
lazyDraw: true,
p1: xy,
p2: xy,
shapeHover: null,
showName: false
},
val
)
);
}
return val;
},
/**
* Set the `fieldsDragConfig` attribute.
*
* @method _setFieldsDragConfig
* @param val
* @protected
*/
_setFieldsDragConfig: function(val) {
var instance = this;
var dropContainer = instance.dropContainer;
return A.merge({
bubbleTargets: instance,
container: dropContainer,
dragConfig: {
plugins: [
{
cfg: {
constrain: dropContainer
},
fn: A.Plugin.DDConstrained
},
{
cfg: {
scrollDelay: 150,
node: dropContainer
},
fn: A.Plugin.DDNodeScroll
}
]
},
nodes: '.' + CSS_DIAGRAM_NODE
},
val || {}
);
},
/**
* Set the `suggestConnectorOverlay` attribute.
*
* @method _setSuggestConnectorOverlay
* @param val
* @protected
*/
_setSuggestConnectorOverlay: function(val) {
var instance = this;
if (!val) {
var docFrag = A.getDoc().invoke('createDocumentFragment'),
boundingBox,
contentBox;
AArray.each(instance.get('availableFields'), function(field) {
var node = field.get('node');
docFrag.appendChild(
node.clone().setData('availableField', node.getData('availableField'))
);
});
val = new A.Overlay({
bodyContent: docFrag,
render: true,
visible: false,
width: 280,
zIndex: 10000
});
boundingBox = val.get('boundingBox');
contentBox = val.get('contentBox');
contentBox.addClass('popover-content');
boundingBox.addClass('popover');
boundingBox.delegate('click', A.bind(instance._onSuggestConnectorNodeClick, instance), '.' +
CSS_PROPERTY_BUILDER_FIELD);
}
return val;
},
/**
* Creates a new instance of `A.DD.Delegate` in `fieldsDrag` attribute.
*
* @method _setupFieldsDrag
* @protected
*/
_setupFieldsDrag: function() {
var instance = this;
var fields = instance.get('fields');
var fieldsDragConfig = instance.get('fieldsDragConfig');
var useARIA = instance.get('useARIA');
instance.fieldsDrag = new A.DD.Delegate(
fieldsDragConfig
);
if (useARIA) {
fields.each(
function(diagramNode) {
var boundingBox = diagramNode.get('boundingBox');
boundingBox.attr('draggable', true);
}
);
}
}
}
});
A.DiagramBuilder = DiagramBuilder;
A.namespace('DiagramBuilder.types').node = A.DiagramNode;
A.namespace('DiagramBuilder.types').state = A.DiagramNodeState;
A.namespace('DiagramBuilder.types').condition = A.DiagramNodeCondition;
A.namespace('DiagramBuilder.types').start = A.DiagramNodeStart;
A.namespace('DiagramBuilder.types').end = A.DiagramNodeEnd;
A.namespace('DiagramBuilder.types').join = A.DiagramNodeJoin;
A.namespace('DiagramBuilder.types').fork = A.DiagramNodeFork;
A.namespace('DiagramBuilder.types').task = A.DiagramNodeTask;