1 (function ($, rf) {
  2 
  3     rf.ui = rf.ui || {};
  4 
  5     rf.ui.PickList = function(id, options) {
  6         var mergedOptions = $.extend({}, defaultOptions, options);
  7         $super.constructor.call(this, id, mergedOptions);
  8         this.namespace = this.namespace || "." + rf.Event.createNamespace(this.name, this.id);
  9         this.attachToDom();
 10         mergedOptions['scrollContainer'] = $(document.getElementById(id + "SourceItems"));
 11         this.sourceList = new rf.ui.ListMulti(id+ "SourceList", mergedOptions);
 12         mergedOptions['scrollContainer'] = $(document.getElementById(id + "TargetItems"));
 13         this.selectItemCss = mergedOptions['selectItemCss'];
 14         var hiddenId = id + "SelValue";
 15         this.hiddenValues = $(document.getElementById(hiddenId));
 16         mergedOptions['hiddenId'] = hiddenId;
 17         this.orderable = mergedOptions['orderable'];
 18 
 19         if (this.orderable) {
 20             this.orderingList = new rf.ui.OrderingList(id+ "Target", mergedOptions);
 21             this.targetList = this.orderingList.list;
 22         } else {
 23             this.targetList = new rf.ui.ListMulti(id+ "TargetList", mergedOptions);
 24         }
 25         this.pickList = $(document.getElementById(id));
 26 
 27         this.addButton = $('.rf-pick-add', this.pickList);
 28         this.addButton.bind("click", $.proxy(this.add, this));
 29         this.addAllButton = $('.rf-pick-add-all', this.pickList);
 30         this.addAllButton.bind("click", $.proxy(this.addAll, this));
 31         this.removeButton = $('.rf-pick-rem', this.pickList);
 32         this.removeButton.bind("click", $.proxy(this.remove, this));
 33         this.removeAllButton = $('.rf-pick-rem-all', this.pickList);
 34         this.removeAllButton.bind("click", $.proxy(this.removeAll, this));
 35         this.disabled = mergedOptions.disabled;
 36 
 37         if (mergedOptions['onadditems'] && typeof mergedOptions['onadditems'] == 'function') {
 38             rf.Event.bind(this.targetList, "additems", mergedOptions['onadditems']);
 39         }
 40         rf.Event.bind(this.targetList, "additems", $.proxy(this.toggleButtons, this));
 41 
 42         this.focused = false;
 43         this.keepingFocus = false;
 44         bindFocusEventHandlers.call(this, mergedOptions);
 45 
 46         // Adding items to the source list happens after removing them from the target list
 47         if (mergedOptions['onremoveitems'] && typeof mergedOptions['onremoveitems'] == 'function') {
 48             rf.Event.bind(this.sourceList, "additems", mergedOptions['onremoveitems']);
 49         }
 50         rf.Event.bind(this.sourceList, "additems", $.proxy(this.toggleButtons, this));
 51 
 52         rf.Event.bind(this.sourceList, "selectItem", $.proxy(this.toggleButtons, this));
 53         rf.Event.bind(this.sourceList, "unselectItem", $.proxy(this.toggleButtons, this));
 54         rf.Event.bind(this.targetList, "selectItem", $.proxy(this.toggleButtons, this));
 55         rf.Event.bind(this.targetList, "unselectItem", $.proxy(this.toggleButtons, this));
 56 
 57         if (mergedOptions['switchByClick']) {
 58             rf.Event.bind(this.sourceList, "click", $.proxy(this.add, this));
 59             rf.Event.bind(this.targetList, "click", $.proxy(this.remove, this));
 60         }
 61 
 62         if (mergedOptions['switchByDblClick']) {
 63             rf.Event.bind(this.sourceList, "dblclick", $.proxy(this.add, this));
 64             rf.Event.bind(this.targetList, "dblclick", $.proxy(this.remove, this));
 65         }
 66 
 67         if (options['onchange'] && typeof options['onchange'] == 'function') {
 68             rf.Event.bind(this, "change" + this.namespace, options['onchange']);
 69         }
 70 
 71         // TODO: Is there a "Richfaces way" of executing a method after page load?
 72         $(document).ready($.proxy(this.toggleButtons, this));
 73     };
 74     rf.BaseComponent.extend(rf.ui.PickList);
 75     var $super = rf.ui.PickList.$super;
 76 
 77     var defaultOptions = {
 78         defaultLabel: "",
 79         itemCss: "rf-pick-opt",
 80         selectItemCss: "rf-pick-sel",
 81         listCss: "rf-pick-lst-cord",
 82         clickRequiredToSelect: true,
 83         switchByClick : false,
 84         switchByDblClick : true,
 85         disabled : false
 86     };
 87 
 88     var bindFocusEventHandlers = function (options) {
 89         // source list
 90         if (options['onsourcefocus'] && typeof options['onsourcefocus'] == 'function') {
 91             rf.Event.bind(this.sourceList, "listfocus" + this.sourceList.namespace, options['onsourcefocus']);
 92         }
 93 
 94         if (options['onsourceblur'] && typeof options['onsourceblur'] == 'function') {
 95             rf.Event.bind(this.sourceList, "listblur" + this.sourceList.namespace, options['onsourceblur']);
 96         }
 97 
 98         // target list
 99         if (options['ontargetfocus'] && typeof options['ontargetfocus'] == 'function') {
100             rf.Event.bind(this.targetList, "listfocus" + this.targetList.namespace, options['ontargetfocus']);
101         }
102         if (options['ontargetblur'] && typeof options['ontargetblur'] == 'function') {
103             rf.Event.bind(this.targetList, "listblur" + this.targetList.namespace, options['ontargetblur']);
104         }
105 
106         // pick list
107         if (options['onfocus'] && typeof options['onfocus'] == 'function') {
108             rf.Event.bind(this, "listfocus" + this.namespace, options['onfocus']);
109         }
110         if (options['onblur'] && typeof options['onblur'] == 'function') {
111             rf.Event.bind(this, "listblur" + this.namespace, options['onblur']);
112         }
113 
114         this.pickList.focusin($.proxy(this.__focusHandler, this));
115         this.pickList.focusout($.proxy(this.__blurHandler, this));
116     };
117 
118     $.extend(rf.ui.PickList.prototype, (function () {
119 
120         return {
121             name : "pickList",
122             defaultLabelClass : "rf-pick-dflt-lbl",
123 
124             getName: function() {
125                 return this.name;
126             },
127             getNamespace: function() {
128                 return this.namespace;
129             },
130 
131             __focusHandler: function(e) {
132                 if (! this.focused) {
133                     this.focused = true;
134                     rf.Event.fire(this, "listfocus" + this.namespace, e);
135                     this.originalValue = this.targetList.csvEncodeValues();
136                 }
137             },
138 
139             __blurHandler: function(e) {
140                 if (this.focused) {
141                     this.focused = false;
142                     rf.Event.fire(this, "listblur" + this.namespace, e);
143                 }
144             },
145 
146             getSourceList: function() {
147                 return this.sourceList;
148             },
149 
150             getTargetList: function() {
151                 return this.targetList;
152             },
153 
154             add: function() {
155                 this.targetList.setFocus();
156                 var items = this.sourceList.removeSelectedItems();
157                 this.targetList.addItems(items);
158                 this.encodeHiddenValues();
159             },
160 
161             remove: function() {
162                 this.sourceList.setFocus();
163                 var items = this.targetList.removeSelectedItems();
164                 this.sourceList.addItems(items);
165                 this.encodeHiddenValues();
166             },
167 
168             addAll: function() {
169                 this.targetList.setFocus();
170                 var items = this.sourceList.removeAllItems();
171                 this.targetList.addItems(items);
172                 this.encodeHiddenValues();
173             },
174 
175             removeAll: function() {
176                 this.sourceList.setFocus();
177                 var items = this.targetList.removeAllItems();
178                 this.sourceList.addItems(items);
179                 this.encodeHiddenValues();
180             },
181 
182             encodeHiddenValues: function() {
183                 var oldValues = this.hiddenValues.val();
184                 var newValues = this.targetList.csvEncodeValues();
185                 if (oldValues !== newValues) {
186                     this.hiddenValues.val(newValues);
187                 }
188                 rf.Event.fire(this, "change" + this.namespace, {oldValues : oldValues, newValues : newValues});
189             },
190 
191             toggleButtons: function() {
192                 this.__toggleButton(this.addButton, this.sourceList.__getItems().filter('.' + this.selectItemCss).length > 0);
193                 this.__toggleButton(this.removeButton, this.targetList.__getItems().filter('.' + this.selectItemCss).length > 0);
194                 this.__toggleButton(this.addAllButton, this.sourceList.__getItems().length > 0);
195                 this.__toggleButton(this.removeAllButton, this.targetList.__getItems().length > 0);
196                 if (this.orderable) {
197                     this.orderingList.toggleButtons();
198                 }
199             },
200 
201             __toggleButton: function(button, enabled) {
202                 if (this.disabled || ! enabled) {
203                     if (! button.hasClass('rf-pick-btn-dis')) {
204                         button.addClass('rf-pick-btn-dis')
205                     }
206                     if (! button.attr('disabled')) {
207                         button.attr('disabled', true);
208                     }
209                 } else {
210                     if (button.hasClass('rf-pick-btn-dis')) {
211                         button.removeClass('rf-pick-btn-dis')
212                     }
213                     if (button.attr('disabled')) {
214                         button.attr('disabled', false);
215                     }
216                 }
217             }
218         };
219     })());
220 
221 })(RichFaces.jQuery, window.RichFaces);
222