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-form-Labelable'>/**
19 </span> * A mixin which allows a component to be configured and decorated with a label and/or error message as is
20 * common for form fields. This is used by e.g. Ext.form.field.Base and Ext.form.FieldContainer
21 * to let them be managed by the Field layout.
23 * NOTE: This mixin is mainly for internal library use and most users should not need to use it directly. It
24 * is more likely you will want to use one of the component classes that import this mixin, such as
25 * Ext.form.field.Base or Ext.form.FieldContainer.
27 * Use of this mixin does not make a component a field in the logical sense, meaning it does not provide any
28 * logic or state related to values or validation; that is handled by the related Ext.form.field.Field
29 * mixin. These two mixins may be used separately (for example Ext.form.FieldContainer is Labelable but not a
30 * Field), or in combination (for example Ext.form.field.Base implements both and has logic for connecting the
33 * Component classes which use this mixin should use the Field layout
34 * or a derivation thereof to properly size and position the label and message according to the component config.
35 * They must also call the {@link #initLabelable} method during component initialization to ensure the mixin gets
38 * @docauthor Jason Johnston <jason@sencha.com>
40 Ext.define("Ext.form.Labelable", {
41 requires: ['Ext.XTemplate'],
43 <span id='Ext-form-Labelable-cfg-labelableRenderTpl'> /**
44 </span> * @cfg {String/String[]/Ext.XTemplate} labelableRenderTpl
45 * The rendering template for the field decorations. Component classes using this mixin should include
46 * logic to use this as their {@link Ext.AbstractComponent#renderTpl renderTpl}, and implement the
47 * {@link #getSubTplMarkup} method to generate the field body content.
50 '<tpl if="!hideLabel && !(!fieldLabel && hideEmptyLabel)">',
51 '<label id="{id}-labelEl"<tpl if="inputId"> for="{inputId}"</tpl> class="{labelCls}"',
52 '<tpl if="labelStyle"> style="{labelStyle}"</tpl>>',
53 '<tpl if="fieldLabel">{fieldLabel}{labelSeparator}</tpl>',
56 '<div class="{baseBodyCls} {fieldBodyCls}" id="{id}-bodyEl" role="presentation">{subTplMarkup}</div>',
57 '<div id="{id}-errorEl" class="{errorMsgCls}" style="display:none"></div>',
58 '<div class="{clearCls}" role="presentation"><!-- --></div>',
65 <span id='Ext-form-Labelable-cfg-activeErrorsTpl'> /**
66 </span> * @cfg {Ext.XTemplate} activeErrorsTpl
67 * The template used to format the Array of error messages passed to {@link #setActiveErrors}
68 * into a single HTML string. By default this renders each message as an item in an unordered list.
71 '<tpl if="errors && errors.length">',
72 '<ul><tpl for="errors"><li<tpl if="xindex == xcount"> class="last"</tpl>>{.}</li></tpl></ul>',
76 <span id='Ext-form-Labelable-property-isFieldLabelable'> /**
77 </span> * @property isFieldLabelable
79 * Flag denoting that this object is labelable as a field. Always true.
81 isFieldLabelable: true,
83 <span id='Ext-form-Labelable-cfg-formItemCls'> /**
84 </span> * @cfg {String} [formItemCls='x-form-item']
85 * A CSS class to be applied to the outermost element to denote that it is participating in the form
88 formItemCls: Ext.baseCSSPrefix + 'form-item',
90 <span id='Ext-form-Labelable-cfg-labelCls'> /**
91 </span> * @cfg {String} [labelCls='x-form-item-label']
92 * The CSS class to be applied to the label element.
93 * This (single) CSS class is used to formulate the renderSelector and drives the field
94 * layout where it is concatenated with a hyphen ('-') and {@link #labelAlign}. To add
95 * additional classes, use {@link #labelClsExtra}.
97 labelCls: Ext.baseCSSPrefix + 'form-item-label',
99 <span id='Ext-form-Labelable-cfg-labelClsExtra'> /**
100 </span> * @cfg {String} labelClsExtra
101 * An optional string of one or more additional CSS classes to add to the label element.
105 <span id='Ext-form-Labelable-cfg-errorMsgCls'> /**
106 </span> * @cfg {String} [errorMsgCls='x-form-error-msg']
107 * The CSS class to be applied to the error message element.
109 errorMsgCls: Ext.baseCSSPrefix + 'form-error-msg',
111 <span id='Ext-form-Labelable-cfg-baseBodyCls'> /**
112 </span> * @cfg {String} [baseBodyCls='x-form-item-body']
113 * The CSS class to be applied to the body content element.
115 baseBodyCls: Ext.baseCSSPrefix + 'form-item-body',
117 <span id='Ext-form-Labelable-cfg-fieldBodyCls'> /**
118 </span> * @cfg {String} fieldBodyCls
119 * An extra CSS class to be applied to the body content element in addition to {@link #fieldBodyCls}.
123 <span id='Ext-form-Labelable-cfg-clearCls'> /**
124 </span> * @cfg {String} [clearCls='x-clear']
125 * The CSS class to be applied to the special clearing div rendered directly after the field
126 * contents wrapper to provide field clearing.
128 clearCls: Ext.baseCSSPrefix + 'clear',
130 <span id='Ext-form-Labelable-cfg-invalidCls'> /**
131 </span> * @cfg {String} [invalidCls='x-form-invalid']
132 * The CSS class to use when marking the component invalid.
134 invalidCls : Ext.baseCSSPrefix + 'form-invalid',
136 <span id='Ext-form-Labelable-cfg-fieldLabel'> /**
137 </span> * @cfg {String} fieldLabel
138 * The label for the field. It gets appended with the {@link #labelSeparator}, and its position
139 * and sizing is determined by the {@link #labelAlign}, {@link #labelWidth}, and {@link #labelPad}
142 fieldLabel: undefined,
144 <span id='Ext-form-Labelable-cfg-labelAlign'> /**
145 </span> * @cfg {String} labelAlign
146 * <p>Controls the position and alignment of the {@link #fieldLabel}. Valid values are:</p>
148 * <li><tt>"left"</tt> (the default) - The label is positioned to the left of the field, with its text
149 * aligned to the left. Its width is determined by the {@link #labelWidth} config.</li>
150 * <li><tt>"top"</tt> - The label is positioned above the field.</li>
151 * <li><tt>"right"</tt> - The label is positioned to the left of the field, with its text aligned
152 * to the right. Its width is determined by the {@link #labelWidth} config.</li>
157 <span id='Ext-form-Labelable-cfg-labelWidth'> /**
158 </span> * @cfg {Number} labelWidth
159 * The width of the {@link #fieldLabel} in pixels. Only applicable if the {@link #labelAlign} is set
160 * to "left" or "right".
164 <span id='Ext-form-Labelable-cfg-labelPad'> /**
165 </span> * @cfg {Number} labelPad
166 * The amount of space in pixels between the {@link #fieldLabel} and the input field.
170 <span id='Ext-form-Labelable-cfg-labelSeparator'> /**
171 </span> * @cfg {String} labelSeparator
172 * Character(s) to be inserted at the end of the {@link #fieldLabel label text}.
174 labelSeparator : ':',
176 <span id='Ext-form-Labelable-cfg-labelStyle'> /**
177 </span> * @cfg {String} labelStyle
178 * A CSS style specification string to apply directly to this field's label.
181 <span id='Ext-form-Labelable-cfg-hideLabel'> /**
182 </span> * @cfg {Boolean} hideLabel
183 * Set to true to completely hide the label element ({@link #fieldLabel} and {@link #labelSeparator}).
184 * Also see {@link #hideEmptyLabel}, which controls whether space will be reserved for an empty fieldLabel.
188 <span id='Ext-form-Labelable-cfg-hideEmptyLabel'> /**
189 </span> * @cfg {Boolean} hideEmptyLabel
190 * <p>When set to <tt>true</tt>, the label element ({@link #fieldLabel} and {@link #labelSeparator}) will be
191 * automatically hidden if the {@link #fieldLabel} is empty. Setting this to <tt>false</tt> will cause the empty
192 * label element to be rendered and space to be reserved for it; this is useful if you want a field without a label
193 * to line up with other labeled fields in the same form.</p>
194 * <p>If you wish to unconditionall hide the label even if a non-empty fieldLabel is configured, then set
195 * the {@link #hideLabel} config to <tt>true</tt>.</p>
197 hideEmptyLabel: true,
199 <span id='Ext-form-Labelable-cfg-preventMark'> /**
200 </span> * @cfg {Boolean} preventMark
201 * <tt>true</tt> to disable displaying any {@link #setActiveError error message} set on this object.
205 <span id='Ext-form-Labelable-cfg-autoFitErrors'> /**
206 </span> * @cfg {Boolean} autoFitErrors
207 * Whether to adjust the component's body area to make room for 'side' or 'under'
208 * {@link #msgTarget error messages}.
212 <span id='Ext-form-Labelable-cfg-msgTarget'> /**
213 </span> * @cfg {String} msgTarget <p>The location where the error message text should display.
214 * Must be one of the following values:</p>
215 * <div class="mdetail-params"><ul>
216 * <li><code>qtip</code> Display a quick tip containing the message when the user hovers over the field. This is the default.
217 * <div class="subdesc"><b>{@link Ext.tip.QuickTipManager#init Ext.tip.QuickTipManager.init} must have been called for this setting to work.</b></div></li>
218 * <li><code>title</code> Display the message in a default browser title attribute popup.</li>
219 * <li><code>under</code> Add a block div beneath the field containing the error message.</li>
220 * <li><code>side</code> Add an error icon to the right of the field, displaying the message in a popup on hover.</li>
221 * <li><code>none</code> Don't display any error message. This might be useful if you are implementing custom error display.</li>
222 * <li><code>[element id]</code> Add the error message directly to the innerHTML of the specified element.</li>
223 * </ul></div>
227 <span id='Ext-form-Labelable-cfg-activeError'> /**
228 </span> * @cfg {String} activeError
229 * If specified, then the component will be displayed with this value as its active error when
230 * first rendered. Use {@link #setActiveError} or {@link #unsetActiveError} to
231 * change it after component creation.
235 <span id='Ext-form-Labelable-method-initLabelable'> /**
236 </span> * Performs initialization of this mixin. Component classes using this mixin should call this method
237 * during their own initialization.
239 initLabelable: function() {
240 this.addCls(this.formItemCls);
243 <span id='Ext-form-Labelable-event-errorchange'> /**
244 </span> * @event errorchange
245 * Fires when the active error message is changed via {@link #setActiveError}.
246 * @param {Ext.form.Labelable} this
247 * @param {String} error The active error message
253 <span id='Ext-form-Labelable-method-getFieldLabel'> /**
254 </span> * Returns the label for the field. Defaults to simply returning the {@link #fieldLabel} config. Can be
255 * overridden to provide
256 * @return {String} The configured field label, or empty string if not defined
258 getFieldLabel: function() {
259 return this.fieldLabel || '';
262 <span id='Ext-form-Labelable-method-getLabelableRenderData'> /**
264 * Generates the arguments for the field decorations {@link #labelableRenderTpl rendering template}.
265 * @return {Object} The template arguments
267 getLabelableRenderData: function() {
269 labelAlign = me.labelAlign,
270 labelCls = me.labelCls,
271 labelClsExtra = me.labelClsExtra,
272 labelPad = me.labelPad,
275 // Calculate label styles up front rather than in the Field layout for speed; this
276 // is safe because label alignment/width/pad are not expected to change.
277 if (labelAlign === 'top') {
278 labelStyle = 'margin-bottom:' + labelPad + 'px;';
280 labelStyle = 'margin-right:' + labelPad + 'px;';
281 // Add the width for border-box browsers; will be set by the Field layout for content-box
282 if (Ext.isBorderBox) {
283 labelStyle += 'width:' + me.labelWidth + 'px;';
289 inputId: me.getInputId(),
290 fieldLabel: me.getFieldLabel(),
291 labelCls: labelClsExtra ? labelCls + ' ' + labelClsExtra : labelCls,
292 labelStyle: labelStyle + (me.labelStyle || ''),
293 subTplMarkup: me.getSubTplMarkup()
296 'hideLabel,hideEmptyLabel,fieldBodyCls,baseBodyCls,errorMsgCls,clearCls,labelSeparator',
301 onLabelableRender: function () {
303 <span id='Ext-form-Labelable-property-labelEl'> /**
304 </span> * @property labelEl
306 * The label Element for this component. Only available after the component has been rendered.
310 <span id='Ext-form-Labelable-property-bodyEl'> /**
311 </span> * @property bodyEl
313 * The div Element wrapping the component's contents. Only available after the component has been rendered.
317 <span id='Ext-form-Labelable-property-errorEl'> /**
318 </span> * @property errorEl
320 * The div Element that will contain the component's error message(s). Note that depending on the
321 * configured {@link #msgTarget}, this element may be hidden in favor of some other form of
322 * presentation, but will always be present in the DOM for use by assistive technologies.
328 <span id='Ext-form-Labelable-method-getSubTplMarkup'> /**
330 * Gets the markup to be inserted into the outer template's bodyEl. Defaults to empty string, should
331 * be implemented by classes including this mixin as needed.
332 * @return {String} The markup to be inserted
334 getSubTplMarkup: function() {
338 <span id='Ext-form-Labelable-method-getInputId'> /**
339 </span> * Get the input id, if any, for this component. This is used as the "for" attribute on the label element.
340 * Implementing subclasses may also use this as e.g. the id for their own <tt>input</tt> element.
341 * @return {String} The input id
343 getInputId: function() {
347 <span id='Ext-form-Labelable-method-getActiveError'> /**
348 </span> * Gets the active error message for this component, if any. This does not trigger
349 * validation on its own, it merely returns any message that the component may already hold.
350 * @return {String} The active error message on the component; if there is no error, an empty string is returned.
352 getActiveError : function() {
353 return this.activeError || '';
356 <span id='Ext-form-Labelable-method-hasActiveError'> /**
357 </span> * Tells whether the field currently has an active error message. This does not trigger
358 * validation on its own, it merely looks for any message that the component may already hold.
361 hasActiveError: function() {
362 return !!this.getActiveError();
365 <span id='Ext-form-Labelable-method-setActiveError'> /**
366 </span> * Sets the active error message to the given string. This replaces the entire error message
367 * contents with the given string. Also see {@link #setActiveErrors} which accepts an Array of
368 * messages and formats them according to the {@link #activeErrorsTpl}.
370 * Note that this only updates the error message element's text and attributes, you'll have
371 * to call doComponentLayout to actually update the field's layout to match. If the field extends
372 * {@link Ext.form.field.Base} you should call {@link Ext.form.field.Base#markInvalid markInvalid} instead.
374 * @param {String} msg The error message
376 setActiveError: function(msg) {
377 this.activeError = msg;
378 this.activeErrors = [msg];
379 this.renderActiveError();
382 <span id='Ext-form-Labelable-method-getActiveErrors'> /**
383 </span> * Gets an Array of any active error messages currently applied to the field. This does not trigger
384 * validation on its own, it merely returns any messages that the component may already hold.
385 * @return {String[]} The active error messages on the component; if there are no errors, an empty Array is returned.
387 getActiveErrors: function() {
388 return this.activeErrors || [];
391 <span id='Ext-form-Labelable-method-setActiveErrors'> /**
392 </span> * Set the active error message to an Array of error messages. The messages are formatted into
393 * a single message string using the {@link #activeErrorsTpl}. Also see {@link #setActiveError}
394 * which allows setting the entire error contents with a single string.
396 * Note that this only updates the error message element's text and attributes, you'll have
397 * to call doComponentLayout to actually update the field's layout to match. If the field extends
398 * {@link Ext.form.field.Base} you should call {@link Ext.form.field.Base#markInvalid markInvalid} instead.
400 * @param {String[]} errors The error messages
402 setActiveErrors: function(errors) {
403 this.activeErrors = errors;
404 this.activeError = this.getTpl('activeErrorsTpl').apply({errors: errors});
405 this.renderActiveError();
408 <span id='Ext-form-Labelable-method-unsetActiveError'> /**
409 </span> * Clears the active error message(s).
411 * Note that this only clears the error message element's text and attributes, you'll have
412 * to call doComponentLayout to actually update the field's layout to match. If the field extends
413 * {@link Ext.form.field.Base} you should call {@link Ext.form.field.Base#clearInvalid clearInvalid} instead.
415 unsetActiveError: function() {
416 delete this.activeError;
417 delete this.activeErrors;
418 this.renderActiveError();
421 <span id='Ext-form-Labelable-method-renderActiveError'> /**
423 * Updates the rendered DOM to match the current activeError. This only updates the content and
424 * attributes, you'll have to call doComponentLayout to actually update the display.
426 renderActiveError: function() {
428 activeError = me.getActiveError(),
429 hasError = !!activeError;
431 if (activeError !== me.lastActiveError) {
432 me.fireEvent('errorchange', me, activeError);
433 me.lastActiveError = activeError;
436 if (me.rendered && !me.isDestroyed && !me.preventMark) {
437 // Add/remove invalid class
438 me.el[hasError ? 'addCls' : 'removeCls'](me.invalidCls);
440 // Update the aria-invalid attribute
441 me.getActionEl().dom.setAttribute('aria-invalid', hasError);
443 // Update the errorEl with the error message text
444 me.errorEl.dom.innerHTML = activeError;
448 <span id='Ext-form-Labelable-method-setFieldDefaults'> /**
449 </span> * Applies a set of default configuration values to this Labelable instance. For each of the
450 * properties in the given object, check if this component hasOwnProperty that config; if not
451 * then it's inheriting a default value from its prototype and we should apply the default value.
452 * @param {Object} defaults The defaults to apply to the object.
454 setFieldDefaults: function(defaults) {
456 Ext.iterate(defaults, function(key, val) {
457 if (!me.hasOwnProperty(key)) {
463 <span id='Ext-form-Labelable-method-getBodyNaturalWidth'> /**
464 </span> * @protected Calculate and return the natural width of the bodyEl. Override to provide custom logic.
465 * Note for implementors: if at all possible this method should be overridden with a custom implementation
466 * that can avoid anything that would cause the browser to reflow, e.g. querying offsetWidth.
468 getBodyNaturalWidth: function() {
469 return this.bodyEl.getWidth();