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; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
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.
25 Ext.define('Ext.layout.component.field.Field', {
27 /* Begin Definitions */
29 alias: ['layout.field'],
31 extend: 'Ext.layout.component.Component',
33 uses: ['Ext.tip.QuickTip', 'Ext.util.TextMetrics'],
39 beforeLayout: function(width, height) {
41 return me.callParent(arguments) || (!me.owner.preventMark && me.activeError !== me.owner.getActiveError());
44 onLayout: function(width, height) {
47 labelStrategy = me.getLabelStrategy(),
48 errorStrategy = me.getErrorStrategy(),
49 isDefined = Ext.isDefined,
50 isNumber = Ext.isNumber,
51 lastSize, autoWidth, autoHeight, info, undef;
53 lastSize = me.lastComponentSize || {};
54 if (!isDefined(width)) {
55 width = lastSize.width;
56 if (width < 0) { //first pass lastComponentSize.width is -Infinity
60 if (!isDefined(height)) {
61 height = lastSize.height;
62 if (height < 0) { //first pass lastComponentSize.height is -Infinity
66 autoWidth = !isNumber(width);
67 autoHeight = !isNumber(height);
71 autoHeight: autoHeight,
72 width: autoWidth ? owner.getBodyNaturalWidth() : width, //always give a pixel width
74 setOuterWidth: false, //whether the outer el width should be set to the calculated width
76 // insets for the bodyEl from each side of the component layout area
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.
89 // perform preparation on the label and error (setting css classes, qtips, etc.)
90 labelStrategy.prepare(owner, info);
91 errorStrategy.prepare(owner, info);
93 // calculate the horizontal insets for the label and error
94 labelStrategy.adjustHorizInsets(owner, info);
95 errorStrategy.adjustHorizInsets(owner, info);
97 // set horizontal styles for label and error based on the current insets
98 labelStrategy.layoutHoriz(owner, info);
99 errorStrategy.layoutHoriz(owner, info);
101 // calculate the vertical insets for the label and error
102 labelStrategy.adjustVertInsets(owner, info);
103 errorStrategy.adjustVertInsets(owner, info);
105 // set vertical styles for label and error based on the current insets
106 labelStrategy.layoutVert(owner, info);
107 errorStrategy.layoutVert(owner, info);
109 // perform sizing of the elements based on the final dimensions and insets
110 if (autoWidth && 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);
114 me.setTargetSize((!autoWidth || info.setOuterWidth ? info.width : undef), info.height);
118 me.activeError = owner.getActiveError();
122 this.getErrorStrategy().onFocus(this.owner);
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.
129 sizeBody: function(info) {
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;
139 me.setElementSize(owner.bodyEl, width, height);
141 // size the bodyEl's inner contents if necessary
142 me.sizeBodyContents(width, height);
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
151 sizeBodyContents: Ext.emptyFn,
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.
158 getLabelStrategy: function() {
160 strategies = me.labelStrategies,
161 labelAlign = me.owner.labelAlign;
162 return strategies[labelAlign] || strategies.base;
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.
169 getErrorStrategy: function() {
172 strategies = me.errorStrategies,
173 msgTarget = owner.msgTarget;
174 return !owner.preventMark && Ext.isString(msgTarget) ?
175 (strategies[msgTarget] || strategies.elementId) :
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.
185 labelStrategies: (function() {
186 var applyIf = Ext.applyIf,
187 emptyFn = Ext.emptyFn,
189 prepare: function(owner, info) {
190 var cls = owner.labelCls + '-' + owner.labelAlign,
191 labelEl = owner.labelEl;
192 if (labelEl && !labelEl.hasCls(cls)) {
196 adjustHorizInsets: emptyFn,
197 adjustVertInsets: emptyFn,
198 layoutHoriz: emptyFn,
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);
208 // Must set outer width to prevent field from wrapping below floated label
209 info.setOuterWidth = true;
211 adjustHorizInsets: function(owner, info) {
213 info.insets.left += owner.labelWidth + owner.labelPad;
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
222 var labelEl = owner.labelEl;
223 if (labelEl && !owner.isLabelSized && !Ext.isBorderBox) {
224 labelEl.setWidth(owner.labelWidth);
225 owner.isLabelSized = true;
234 <span id='Ext-layout-component-field-Field-property-top'> /**
235 </span> * Label displayed above the bodyEl
238 adjustVertInsets: function(owner, info) {
239 var labelEl = owner.labelEl;
241 info.insets.top += Ext.util.TextMetrics.measure(labelEl, owner.fieldLabel, info.width).height +
242 labelEl.getFrameWidth('tb') + owner.labelPad;
247 <span id='Ext-layout-component-field-Field-property-left'> /**
248 </span> * Label displayed to the left of the bodyEl
252 <span id='Ext-layout-component-field-Field-property-right'> /**
253 </span> * Same as left, only difference is text-align in CSS
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.
265 errorStrategies: (function() {
266 function setDisplayed(el, displayed) {
267 var wasDisplayed = el.getStyle('display') !== 'none';
268 if (displayed !== wasDisplayed) {
269 el.setDisplayed(displayed);
273 function setStyle(el, name, value) {
274 if (el.getStyle(name) !== value) {
275 el.setStyle(name, value);
279 function showTip(owner) {
280 var tip = Ext.layout.component.field.Field.tip,
283 if (tip && tip.isVisible()) {
284 target = tip.activeTarget;
285 if (target && target.el === owner.getActionEl().dom) {
291 var applyIf = Ext.applyIf,
292 emptyFn = Ext.emptyFn,
294 prepare: function(owner) {
295 setDisplayed(owner.errorEl, false);
297 adjustHorizInsets: emptyFn,
298 adjustVertInsets: emptyFn,
299 layoutHoriz: emptyFn,
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
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());
318 adjustHorizInsets: function(owner, info) {
319 if (owner.autoFitErrors && owner.hasActiveError()) {
320 info.insets.right += owner.errorEl.getWidth();
323 layoutHoriz: function(owner, info) {
324 if (owner.hasActiveError()) {
325 setStyle(owner.errorEl, 'left', info.width - info.insets.right + 'px');
328 layoutVert: function(owner, info) {
329 if (owner.hasActiveError()) {
330 setStyle(owner.errorEl, 'top', info.insets.top + 'px');
336 <span id='Ext-layout-component-field-Field-property-under'> /**
337 </span> * Error message displayed underneath the bodyEl
340 prepare: function(owner) {
341 var errorEl = owner.errorEl,
342 cls = Ext.baseCSSPrefix + 'form-invalid-under';
343 if (!errorEl.hasCls(cls)) {
346 setDisplayed(errorEl, owner.hasActiveError());
348 adjustVertInsets: function(owner, info) {
349 if (owner.autoFitErrors) {
350 info.insets.bottom += owner.errorEl.getHeight();
353 layoutHoriz: function(owner, info) {
354 var errorEl = owner.errorEl,
355 insets = info.insets;
357 setStyle(errorEl, 'width', info.width - insets.right - insets.left + 'px');
358 setStyle(errorEl, 'marginLeft', insets.left + 'px');
362 <span id='Ext-layout-component-field-Field-property-qtip'> /**
363 </span> * Error displayed as QuickTip on hover of the field container
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() || '');
374 <span id='Ext-layout-component-field-Field-property-title'> /**
375 </span> * Error displayed as title tip on hover of the field container
378 prepare: function(owner) {
379 setDisplayed(owner.errorEl, false);
380 owner.el.dom.title = owner.getActiveError() || '';
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
388 prepare: function(owner) {
389 setDisplayed(owner.errorEl, false);
390 var targetEl = Ext.fly(owner.msgTarget);
392 targetEl.dom.innerHTML = owner.getActiveError() || '';
393 targetEl.setDisplayed(owner.hasActiveError());
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.
405 initTip: function() {
408 tip = this.tip = Ext.create('Ext.tip.QuickTip', {
409 baseCls: Ext.baseCSSPrefix + 'form-invalid-tip',
410 renderTo: Ext.getBody()
412 tip.tagConfig = Ext.apply({}, {attribute: 'errorqtip'}, tip.tagConfig);
416 <span id='Ext-layout-component-field-Field-method-destroyTip'> /**
417 </span> * Destroy the error tip instance.
419 destroyTip: function() {