[76] | 1 | /*! |
---|
| 2 | * Ext JS Library 3.4.0 |
---|
| 3 | * Copyright(c) 2006-2011 Sencha Inc. |
---|
| 4 | * licensing@sencha.com |
---|
| 5 | * http://www.sencha.com/license |
---|
| 6 | */ |
---|
| 7 | /** |
---|
| 8 | * @class Ext.layout.FormLayout |
---|
| 9 | * @extends Ext.layout.AnchorLayout |
---|
| 10 | * <p>This layout manager is specifically designed for rendering and managing child Components of |
---|
| 11 | * {@link Ext.form.FormPanel forms}. It is responsible for rendering the labels of |
---|
| 12 | * {@link Ext.form.Field Field}s.</p> |
---|
| 13 | * |
---|
| 14 | * <p>This layout manager is used when a Container is configured with the <tt>layout:'form'</tt> |
---|
| 15 | * {@link Ext.Container#layout layout} config option, and should generally not need to be created directly |
---|
| 16 | * via the new keyword. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p> |
---|
| 17 | * |
---|
| 18 | * <p>In an application, it will usually be preferrable to use a {@link Ext.form.FormPanel FormPanel} |
---|
| 19 | * (which is configured with FormLayout as its layout class by default) since it also provides built-in |
---|
| 20 | * functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form.</p> |
---|
| 21 | * |
---|
| 22 | * <p>A {@link Ext.Container Container} <i>using</i> the FormLayout layout manager (e.g. |
---|
| 23 | * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) can also accept the following |
---|
| 24 | * layout-specific config properties:<div class="mdetail-params"><ul> |
---|
| 25 | * <li><b><tt>{@link Ext.form.FormPanel#hideLabels hideLabels}</tt></b></li> |
---|
| 26 | * <li><b><tt>{@link Ext.form.FormPanel#labelAlign labelAlign}</tt></b></li> |
---|
| 27 | * <li><b><tt>{@link Ext.form.FormPanel#labelPad labelPad}</tt></b></li> |
---|
| 28 | * <li><b><tt>{@link Ext.form.FormPanel#labelSeparator labelSeparator}</tt></b></li> |
---|
| 29 | * <li><b><tt>{@link Ext.form.FormPanel#labelWidth labelWidth}</tt></b></li> |
---|
| 30 | * </ul></div></p> |
---|
| 31 | * |
---|
| 32 | * <p>Any Component (including Fields) managed by FormLayout accepts the following as a config option: |
---|
| 33 | * <div class="mdetail-params"><ul> |
---|
| 34 | * <li><b><tt>{@link Ext.Component#anchor anchor}</tt></b></li> |
---|
| 35 | * </ul></div></p> |
---|
| 36 | * |
---|
| 37 | * <p>Any Component managed by FormLayout may be rendered as a form field (with an associated label) by |
---|
| 38 | * configuring it with a non-null <b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b>. Components configured |
---|
| 39 | * in this way may be configured with the following options which affect the way the FormLayout renders them: |
---|
| 40 | * <div class="mdetail-params"><ul> |
---|
| 41 | * <li><b><tt>{@link Ext.Component#clearCls clearCls}</tt></b></li> |
---|
| 42 | * <li><b><tt>{@link Ext.Component#fieldLabel fieldLabel}</tt></b></li> |
---|
| 43 | * <li><b><tt>{@link Ext.Component#hideLabel hideLabel}</tt></b></li> |
---|
| 44 | * <li><b><tt>{@link Ext.Component#itemCls itemCls}</tt></b></li> |
---|
| 45 | * <li><b><tt>{@link Ext.Component#labelSeparator labelSeparator}</tt></b></li> |
---|
| 46 | * <li><b><tt>{@link Ext.Component#labelStyle labelStyle}</tt></b></li> |
---|
| 47 | * </ul></div></p> |
---|
| 48 | * |
---|
| 49 | * <p>Example usage:</p> |
---|
| 50 | * <pre><code> |
---|
| 51 | // Required if showing validation messages |
---|
| 52 | Ext.QuickTips.init(); |
---|
| 53 | |
---|
| 54 | // While you can create a basic Panel with layout:'form', practically |
---|
| 55 | // you should usually use a FormPanel to also get its form functionality |
---|
| 56 | // since it already creates a FormLayout internally. |
---|
| 57 | var form = new Ext.form.FormPanel({ |
---|
| 58 | title: 'Form Layout', |
---|
| 59 | bodyStyle: 'padding:15px', |
---|
| 60 | width: 350, |
---|
| 61 | defaultType: 'textfield', |
---|
| 62 | defaults: { |
---|
| 63 | // applied to each contained item |
---|
| 64 | width: 230, |
---|
| 65 | msgTarget: 'side' |
---|
| 66 | }, |
---|
| 67 | items: [{ |
---|
| 68 | fieldLabel: 'First Name', |
---|
| 69 | name: 'first', |
---|
| 70 | allowBlank: false, |
---|
| 71 | {@link Ext.Component#labelSeparator labelSeparator}: ':' // override labelSeparator layout config |
---|
| 72 | },{ |
---|
| 73 | fieldLabel: 'Last Name', |
---|
| 74 | name: 'last' |
---|
| 75 | },{ |
---|
| 76 | fieldLabel: 'Email', |
---|
| 77 | name: 'email', |
---|
| 78 | vtype:'email' |
---|
| 79 | }, { |
---|
| 80 | xtype: 'textarea', |
---|
| 81 | hideLabel: true, // override hideLabels layout config |
---|
| 82 | name: 'msg', |
---|
| 83 | anchor: '100% -53' |
---|
| 84 | } |
---|
| 85 | ], |
---|
| 86 | buttons: [ |
---|
| 87 | {text: 'Save'}, |
---|
| 88 | {text: 'Cancel'} |
---|
| 89 | ], |
---|
| 90 | layoutConfig: { |
---|
| 91 | {@link #labelSeparator}: '~' // superseded by assignment below |
---|
| 92 | }, |
---|
| 93 | // config options applicable to container when layout='form': |
---|
| 94 | hideLabels: false, |
---|
| 95 | labelAlign: 'left', // or 'right' or 'top' |
---|
| 96 | {@link Ext.form.FormPanel#labelSeparator labelSeparator}: '>>', // takes precedence over layoutConfig value |
---|
| 97 | labelWidth: 65, // defaults to 100 |
---|
| 98 | labelPad: 8 // defaults to 5, must specify labelWidth to be honored |
---|
| 99 | }); |
---|
| 100 | </code></pre> |
---|
| 101 | */ |
---|
| 102 | Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, { |
---|
| 103 | |
---|
| 104 | /** |
---|
| 105 | * @cfg {String} labelSeparator |
---|
| 106 | * See {@link Ext.form.FormPanel}.{@link Ext.form.FormPanel#labelSeparator labelSeparator}. Configuration |
---|
| 107 | * of this property at the <b>container</b> level takes precedence. |
---|
| 108 | */ |
---|
| 109 | labelSeparator : ':', |
---|
| 110 | |
---|
| 111 | /** |
---|
| 112 | * Read only. The CSS style specification string added to field labels in this layout if not |
---|
| 113 | * otherwise {@link Ext.Component#labelStyle specified by each contained field}. |
---|
| 114 | * @type String |
---|
| 115 | * @property labelStyle |
---|
| 116 | */ |
---|
| 117 | |
---|
| 118 | /** |
---|
| 119 | * @cfg {Boolean} trackLabels |
---|
| 120 | * True to show/hide the field label when the field is hidden. Defaults to <tt>true</tt>. |
---|
| 121 | */ |
---|
| 122 | trackLabels: true, |
---|
| 123 | |
---|
| 124 | type: 'form', |
---|
| 125 | |
---|
| 126 | onRemove: function(c){ |
---|
| 127 | Ext.layout.FormLayout.superclass.onRemove.call(this, c); |
---|
| 128 | if(this.trackLabels){ |
---|
| 129 | c.un('show', this.onFieldShow, this); |
---|
| 130 | c.un('hide', this.onFieldHide, this); |
---|
| 131 | } |
---|
| 132 | // check for itemCt, since we may be removing a fieldset or something similar |
---|
| 133 | var el = c.getPositionEl(), |
---|
| 134 | ct = c.getItemCt && c.getItemCt(); |
---|
| 135 | if (c.rendered && ct) { |
---|
| 136 | if (el && el.dom) { |
---|
| 137 | el.insertAfter(ct); |
---|
| 138 | } |
---|
| 139 | Ext.destroy(ct); |
---|
| 140 | Ext.destroyMembers(c, 'label', 'itemCt'); |
---|
| 141 | if (c.customItemCt) { |
---|
| 142 | Ext.destroyMembers(c, 'getItemCt', 'customItemCt'); |
---|
| 143 | } |
---|
| 144 | } |
---|
| 145 | }, |
---|
| 146 | |
---|
| 147 | // private |
---|
| 148 | setContainer : function(ct){ |
---|
| 149 | Ext.layout.FormLayout.superclass.setContainer.call(this, ct); |
---|
| 150 | if(ct.labelAlign){ |
---|
| 151 | ct.addClass('x-form-label-'+ct.labelAlign); |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | if(ct.hideLabels){ |
---|
| 155 | Ext.apply(this, { |
---|
| 156 | labelStyle: 'display:none', |
---|
| 157 | elementStyle: 'padding-left:0;', |
---|
| 158 | labelAdjust: 0 |
---|
| 159 | }); |
---|
| 160 | }else{ |
---|
| 161 | this.labelSeparator = Ext.isDefined(ct.labelSeparator) ? ct.labelSeparator : this.labelSeparator; |
---|
| 162 | ct.labelWidth = ct.labelWidth || 100; |
---|
| 163 | if(Ext.isNumber(ct.labelWidth)){ |
---|
| 164 | var pad = Ext.isNumber(ct.labelPad) ? ct.labelPad : 5; |
---|
| 165 | Ext.apply(this, { |
---|
| 166 | labelAdjust: ct.labelWidth + pad, |
---|
| 167 | labelStyle: 'width:' + ct.labelWidth + 'px;', |
---|
| 168 | elementStyle: 'padding-left:' + (ct.labelWidth + pad) + 'px' |
---|
| 169 | }); |
---|
| 170 | } |
---|
| 171 | if(ct.labelAlign == 'top'){ |
---|
| 172 | Ext.apply(this, { |
---|
| 173 | labelStyle: 'width:auto;', |
---|
| 174 | labelAdjust: 0, |
---|
| 175 | elementStyle: 'padding-left:0;' |
---|
| 176 | }); |
---|
| 177 | } |
---|
| 178 | } |
---|
| 179 | }, |
---|
| 180 | |
---|
| 181 | // private |
---|
| 182 | isHide: function(c){ |
---|
| 183 | return c.hideLabel || this.container.hideLabels; |
---|
| 184 | }, |
---|
| 185 | |
---|
| 186 | onFieldShow: function(c){ |
---|
| 187 | c.getItemCt().removeClass('x-hide-' + c.hideMode); |
---|
| 188 | |
---|
| 189 | // Composite fields will need to layout after the container is made visible |
---|
| 190 | if (c.isComposite) { |
---|
| 191 | c.doLayout(); |
---|
| 192 | } |
---|
| 193 | }, |
---|
| 194 | |
---|
| 195 | onFieldHide: function(c){ |
---|
| 196 | c.getItemCt().addClass('x-hide-' + c.hideMode); |
---|
| 197 | }, |
---|
| 198 | |
---|
| 199 | //private |
---|
| 200 | getLabelStyle: function(s){ |
---|
| 201 | var ls = '', items = [this.labelStyle, s]; |
---|
| 202 | for (var i = 0, len = items.length; i < len; ++i){ |
---|
| 203 | if (items[i]){ |
---|
| 204 | ls += items[i]; |
---|
| 205 | if (ls.substr(-1, 1) != ';'){ |
---|
| 206 | ls += ';'; |
---|
| 207 | } |
---|
| 208 | } |
---|
| 209 | } |
---|
| 210 | return ls; |
---|
| 211 | }, |
---|
| 212 | |
---|
| 213 | /** |
---|
| 214 | * @cfg {Ext.Template} fieldTpl |
---|
| 215 | * A {@link Ext.Template#compile compile}d {@link Ext.Template} for rendering |
---|
| 216 | * the fully wrapped, labeled and styled form Field. Defaults to:</p><pre><code> |
---|
| 217 | new Ext.Template( |
---|
| 218 | '<div class="x-form-item {itemCls}" tabIndex="-1">', |
---|
| 219 | '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>', |
---|
| 220 | '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">', |
---|
| 221 | '</div><div class="{clearCls}"></div>', |
---|
| 222 | '</div>' |
---|
| 223 | ); |
---|
| 224 | </code></pre> |
---|
| 225 | * <p>This may be specified to produce a different DOM structure when rendering form Fields.</p> |
---|
| 226 | * <p>A description of the properties within the template follows:</p><div class="mdetail-params"><ul> |
---|
| 227 | * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper |
---|
| 228 | * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt> |
---|
| 229 | * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt> |
---|
| 230 | * supplied at the container level.</div></li> |
---|
| 231 | * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li> |
---|
| 232 | * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc"> |
---|
| 233 | * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the |
---|
| 234 | * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li> |
---|
| 235 | * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this |
---|
| 236 | * field (defaults to <tt>''</tt>)</div></li> |
---|
| 237 | * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after |
---|
| 238 | * the text of the label for this field (defaults to a colon <tt>':'</tt> or the |
---|
| 239 | * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li> |
---|
| 240 | * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li> |
---|
| 241 | * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div |
---|
| 242 | * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li> |
---|
| 243 | * </ul></div> |
---|
| 244 | * <p>Also see <tt>{@link #getTemplateArgs}</tt></p> |
---|
| 245 | */ |
---|
| 246 | |
---|
| 247 | /** |
---|
| 248 | * @private |
---|
| 249 | * |
---|
| 250 | */ |
---|
| 251 | renderItem : function(c, position, target){ |
---|
| 252 | if(c && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){ |
---|
| 253 | var args = this.getTemplateArgs(c); |
---|
| 254 | if(Ext.isNumber(position)){ |
---|
| 255 | position = target.dom.childNodes[position] || null; |
---|
| 256 | } |
---|
| 257 | if(position){ |
---|
| 258 | c.itemCt = this.fieldTpl.insertBefore(position, args, true); |
---|
| 259 | }else{ |
---|
| 260 | c.itemCt = this.fieldTpl.append(target, args, true); |
---|
| 261 | } |
---|
| 262 | if(!c.getItemCt){ |
---|
| 263 | // Non form fields don't have getItemCt, apply it here |
---|
| 264 | // This will get cleaned up in onRemove |
---|
| 265 | Ext.apply(c, { |
---|
| 266 | getItemCt: function(){ |
---|
| 267 | return c.itemCt; |
---|
| 268 | }, |
---|
| 269 | customItemCt: true |
---|
| 270 | }); |
---|
| 271 | } |
---|
| 272 | c.label = c.getItemCt().child('label.x-form-item-label'); |
---|
| 273 | if(!c.rendered){ |
---|
| 274 | c.render('x-form-el-' + c.id); |
---|
| 275 | }else if(!this.isValidParent(c, target)){ |
---|
| 276 | Ext.fly('x-form-el-' + c.id).appendChild(c.getPositionEl()); |
---|
| 277 | } |
---|
| 278 | if(this.trackLabels){ |
---|
| 279 | if(c.hidden){ |
---|
| 280 | this.onFieldHide(c); |
---|
| 281 | } |
---|
| 282 | c.on({ |
---|
| 283 | scope: this, |
---|
| 284 | show: this.onFieldShow, |
---|
| 285 | hide: this.onFieldHide |
---|
| 286 | }); |
---|
| 287 | } |
---|
| 288 | this.configureItem(c); |
---|
| 289 | }else { |
---|
| 290 | Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments); |
---|
| 291 | } |
---|
| 292 | }, |
---|
| 293 | |
---|
| 294 | /** |
---|
| 295 | * <p>Provides template arguments for rendering the fully wrapped, labeled and styled form Field.</p> |
---|
| 296 | * <p>This method returns an object hash containing properties used by the layout's {@link #fieldTpl} |
---|
| 297 | * to create a correctly wrapped, labeled and styled form Field. This may be overriden to |
---|
| 298 | * create custom layouts. The properties which must be returned are:</p><div class="mdetail-params"><ul> |
---|
| 299 | * <li><b><tt>itemCls</tt></b> : String<div class="sub-desc">The CSS class applied to the outermost div wrapper |
---|
| 300 | * that contains this field label and field element (the default class is <tt>'x-form-item'</tt> and <tt>itemCls</tt> |
---|
| 301 | * will be added to that). If supplied, <tt>itemCls</tt> at the field level will override the default <tt>itemCls</tt> |
---|
| 302 | * supplied at the container level.</div></li> |
---|
| 303 | * <li><b><tt>id</tt></b> : String<div class="sub-desc">The id of the Field</div></li> |
---|
| 304 | * <li><b><tt>{@link #labelStyle}</tt></b> : String<div class="sub-desc"> |
---|
| 305 | * A CSS style specification string to add to the field label for this field (defaults to <tt>''</tt> or the |
---|
| 306 | * {@link #labelStyle layout's value for <tt>labelStyle</tt>}).</div></li> |
---|
| 307 | * <li><b><tt>label</tt></b> : String<div class="sub-desc">The text to display as the label for this |
---|
| 308 | * field (defaults to the field's configured fieldLabel property)</div></li> |
---|
| 309 | * <li><b><tt>{@link #labelSeparator}</tt></b> : String<div class="sub-desc">The separator to display after |
---|
| 310 | * the text of the label for this field (defaults to a colon <tt>':'</tt> or the |
---|
| 311 | * {@link #labelSeparator layout's value for labelSeparator}). To hide the separator use empty string ''.</div></li> |
---|
| 312 | * <li><b><tt>elementStyle</tt></b> : String<div class="sub-desc">The styles text for the input element's wrapper.</div></li> |
---|
| 313 | * <li><b><tt>clearCls</tt></b> : String<div class="sub-desc">The CSS class to apply to the special clearing div |
---|
| 314 | * rendered directly after each form field wrapper (defaults to <tt>'x-form-clear-left'</tt>)</div></li> |
---|
| 315 | * </ul></div> |
---|
| 316 | * @param (Ext.form.Field} field The {@link Ext.form.Field Field} being rendered. |
---|
| 317 | * @return {Object} An object hash containing the properties required to render the Field. |
---|
| 318 | */ |
---|
| 319 | getTemplateArgs: function(field) { |
---|
| 320 | var noLabelSep = !field.fieldLabel || field.hideLabel, |
---|
| 321 | itemCls = (field.itemCls || this.container.itemCls || '') + (field.hideLabel ? ' x-hide-label' : ''); |
---|
| 322 | |
---|
| 323 | // IE9 quirks needs an extra, identifying class on wrappers of TextFields |
---|
| 324 | if (Ext.isIE9 && Ext.isIEQuirks && field instanceof Ext.form.TextField) { |
---|
| 325 | itemCls += ' x-input-wrapper'; |
---|
| 326 | } |
---|
| 327 | |
---|
| 328 | return { |
---|
| 329 | id : field.id, |
---|
| 330 | label : field.fieldLabel, |
---|
| 331 | itemCls : itemCls, |
---|
| 332 | clearCls : field.clearCls || 'x-form-clear-left', |
---|
| 333 | labelStyle : this.getLabelStyle(field.labelStyle), |
---|
| 334 | elementStyle : this.elementStyle || '', |
---|
| 335 | labelSeparator: noLabelSep ? '' : (Ext.isDefined(field.labelSeparator) ? field.labelSeparator : this.labelSeparator) |
---|
| 336 | }; |
---|
| 337 | }, |
---|
| 338 | |
---|
| 339 | // private |
---|
| 340 | adjustWidthAnchor: function(value, c){ |
---|
| 341 | if(c.label && !this.isHide(c) && (this.container.labelAlign != 'top')){ |
---|
| 342 | var adjust = Ext.isIE6 || (Ext.isIE && !Ext.isStrict); |
---|
| 343 | return value - this.labelAdjust + (adjust ? -3 : 0); |
---|
| 344 | } |
---|
| 345 | return value; |
---|
| 346 | }, |
---|
| 347 | |
---|
| 348 | adjustHeightAnchor : function(value, c){ |
---|
| 349 | if(c.label && !this.isHide(c) && (this.container.labelAlign == 'top')){ |
---|
| 350 | return value - c.label.getHeight(); |
---|
| 351 | } |
---|
| 352 | return value; |
---|
| 353 | }, |
---|
| 354 | |
---|
| 355 | // private |
---|
| 356 | isValidParent : function(c, target){ |
---|
| 357 | return target && this.container.getEl().contains(c.getPositionEl()); |
---|
| 358 | } |
---|
| 359 | |
---|
| 360 | /** |
---|
| 361 | * @property activeItem |
---|
| 362 | * @hide |
---|
| 363 | */ |
---|
| 364 | }); |
---|
| 365 | |
---|
| 366 | Ext.Container.LAYOUTS['form'] = Ext.layout.FormLayout; |
---|