Implementation of emptyText

* tested with textfield and combobox , on form and vbox layouts, on IE9,FF,Chrome
* does not relay on html5 placeholder or "placeholder hacks" that quirks field's value
* works correctly with password text fields ( inputType='password' ) on all (tested) browsers
* allows to customize emptyText when field is focused ( nice and popular effect observed on leading web services )

- The code injects element before the input in a way that it covers it ,without interfering with the input.
- Works out of the box for any text field with 'emptyText' ( after including/requiring the override )
- text field may have 2 properties :

emptyTextCls : Customize empty text style ( and position it properly with top & left )
emptyTextFocusedCls : Customize focused empty text style


snapshots from IE9 , with password text field :

et1.JPG

et2.png

et3.JPG




Code:
/**
 * eptyText property implementation for text fields
 *
 * - Cross-browser ( does not relay on placeHolder )
 * - Works with password fields
 * - Provides ability to customize the empty text when field is focused
 */
Ext.define('patches.TextFieldEmptyText', {
    override:'Ext.form.field.Text',


    /**
     * @property {String} emptyTextCls
     * Customize empty text style ( and position it properly with top & left )
     */


    /**
     * @property {String} emptyTextFocusedCls
     * Customize focused empty text style
     */


    /**
     * bind to events affecting the empty-text
     * @override
     * @private
     */
    initComponent:function(){


        if(this.emptyText) {


            //Prevent default behaviour
            Ext.apply(this, {
                _emptyText:this.emptyText,
                emptyText:null,
                enableKeyEvents:true
            });


            //events that (may) trigger changes in empty-text-element
            this.on({
                scope:this,
                focus:this._handleEmptyText,
                blur:this._handleEmptyText,
                change:this._handleEmptyText
            });
        }


        this.callParent();
    },


    /**
     * @override
     * @private
     * Inject Empty-text
     */
    onRender:function(){


        this.callParent();


        if(this._emptyText) {


            // Inject element for the empty text.
            this._emptyTextEl = Ext.DomHelper.insertBefore(this.inputEl, {
                cls:this.emptyTextCls,
                style:'position:relative;' +  //The element must be relative to cover the input element;
                    'height:0px;' +     // The element must be without height to not affect layout
                    'pointer-events:none;', // optimization for supporting browsers
                html:this._emptyText
            }, true);


            // Because empty text covers inputEl , it's required to forward the focus.
            // "pointer-events:none" removes this need on supporting browsers.
            this.mon(this._emptyTextEl, 'click', function(){
                this.focus(false, 0)
            }, this)


            this._handleEmptyText();
        }
    },


    /**
     * Update Empty-text appearance
     * @private
     */
    _handleEmptyText:function(){


        if(!this.rendered || !this._emptyTextEl) return;


        var rawValue = this.getRawValue(),
            isEmpty = (!rawValue.length);


        //Trigger empty-text visibility according to emptiness of the field
        if(isEmpty) {
            this._emptyTextEl.show();


            //trigger special style indicating that the empty-text is now focused.
            // usually it's a slightly brighter text color that regular empty-text
            if(this.hasFocus) {
                this._emptyTextEl.addCls(this.emptyTextFocusedCls);
            } else {
                this._emptyTextEl.removeCls(this.emptyTextFocusedCls);
            }


        } else {
            this._emptyTextEl.hide();
        }


    }


});