      1 (function ($, rf) {
      2
      3     rf.ui = rf.ui || {};
      4
      5     // Constructor definition
      6     rf.ui.AutocompleteBase = function(componentId, selectId, fieldId, options) {
      7         // call constructor of parent class
      8         $super.constructor.call(this, componentId);
      9         this.selectId = selectId;
     10         this.fieldId = fieldId;
     11         this.options = $.extend({}, defaultOptions, options);
     12         this.namespace = this.namespace || "." + rf.Event.createNamespace(this.name, this.selectId);
     13         this.currentValue = $(rf.getDomElement(fieldId)).val();
     14         this.tempValue = this.getValue();
     15         this.isChanged = this.tempValue.length != 0;
     16         bindEventHandlers.call(this);
     17     };
     18
     19     // Extend component class and add protected methods from parent class to our container
     20     rf.BaseComponent.extend(rf.ui.AutocompleteBase);
     21
     22     // define super class link
     23     var $super = rf.ui.AutocompleteBase.$super;
     24
     25     var defaultOptions = {
     26         changeDelay:8
     27     };
     28
     29     var bindEventHandlers = function() {
     30
     31         var inputEventHandlers = {};
     32
     33         if (this.options.buttonId) {
     34             inputEventHandlers["mousedown" + this.namespace] = onButtonShow;
     35             inputEventHandlers["mouseup" + this.namespace] = onSelectMouseUp;
     36             rf.Event.bindById(this.options.buttonId, inputEventHandlers, this);
     37         }
     38
     39         inputEventHandlers = {};
     40         inputEventHandlers["focus" + this.namespace] = onFocus;
     41         inputEventHandlers["blur" + this.namespace] = onBlur;
     42         inputEventHandlers["click" + this.namespace] = onClick;
     43         inputEventHandlers["keydown" + this.namespace] = onKeyDown;
     44         inputEventHandlers["change" + this.namespace] = function (event) {
     45             if (this.focused) {
     46                 event.stopPropagation()
     47             }
     48         };
     49         rf.Event.bindById(this.fieldId, inputEventHandlers, this);
     50
     51         inputEventHandlers = {};
     52         inputEventHandlers["mousedown" + this.namespace] = onSelectMouseDown;
     53         inputEventHandlers["mouseup" + this.namespace] = onSelectMouseUp;
     54         rf.Event.bindById(this.selectId, inputEventHandlers, this);
     55     };
     56
     57     var onSelectMouseDown = function () {
     58         this.isMouseDown = true;
     59     };
     60     var onSelectMouseUp = function () {
     61         rf.getDomElement(this.fieldId).focus();
     62     };
     63
     64     var onButtonShow = function (event) {
     65         this.isMouseDown = true;
     66         if (this.timeoutId) {
     67             window.clearTimeout(this.timeoutId);
     68             this.timeoutId = null;
     69         }
     70
     71         rf.getDomElement(this.fieldId).focus();
     72         if (this.isVisible) {
     73             this.__hide(event);
     74         } else {
     75             onShow.call(this, event);
     76         }
     77     };
     78
     79     var onFocus = function (event) {
     80         if (!this.focused) {
     81             this.__focusValue = this.getValue();
     82             this.focused = true;
     83             this.invokeEvent("focus", rf.getDomElement(this.fieldId), event);
     84         }
     85     };
     86
     87     var onBlur = function (event) {
     88         if (this.isMouseDown) {
     89             rf.getDomElement(this.fieldId).focus();
     90             this.isMouseDown = false;
     91         } else if (!this.isMouseDown) {
     92             if (this.isVisible) {
     93                 var _this = this;
     94                 this.timeoutId = window.setTimeout(function() {
     95                     if (_this.isVisible) {
     96                         _this.__hide(event);
     97                     }
     98                 }, 200);
     99             }
    100             if (this.focused) {
    101                 this.focused = false;
    102                 this.invokeEvent("blur", rf.getDomElement(this.fieldId), event);
    103                 if (this.__focusValue != this.getValue()) {
    104                     this.invokeEvent("change", rf.getDomElement(this.fieldId), event);
    105                 }
    106             }
    107         }
    108     };
    109
    110     var onClick = function (event) {
    111     };
    112
    113     var onChange = function (event) {
    114         if (this.isChanged) {
    115             if (this.getValue() == this.tempValue) return;
    116         }
    117         this.isChanged = false;
    118         var value = this.getValue();
    119         var flag = value != this.currentValue;
    120         //TODO: is it needed to chesk keys?
    121         //TODO: we need to set value when autoFill used when LEFT or RIGHT was pressed
    122         if (event.keyCode == rf.KEYS.LEFT || event.keyCode == rf.KEYS.RIGHT || flag) {
    123             if (flag) {
    124                 this.currentValue = this.getValue();
    125                 this.__onChangeValue(event, undefined, (!this.isVisible ? this.__show : undefined));
    126             } else if (this.isVisible) {
    127                 this.__onChangeValue(event);
    128             }
    129         }
    130     };
    131
    132     var onShow = function (event) {
    133         if (this.isChanged) {
    134             this.isChanged = false;
    135             onChange.call(this, {});
    136         } else {
    137             !this.__updateState(event) && this.__show(event);
    138         }
    139     };
    140
    141     var onKeyDown = function (event) {
    142         switch (event.keyCode) {
    143             case rf.KEYS.UP:
    144                 event.preventDefault();
    145                 if (this.isVisible) {
    146                     this.__onKeyUp(event);
    147                 }
    148                 break;
    149             case rf.KEYS.DOWN:
    150                 event.preventDefault();
    151                 if (this.isVisible) {
    152                     this.__onKeyDown(event);
    153                 } else {
    154                     onShow.call(this, event);
    155                 }
    156                 break;
    157             case rf.KEYS.PAGEUP:
    158                 if (this.isVisible) {
    159                     event.preventDefault();
    160                     this.__onPageUp(event);
    161                 }
    162                 break;
    163             case rf.KEYS.PAGEDOWN:
    164                 if (this.isVisible) {
    165                     event.preventDefault();
    166                     this.__onPageDown(event);
    167                 }
    168                 break;
    169             case rf.KEYS.HOME:
    170                 if (this.isVisible) {
    171                     event.preventDefault();
    172                     this.__onKeyHome(event);
    173                 }
    174                 break;
    175             case rf.KEYS.END:
    176                 if (this.isVisible) {
    177                     event.preventDefault();
    178                     this.__onKeyEnd(event);
    179                 }
    180                 break;
    181             case rf.KEYS.RETURN:
    182                 if (this.isVisible) {
    183                     event.preventDefault();
    184                     this.__onEnter(event);
    185                     //TODO: bind form submit event handler to cancel form submit under the opera
    186                     //cancelSubmit = true;
    187                     this.__hide(event);
    188                     return false;
    189                 }
    190                 break;
    191             case rf.KEYS.ESC:
    192                 this.__hide(event);
    193                 break;
    194             default:
    195                 if (!this.options.selectOnly) {
    196                     var _this = this;
    197                     window.clearTimeout(this.changeTimerId);
    198                     this.changeTimerId = window.setTimeout(function() {
    199                         onChange.call(_this, event);
    200                     }, this.options.changeDelay)
    201                 }
    202                 break;
    203         }
    204     };
    205
    206     /*
    207      * public API functions definition
    208      */
    209     var show = function (event) {
    210         if (!this.isVisible) {
    211             if (this.__onBeforeShow(event) != false) {
    212                 this.scrollElements = rf.Event.bindScrollEventHandlers(this.selectId, this.__hide, this, this.namespace);
    213                 var element = rf.getDomElement(this.selectId);
    214                 if (this.options.attachToBody) {
    215                     this.parentElement = element.parentNode;
    216                     document.body.appendChild(element);
    217                 }
    218                 $(element).setPosition({id: this.fieldId}, {type:"DROPDOWN"}).show();
    219                 this.isVisible = true;
    220                 this.__onShow(event);
    221             }
    222         }
    223     };
    224     var hide = function (event) {
    225         if (this.isVisible) {
    226             this.__conceal();
    227             this.isVisible = false;
    228             this.__onHide(event);
    229         }
    230     };
    231
    232     var conceal = function () {
    233         if (this.isVisible) {
    234             if (this.scrollElements) {
    235                 rf.Event.unbindScrollEventHandlers(this.scrollElements, this);
    236                 this.scrollElements = null;
    237             }
    238             $(rf.getDomElement(this.selectId)).hide();
    239             if (this.options.attachToBody && this.parentElement) {
    240                 this.parentElement.appendChild(rf.getDomElement(this.selectId));
    241                 this.parentElement = null;
    242             }
    243         }
    244     };
    245
    246     var updateInputValue = function (value) {
    247         if (this.fieldId) {
    248             rf.getDomElement(this.fieldId).value = value;
    249             return value;
    250         } else {
    251             return "";
    252         }
    253     };
    254
    255     /*
    256      * Prototype definition
    257      */
    258     $.extend(rf.ui.AutocompleteBase.prototype, (function () {
    259         return {
    260             /*
    261              * public API functions
    262              */
    263             name:"AutocompleteBase",
    264             showPopup: function (event) {
    265                 if (!this.focused) {
    266                     rf.getDomElement(this.fieldId).focus();
    267                 }
    268                 onShow.call(this, event);
    269             },
    270             hidePopup: function (event) {
    271                 this.__hide(event)
    272             },
    273             getNamespace: function () {
    274                 return this.namespace;
    275             },
    276             getValue: function () {
    277                 return this.fieldId ? rf.getDomElement(this.fieldId).value : "";
    278             },
    279             setValue: function (value) {
    280                 if (value == this.currentValue) return;
    281                 updateInputValue.call(this, value);
    282                 this.isChanged = true;
    283             },
    284             /*
    285              * Protected methods
    286              */
    287             __updateInputValue: updateInputValue,
    288             __show: show,
    289             __hide: hide,
    290             __conceal: conceal,
    291             /*
    292              * abstract protected methods
    293              */
    294             __onChangeValue: function (event) {
    295             },
    296             __onKeyUp: function (event) {
    297             },
    298             __onKeyDown: function (event) {
    299             },
    300             __onPageUp: function (event) {
    301             },
    302             __onPageDown: function (event) {
    303             },
    304             __onKeyHome: function (event) {
    305             },
    306             __onKeyEnd: function (event) {
    307             },
    308             __onBeforeShow: function (event) {
    309             },
    310             __onShow: function (event) {
    311             },
    312             __onHide: function (event) {
    313             },
    314             /*
    315              * Destructor
    316              */
    317             destroy: function () {
    318                 this.parentNode = null;
    319                 if (this.scrollElements) {
    320                     rf.Event.unbindScrollEventHandlers(this.scrollElements, this);
    321                     this.scrollElements = null;
    322                 }
    323                 this.options.buttonId && rf.Event.unbindById(this.options.buttonId, this.namespace);
    324                 rf.Event.unbindById(this.fieldId, this.namespace);
    325                 rf.Event.unbindById(this.selectId, this.namespace);
    326                 $super.destroy.call(this);
    327             }
    328         };
    329     })());
    330 })(RichFaces.jQuery, RichFaces);
    331