Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Field2.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-layout-component-field-Field'>/**
19 </span> * @class Ext.layout.component.field.Field
20  * @extends Ext.layout.component.Component
21  * Layout class for components with {@link Ext.form.Labelable field labeling}, handling the sizing and alignment of
22  * the form control, label, and error message treatment.
23  * @private
24  */
25 Ext.define('Ext.layout.component.field.Field', {
26
27     /* Begin Definitions */
28
29     alias: ['layout.field'],
30
31     extend: 'Ext.layout.component.Component',
32
33     uses: ['Ext.tip.QuickTip', 'Ext.util.TextMetrics'],
34
35     /* End Definitions */
36
37     type: 'field',
38
39     beforeLayout: function(width, height) {
40         var me = this;
41         return me.callParent(arguments) || (!me.owner.preventMark &amp;&amp; me.activeError !== me.owner.getActiveError());
42     },
43
44     onLayout: function(width, height) {
45         var me = this,
46             owner = me.owner,
47             labelStrategy = me.getLabelStrategy(),
48             errorStrategy = me.getErrorStrategy(),
49             isDefined = Ext.isDefined,
50             isNumber = Ext.isNumber,
51             lastSize, autoWidth, autoHeight, info, undef;
52
53         lastSize = me.lastComponentSize || {};
54         if (!isDefined(width)) {
55             width = lastSize.width;
56             if (width &lt; 0) { //first pass lastComponentSize.width is -Infinity
57                 width = undef;
58             }
59         }
60         if (!isDefined(height)) {
61             height = lastSize.height;
62             if (height &lt; 0) { //first pass lastComponentSize.height is -Infinity
63                 height = undef;
64             }
65         }
66         autoWidth = !isNumber(width);
67         autoHeight = !isNumber(height);
68
69         info = {
70             autoWidth: autoWidth,
71             autoHeight: autoHeight,
72             width: autoWidth ? owner.getBodyNaturalWidth() : width, //always give a pixel width
73             height: height,
74             setOuterWidth: false, //whether the outer el width should be set to the calculated width
75
76             // insets for the bodyEl from each side of the component layout area
77             insets: {
78                 top: 0,
79                 right: 0,
80                 bottom: 0,
81                 left: 0
82             }
83         };
84
85         // NOTE the order of calculating insets and setting styles here is very important; we must first
86         // calculate and set horizontal layout alone, as the horizontal sizing of elements can have an impact
87         // on the vertical sizes due to wrapping, then calculate and set the vertical layout.
88
89         // perform preparation on the label and error (setting css classes, qtips, etc.)
90         labelStrategy.prepare(owner, info);
91         errorStrategy.prepare(owner, info);
92
93         // calculate the horizontal insets for the label and error
94         labelStrategy.adjustHorizInsets(owner, info);
95         errorStrategy.adjustHorizInsets(owner, info);
96
97         // set horizontal styles for label and error based on the current insets
98         labelStrategy.layoutHoriz(owner, info);
99         errorStrategy.layoutHoriz(owner, info);
100
101         // calculate the vertical insets for the label and error
102         labelStrategy.adjustVertInsets(owner, info);
103         errorStrategy.adjustVertInsets(owner, info);
104
105         // set vertical styles for label and error based on the current insets
106         labelStrategy.layoutVert(owner, info);
107         errorStrategy.layoutVert(owner, info);
108
109         // perform sizing of the elements based on the final dimensions and insets
110         if (autoWidth &amp;&amp; autoHeight) {
111             // Don't use setTargetSize if auto-sized, so the calculated size is not reused next time
112             me.setElementSize(owner.el, (info.setOuterWidth ? info.width : undef), info.height);
113         } else {
114             me.setTargetSize((!autoWidth || info.setOuterWidth ? info.width : undef), info.height);
115         }
116         me.sizeBody(info);
117
118         me.activeError = owner.getActiveError();
119     },
120     
121     onFocus: function(){
122         this.getErrorStrategy().onFocus(this.owner);    
123     },
124
125
126 <span id='Ext-layout-component-field-Field-method-sizeBody'>    /**
127 </span>     * Perform sizing and alignment of the bodyEl (and children) to match the calculated insets.
128      */
129     sizeBody: function(info) {
130         var me = this,
131             owner = me.owner,
132             insets = info.insets,
133             totalWidth = info.width,
134             totalHeight = info.height,
135             width = Ext.isNumber(totalWidth) ? totalWidth - insets.left - insets.right : totalWidth,
136             height = Ext.isNumber(totalHeight) ? totalHeight - insets.top - insets.bottom : totalHeight;
137
138         // size the bodyEl
139         me.setElementSize(owner.bodyEl, width, height);
140
141         // size the bodyEl's inner contents if necessary
142         me.sizeBodyContents(width, height);
143     },
144
145 <span id='Ext-layout-component-field-Field-property-sizeBodyContents'>    /**
146 </span>     * Size the contents of the field body, given the full dimensions of the bodyEl. Does nothing by
147      * default, subclasses can override to handle their specific contents.
148      * @param {Number} width The bodyEl width
149      * @param {Number} height The bodyEl height
150      */
151     sizeBodyContents: Ext.emptyFn,
152
153
154 <span id='Ext-layout-component-field-Field-method-getLabelStrategy'>    /**
155 </span>     * Return the set of strategy functions from the {@link #labelStrategies labelStrategies collection}
156      * that is appropriate for the field's {@link Ext.form.Labelable#labelAlign labelAlign} config.
157      */
158     getLabelStrategy: function() {
159         var me = this,
160             strategies = me.labelStrategies,
161             labelAlign = me.owner.labelAlign;
162         return strategies[labelAlign] || strategies.base;
163     },
164
165 <span id='Ext-layout-component-field-Field-method-getErrorStrategy'>    /**
166 </span>     * Return the set of strategy functions from the {@link #errorStrategies errorStrategies collection}
167      * that is appropriate for the field's {@link Ext.form.Labelable#msgTarget msgTarget} config.
168      */
169     getErrorStrategy: function() {
170         var me = this,
171             owner = me.owner,
172             strategies = me.errorStrategies,
173             msgTarget = owner.msgTarget;
174         return !owner.preventMark &amp;&amp; Ext.isString(msgTarget) ?
175                 (strategies[msgTarget] || strategies.elementId) :
176                 strategies.none;
177     },
178
179
180
181 <span id='Ext-layout-component-field-Field-property-labelStrategies'>    /**
182 </span>     * Collection of named strategies for laying out and adjusting labels to accommodate error messages.
183      * An appropriate one will be chosen based on the owner field's {@link Ext.form.Labelable#labelAlign} config.
184      */
185     labelStrategies: (function() {
186         var applyIf = Ext.applyIf,
187             emptyFn = Ext.emptyFn,
188             base = {
189                 prepare: function(owner, info) {
190                     var cls = owner.labelCls + '-' + owner.labelAlign,
191                         labelEl = owner.labelEl;
192                     if (labelEl &amp;&amp; !labelEl.hasCls(cls)) {
193                         labelEl.addCls(cls);
194                     }
195                 },
196                 adjustHorizInsets: emptyFn,
197                 adjustVertInsets: emptyFn,
198                 layoutHoriz: emptyFn,
199                 layoutVert: emptyFn
200             },
201             left = applyIf({
202                 prepare: function(owner, info) {
203                     base.prepare(owner, info);
204                     // If auto width, add the label width to the body's natural width.
205                     if (info.autoWidth) {
206                         info.width += (!owner.labelEl ? 0 : owner.labelWidth + owner.labelPad);
207                     }
208                     // Must set outer width to prevent field from wrapping below floated label
209                     info.setOuterWidth = true;
210                 },
211                 adjustHorizInsets: function(owner, info) {
212                     if (owner.labelEl) {
213                         info.insets.left += owner.labelWidth + owner.labelPad;
214                     }
215                 },
216                 layoutHoriz: function(owner, info) {
217                     // For content-box browsers we can't rely on Labelable.js#getLabelableRenderData
218                     // setting the width style because it needs to account for the final calculated
219                     // padding/border styles for the label. So we set the width programmatically here to
220                     // normalize content-box sizing, while letting border-box browsers use the original
221                     // width style.
222                     var labelEl = owner.labelEl;
223                     if (labelEl &amp;&amp; !owner.isLabelSized &amp;&amp; !Ext.isBorderBox) {
224                         labelEl.setWidth(owner.labelWidth);
225                         owner.isLabelSized = true;
226                     }
227                 }
228             }, base);
229
230
231         return {
232             base: base,
233
234 <span id='Ext-layout-component-field-Field-property-top'>            /**
235 </span>             * Label displayed above the bodyEl
236              */
237             top: applyIf({
238                 adjustVertInsets: function(owner, info) {
239                     var labelEl = owner.labelEl;
240                     if (labelEl) {
241                         info.insets.top += Ext.util.TextMetrics.measure(labelEl, owner.fieldLabel, info.width).height +
242                                            labelEl.getFrameWidth('tb') + owner.labelPad;
243                     }
244                 }
245             }, base),
246
247 <span id='Ext-layout-component-field-Field-property-left'>            /**
248 </span>             * Label displayed to the left of the bodyEl
249              */
250             left: left,
251
252 <span id='Ext-layout-component-field-Field-property-right'>            /**
253 </span>             * Same as left, only difference is text-align in CSS
254              */
255             right: left
256         };
257     })(),
258
259
260
261 <span id='Ext-layout-component-field-Field-property-errorStrategies'>    /**
262 </span>     * Collection of named strategies for laying out and adjusting insets to accommodate error messages.
263      * An appropriate one will be chosen based on the owner field's {@link Ext.form.Labelable#msgTarget} config.
264      */
265     errorStrategies: (function() {
266         function setDisplayed(el, displayed) {
267             var wasDisplayed = el.getStyle('display') !== 'none';
268             if (displayed !== wasDisplayed) {
269                 el.setDisplayed(displayed);
270             }
271         }
272
273         function setStyle(el, name, value) {
274             if (el.getStyle(name) !== value) {
275                 el.setStyle(name, value);
276             }
277         }
278         
279         function showTip(owner) {
280             var tip = Ext.layout.component.field.Field.tip,
281                 target;
282                 
283             if (tip &amp;&amp; tip.isVisible()) {
284                 target = tip.activeTarget;
285                 if (target &amp;&amp; target.el === owner.getActionEl().dom) {
286                     tip.toFront(true);
287                 }
288             }
289         }
290
291         var applyIf = Ext.applyIf,
292             emptyFn = Ext.emptyFn,
293             base = {
294                 prepare: function(owner) {
295                     setDisplayed(owner.errorEl, false);
296                 },
297                 adjustHorizInsets: emptyFn,
298                 adjustVertInsets: emptyFn,
299                 layoutHoriz: emptyFn,
300                 layoutVert: emptyFn,
301                 onFocus: emptyFn
302             };
303
304         return {
305             none: base,
306
307 <span id='Ext-layout-component-field-Field-property-side'>            /**
308 </span>             * Error displayed as icon (with QuickTip on hover) to right of the bodyEl
309              */
310             side: applyIf({
311                 prepare: function(owner) {
312                     var errorEl = owner.errorEl;
313                     errorEl.addCls(Ext.baseCSSPrefix + 'form-invalid-icon');
314                     Ext.layout.component.field.Field.initTip();
315                     errorEl.dom.setAttribute('data-errorqtip', owner.getActiveError() || '');
316                     setDisplayed(errorEl, owner.hasActiveError());
317                 },
318                 adjustHorizInsets: function(owner, info) {
319                     if (owner.autoFitErrors &amp;&amp; owner.hasActiveError()) {
320                         info.insets.right += owner.errorEl.getWidth();
321                     }
322                 },
323                 layoutHoriz: function(owner, info) {
324                     if (owner.hasActiveError()) {
325                         setStyle(owner.errorEl, 'left', info.width - info.insets.right + 'px');
326                     }
327                 },
328                 layoutVert: function(owner, info) {
329                     if (owner.hasActiveError()) {
330                         setStyle(owner.errorEl, 'top', info.insets.top + 'px');
331                     }
332                 },
333                 onFocus: showTip
334             }, base),
335
336 <span id='Ext-layout-component-field-Field-property-under'>            /**
337 </span>             * Error message displayed underneath the bodyEl
338              */
339             under: applyIf({
340                 prepare: function(owner) {
341                     var errorEl = owner.errorEl,
342                         cls = Ext.baseCSSPrefix + 'form-invalid-under';
343                     if (!errorEl.hasCls(cls)) {
344                         errorEl.addCls(cls);
345                     }
346                     setDisplayed(errorEl, owner.hasActiveError());
347                 },
348                 adjustVertInsets: function(owner, info) {
349                     if (owner.autoFitErrors) {
350                         info.insets.bottom += owner.errorEl.getHeight();
351                     }
352                 },
353                 layoutHoriz: function(owner, info) {
354                     var errorEl = owner.errorEl,
355                         insets = info.insets;
356
357                     setStyle(errorEl, 'width', info.width - insets.right - insets.left + 'px');
358                     setStyle(errorEl, 'marginLeft', insets.left + 'px');
359                 }
360             }, base),
361
362 <span id='Ext-layout-component-field-Field-property-qtip'>            /**
363 </span>             * Error displayed as QuickTip on hover of the field container
364              */
365             qtip: applyIf({
366                 prepare: function(owner) {
367                     setDisplayed(owner.errorEl, false);
368                     Ext.layout.component.field.Field.initTip();
369                     owner.getActionEl().dom.setAttribute('data-errorqtip', owner.getActiveError() || '');
370                 },
371                 onFocus: showTip
372             }, base),
373
374 <span id='Ext-layout-component-field-Field-property-title'>            /**
375 </span>             * Error displayed as title tip on hover of the field container
376              */
377             title: applyIf({
378                 prepare: function(owner) {
379                     setDisplayed(owner.errorEl, false);
380                     owner.el.dom.title = owner.getActiveError() || '';
381                 }
382             }, base),
383
384 <span id='Ext-layout-component-field-Field-property-elementId'>            /**
385 </span>             * Error message displayed as content of an element with a given id elsewhere in the app
386              */
387             elementId: applyIf({
388                 prepare: function(owner) {
389                     setDisplayed(owner.errorEl, false);
390                     var targetEl = Ext.fly(owner.msgTarget);
391                     if (targetEl) {
392                         targetEl.dom.innerHTML = owner.getActiveError() || '';
393                         targetEl.setDisplayed(owner.hasActiveError());
394                     }
395                 }
396             }, base)
397         };
398     })(),
399
400     statics: {
401 <span id='Ext-layout-component-field-Field-method-initTip'>        /**
402 </span>         * Use a custom QuickTip instance separate from the main QuickTips singleton, so that we
403          * can give it a custom frame style. Responds to errorqtip rather than the qtip property.
404          */
405         initTip: function() {
406             var tip = this.tip;
407             if (!tip) {
408                 tip = this.tip = Ext.create('Ext.tip.QuickTip', {
409                     baseCls: Ext.baseCSSPrefix + 'form-invalid-tip',
410                     renderTo: Ext.getBody()
411                 });
412                 tip.tagConfig = Ext.apply({}, {attribute: 'errorqtip'}, tip.tagConfig);
413             }
414         },
415
416 <span id='Ext-layout-component-field-Field-method-destroyTip'>        /**
417 </span>         * Destroy the error tip instance.
418          */
419         destroyTip: function() {
420             var tip = this.tip;
421             if (tip) {
422                 tip.destroy();
423                 delete this.tip;
424             }
425         }
426     }
427
428 });
429 </pre>
430 </body>
431 </html>