1 (function ($, rf) {
  2 
  3     rf.ui = rf.ui || {};
  4 
  5     rf.ui.Select = function(id, options) {
  6         this.id = id;
  7         var mergedOptions = $.extend({}, defaultOptions, options);
  8         mergedOptions['attachTo'] = id;
  9         mergedOptions['scrollContainer'] = $(document.getElementById(id + "Items")).parent()[0];
 10         mergedOptions['focusKeeperEnabled'] = false;
 11         $super.constructor.call(this, id, mergedOptions);
 12 
 13         this.options = mergedOptions;
 14         this.defaultLabel = mergedOptions.defaultLabel;
 15         var inputLabel = this.__getValue();
 16         this.initialValue = (inputLabel != this.defaultLabel) ? inputLabel : "";
 17         this.selValueInput = $(document.getElementById(id + "selValue"));
 18         this.container = this.selValueInput.parent();
 19         this.clientSelectItems = mergedOptions.clientSelectItems;
 20         this.filterFunction = mergedOptions.filterFunction;
 21 
 22 
 23         if (mergedOptions.showControl && !mergedOptions.disabled) {
 24             this.container.bind("mousedown", $.proxy(this.__onBtnMouseDown, this))
 25                 .bind("mouseup", $.proxy(this.__onMouseUp, this));
 26         }
 27 
 28         this.selectFirst = mergedOptions.selectFirst;
 29         this.popupList = new rf.ui.PopupList((id + "List"), this, mergedOptions);
 30         this.list = this.popupList.__getList();
 31         this.listElem = $(document.getElementById(id + "List"));
 32 
 33         this.listElem.bind("mousedown", $.proxy(this.__onListMouseDown, this));
 34         this.listElem.bind("mouseup", $.proxy(this.__onMouseUp, this));
 35 
 36         var listEventHandlers = {};
 37         listEventHandlers["listshow" + this.namespace] = $.proxy(this.__listshowHandler, this);
 38         listEventHandlers["listhide" + this.namespace] = $.proxy(this.__listhideHandler, this);
 39         listEventHandlers["change" + this.namespace] = $.proxy(this.__onInputChangeHandler, this);
 40         rf.Event.bind(this.input, listEventHandlers, this);
 41 
 42         this.originalItems = this.list.__getItems();
 43         this.enableManualInput = mergedOptions.enableManualInput;
 44 
 45         if (this.originalItems.length > 0 && this.enableManualInput) {
 46             this.cache = new rf.utils.Cache("", this.originalItems, getData, true);
 47         }
 48         this.changeDelay = mergedOptions.changeDelay;
 49     };
 50 
 51     rf.ui.InputBase.extend(rf.ui.Select);
 52     var $super = rf.ui.Select.$super;
 53 
 54     var defaultOptions = {
 55         defaultLabel: "",
 56         selectFirst: true,
 57         showControl: true,
 58         enableManualInput: false,
 59         itemCss: "rf-sel-opt",
 60         selectItemCss: "rf-sel-sel",
 61         listCss: "rf-sel-lst-cord",
 62         changeDelay: 8,
 63         disabled: false,
 64         filterFunction : undefined
 65     };
 66 
 67     var REGEXP_TRIM = /^[\n\s]*(.*)[\n\s]*$/;
 68 
 69     var getData = function (nodeList) {
 70         var data = [];
 71         nodeList.each(function () {
 72             ;
 73             data.push($(this).text().replace(REGEXP_TRIM, "$1"));
 74         });
 75         return data;
 76     }
 77 
 78     $.extend(rf.ui.Select.prototype, ( function () {
 79         return{
 80             name : "select",
 81             defaultLabelClass : "rf-sel-dflt-lbl",
 82 
 83             __listshowHandler: function(e) {
 84             },
 85 
 86             __listhideHandler: function(e) {
 87             },
 88             
 89             __onInputChangeHandler: function(e) {
 90                 this.__setValue(this.input.val());
 91             },
 92 
 93             __onBtnMouseDown: function(e) {
 94                 if (!this.popupList.isVisible()) {
 95                     this.__updateItems();
 96                     this.__showPopup();
 97                 } else {
 98                     this.__hidePopup();
 99                 }
100                 this.isMouseDown = true;
101             },
102 
103             __focusHandler: function(e) {
104                 if (!this.focused) {
105                     if (this.__getValue() == this.defaultLabel) {
106                         this.__setValue("");
107                     }
108                     this.focusValue = this.selValueInput.val();
109                     this.focused = true;
110                     this.invokeEvent.call(this, "focus", document.getElementById(this.id), e);
111                 }
112             },
113 
114             __keydownHandler: function(e) {
115                 var code;
116 
117                 if (e.keyCode) {
118                     code = e.keyCode;
119                 } else if (e.which) {
120                     code = e.which;
121                 }
122 
123                 var visible = this.popupList.isVisible();
124 
125                 switch (code) {
126                     case rf.KEYS.DOWN:
127                         e.preventDefault();
128                         if (!visible) {
129                             this.__updateItems();
130                             this.__showPopup();
131                         } else {
132                             this.list.__selectNext();
133                         }
134                         break;
135 
136                     case rf.KEYS.UP:
137                         e.preventDefault();
138                         if (visible) {
139                             this.list.__selectPrev();
140                         }
141                         break;
142 
143                     case rf.KEYS.RETURN:
144                         e.preventDefault();
145                         if (visible) {
146                             this.list.__selectCurrent();
147                         }
148                         return false;
149                         break;
150 
151                     case rf.KEYS.TAB:
152                         break;
153 
154                     case rf.KEYS.ESC:
155                         e.preventDefault();
156                         if (visible) {
157                             this.__hidePopup();
158                         }
159                         break;
160 
161                     default:
162                         var _this = this;
163                         window.clearTimeout(this.changeTimerId);
164                         this.changeTimerId = window.setTimeout(function() {
165                             _this.__onChangeValue(e);
166                         }, this.changeDelay);
167                         break;
168                 }
169             },
170 
171             __onChangeValue: function(e) {
172                 this.list.__selectByIndex();
173                 var newValue = this.__getValue();
174                 if (this.cache && this.cache.isCached(newValue)) {
175                     this.__updateItems();
176 
177                     if (this.list.__getItems().length != 0) {
178                         this.container.removeClass("rf-sel-fld-err");
179                     } else {
180                         this.container.addClass("rf-sel-fld-err");
181                     }
182 
183                     if (!this.popupList.isVisible()) {
184                         this.__showPopup();
185                     }
186                 }
187             },
188 
189             __blurHandler: function(e) {
190                 if (!this.isMouseDown) {
191                     var that = this;
192                     this.timeoutId = window.setTimeout(function() {
193                         if (that.input !== null) {
194                             that.onblur(e);
195                         }
196                     }, 200);
197                 } else {
198                     this.__setInputFocus();
199                     this.isMouseDown = false;
200                 }
201             },
202 
203             __onListMouseDown: function(e) {
204                 this.isMouseDown = true;
205             },
206 
207             __onMouseUp: function(e) {
208                 this.isMouseDown = false;
209                 this.__setInputFocus();
210             },
211 
212             __updateItems: function() {
213                 var newValue = this.__getValue();
214                 newValue = (newValue != this.defaultLabel) ? newValue : "";
215                 this.__updateItemsFromCache(newValue);
216 
217                 if (this.selectFirst) {
218                     this.list.__selectByIndex(0);
219                 }
220             },
221 
222             __updateItemsFromCache: function(value) {
223                 if (this.originalItems.length > 0 && this.enableManualInput) {
224                     var newItems = this.cache.getItems(value, this.filterFunction);
225                     var items = $(newItems);
226                     this.list.__setItems(items);
227                     $(document.getElementById(this.id + "Items")).empty().append(items);
228                 }
229             },
230 
231             __getClientItemFromCache: function(inputLabel) {
232                 var value;
233                 var label;
234                 if (this.enableManualInput) {
235                     var items = this.cache.getItems(inputLabel, this.filterFunction);
236                     if (items && items.length > 0) {
237                         var first = $(items[0]);
238                         $.each(this.clientSelectItems, function() {
239                             if (this.id == first.attr("id")) {
240                                 label = this.label;
241                                 value = this.value;
242                                 return false;
243                             }
244                         });
245                     } else {
246                         label = inputLabel;
247                         value = "";
248                     }
249                 }
250 
251                 if (label) {
252                     return {'label': label, 'value': value};
253                 }
254             },
255 
256             __getClientItem: function(inputLabel) {
257                 var value;
258                 var label = inputLabel;
259                 $.each(this.clientSelectItems, function() {
260                     if (label == this.label) {
261                         value = this.value;
262                     }
263                 });
264 
265                 if (label && value) {
266                     return {'label': label, 'value': value};
267                 }
268             },
269 
270             __showPopup: function() {
271                 this.popupList.show();
272                 this.invokeEvent.call(this, "listshow", document.getElementById(this.id));
273             },
274 
275             __hidePopup: function() {
276                 this.popupList.hide();
277                 this.invokeEvent.call(this, "listhide", document.getElementById(this.id));
278             },
279 
280             showPopup: function() {
281                 if (!this.popupList.isVisible()) {
282                     this.__updateItems();
283                     this.__showPopup();
284                 }
285                 this.__setInputFocus();
286                 if (!this.focused) {
287                     if (this.__getValue() == this.defaultLabel) {
288                         this.__setValue("");
289                     }
290                     this.focusValue = this.selValueInput.val();
291                     this.focused = true;
292                     this.invokeEvent.call(this, "focus", document.getElementById(this.id));
293                 }
294             },
295 
296             hidePopup: function() {
297                 if (this.popupList.isVisible()) {
298                     this.__hidePopup();
299                     var inputLabel = this.__getValue();
300 
301                     if (!inputLabel || inputLabel == "") {
302                         this.__setValue(this.defaultLabel);
303                         this.selValueInput.val("");
304                     }
305 
306                     this.focused = false;
307                     this.invokeEvent.call(this, "blur", document.getElementById(this.id));
308                     if (this.focusValue != this.selValueInput.val()) {
309                         this.invokeEvent.call(this, "change", document.getElementById(this.id));
310                     }
311                 }
312             },
313 
314             processItem: function(item) {
315                 var key = $(item).attr("id");
316                 var label;
317                 $.each(this.clientSelectItems, function() {
318                     if (this.id == key) {
319                         label = this.label;
320                         return false;
321                     }
322                 });
323                 this.__setValue(label);
324                 this.__hidePopup();
325                 this.__setInputFocus();
326                 this.__save();
327 
328                 this.invokeEvent.call(this, "selectitem", document.getElementById(this.id));
329             },
330 
331             __save: function() {
332                 var value = "";
333                 var label = "";
334                 var inputLabel = this.__getValue();
335                 var clientSelectItem;
336 
337                 if (inputLabel && inputLabel != "") {
338                     if (this.enableManualInput) {
339                         clientSelectItem = this.__getClientItemFromCache(inputLabel);
340                     } else {
341                         clientSelectItem = this.__getClientItem(inputLabel);
342                     }
343 
344                     if (clientSelectItem) {
345                         label = clientSelectItem.label;
346                         value = clientSelectItem.value;
347                     }
348                 }
349 
350                 this.__setValue(label);
351                 this.selValueInput.val(value);
352             },
353 
354             onblur: function(e) {
355                 this.__hidePopup();
356                 var inputLabel = this.__getValue();
357 
358                 if (!inputLabel || inputLabel == "") {
359                     this.__setValue(this.defaultLabel);
360                     this.selValueInput.val("");
361                 }
362 
363                 this.focused = false;
364                 this.invokeEvent.call(this, "blur", document.getElementById(this.id), e);
365                 if (this.focusValue != this.selValueInput.val()) {
366                     this.invokeEvent.call(this, "change", document.getElementById(this.id), e);
367                 }
368             },
369 
370             getValue: function() {
371                 return this.selValueInput.val();
372             },
373 
374             setValue: function(value) {
375                 if (value == null || value == '') {
376                     this.__setValue('');
377                     this.__save();
378                     this.__updateItems();
379                     return;
380                 }
381                 var item;
382                 for (var i = 0; i < this.clientSelectItems.length; i++) {
383                     item = this.clientSelectItems[i];
384                     if (item.value == value) {
385                         this.__setValue(item.label);
386                         this.__save();
387                         this.list.__selectByIndex(i);
388                         return;
389                     }
390                 }
391             },
392 
393             getLabel: function() {
394                 return this.__getValue();
395             },
396 
397             destroy: function() {
398                 this.popupList.destroy();
399                 this.popupList = null;
400                 $super.destroy.call(this);
401             }
402         }
403     })());
404     
405     // client-side validation
406     rf.csv = rf.csv || {};
407     rf.csv.validateSelectLabelValue = function (input, id, params, msg) {
408         var value = $(document.getElementById(id + 'selValue')).val();
409         var label = $(document.getElementById(id + 'Input')).val();
410         
411         var defaultLabel = RichFaces.component(id).defaultLabel;
412         
413         if (!value && label && (label != defaultLabel)) {
414             throw rf.csv.getMessage(null, 'UISELECTONE_INVALID', [id, ""]);
415         }
416     };
417 
418 })(RichFaces.jQuery, window.RichFaces);