/**
* The Property Builder
*
* @module aui-property-builder
*/
var Lang = A.Lang,
isArray = Lang.isArray,
isNumber = Lang.isNumber,
isObject = Lang.isObject,
isAvailableField = function(val) {
return A.instanceOf(val, A.PropertyBuilderAvailableField);
},
AArray = A.Array,
aGetClassName = A.getClassName,
CSS_CLEARFIX = aGetClassName('clearfix'),
CSS_PROPERTY_BUILDER_CANVAS = aGetClassName('property', 'builder', 'canvas'),
CSS_PROPERTY_BUILDER_CONTENT_CONTAINER = aGetClassName('property', 'builder', 'content', 'container'),
CSS_PROPERTY_BUILDER_DROP_CONTAINER = aGetClassName('property', 'builder', 'drop', 'container'),
CSS_PROPERTY_BUILDER_FIELD_DRAGGABLE = A.getClassName('property', 'builder', 'field', 'draggable'),
CSS_PROPERTY_BUILDER_FIELDS_CONTAINER = aGetClassName('property', 'builder', 'fields', 'container'),
CSS_LAYOUT = aGetClassName('layout');
/**
* A base class for PropertyBuilder.
*
* @class A.PropertyBuilder
* @extends A.Component
* @uses A.PropertyBuilderFieldSupport
* @param {Object} config Object literal specifying widget configuration
* properties.
* @constructor
*/
var PropertyBuilder = A.Component.create({
/**
* Static property provides a string to identify the class.
*
* @property NAME
* @type String
* @static
*/
NAME: 'property-builder',
/**
* Static property used to define the default attribute
* configuration for the `A.PropertyBuilder`.
*
* @property ATTRS
* @type Object
* @static
*/
ATTRS: {
/**
* List of available fields.
*
* @attribute availableFields
* @type Array
*/
availableFields: {
setter: '_setAvailableFields',
validator: isArray
},
/**
* The configuration object for draggable available fields.
*
* @attribute availableFieldsDragConfig
* @default null
* @type Object
*/
availableFieldsDragConfig: {
value: null,
setter: '_setAvailableFieldsDragConfig',
validator: isObject
},
/**
* A node created using the `CANVAS_TEMPLATE` template.
*
* @attribute canvas
*/
canvas: {
valueFn: function() {
return A.Node.create(this.CANVAS_TEMPLATE);
}
},
/**
* The configuration object for drop container node.
*
* @attribute dropConfig
* @default null
* @type Object
*/
dropConfig: {
value: null,
setter: '_setDropConfig',
validator: isObject
},
/**
* Host node for content created using the `CONTENT_CONTAINER_TEMPLATE`
* template.
*
* @attribute contentContainer
*/
contentContainer: {
valueFn: function() {
return A.Node.create(this.CONTENT_CONTAINER_TEMPLATE);
}
},
/**
* Host node for drop created using the `DROP_CONTAINER_TEMPLATE`
* template.
*
* @attribute dropContainer
*/
dropContainer: {
valueFn: function() {
return A.Node.create(this.DROP_CONTAINER_TEMPLATE);
}
},
/**
* Host node for fields created using the `FIELDS_CONTAINER_TEMPLATE`
* template.
*
* @attribute fieldsContainer
*/
fieldsContainer: {
valueFn: function() {
return A.Node.create(this.FIELDS_CONTAINER_TEMPLATE);
}
}
},
/**
* Object hash, defining how attribute values have to be parsed from markup.
*
* @property HTML_PARSER
* @type Object
* @static
*/
HTML_PARSER: {
contentContainer: '.' + CSS_PROPERTY_BUILDER_CONTENT_CONTAINER,
dropContainer: '.' + CSS_PROPERTY_BUILDER_DROP_CONTAINER,
fieldsContainer: '.' + CSS_PROPERTY_BUILDER_FIELDS_CONTAINER,
canvas: '.' + CSS_PROPERTY_BUILDER_CANVAS
},
/**
* Static property used to define the UI attributes.
*
* @property UI_ATTRS
* @type Array
* @static
*/
UI_ATTRS: ['availableFields', 'fields'],
/**
* Static property used to define the augmented classes.
*
* @property AUGMENTS
* @type Array
* @static
*/
AUGMENTS: [A.PropertyBuilderFieldSupport, A.PropertyBuilderSettings],
prototype: {
CANVAS_TEMPLATE: '<div tabindex="1" class="' + CSS_PROPERTY_BUILDER_CANVAS + '"></div>',
CONTENT_CONTAINER_TEMPLATE: '<div class="' + CSS_PROPERTY_BUILDER_CONTENT_CONTAINER + '"></div>',
DROP_CONTAINER_TEMPLATE: '<div class="' + CSS_PROPERTY_BUILDER_DROP_CONTAINER + '"></div>',
FIELDS_CONTAINER_TEMPLATE: '<ul class="' + [CSS_PROPERTY_BUILDER_FIELDS_CONTAINER, CSS_CLEARFIX].join(' ') +
'"></ul>',
fieldsNode: null,
settingsNode: null,
/**
* Construction logic executed during `A.PropertyBuilder`
* instantiation. Lifecycle.
*
* @method initializer
* @protected
*/
initializer: function() {
var instance = this;
this.publish('render');
instance.after({
render: instance._afterRender,
'model:change': instance._afterModelChange
});
instance.after(instance._afterUiSetHeight, instance, '_uiSetHeight');
instance.canvas = instance.get('canvas');
instance.contentContainer = instance.get('contentContainer');
instance.dropContainer = instance.get('dropContainer');
instance.fieldsContainer = instance.get('fieldsContainer');
},
/**
* Checks if the `availableFields` are draggable.
*
* @method isAvailableFieldsDrag
* @param drag
* @return {Boolean}
*/
isAvailableFieldsDrag: function(drag) {
var instance = this;
var availableFieldsDrag = instance.availableFieldsDrag;
return (drag === availableFieldsDrag.dd);
},
/**
* Plots a collection of fields.
*
* @method plotFields
*/
plotFields: function() {
var instance = this;
var fields = instance.get('fields');
fields.each(function(field) {
instance.plotField(field);
});
},
/**
* Render the `A.PropertyBuilder` component instance. Lifecycle.
*
* @method renderUI
* @protected
*/
renderUI: function() {
var instance = this;
instance.fire('render');
instance._renderCanvas();
instance._uiSetAvailableFields(
instance.get('availableFields')
);
},
/**
* Sync the `A.PropertyBuilder` UI. Lifecycle.
*
* @method syncUI
* @protected
*/
syncUI: function() {
var instance = this;
var contentBox = instance.get('contentBox');
instance._setupDrop();
instance._setupAvailableFieldsDrag();
contentBox.addClass(CSS_LAYOUT);
},
/**
* Fires after `A.PropertyBuilder` instance is rendered.
*
* @method _afterRender
* @param event
* @protected
*/
_afterRender: function() {
var instance = this;
instance.plotFields();
},
/**
* Fires after setting height in the UI.
*
* @method _afterUiSetHeight
* @param val
* @protected
*/
_afterUiSetHeight: function(val) {
var instance = this;
instance.contentContainer.setStyle('height', isNumber(val) ? val + instance.DEF_UNIT : val);
instance.dropContainer.setStyle('height', isNumber(val) ? val + instance.DEF_UNIT : val);
},
/**
* Renders the `canvas` attribute.
*
* @method _renderCanvas
* @protected
*/
_renderCanvas: function() {
var instance = this;
var contentBox = instance.get('contentBox');
var canvas = instance.canvas;
var contentContainer = instance.contentContainer;
var dropContainer = instance.dropContainer;
if (!canvas.inDoc()) {
contentContainer.appendChild(canvas);
}
if (!dropContainer.inDoc()) {
canvas.appendChild(dropContainer);
}
if (contentContainer.inDoc()) {
contentContainer.get('parentNode').append(contentContainer);
}
else {
contentBox.appendChild(contentContainer);
}
},
/**
* Creates a new instance of `A.DD.Drop` in `drop` attribute.
*
* @method _setupDrop
* @protected
*/
_setupDrop: function() {
var instance = this;
instance.drop = new A.DD.Drop(
instance.get('dropConfig')
);
},
/**
* Creates a new instance of `A.DD.Delegate` in `availableFieldsDrag`
* attribute.
*
* @method _setupAvailableFieldsDrag
* @protected
*/
_setupAvailableFieldsDrag: function() {
var instance = this;
instance.availableFieldsDrag = new A.DD.Delegate(
instance.get('availableFieldsDragConfig')
);
},
/**
* Sets the `availableFields` attribute.
*
* @method _setAvailableFields
* @param val
* @protected
*/
_setAvailableFields: function(val) {
var fields = [];
AArray.each(val, function(field) {
fields.push(
isAvailableField(field) ? field : new A.PropertyBuilderAvailableField(field)
);
});
return fields;
},
/**
* Set the `dropConfig` attribute.
*
* @method _setDropConfig
* @param val
* @protected
*/
_setDropConfig: function(val) {
var instance = this;
return A.merge({
bubbleTargets: instance,
groups: ['availableFields'],
node: instance.dropContainer
},
val || {}
);
},
/**
* Set the `availableFieldsDragConfig` attribute.
*
* @method _setAvailableFieldsDragConfig
* @param val
* @protected
*/
_setAvailableFieldsDragConfig: function(val) {
var instance = this;
return A.merge({
bubbleTargets: instance,
container: instance.get('boundingBox'),
dragConfig: {
groups: ['availableFields'],
plugins: [
{
cfg: {
moveOnEnd: false
},
fn: A.Plugin.DDProxy
}
]
},
nodes: '.' + CSS_PROPERTY_BUILDER_FIELD_DRAGGABLE
},
val || {}
);
},
/**
* Sets the `availableFields` attribute in the UI.
*
* @method _uiSetAvailableFields
* @param val
* @protected
*/
_uiSetAvailableFields: function(val) {
var instance = this;
var fieldsNode = instance.fieldsNode;
if (fieldsNode) {
var docFrag = A.getDoc().invoke('createDocumentFragment');
AArray.each(val, function(field) {
docFrag.appendChild(field.get('node'));
});
fieldsNode.setContent(
instance.fieldsContainer.setContent(docFrag)
);
}
},
/**
* Sets the `fields` attribute in the UI.
*
* @method _uiSetFields
* @param event
* @protected
*/
_uiSetFields: function() {
var instance = this;
if (instance.get('rendered')) {
instance.plotFields();
}
}
}
});
A.PropertyBuilder = PropertyBuilder;