inputEx Documentation
Back to homepage
inputEx Documentation
> ListField.js
0.2.2
This is the source view for ListField.js
(function() { var inputEx = YAHOO.inputEx, lang = YAHOO.lang, Event = YAHOO.util.Event, Dom = YAHOO.util.Dom; /** * @class Meta field to create a list of other fields * @extends inputEx.Field * @constructor * @param {Object} options Added options: *
*
sortable: Add arrows to sort the items if true (default false)
*
elementType: an element type definition (default is {type: 'string'})
*
useButtons: use buttons instead of links (default false)
*
unique: require values to be unique (default false)
*
listAddLabel: if useButtons is false, text to add an item
*
listRemoveLabel: if useButtons is false, text to remove an item
*
*/ inputEx.ListField = function(options) { /** * List of all the subField instances */ this.subFields = []; inputEx.ListField.superclass.constructor.call(this, options); }; lang.extend(inputEx.ListField,inputEx.Field, /** * @scope inputEx.ListField.prototype */ { /** * Set the ListField classname * @param {Object} options Options object (inputEx inputParams) as passed to the constructor */ setOptions: function(options) { inputEx.ListField.superclass.setOptions.call(this, options); this.options.className = options.className ? options.className : 'inputEx-Field inputEx-ListField'; this.options.sortable = lang.isUndefined(options.sortable) ? false : options.sortable; this.options.elementType = options.elementType || {type: 'string'}; this.options.useButtons = lang.isUndefined(options.useButtons) ? false : options.useButtons; this.options.unique = lang.isUndefined(options.unique) ? false : options.unique; this.options.listAddLabel = options.listAddLabel || inputEx.messages.listAddLink; this.options.listRemoveLabel = options.listRemoveLabel || inputEx.messages.listRemoveLink; }, /** * Render the addButton */ renderComponent: function() { // Add element button if(this.options.useButtons) { this.addButton = inputEx.cn('img', {src: inputEx.spacerUrl, className: 'inputEx-ListField-addButton'}); this.fieldContainer.appendChild(this.addButton); } // List label this.fieldContainer.appendChild( inputEx.cn('span', null, {marginLeft: "4px"}, this.options.listLabel) ); // Div element to contain the children this.childContainer = inputEx.cn('div', {className: 'inputEx-ListField-childContainer'}); this.fieldContainer.appendChild(this.childContainer); // Add link if(!this.options.useButtons) { this.addButton = inputEx.cn('a', {className: 'inputEx-List-link'}, null, this.options.listAddLabel); this.fieldContainer.appendChild(this.addButton); } }, /** * Handle the click event on the add button */ initEvents: function() { Event.addListener(this.addButton, 'click', this.onAddButton, this, true); }, /** * Validate each field * @returns {Boolean} true if all fields validate, required fields are not empty and unique constraint (if specified) is not violated */ validate: function() { var response = true; var uniques = {}; // Validate all the sub fields for (var i = 0 ; i < this.subFields.length && response; i++) { var input = this.subFields[i]; input.setClassFromState(); // update field classes (mark invalid fields...) var state = input.getState(); if( state == inputEx.stateRequired || state == inputEx.stateInvalid ) { response = false; // but keep looping on fields to set classes } if(this.options.unique) { var hash = lang.dump(input.getValue()); //logDebug('listfied index ',i, 'hash', hash); if(uniques[hash]) { response = false; // not unique } else { uniques[hash] = true; } } } return response; }, /** * Set the value of all the subfields * @param {Array} value The list of values to set * @param {boolean} [sendUpdatedEvt] (optional) Wether this setValue should fire the updatedEvt or not (default is true, pass false to NOT send the event) */ setValue: function(value, sendUpdatedEvt) { if(!lang.isArray(value) ) { // TODO: throw exceptions ? return; } // Set the values (and add the lines if necessary) for(var i = 0 ; i < value.length ; i++) { if(i == this.subFields.length) { this.addElement(value[i]); } else { this.subFields[i].setValue(value[i], false); } } // Remove additional subFields var additionalElements = this.subFields.length-value.length; if(additionalElements > 0) { for(var i = 0 ; i < additionalElements ; i++) { this.removeElement(value.length); } }; inputEx.ListField.superclass.setValue.call(this, value, sendUpdatedEvt); }, /** * Return the array of values * @return {Array} The array */ getValue: function() { var values = []; for(var i = 0 ; i < this.subFields.length ; i++) { values[i] = this.subFields[i].getValue(); } return values; }, /** * Adds an element * @param {Any} The initial value of the subfield to create * @return {inputEx.Field} SubField added instance */ addElement: function(value) { // Render the subField var subFieldEl = this.renderSubField(value); // Adds it to the local list this.subFields.push(subFieldEl); return subFieldEl; }, /** * Add a new element to the list and fire updated event * @param {Event} e The original click event */ onAddButton: function(e) { Event.stopEvent(e); // Add a field with no value: var subFieldEl = this.addElement(); // Focus on this field subFieldEl.focus(); // Fire updated ! this.fireUpdatedEvt(); }, /** * Adds a new line to the List Field * @param {Any} The initial value of the subfield to create * @return {inputEx.Field} instance of the created field (inputEx.Field or derivative) */ renderSubField: function(value) { // Div that wraps the deleteButton + the subField var newDiv = inputEx.cn('div'); // Delete button if(this.options.useButtons) { var delButton = inputEx.cn('img', {src: inputEx.spacerUrl, className: 'inputEx-ListField-delButton'}); Event.addListener( delButton, 'click', this.onDelete, this, true); newDiv.appendChild( delButton ); } // Instanciate the new subField var opts = lang.merge({}, this.options.elementType); if(!opts.inputParams) opts.inputParams = {}; if(!lang.isUndefined(value)) opts.inputParams.value = value; var el = inputEx.buildField(opts); var subFieldEl = el.getEl(); Dom.setStyle(subFieldEl, 'margin-left', '4px'); Dom.setStyle(subFieldEl, 'float', 'left'); newDiv.appendChild( subFieldEl ); // Subscribe the onChange event to resend it el.updatedEvt.subscribe(this.onChange, this, true); // Arrows to order: if(this.options.sortable) { var arrowUp = inputEx.cn('div', {className: 'inputEx-ListField-Arrow inputEx-ListField-ArrowUp'}); Event.addListener(arrowUp, 'click', this.onArrowUp, this, true); var arrowDown = inputEx.cn('div', {className: 'inputEx-ListField-Arrow inputEx-ListField-ArrowDown'}); Event.addListener(arrowDown, 'click', this.onArrowDown, this, true); newDiv.appendChild( arrowUp ); newDiv.appendChild( arrowDown ); } // Delete link if(!this.options.useButtons) { var delButton = inputEx.cn('a', {className: 'inputEx-List-link'}, null, this.options.listRemoveLabel); Event.addListener( delButton, 'click', this.onDelete, this, true); newDiv.appendChild( delButton ); } // Line breaker newDiv.appendChild( inputEx.cn('div', null, {clear: "both"}) ); this.childContainer.appendChild(newDiv); return el; }, /** * Switch a subField with its previous one * Called when the user clicked on the up arrow of a sortable list * @param {Event} e Original click event */ onArrowUp: function(e) { var childElement = Event.getTarget(e).parentNode; var previousChildNode = null; var nodeIndex = -1; for(var i = 1 ; i < childElement.parentNode.childNodes.length ; i++) { var el=childElement.parentNode.childNodes[i]; if(el == childElement) { previousChildNode = childElement.parentNode.childNodes[i-1]; nodeIndex = i; break; } } if(previousChildNode) { // Remove the line var removedEl = this.childContainer.removeChild(childElement); // Adds it before the previousChildNode var insertedEl = this.childContainer.insertBefore(removedEl, previousChildNode); // Swap this.subFields elements (i,i-1) var temp = this.subFields[nodeIndex]; this.subFields[nodeIndex] = this.subFields[nodeIndex-1]; this.subFields[nodeIndex-1] = temp; // Color Animation if(this.arrowAnim) { this.arrowAnim.stop(true); } this.arrowAnim = new YAHOO.util.ColorAnim(insertedEl, {backgroundColor: { from: '#eeee33' , to: '#eeeeee' }}, 0.4); this.arrowAnim.onComplete.subscribe(function() { Dom.setStyle(insertedEl, 'background-color', ''); }); this.arrowAnim.animate(); // Fire updated ! this.fireUpdatedEvt(); } }, /** * Switch a subField with its next one * Called when the user clicked on the down arrow of a sortable list * @param {Event} e Original click event */ onArrowDown: function(e) { var childElement = Event.getTarget(e).parentNode; var nodeIndex = -1; var nextChildNode = null; for(var i = 0 ; i < childElement.parentNode.childNodes.length ; i++) { var el=childElement.parentNode.childNodes[i]; if(el == childElement) { nextChildNode = childElement.parentNode.childNodes[i+1]; nodeIndex = i; break; } } if(nextChildNode) { // Remove the line var removedEl = this.childContainer.removeChild(childElement); // Adds it after the nextChildNode var insertedEl = Dom.insertAfter(removedEl, nextChildNode); // Swap this.subFields elements (i,i+1) var temp = this.subFields[nodeIndex]; this.subFields[nodeIndex] = this.subFields[nodeIndex+1]; this.subFields[nodeIndex+1] = temp; // Color Animation if(this.arrowAnim) { this.arrowAnim.stop(true); } this.arrowAnim = new YAHOO.util.ColorAnim(insertedEl, {backgroundColor: { from: '#eeee33' , to: '#eeeeee' }}, 1); this.arrowAnim.onComplete.subscribe(function() { Dom.setStyle(insertedEl, 'background-color', ''); }); this.arrowAnim.animate(); // Fire updated ! this.fireUpdatedEvt(); } }, /** * Called when the user clicked on a delete button. * @param {Event} e The original click event */ onDelete: function(e) { Event.stopEvent(e); // Get the wrapping div element var elementDiv = Event.getTarget(e).parentNode; // Get the index of the subField var index = -1; var subFieldEl = elementDiv.childNodes[this.options.useButtons ? 1 : 0]; for(var i = 0 ; i < this.subFields.length ; i++) { if(this.subFields[i].getEl() == subFieldEl) { index = i; break; } } // Remove it if(index != -1) { this.removeElement(index); } // Fire the updated event this.fireUpdatedEvt(); }, /** * Remove the line from the dom and the subField from the list. * @param {integer} index The index of the element to remove */ removeElement: function(index) { var elementDiv = this.subFields[index].getEl().parentNode; this.subFields[index] = undefined; this.subFields = inputEx.compactArray(this.subFields); // Remove the element elementDiv.parentNode.removeChild(elementDiv); } }); /** * Register this class as "list" type */ inputEx.registerType("list", inputEx.ListField); inputEx.messages.listAddLink = "Add"; inputEx.messages.listRemoveLink = "remove"; })();
Pages
Index
Getting Started
Overview
Markup structure
Migrate from 0.1.0
Field development
DOM functions
Internationalization
Visualization
Examples
Classes
(treeview)
inputEx
inputEx.AutoComplete
inputEx.BirthdateField
inputEx.CheckBox
inputEx.ColorField
inputEx.ColorField2
inputEx.CombineField
inputEx.DateField
inputEx.DatePickerField
inputEx.DateSplitField
inputEx.DateTimeField
inputEx.DSSelectField
inputEx.EmailField
inputEx.Field
inputEx.FileField
inputEx.Form
inputEx.formForMethod
inputEx.FrenchDate
inputEx.FrenchPhone
inputEx.generateServiceForm
inputEx.Group
inputEx.HiddenField
inputEx.ImagemapField
inputEx.InPlaceEdit
inputEx.IntegerField
inputEx.IPv4Field
inputEx.JsonSchema
inputEx.JsonSchema.Builder
inputEx.ListField
inputEx.MapField
inputEx.MenuField
inputEx.MultiAutoComplete
inputEx.MultiSelectField
inputEx.NumberField
inputEx.PairField
inputEx.PasswordField
inputEx.RadioButton
inputEx.RadioField
inputEx.RTEField
inputEx.SelectField
inputEx.SliderField
inputEx.StringField
inputEx.Textarea
inputEx.TimeField
inputEx.TreeField
inputEx.TypeField
inputEx.UneditableField
inputEx.UpperCaseField
inputEx.UrlField
inputEx.VectorField
inputEx.widget
inputEx.widget.DataTable
inputEx.widget.DDList
inputEx.widget.DDListItem
inputEx.widget.Dialog
inputEx.widget.InputExCellEditor
inputEx.widget.JsonTreeInspector
Files
AutoComplete.js
BirthdateField.js
CheckBox.js
ColorField.js
ColorField2.js
CombineField.js
DataTable-beta.js
DateField.js
DatePickerField.js
DateSplitField.js
DateTimeField.js
ddlist.js
Dialog-beta.js
DSSelectField.js
EmailField.js
Field.js
FileField-beta.js
Form.js
fr.js
FrenchDate.js
FrenchPhone.js
Group.js
HiddenField.js
ImagemapField.js
InPlaceEdit.js
inputex-loader.js
inputex-rpc.js
inputex.js
IntegerField.js
IPv4Field.js
it.js
json-schema.js
json-tree-inspector.js
ListField.js
MapField.js
MenuField.js
MultiAutoComplete.js
MultiSelectField.js
NumberField.js
PairField.js
PasswordField.js
RadioButton.js
RadioField.js
RTEField.js
SelectField.js
SliderField.js
StringField.js
Textarea.js
TimeField.js
TreeField.js
TypeField.js
UneditableField.js
UpperCaseField.js
UrlField.js
VectorField.js
Visus.js
Copyright (c) 2007-2009
Eric Abouaf
. All rights reserved.
Generated by
JsDoc Toolkit
2.0.0 on Wed, 04 Mar 2009 15:41:29 GMT using
neyricjslibs-template
.