+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>The source code</title>
+ <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="../prettify/prettify.js"></script>
+ <style type="text/css">
+ .highlight { display: block; background-color: #ddd; }
+ </style>
+ <script type="text/javascript">
+ function highlight() {
+ document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
+ }
+ </script>
+</head>
+<body onload="prettyPrint(); highlight();">
+ <pre class="prettyprint lang-js"><span id='Ext-layout-component-field-Field'>/**
+</span> * @class Ext.layout.component.field.Field
+ * @extends Ext.layout.component.Component
+ * Layout class for components with {@link Ext.form.Labelable field labeling}, handling the sizing and alignment of
+ * the form control, label, and error message treatment.
+ * @private
+ */
+Ext.define('Ext.layout.component.field.Field', {
+
+ /* Begin Definitions */
+
+ alias: ['layout.field'],
+
+ extend: 'Ext.layout.component.Component',
+
+ uses: ['Ext.tip.QuickTip', 'Ext.util.TextMetrics'],
+
+ /* End Definitions */
+
+ type: 'field',
+
+ beforeLayout: function(width, height) {
+ var me = this;
+ return me.callParent(arguments) || (!me.owner.preventMark && me.activeError !== me.owner.getActiveError());
+ },
+
+ onLayout: function(width, height) {
+ var me = this,
+ owner = me.owner,
+ labelStrategy = me.getLabelStrategy(),
+ errorStrategy = me.getErrorStrategy(),
+ isDefined = Ext.isDefined,
+ isNumber = Ext.isNumber,
+ lastSize, autoWidth, autoHeight, info, undef;
+
+ lastSize = me.lastComponentSize || {};
+ if (!isDefined(width)) {
+ width = lastSize.width;
+ if (width < 0) { //first pass lastComponentSize.width is -Infinity
+ width = undef;
+ }
+ }
+ if (!isDefined(height)) {
+ height = lastSize.height;
+ if (height < 0) { //first pass lastComponentSize.height is -Infinity
+ height = undef;
+ }
+ }
+ autoWidth = !isNumber(width);
+ autoHeight = !isNumber(height);
+
+ info = {
+ autoWidth: autoWidth,
+ autoHeight: autoHeight,
+ width: autoWidth ? owner.getBodyNaturalWidth() : width, //always give a pixel width
+ height: height,
+ setOuterWidth: false, //whether the outer el width should be set to the calculated width
+
+ // insets for the bodyEl from each side of the component layout area
+ insets: {
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0
+ }
+ };
+
+ // NOTE the order of calculating insets and setting styles here is very important; we must first
+ // calculate and set horizontal layout alone, as the horizontal sizing of elements can have an impact
+ // on the vertical sizes due to wrapping, then calculate and set the vertical layout.
+
+ // perform preparation on the label and error (setting css classes, qtips, etc.)
+ labelStrategy.prepare(owner, info);
+ errorStrategy.prepare(owner, info);
+
+ // calculate the horizontal insets for the label and error
+ labelStrategy.adjustHorizInsets(owner, info);
+ errorStrategy.adjustHorizInsets(owner, info);
+
+ // set horizontal styles for label and error based on the current insets
+ labelStrategy.layoutHoriz(owner, info);
+ errorStrategy.layoutHoriz(owner, info);
+
+ // calculate the vertical insets for the label and error
+ labelStrategy.adjustVertInsets(owner, info);
+ errorStrategy.adjustVertInsets(owner, info);
+
+ // set vertical styles for label and error based on the current insets
+ labelStrategy.layoutVert(owner, info);
+ errorStrategy.layoutVert(owner, info);
+
+ // perform sizing of the elements based on the final dimensions and insets
+ if (autoWidth && autoHeight) {
+ // Don't use setTargetSize if auto-sized, so the calculated size is not reused next time
+ me.setElementSize(owner.el, (info.setOuterWidth ? info.width : undef), info.height);
+ } else {
+ me.setTargetSize((!autoWidth || info.setOuterWidth ? info.width : undef), info.height);
+ }
+ me.sizeBody(info);
+
+ me.activeError = owner.getActiveError();
+ },
+
+
+<span id='Ext-layout-component-field-Field-method-sizeBody'> /**
+</span> * Perform sizing and alignment of the bodyEl (and children) to match the calculated insets.
+ */
+ sizeBody: function(info) {
+ var me = this,
+ owner = me.owner,
+ insets = info.insets,
+ totalWidth = info.width,
+ totalHeight = info.height,
+ width = Ext.isNumber(totalWidth) ? totalWidth - insets.left - insets.right : totalWidth,
+ height = Ext.isNumber(totalHeight) ? totalHeight - insets.top - insets.bottom : totalHeight;
+
+ // size the bodyEl
+ me.setElementSize(owner.bodyEl, width, height);
+
+ // size the bodyEl's inner contents if necessary
+ me.sizeBodyContents(width, height);
+ },
+
+<span id='Ext-layout-component-field-Field-property-sizeBodyContents'> /**
+</span> * Size the contents of the field body, given the full dimensions of the bodyEl. Does nothing by
+ * default, subclasses can override to handle their specific contents.
+ * @param {Number} width The bodyEl width
+ * @param {Number} height The bodyEl height
+ */
+ sizeBodyContents: Ext.emptyFn,
+
+
+<span id='Ext-layout-component-field-Field-method-getLabelStrategy'> /**
+</span> * Return the set of strategy functions from the {@link #labelStrategies labelStrategies collection}
+ * that is appropriate for the field's {@link Ext.form.field.Field#labelAlign labelAlign} config.
+ */
+ getLabelStrategy: function() {
+ var me = this,
+ strategies = me.labelStrategies,
+ labelAlign = me.owner.labelAlign;
+ return strategies[labelAlign] || strategies.base;
+ },
+
+<span id='Ext-layout-component-field-Field-method-getErrorStrategy'> /**
+</span> * Return the set of strategy functions from the {@link #errorStrategies errorStrategies collection}
+ * that is appropriate for the field's {@link Ext.form.field.Field#msgTarget msgTarget} config.
+ */
+ getErrorStrategy: function() {
+ var me = this,
+ owner = me.owner,
+ strategies = me.errorStrategies,
+ msgTarget = owner.msgTarget;
+ return !owner.preventMark && Ext.isString(msgTarget) ?
+ (strategies[msgTarget] || strategies.elementId) :
+ strategies.none;
+ },
+
+
+
+<span id='Ext-layout-component-field-Field-property-labelStrategies'> /**
+</span> * Collection of named strategies for laying out and adjusting labels to accommodate error messages.
+ * An appropriate one will be chosen based on the owner field's {@link Ext.form.field.Field#labelAlign} config.
+ */
+ labelStrategies: (function() {
+ var applyIf = Ext.applyIf,
+ emptyFn = Ext.emptyFn,
+ base = {
+ prepare: function(owner, info) {
+ var cls = owner.labelCls + '-' + owner.labelAlign,
+ labelEl = owner.labelEl;
+ if (labelEl && !labelEl.hasCls(cls)) {
+ labelEl.addCls(cls);
+ }
+ },
+ adjustHorizInsets: emptyFn,
+ adjustVertInsets: emptyFn,
+ layoutHoriz: emptyFn,
+ layoutVert: emptyFn
+ },
+ left = applyIf({
+ prepare: function(owner, info) {
+ base.prepare(owner, info);
+ // If auto width, add the label width to the body's natural width.
+ if (info.autoWidth) {
+ info.width += (!owner.labelEl ? 0 : owner.labelWidth + owner.labelPad);
+ }
+ // Must set outer width to prevent field from wrapping below floated label
+ info.setOuterWidth = true;
+ },
+ adjustHorizInsets: function(owner, info) {
+ if (owner.labelEl) {
+ info.insets.left += owner.labelWidth + owner.labelPad;
+ }
+ },
+ layoutHoriz: function(owner, info) {
+ // For content-box browsers we can't rely on Labelable.js#getLabelableRenderData
+ // setting the width style because it needs to account for the final calculated
+ // padding/border styles for the label. So we set the width programmatically here to
+ // normalize content-box sizing, while letting border-box browsers use the original
+ // width style.
+ var labelEl = owner.labelEl;
+ if (labelEl && !owner.isLabelSized && !Ext.isBorderBox) {
+ labelEl.setWidth(owner.labelWidth);
+ owner.isLabelSized = true;
+ }
+ }
+ }, base);
+
+
+ return {
+ base: base,
+
+<span id='Ext-layout-component-field-Field-property-top'> /**
+</span> * Label displayed above the bodyEl
+ */
+ top: applyIf({
+ adjustVertInsets: function(owner, info) {
+ var labelEl = owner.labelEl;
+ if (labelEl) {
+ info.insets.top += Ext.util.TextMetrics.measure(labelEl, owner.fieldLabel, info.width).height +
+ labelEl.getFrameWidth('tb') + owner.labelPad;
+ }
+ }
+ }, base),
+
+<span id='Ext-layout-component-field-Field-property-left'> /**
+</span> * Label displayed to the left of the bodyEl
+ */
+ left: left,
+
+<span id='Ext-layout-component-field-Field-property-right'> /**
+</span> * Same as left, only difference is text-align in CSS
+ */
+ right: left
+ };
+ })(),
+
+
+
+<span id='Ext-layout-component-field-Field-property-errorStrategies'> /**
+</span> * Collection of named strategies for laying out and adjusting insets to accommodate error messages.
+ * An appropriate one will be chosen based on the owner field's {@link Ext.form.field.Field#msgTarget} config.
+ */
+ errorStrategies: (function() {
+ function setDisplayed(el, displayed) {
+ var wasDisplayed = el.getStyle('display') !== 'none';
+ if (displayed !== wasDisplayed) {
+ el.setDisplayed(displayed);
+ }
+ }
+
+ function setStyle(el, name, value) {
+ if (el.getStyle(name) !== value) {
+ el.setStyle(name, value);
+ }
+ }
+
+ var applyIf = Ext.applyIf,
+ emptyFn = Ext.emptyFn,
+ base = {
+ prepare: function(owner) {
+ setDisplayed(owner.errorEl, false);
+ },
+ adjustHorizInsets: emptyFn,
+ adjustVertInsets: emptyFn,
+ layoutHoriz: emptyFn,
+ layoutVert: emptyFn
+ };
+
+ return {
+ none: base,
+
+<span id='Ext-layout-component-field-Field-property-side'> /**
+</span> * Error displayed as icon (with QuickTip on hover) to right of the bodyEl
+ */
+ side: applyIf({
+ prepare: function(owner) {
+ var errorEl = owner.errorEl;
+ errorEl.addCls(Ext.baseCSSPrefix + 'form-invalid-icon');
+ Ext.layout.component.field.Field.initTip();
+ errorEl.dom.setAttribute('data-errorqtip', owner.getActiveError() || '');
+ setDisplayed(errorEl, owner.hasActiveError());
+ },
+ adjustHorizInsets: function(owner, info) {
+ if (owner.autoFitErrors && owner.hasActiveError()) {
+ info.insets.right += owner.errorEl.getWidth();
+ }
+ },
+ layoutHoriz: function(owner, info) {
+ if (owner.hasActiveError()) {
+ setStyle(owner.errorEl, 'left', info.width - info.insets.right + 'px');
+ }
+ },
+ layoutVert: function(owner, info) {
+ if (owner.hasActiveError()) {
+ setStyle(owner.errorEl, 'top', info.insets.top + 'px');
+ }
+ }
+ }, base),
+
+<span id='Ext-layout-component-field-Field-property-under'> /**
+</span> * Error message displayed underneath the bodyEl
+ */
+ under: applyIf({
+ prepare: function(owner) {
+ var errorEl = owner.errorEl,
+ cls = Ext.baseCSSPrefix + 'form-invalid-under';
+ if (!errorEl.hasCls(cls)) {
+ errorEl.addCls(cls);
+ }
+ setDisplayed(errorEl, owner.hasActiveError());
+ },
+ adjustVertInsets: function(owner, info) {
+ if (owner.autoFitErrors) {
+ info.insets.bottom += owner.errorEl.getHeight();
+ }
+ },
+ layoutHoriz: function(owner, info) {
+ var errorEl = owner.errorEl,
+ insets = info.insets;
+
+ setStyle(errorEl, 'width', info.width - insets.right - insets.left + 'px');
+ setStyle(errorEl, 'marginLeft', insets.left + 'px');
+ }
+ }, base),
+
+<span id='Ext-layout-component-field-Field-property-qtip'> /**
+</span> * Error displayed as QuickTip on hover of the field container
+ */
+ qtip: applyIf({
+ prepare: function(owner) {
+ setDisplayed(owner.errorEl, false);
+ Ext.layout.component.field.Field.initTip();
+ owner.getActionEl().dom.setAttribute('data-errorqtip', owner.getActiveError() || '');
+ }
+ }, base),
+
+<span id='Ext-layout-component-field-Field-property-title'> /**
+</span> * Error displayed as title tip on hover of the field container
+ */
+ title: applyIf({
+ prepare: function(owner) {
+ setDisplayed(owner.errorEl, false);
+ owner.el.dom.title = owner.getActiveError() || '';
+ }
+ }, base),
+
+<span id='Ext-layout-component-field-Field-property-elementId'> /**
+</span> * Error message displayed as content of an element with a given id elsewhere in the app
+ */
+ elementId: applyIf({
+ prepare: function(owner) {
+ setDisplayed(owner.errorEl, false);
+ var targetEl = Ext.fly(owner.msgTarget);
+ if (targetEl) {
+ targetEl.dom.innerHTML = owner.getActiveError() || '';
+ targetEl.setDisplayed(owner.hasActiveError());
+ }
+ }
+ }, base)
+ };
+ })(),
+
+ statics: {
+<span id='Ext-layout-component-field-Field-method-initTip'> /**
+</span> * Use a custom QuickTip instance separate from the main QuickTips singleton, so that we
+ * can give it a custom frame style. Responds to errorqtip rather than the qtip property.
+ */
+ initTip: function() {
+ var tip = this.tip;
+ if (!tip) {
+ tip = this.tip = Ext.create('Ext.tip.QuickTip', {
+ baseCls: Ext.baseCSSPrefix + 'form-invalid-tip',
+ renderTo: Ext.getBody()
+ });
+ tip.tagConfig = Ext.apply({}, {attribute: 'errorqtip'}, tip.tagConfig);
+ }
+ },
+
+<span id='Ext-layout-component-field-Field-method-destroyTip'> /**
+</span> * Destroy the error tip instance.
+ */
+ destroyTip: function() {
+ var tip = this.tip;
+ if (tip) {
+ tip.destroy();
+ delete this.tip;
+ }
+ }
+ }
+
+});
+</pre>
+</body>
+</html>