3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
4 <title>The source code</title>
5 <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6 <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8 <body onload="prettyPrint();">
9 <pre class="prettyprint lang-js">/*!
10 * Ext JS Library 3.3.1
11 * Copyright(c) 2006-2010 Sencha Inc.
12 * licensing@sencha.com
13 * http://www.sencha.com/license
15 <div id="cls-Ext.form.CompositeField"></div>/**
16 * @class Ext.form.CompositeField
17 * @extends Ext.form.Field
18 * Composite field allowing a number of form Fields to be rendered on the same row. The fields are rendered
19 * using an hbox layout internally, so all of the normal HBox layout config items are available. Example usage:
22 xtype: 'compositefield',
43 * In the example above the composite's fieldLabel will be set to 'Title, First, Last' as it groups the fieldLabels
44 * of each of its children. This can be overridden by setting a fieldLabel on the compositefield itself:
47 xtype: 'compositefield',
48 fieldLabel: 'Custom label',
52 * Any Ext.form.* component can be placed inside a composite field.
54 Ext.form.CompositeField = Ext.extend(Ext.form.Field, {
56 <div id="prop-Ext.form.CompositeField-defaultMargins"></div>/**
57 * @property defaultMargins
59 * The margins to apply by default to each field in the composite
61 defaultMargins: '0 5 0 0',
63 <div id="prop-Ext.form.CompositeField-skipLastItemMargin"></div>/**
64 * @property skipLastItemMargin
66 * If true, the defaultMargins are not applied to the last item in the composite field set (defaults to true)
68 skipLastItemMargin: true,
70 <div id="prop-Ext.form.CompositeField-isComposite"></div>/**
71 * @property isComposite
73 * Signifies that this is a Composite field
77 <div id="prop-Ext.form.CompositeField-combineErrors"></div>/**
78 * @property combineErrors
80 * True to combine errors from the individual fields into a single error message at the CompositeField level (defaults to true)
84 <div id="cfg-Ext.form.CompositeField-labelConnector"></div>/**
85 * @cfg {String} labelConnector The string to use when joining segments of the built label together (defaults to ', ')
89 <div id="cfg-Ext.form.CompositeField-defaults"></div>/**
90 * @cfg {Object} defaults Any default properties to assign to the child fields.
94 //Builds the composite field label
95 initComponent: function() {
100 for (var i=0, j = items.length; i < j; i++) {
103 if (!Ext.isEmpty(item.ref)){
104 item.ref = '../' + item.ref;
107 labels.push(item.fieldLabel);
110 Ext.applyIf(item, this.defaults);
112 //apply default margins to each item except the last
113 if (!(i == j - 1 && this.skipLastItemMargin)) {
114 Ext.applyIf(item, {margins: this.defaultMargins});
118 this.fieldLabel = this.fieldLabel || this.buildLabel(labels);
120 <div id="prop-Ext.form.CompositeField-fieldErrors"></div>/**
121 * @property fieldErrors
122 * @type Ext.util.MixedCollection
123 * MixedCollection of current errors on the Composite's subfields. This is used internally to track when
124 * to show and hide error messages at the Composite level. Listeners are attached to the MixedCollection's
125 * add, remove and replace events to update the error icon in the UI as errors are added or removed.
127 this.fieldErrors = new Ext.util.MixedCollection(true, function(item) {
131 this.fieldErrors.on({
133 add : this.updateInvalidMark,
134 remove : this.updateInvalidMark,
135 replace: this.updateInvalidMark
138 Ext.form.CompositeField.superclass.initComponent.apply(this, arguments);
140 this.innerCt = new Ext.Container({
143 cls : 'x-form-composite',
144 defaultMargins: '0 3 0 0',
147 this.innerCt.ownerCt = undefined;
149 var fields = this.innerCt.findBy(function(c) {
150 return c.isFormField;
153 <div id="prop-Ext.form.CompositeField-items"></div>/**
155 * @type Ext.util.MixedCollection
156 * Internal collection of all of the subfields in this Composite
158 this.items = new Ext.util.MixedCollection();
159 this.items.addAll(fields);
165 * Creates an internal container using hbox and renders the fields to it
167 onRender: function(ct, position) {
169 <div id="prop-Ext.form.CompositeField-innerCt"></div>/**
171 * @type Ext.Container
172 * A container configured with hbox layout which is responsible for laying out the subfields
174 var innerCt = this.innerCt;
177 this.el = innerCt.getEl();
179 //if we're combining subfield errors into a single message, override the markInvalid and clearInvalid
180 //methods of each subfield and show them at the Composite level instead
181 if (this.combineErrors) {
182 this.eachItem(function(field) {
184 markInvalid : this.onFieldMarkInvalid.createDelegate(this, [field], 0),
185 clearInvalid: this.onFieldClearInvalid.createDelegate(this, [field], 0)
190 //set the label 'for' to the first item
191 var l = this.el.parent().parent().child('label', true);
193 l.setAttribute('for', this.items.items[0].id);
197 Ext.form.CompositeField.superclass.onRender.apply(this, arguments);
200 <div id="method-Ext.form.CompositeField-onFieldMarkInvalid"></div>/**
201 * Called if combineErrors is true and a subfield's markInvalid method is called.
202 * By default this just adds the subfield's error to the internal fieldErrors MixedCollection
203 * @param {Ext.form.Field} field The field that was marked invalid
204 * @param {String} message The error message
206 onFieldMarkInvalid: function(field, message) {
207 var name = field.getName(),
210 errorName: field.fieldLabel || name,
214 this.fieldErrors.replace(name, error);
216 field.el.addClass(field.invalidClass);
219 <div id="method-Ext.form.CompositeField-onFieldClearInvalid"></div>/**
220 * Called if combineErrors is true and a subfield's clearInvalid method is called.
221 * By default this just updates the internal fieldErrors MixedCollection.
222 * @param {Ext.form.Field} field The field that was marked invalid
224 onFieldClearInvalid: function(field) {
225 this.fieldErrors.removeKey(field.getName());
227 field.el.removeClass(field.invalidClass);
232 * Called after a subfield is marked valid or invalid, this checks to see if any of the subfields are
233 * currently invalid. If any subfields are invalid it builds a combined error message marks the composite
234 * invalid, otherwise clearInvalid is called
236 updateInvalidMark: function() {
237 var ieStrict = Ext.isIE6 && Ext.isStrict;
239 if (this.fieldErrors.length == 0) {
242 //IE6 in strict mode has a layout bug when using 'under' as the error message target. This fixes it
244 this.clearInvalid.defer(50, this);
247 var message = this.buildCombinedErrorMessage(this.fieldErrors.items);
250 this.markInvalid(message);
252 //IE6 in strict mode has a layout bug when using 'under' as the error message target. This fixes it
254 this.markInvalid(message);
259 <div id="method-Ext.form.CompositeField-validateValue"></div>/**
260 * Performs validation checks on each subfield and returns false if any of them fail validation.
261 * @return {Boolean} False if any subfield failed validation
263 validateValue: function() {
266 this.eachItem(function(field) {
267 if (!field.isValid()) valid = false;
273 <div id="method-Ext.form.CompositeField-buildCombinedErrorMessage"></div>/**
274 * Takes an object containing error messages for contained fields, returning a combined error
275 * string (defaults to just placing each item on a new line). This can be overridden to provide
276 * custom combined error message handling.
277 * @param {Array} errors Array of errors in format: [{field: 'title', error: 'some error'}]
278 * @return {String} The combined error message
280 buildCombinedErrorMessage: function(errors) {
284 for (var i = 0, j = errors.length; i < j; i++) {
287 combined.push(String.format("{0}: {1}", error.errorName, error.error));
290 return combined.join("<br />");
293 <div id="method-Ext.form.CompositeField-sortErrors"></div>/**
294 * Sorts the internal fieldErrors MixedCollection by the order in which the fields are defined.
295 * This is called before displaying errors to ensure that the errors are presented in the expected order.
296 * This function can be overridden to provide a custom sorting order if needed.
298 sortErrors: function() {
299 var fields = this.items;
301 this.fieldErrors.sort("ASC", function(a, b) {
302 var findByName = function(key) {
303 return function(field) {
304 return field.getName() == key;
308 var aIndex = fields.findIndexBy(findByName(a.field)),
309 bIndex = fields.findIndexBy(findByName(b.field));
311 return aIndex < bIndex ? -1 : 1;
315 <div id="method-Ext.form.CompositeField-reset"></div>/**
316 * Resets each field in the composite to their previous value
319 this.eachItem(function(item) {
323 // Defer the clearInvalid so if BaseForm's collection is being iterated it will be called AFTER it is complete.
324 // Important because reset is being called on both the group and the individual items.
330 <div id="method-Ext.form.CompositeField-clearInvalidChildren"></div>/**
331 * Calls clearInvalid on all child fields. This is a convenience function and should not often need to be called
332 * as fields usually take care of clearing themselves
334 clearInvalidChildren: function() {
335 this.eachItem(function(item) {
340 <div id="method-Ext.form.CompositeField-buildLabel"></div>/**
341 * Builds a label string from an array of subfield labels.
342 * By default this just joins the labels together with a comma
343 * @param {Array} segments Array of each of the labels in the composite field's subfields
344 * @return {String} The built label
346 buildLabel: function(segments) {
347 return Ext.clean(segments).join(this.labelConnector);
350 <div id="method-Ext.form.CompositeField-isDirty"></div>/**
351 * Checks each field in the composite and returns true if any is dirty
352 * @return {Boolean} True if any field is dirty
355 //override the behaviour to check sub items.
356 if (this.disabled || !this.rendered) {
361 this.eachItem(function(item){
372 * Convenience function which passes the given function to every item in the composite
373 * @param {Function} fn The function to call
374 * @param {Object} scope Optional scope object
376 eachItem: function(fn, scope) {
377 if(this.items && this.items.each){
378 this.items.each(fn, scope || this);
384 * Passes the resize call through to the inner panel
386 onResize: function(adjWidth, adjHeight, rawWidth, rawHeight) {
387 var innerCt = this.innerCt;
389 if (this.rendered && innerCt.rendered) {
390 innerCt.setSize(adjWidth, adjHeight);
393 Ext.form.CompositeField.superclass.onResize.apply(this, arguments);
398 * Forces the internal container to be laid out again
400 doLayout: function(shallow, force) {
402 var innerCt = this.innerCt;
404 innerCt.forceLayout = this.ownerCt.forceLayout;
405 innerCt.doLayout(shallow, force);
412 beforeDestroy: function(){
413 Ext.destroy(this.innerCt);
415 Ext.form.CompositeField.superclass.beforeDestroy.call(this);
418 //override the behaviour to check sub items.
419 setReadOnly : function(readOnly) {
420 if (readOnly == undefined) {
423 readOnly = !!readOnly;
426 this.eachItem(function(item){
427 item.setReadOnly(readOnly);
430 this.readOnly = readOnly;
433 onShow : function() {
434 Ext.form.CompositeField.superclass.onShow.call(this);
438 //override the behaviour to check sub items.
439 onDisable : function(){
440 this.eachItem(function(item){
445 //override the behaviour to check sub items.
446 onEnable : function(){
447 this.eachItem(function(item){
453 Ext.reg('compositefield', Ext.form.CompositeField);</pre>