/**
* The Form Builder Field Types Component
*
* @module aui-form-builder
* @submodule aui-form-builder-field-types
*/
/**
* `A.FormBuilder` extension, which is responsible for all the logic related
* to field types.
*
* @class A.FormBuilderFieldTypes
* @param {Object} config Object literal specifying layout builder configuration
* properties.
* @constructor
*/
A.FormBuilderFieldTypes = function() {};
A.FormBuilderFieldTypes.prototype = {
/**
* Construction logic executed during the `A.FormBuilderFieldTypes`
* instantiation. Lifecycle.
*
* @method initializer
* @protected
*/
initializer: function() {
this.after('fieldTypesChange', this._afterFieldTypesChange);
this.after('form-builder-field-types-modal:selectFieldType', this._afterSelectFieldType);
},
/**
* Destructor lifecycle implementation for the `A.FormBuilderFieldTypes` class.
* Lifecycle.
*
* @method destructor
* @protected
*/
destructor: function() {
A.Array.each(this.get('fieldTypes'), function(field) {
field.destroy();
});
this.get('fieldTypesModal').destroy();
},
/**
* Disables unique fields for the field class that the given field is an
* instance of.
*
* @method disableUniqueFieldType
* @param {A.FormField} field
*/
disableUniqueFieldType: function(field) {
var fieldType = this.findTypeOfField(field);
if (fieldType.get('unique')) {
fieldType.set('disabled', true);
}
},
/**
* Finds the type of the given field.
*
* @method findTypeOfField
* @param {A.FormBuilderFieldBase} field
*/
findTypeOfField: function(field) {
var fieldTypes = this.get('fieldTypes'),
i;
for (i = 0; i < fieldTypes.length; i++) {
if (field.constructor === fieldTypes[i].get('fieldClass')) {
return fieldTypes[i];
}
}
},
/**
* Hides the fields modal.
*
* @method hideFieldsPanel
*/
hideFieldsPanel: function() {
var fieldTypesModal = this.get('fieldTypesModal');
fieldTypesModal.hide();
},
/**
* Adds a the given field types to this form builder.
*
* @method registerFieldTypes
* @param {Array | Object | A.FormBuilderFieldType} typesToAdd This can be
* either an array of items or a single item. Each item should be either
* an instance of `A.FormBuilderFieldType`, or the configuration object
* to be used when instantiating one.
*/
registerFieldTypes: function(typesToAdd) {
var fieldTypes = this.get('fieldTypes');
typesToAdd = A.Lang.isArray(typesToAdd) ? typesToAdd : [typesToAdd];
A.Array.each(typesToAdd, function(type) {
fieldTypes.push(type);
});
this.set('fieldTypes', fieldTypes);
},
/**
* Shows the fields modal.
*
* @method showFieldsPanel
*/
showFieldsPanel: function() {
var fieldTypesModal = this.get('fieldTypesModal');
if (!fieldTypesModal.get('rendered')) {
fieldTypesModal.render();
}
fieldTypesModal.show();
},
/**
* Removes the given field types from this form builder.
*
* @method unregisterFieldTypes
* @param {Array | String | A.FormBuilderFieldType} typesToRemove This can be
* either an array of items, or a single one. For each item, if it's a
* string, the form builder will remove all registered field types with
* a field class that matches it. For items that are instances of
* `A.FormBuilderFieldType`, only the same instances will be removed.
*/
unregisterFieldTypes: function(typesToRemove) {
var instance = this;
typesToRemove = A.Lang.isArray(typesToRemove) ? typesToRemove : [typesToRemove];
A.Array.each(typesToRemove, function(type) {
instance._unregisterFieldType(type);
});
this.set('fieldTypes', this.get('fieldTypes'));
},
/**
* Fired after the `fieldTypes` attribute is set.
*
* @method _afterFieldTypesChange
* @param {EventFacade} event
* @protected
*/
_afterFieldTypesChange: function(event) {
this.get('fieldTypesModal').set('fieldTypes', event.newVal);
},
/**
* Fired after a field type is selected by the user.
*
* @method _afterSelectFieldType
* @param {EventFacade} event
* @protected
*/
_afterSelectFieldType: function(event) {
var field,
fieldType = event.fieldType;
if (!fieldType.get('disabled')) {
field = new(fieldType.get('fieldClass'))(fieldType.get('defaultConfig'));
this.showFieldSettingsPanel(field, fieldType.get('label'));
}
},
/**
* Check on all created fields if there is one of the same type
* of the parameter.
*
* @method _checkActiveLayoutHasFieldType
* @param {Object} fieldType
* @return {Boolean}
* @protected
*/
_checkActiveLayoutHasFieldType: function(fieldType) {
var col,
cols,
fieldList,
row,
rows = this.getActiveLayout().get('rows');
for (row = 0; row < rows.length; row++) {
cols = rows[row].get('cols');
for (col = 0; col < cols.length; col++) {
fieldList = cols[col].get('value');
if (fieldList && this._checkListHasFieldType(fieldList, fieldType)) {
return true;
}
}
}
return false;
},
/**
* Checks on all fields of a field list if there is one of the
* same type of the parameter.
*
* @method _checkListHasFieldType
* @param {A.FormBuilderFIeldList} fieldList
* @param {Object} fieldType
* @return {Boolean}
* @protected
*/
_checkListHasFieldType: function(fieldList, fieldType) {
var fields = fieldList.get('fields'),
i;
for (i = 0; i < fields.length; i++) {
if (this._hasFieldType(fieldType, fields[i])) {
return true;
}
}
return false;
},
/**
* Checks if the given field is of the given field type.
*
* @method _hasFieldType
* @param {A.FormBuilderFieldType} fieldType
* @param {A.FormField} field
* @return {Boolean}
* @protected
*/
_hasFieldType: function(fieldType, field) {
var i,
nestedFields = field.get('nestedFields');
if (field.constructor === fieldType.get('fieldClass')) {
return true;
}
for (i = 0; i < nestedFields.length; i++) {
if (this._hasFieldType(fieldType, nestedFields[i])) {
return true;
}
}
return false;
},
/**
* Sets the `fieldTypes` attribute.
*
* @method _setFieldTypes
* @param {Object | A.FormBuilderFieldType} val
* @return {A.FormBuilderFieldType}
* @protected
*/
_setFieldTypes: function(val) {
for (var i = 0; i < val.length; i++) {
if (!A.instanceOf(val[i], A.FormBuilderFieldType)) {
val[i] = new A.FormBuilderFieldType(val[i]);
}
}
return val;
},
/**
* Removes a single given field type from this form builder.
*
* @method _unregisterFieldType
* @param {String | A.FormBuilderFieldType} fieldType
* @protected
*/
_unregisterFieldType: function(fieldType) {
var fieldTypes = this.get('fieldTypes'),
i;
if (A.Lang.isFunction(fieldType)) {
for (i = fieldTypes.length - 1; i >= 0; i--) {
if (fieldTypes[i].get('fieldClass') === fieldType) {
this._unregisterFieldTypeByIndex(i);
}
}
}
else {
this._unregisterFieldTypeByIndex(fieldTypes.indexOf(fieldType));
}
},
/**
* Unregisters the field type at the given index.
*
* @method _unregisterFieldTypeByIndex
* @param {Number} index
* @protected
*/
_unregisterFieldTypeByIndex: function(index) {
var fieldTypes = this.get('fieldTypes');
if (index !== -1) {
fieldTypes[index].destroy();
fieldTypes.splice(index, 1);
}
},
/**
* Enable or disable unique FieldTypes based on created Fields.
*
* @method _updateUniqueFieldType
* @protected
*/
_updateUniqueFieldType: function() {
var instance = this;
A.Array.each(instance.get('fieldTypes'), function(fieldType) {
if (fieldType.get('unique')) {
fieldType.set('disabled', instance._checkActiveLayoutHasFieldType(fieldType));
}
});
},
/**
* Default value for the modal displayed to select a field.
*
* @method _valueFieldTypesModal
* @return {A.FormBuilderFieldTypesModal}
* @protected
*/
_valueFieldTypesModal: function() {
var fieldTypesModal = new A.FormBuilderFieldTypesModal({
centered: true,
cssClass: 'form-builder-modal',
draggable: false,
fieldTypes: this.get('fieldTypes'),
modal: true,
resizable: false,
visible: false,
zIndex: 4
});
fieldTypesModal.addTarget(this);
return fieldTypesModal;
}
};
/**
* Static property used to define the default attribute
* configuration for the `A.FormBuilderFieldTypes`.
*
* @property ATTRS
* @type Object
* @static
*/
A.FormBuilderFieldTypes.ATTRS = {
/**
* The collection of field types that can be selected as fields for
* this form builder.
*
* @attribute fieldTypes
* @default []
* @type Array
*/
fieldTypes: {
setter: '_setFieldTypes',
validator: A.Lang.isArray,
value: []
},
/**
* The modal that will be used to select a field type.
*
* @attribute fieldTypesModal
* @type `A.FormBuilderFieldTypesModal`
*/
fieldTypesModal: {
valueFn: '_valueFieldTypesModal'
}
};