Field.js
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:21k
源码类别:

中间件编程

开发平台:

JavaScript

  1. /*!
  2.  * Ext JS Library 3.0.0
  3.  * Copyright(c) 2006-2009 Ext JS, LLC
  4.  * licensing@extjs.com
  5.  * http://www.extjs.com/license
  6.  */
  7. /**
  8.  * @class Ext.form.Field
  9.  * @extends Ext.BoxComponent
  10.  * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
  11.  * @constructor
  12.  * Creates a new Field
  13.  * @param {Object} config Configuration options
  14.  * @xtype field
  15.  */
  16. Ext.form.Field = Ext.extend(Ext.BoxComponent,  {
  17.     /**
  18.      * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password, file (defaults
  19.      * to "text"). The types "file" and "password" must be used to render those field types currently -- there are
  20.      * no separate Ext components for those. Note that if you use <tt>inputType:'file'</tt>, {@link #emptyText}
  21.      * is not supported and should be avoided.
  22.      */
  23.     /**
  24.      * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered,
  25.      * not those which are built via applyTo (defaults to undefined).
  26.      */
  27.     /**
  28.      * @cfg {Mixed} value A value to initialize this field with (defaults to undefined).
  29.      */
  30.     /**
  31.      * @cfg {String} name The field's HTML name attribute (defaults to "").
  32.      * <b>Note</b>: this property must be set if this field is to be automatically included with
  33.      * {@link Ext.form.BasicForm#submit form submit()}.
  34.      */
  35.     /**
  36.      * @cfg {String} cls A custom CSS class to apply to the field's underlying element (defaults to "").
  37.      */
  38.     /**
  39.      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
  40.      */
  41.     invalidClass : "x-form-invalid",
  42.     /**
  43.      * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided
  44.      * (defaults to "The value in this field is invalid")
  45.      */
  46.     invalidText : "The value in this field is invalid",
  47.     /**
  48.      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
  49.      */
  50.     focusClass : "x-form-focus",
  51.     /**
  52.      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
  53.       automatic validation (defaults to "keyup").
  54.      */
  55.     validationEvent : "keyup",
  56.     /**
  57.      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
  58.      */
  59.     validateOnBlur : true,
  60.     /**
  61.      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation
  62.      * is initiated (defaults to 250)
  63.      */
  64.     validationDelay : 250,
  65.     /**
  66.      * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or true for a default
  67.      * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.
  68.      * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details.  Defaults to:</p>
  69.      * <pre><code>{tag: "input", type: "text", size: "20", autocomplete: "off"}</code></pre>
  70.      */
  71.     defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
  72.     /**
  73.      * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
  74.      */
  75.     fieldClass : "x-form-field",
  76.     /**
  77.      * @cfg {String} msgTarget The location where error text should display.  Should be one of the following values
  78.      * (defaults to 'qtip'):
  79.      *<pre>
  80. Value         Description
  81. -----------   ----------------------------------------------------------------------
  82. qtip          Display a quick tip when the user hovers over the field
  83. title         Display a default browser title attribute popup
  84. under         Add a block div beneath the field containing the error text
  85. side          Add an error icon to the right of the field with a popup on hover
  86. [element id]  Add the error text directly to the innerHTML of the specified element
  87. </pre>
  88.      */
  89.     msgTarget : 'qtip',
  90.     /**
  91.      * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field
  92.      * (defaults to 'normal').
  93.      */
  94.     msgFx : 'normal',
  95.     /**
  96.      * @cfg {Boolean} readOnly <tt>true</tt> to mark the field as readOnly in HTML
  97.      * (defaults to <tt>false</tt>).
  98.      * <br><p><b>Note</b>: this only sets the element's readOnly DOM attribute.
  99.      * Setting <code>readOnly=true</code>, for example, will not disable triggering a
  100.      * ComboBox or DateField; it gives you the option of forcing the user to choose
  101.      * via the trigger without typing in the text box. To hide the trigger use
  102.      * <code>{@link Ext.form.TriggerField#hideTrigger hideTrigger}</code>.</p>
  103.      */
  104.     readOnly : false,
  105.     /**
  106.      * @cfg {Boolean} disabled True to disable the field (defaults to false).
  107.      * <p>Be aware that conformant with the <a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.12.1">HTML specification</a>,
  108.      * disabled Fields will not be {@link Ext.form.BasicForm#submit submitted}.</p>
  109.      */
  110.     disabled : false,
  111.     // private
  112.     isFormField : true,
  113.     // private
  114.     hasFocus : false,
  115.     // private
  116.     initComponent : function(){
  117.         Ext.form.Field.superclass.initComponent.call(this);
  118.         this.addEvents(
  119.             /**
  120.              * @event focus
  121.              * Fires when this field receives input focus.
  122.              * @param {Ext.form.Field} this
  123.              */
  124.             'focus',
  125.             /**
  126.              * @event blur
  127.              * Fires when this field loses input focus.
  128.              * @param {Ext.form.Field} this
  129.              */
  130.             'blur',
  131.             /**
  132.              * @event specialkey
  133.              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.
  134.              * To handle other keys see {@link Ext.Panel#keys} or {@link Ext.KeyMap}.
  135.              * You can check {@link Ext.EventObject#getKey} to determine which key was pressed.
  136.              * For example: <pre><code>
  137. var form = new Ext.form.FormPanel({
  138.     ...
  139.     items: [{
  140.             fieldLabel: 'Field 1',
  141.             name: 'field1',
  142.             allowBlank: false
  143.         },{
  144.             fieldLabel: 'Field 2',
  145.             name: 'field2',
  146.             listeners: {
  147.                 specialkey: function(field, e){
  148.                     // e.HOME, e.END, e.PAGE_UP, e.PAGE_DOWN,
  149.                     // e.TAB, e.ESC, arrow keys: e.LEFT, e.RIGHT, e.UP, e.DOWN
  150.                     if (e.{@link Ext.EventObject#getKey getKey()} == e.ENTER) {
  151.                         var form = field.ownerCt.getForm();
  152.                         form.submit();
  153.                     }
  154.                 }
  155.             }
  156.         }
  157.     ],
  158.     ...
  159. });
  160.              * </code></pre>
  161.              * @param {Ext.form.Field} this
  162.              * @param {Ext.EventObject} e The event object
  163.              */
  164.             'specialkey',
  165.             /**
  166.              * @event change
  167.              * Fires just before the field blurs if the field value has changed.
  168.              * @param {Ext.form.Field} this
  169.              * @param {Mixed} newValue The new value
  170.              * @param {Mixed} oldValue The original value
  171.              */
  172.             'change',
  173.             /**
  174.              * @event invalid
  175.              * Fires after the field has been marked as invalid.
  176.              * @param {Ext.form.Field} this
  177.              * @param {String} msg The validation message
  178.              */
  179.             'invalid',
  180.             /**
  181.              * @event valid
  182.              * Fires after the field has been validated with no errors.
  183.              * @param {Ext.form.Field} this
  184.              */
  185.             'valid'
  186.         );
  187.     },
  188.     /**
  189.      * Returns the {@link Ext.form.Field#name name} or {@link Ext.form.ComboBox#hiddenName hiddenName}
  190.      * attribute of the field if available.
  191.      * @return {String} name The field {@link Ext.form.Field#name name} or {@link Ext.form.ComboBox#hiddenName hiddenName}  
  192.      */
  193.     getName: function(){
  194.         return this.rendered && this.el.dom.name ? this.el.dom.name : this.name || this.id || '';
  195.     },
  196.     // private
  197.     onRender : function(ct, position){
  198.         if(!this.el){
  199.             var cfg = this.getAutoCreate();
  200.             if(!cfg.name){
  201.                 cfg.name = this.name || this.id;
  202.             }
  203.             if(this.inputType){
  204.                 cfg.type = this.inputType;
  205.             }
  206.             this.autoEl = cfg;
  207.         }
  208.         Ext.form.Field.superclass.onRender.call(this, ct, position);
  209.         
  210.         var type = this.el.dom.type;
  211.         if(type){
  212.             if(type == 'password'){
  213.                 type = 'text';
  214.             }
  215.             this.el.addClass('x-form-'+type);
  216.         }
  217.         if(this.readOnly){
  218.             this.el.dom.readOnly = true;
  219.         }
  220.         if(this.tabIndex !== undefined){
  221.             this.el.dom.setAttribute('tabIndex', this.tabIndex);
  222.         }
  223.         this.el.addClass([this.fieldClass, this.cls]);
  224.     },
  225.     // private
  226.     getItemCt : function(){
  227.         return this.el.up('.x-form-item', 4);
  228.     },
  229.     // private
  230.     initValue : function(){
  231.         if(this.value !== undefined){
  232.             this.setValue(this.value);
  233.         }else if(!Ext.isEmpty(this.el.dom.value) && this.el.dom.value != this.emptyText){
  234.             this.setValue(this.el.dom.value);
  235.         }
  236.         /**
  237.          * The original value of the field as configured in the {@link #value} configuration, or
  238.          * as loaded by the last form load operation if the form's {@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
  239.          * setting is <code>true</code>.
  240.          * @type mixed
  241.          * @property originalValue
  242.          */
  243.         this.originalValue = this.getValue();
  244.     },
  245.     /**
  246.      * <p>Returns true if the value of this Field has been changed from its original value.
  247.      * Will return false if the field is disabled or has not been rendered yet.</p>
  248.      * <p>Note that if the owning {@link Ext.form.BasicForm form} was configured with
  249.      * {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
  250.      * then the <i>original value</i> is updated when the values are loaded by
  251.      * {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#setValues setValues}.</p>
  252.      * @return {Boolean} True if this field has been changed from its original value (and
  253.      * is not disabled), false otherwise.
  254.      */
  255.     isDirty : function() {
  256.         if(this.disabled || !this.rendered) {
  257.             return false;
  258.         }
  259.         return String(this.getValue()) !== String(this.originalValue);
  260.     },
  261.     // private
  262.     afterRender : function(){
  263.         Ext.form.Field.superclass.afterRender.call(this);
  264.         this.initEvents();
  265.         this.initValue();
  266.     },
  267.     // private
  268.     fireKey : function(e){
  269.         if(e.isSpecialKey()){
  270.             this.fireEvent("specialkey", this, e);
  271.         }
  272.     },
  273.     /**
  274.      * Resets the current field value to the originally loaded value and clears any validation messages.
  275.      * See {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
  276.      */
  277.     reset : function(){
  278.         this.setValue(this.originalValue);
  279.         this.clearInvalid();
  280.     },
  281.     // private
  282.     initEvents : function(){
  283.         this.mon(this.el, Ext.EventManager.useKeydown ? "keydown" : "keypress", this.fireKey,  this);
  284.         this.mon(this.el, 'focus', this.onFocus, this);
  285.         // fix weird FF/Win editor issue when changing OS window focus
  286.         var o = this.inEditor && Ext.isWindows && Ext.isGecko ? {buffer:10} : null;
  287.         this.mon(this.el, 'blur', this.onBlur, this, o);
  288.     },
  289.     // private
  290.     onFocus : function(){
  291.         if(this.focusClass){
  292.             this.el.addClass(this.focusClass);
  293.         }
  294.         if(!this.hasFocus){
  295.             this.hasFocus = true;
  296.             this.startValue = this.getValue();
  297.             this.fireEvent("focus", this);
  298.         }
  299.     },
  300.     // private
  301.     beforeBlur : Ext.emptyFn,
  302.     // private
  303.     onBlur : function(){
  304.         this.beforeBlur();
  305.         if(this.focusClass){
  306.             this.el.removeClass(this.focusClass);
  307.         }
  308.         this.hasFocus = false;
  309.         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
  310.             this.validate();
  311.         }
  312.         var v = this.getValue();
  313.         if(String(v) !== String(this.startValue)){
  314.             this.fireEvent('change', this, v, this.startValue);
  315.         }
  316.         this.fireEvent("blur", this);
  317.     },
  318.     /**
  319.      * Returns whether or not the field value is currently valid
  320.      * @param {Boolean} preventMark True to disable marking the field invalid
  321.      * @return {Boolean} True if the value is valid, else false
  322.      */
  323.     isValid : function(preventMark){
  324.         if(this.disabled){
  325.             return true;
  326.         }
  327.         var restore = this.preventMark;
  328.         this.preventMark = preventMark === true;
  329.         var v = this.validateValue(this.processValue(this.getRawValue()));
  330.         this.preventMark = restore;
  331.         return v;
  332.     },
  333.     /**
  334.      * Validates the field value
  335.      * @return {Boolean} True if the value is valid, else false
  336.      */
  337.     validate : function(){
  338.         if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
  339.             this.clearInvalid();
  340.             return true;
  341.         }
  342.         return false;
  343.     },
  344.     // protected - should be overridden by subclasses if necessary to prepare raw values for validation
  345.     processValue : function(value){
  346.         return value;
  347.     },
  348.     // private
  349.     // Subclasses should provide the validation implementation by overriding this
  350.     validateValue : function(value){
  351.         return true;
  352.     },
  353.     /**
  354.      * Mark this field as invalid, using {@link #msgTarget} to determine how to display the error and
  355.      * applying {@link #invalidClass} to the field's element.
  356.      * @param {String} msg (optional) The validation message (defaults to {@link #invalidText})
  357.      */
  358.     markInvalid : function(msg){
  359.         if(!this.rendered || this.preventMark){ // not rendered
  360.             return;
  361.         }
  362.         msg = msg || this.invalidText;
  363.         var mt = this.getMessageHandler();
  364.         if(mt){
  365.             mt.mark(this, msg);
  366.         }else if(this.msgTarget){
  367.             this.el.addClass(this.invalidClass);
  368.             var t = Ext.getDom(this.msgTarget);
  369.             if(t){
  370.                 t.innerHTML = msg;
  371.                 t.style.display = this.msgDisplay;
  372.             }
  373.         }
  374.         this.fireEvent('invalid', this, msg);
  375.     },
  376.     /**
  377.      * Clear any invalid styles/messages for this field
  378.      */
  379.     clearInvalid : function(){
  380.         if(!this.rendered || this.preventMark){ // not rendered
  381.             return;
  382.         }
  383.         this.el.removeClass(this.invalidClass);
  384.         var mt = this.getMessageHandler();
  385.         if(mt){
  386.             mt.clear(this);
  387.         }else if(this.msgTarget){
  388.             this.el.removeClass(this.invalidClass);
  389.             var t = Ext.getDom(this.msgTarget);
  390.             if(t){
  391.                 t.innerHTML = '';
  392.                 t.style.display = 'none';
  393.             }
  394.         }
  395.         this.fireEvent('valid', this);
  396.     },
  397.     // private
  398.     getMessageHandler : function(){
  399.         return Ext.form.MessageTargets[this.msgTarget];
  400.     },
  401.     // private
  402.     getErrorCt : function(){
  403.         return this.el.findParent('.x-form-element', 5, true) || // use form element wrap if available
  404.             this.el.findParent('.x-form-field-wrap', 5, true);   // else direct field wrap
  405.     },
  406.     // private
  407.     alignErrorIcon : function(){
  408.         this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
  409.     },
  410.     /**
  411.      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
  412.      * @return {Mixed} value The field value
  413.      */
  414.     getRawValue : function(){
  415.         var v = this.rendered ? this.el.getValue() : Ext.value(this.value, '');
  416.         if(v === this.emptyText){
  417.             v = '';
  418.         }
  419.         return v;
  420.     },
  421.     /**
  422.      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
  423.      * @return {Mixed} value The field value
  424.      */
  425.     getValue : function(){
  426.         if(!this.rendered) {
  427.             return this.value;
  428.         }
  429.         var v = this.el.getValue();
  430.         if(v === this.emptyText || v === undefined){
  431.             v = '';
  432.         }
  433.         return v;
  434.     },
  435.     /**
  436.      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
  437.      * @param {Mixed} value The value to set
  438.      * @return {Mixed} value The field value that is set
  439.      */
  440.     setRawValue : function(v){
  441.         return (this.el.dom.value = (Ext.isEmpty(v) ? '' : v));
  442.     },
  443.     /**
  444.      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
  445.      * @param {Mixed} value The value to set
  446.      * @return {Ext.form.Field} this
  447.      */
  448.     setValue : function(v){
  449.         this.value = v;
  450.         if(this.rendered){
  451.             this.el.dom.value = (Ext.isEmpty(v) ? '' : v);
  452.             this.validate();
  453.         }
  454.         return this;
  455.     },
  456.     // private, does not work for all fields
  457.     append : function(v){
  458.          this.setValue([this.getValue(), v].join(''));
  459.     },
  460.     // private
  461.     adjustSize : function(w, h){
  462.         var s = Ext.form.Field.superclass.adjustSize.call(this, w, h);
  463.         s.width = this.adjustWidth(this.el.dom.tagName, s.width);
  464.         if(this.offsetCt){
  465.             var ct = this.getItemCt();
  466.             s.width -= ct.getFrameWidth('lr');
  467.             s.height -= ct.getFrameWidth('tb');
  468.         }
  469.         return s;
  470.     },
  471.     // private
  472.     adjustWidth : function(tag, w){
  473.         if(typeof w == 'number' && (Ext.isIE && (Ext.isIE6 || !Ext.isStrict)) && /input|textarea/i.test(tag) && !this.inEditor){
  474.             return w - 3;
  475.         }
  476.         return w;
  477.     }
  478.     /**
  479.      * @cfg {Boolean} autoWidth @hide
  480.      */
  481.     /**
  482.      * @cfg {Boolean} autoHeight @hide
  483.      */
  484.     /**
  485.      * @cfg {String} autoEl @hide
  486.      */
  487. });
  488. Ext.form.MessageTargets = {
  489.     'qtip' : {
  490.         mark: function(field, msg){
  491.             field.el.addClass(field.invalidClass);
  492.             field.el.dom.qtip = msg;
  493.             field.el.dom.qclass = 'x-form-invalid-tip';
  494.             if(Ext.QuickTips){ // fix for floating editors interacting with DND
  495.                 Ext.QuickTips.enable();
  496.             }
  497.         },
  498.         clear: function(field){
  499.             field.el.removeClass(field.invalidClass);
  500.             field.el.dom.qtip = '';
  501.         }
  502.     },
  503.     'title' : {
  504.         mark: function(field, msg){
  505.             field.el.addClass(field.invalidClass);
  506.             field.el.dom.title = msg;
  507.         },
  508.         clear: function(field){
  509.             field.el.dom.title = '';
  510.         }
  511.     },
  512.     'under' : {
  513.         mark: function(field, msg){
  514.             field.el.addClass(field.invalidClass);
  515.             if(!field.errorEl){
  516.                 var elp = field.getErrorCt();
  517.                 if(!elp){ // field has no container el
  518.                     field.el.dom.title = msg;
  519.                     return;
  520.                 }
  521.                 field.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
  522.                 field.errorEl.setWidth(elp.getWidth(true)-20);
  523.             }
  524.             field.errorEl.update(msg);
  525.             Ext.form.Field.msgFx[field.msgFx].show(field.errorEl, field);
  526.         },
  527.         clear: function(field){
  528.             field.el.removeClass(field.invalidClass);
  529.             if(field.errorEl){
  530.                 Ext.form.Field.msgFx[field.msgFx].hide(field.errorEl, field);
  531.             }else{
  532.                 field.el.dom.title = '';
  533.             }
  534.         }
  535.     },
  536.     'side' : {
  537.         mark: function(field, msg){
  538.             field.el.addClass(field.invalidClass);
  539.             if(!field.errorIcon){
  540.                 var elp = field.getErrorCt();
  541.                 if(!elp){ // field has no container el
  542.                     field.el.dom.title = msg;
  543.                     return;
  544.                 }
  545.                 field.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
  546.             }
  547.             field.alignErrorIcon();
  548.             field.errorIcon.dom.qtip = msg;
  549.             field.errorIcon.dom.qclass = 'x-form-invalid-tip';
  550.             field.errorIcon.show();
  551.             field.on('resize', field.alignErrorIcon, field);
  552.         },
  553.         clear: function(field){
  554.             field.el.removeClass(field.invalidClass);
  555.             if(field.errorIcon){
  556.                 field.errorIcon.dom.qtip = '';
  557.                 field.errorIcon.hide();
  558.                 field.un('resize', field.alignErrorIcon, field);
  559.             }else{
  560.                 field.el.dom.title = '';
  561.             }
  562.         }
  563.     }
  564. };
  565. // anything other than normal should be considered experimental
  566. Ext.form.Field.msgFx = {
  567.     normal : {
  568.         show: function(msgEl, f){
  569.             msgEl.setDisplayed('block');
  570.         },
  571.         hide : function(msgEl, f){
  572.             msgEl.setDisplayed(false).update('');
  573.         }
  574.     },
  575.     slide : {
  576.         show: function(msgEl, f){
  577.             msgEl.slideIn('t', {stopFx:true});
  578.         },
  579.         hide : function(msgEl, f){
  580.             msgEl.slideOut('t', {stopFx:true,useDisplay:true});
  581.         }
  582.     },
  583.     slideRight : {
  584.         show: function(msgEl, f){
  585.             msgEl.fixDisplay();
  586.             msgEl.alignTo(f.el, 'tl-tr');
  587.             msgEl.slideIn('l', {stopFx:true});
  588.         },
  589.         hide : function(msgEl, f){
  590.             msgEl.slideOut('l', {stopFx:true,useDisplay:true});
  591.         }
  592.     }
  593. };
  594. Ext.reg('field', Ext.form.Field);