1 (function ($, rf) {
  2 
  3     rf.ui = rf.ui || {};
  4 
  5     rf.ui.OrderingList = 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 + "Items"));
 11         this.orderingList = $(document.getElementById(id));
 12         this.list = new rf.ui.ListMulti(id+ "List", mergedOptions);
 13         var hiddenId = mergedOptions['hiddenId'] ===null ? id + "SelValue" : mergedOptions['hiddenId'];
 14         this.hiddenValues = $(document.getElementById(hiddenId));
 15         this.selectItemCss = mergedOptions['selectItemCss'];
 16         this.disabled = mergedOptions.disabled;
 17 
 18         this.upButton = $('.rf-ord-up', this.orderingList);
 19         this.upButton.bind("click", $.proxy(this.up, this));
 20         this.upTopButton = $('.rf-ord-up-tp', this.orderingList);
 21         this.upTopButton.bind("click", $.proxy(this.upTop, this));
 22         this.downButton = $('.rf-ord-dn', this.orderingList);
 23         this.downButton.bind("click", $.proxy(this.down, this));
 24         this.downBottomButton = $('.rf-ord-dn-bt', this.orderingList);
 25         this.downBottomButton.bind("click", $.proxy(this.downBottom, this));
 26 
 27         this.focused = false;
 28         this.keepingFocus = false;
 29         bindFocusEventHandlers.call(this, mergedOptions);
 30 
 31         if (mergedOptions['onmoveitems'] && typeof mergedOptions['onmoveitems'] == 'function') {
 32             rf.Event.bind(this.list, "moveitems", mergedOptions['onmoveitems']);
 33         }
 34         rf.Event.bind(this.list, "moveitems", $.proxy(this.toggleButtons, this));
 35 
 36         rf.Event.bind(this.list, "selectItem", $.proxy(this.toggleButtons, this));
 37         rf.Event.bind(this.list, "unselectItem", $.proxy(this.toggleButtons, this));
 38 
 39         rf.Event.bind(this.list, "keydown" + this.list.namespace, $.proxy(this.__keydownHandler, this));
 40 
 41         if (options['onchange'] && typeof options['onchange'] == 'function') {
 42             rf.Event.bind(this, "change" + this.namespace, options['onchange']);
 43         }
 44 
 45         // TODO: Is there a "Richfaces way" of executing a method after page load?
 46         $(document).ready($.proxy(this.toggleButtons, this));
 47     };
 48     rf.BaseComponent.extend(rf.ui.OrderingList);
 49     var $super = rf.ui.OrderingList.$super;
 50 
 51     var defaultOptions = {
 52         defaultLabel: "",
 53         itemCss: "rf-ord-opt",
 54         selectItemCss: "rf-ord-sel",
 55         listCss: "rf-ord-lst-cord",
 56         clickRequiredToSelect: true,
 57         disabled : false,
 58         hiddenId : null
 59     };
 60 
 61     var bindFocusEventHandlers = function (options) {
 62         if (options['onfocus'] && typeof options['onfocus'] == 'function') {
 63             rf.Event.bind(this, "listfocus" + this.namespace, options['onfocus']);
 64         }
 65         if (options['onblur'] && typeof options['onblur'] == 'function') {
 66             rf.Event.bind(this, "listblur" + this.namespace, options['onblur']);
 67         }
 68 
 69         var focusEventHandlers = {};
 70         focusEventHandlers["listfocus" + this.list.namespace] = $.proxy(this.__focusHandler, this);
 71         focusEventHandlers["listblur" + this.list.namespace] = $.proxy(this.__blurHandler, this);
 72         rf.Event.bind(this.list, focusEventHandlers, this);
 73 
 74         focusEventHandlers = {};
 75         focusEventHandlers["focus" + this.namespace] = $.proxy(this.__focusHandler, this);
 76         focusEventHandlers["blur" + this.namespace] = $.proxy(this.__blurHandler, this);
 77         rf.Event.bind(this.upButton, focusEventHandlers, this);
 78         rf.Event.bind(this.upTopButton, focusEventHandlers, this);
 79         rf.Event.bind(this.downButton, focusEventHandlers, this);
 80         rf.Event.bind(this.downBottomButton, focusEventHandlers, this);
 81     };
 82 
 83 
 84     $.extend(rf.ui.OrderingList.prototype, (function () {
 85 
 86         return {
 87             name : "ordList",
 88             defaultLabelClass : "rf-ord-dflt-lbl",
 89 
 90             getName: function() {
 91                 return this.name;
 92             },
 93             getNamespace: function() {
 94                 return this.namespace;
 95             },
 96 
 97             __focusHandler: function(e) {
 98                 this.keepingFocus = this.focused;
 99                 if (! this.focused) {
100                     this.focused = true;
101                     rf.Event.fire(this, "listfocus" + this.namespace, e);
102                 }
103             },
104 
105             __blurHandler: function(e) {
106                 var that = this;
107                 this.timeoutId = window.setTimeout(function() {
108                     if (!that.keepingFocus) { // If no other orderingList "sub" component has grabbed the focus during the timeout
109                         that.focused = false;
110                         rf.Event.fire(that, "listblur" + that.namespace, e);
111                     }
112                     that.keepingFocus = false;
113                 }, 200);
114             },
115 
116             __keydownHandler: function(e) {
117                 if (e.isDefaultPrevented()) return;
118                 if (! e.metaKey) return;
119 
120                 var code;
121                 if (e.keyCode) {
122                     code = e.keyCode;
123                 } else if (e.which) {
124                     code = e.which;
125                 }
126 
127                 switch (code) {
128                     case rf.KEYS.DOWN:
129                         e.preventDefault();
130                         this.down();
131                         break;
132 
133                     case rf.KEYS.UP:
134                         e.preventDefault();
135                         this.up();
136                         break;
137 
138                     case rf.KEYS.HOME:
139                         e.preventDefault();
140                         this.upTop();
141                         break;
142 
143                     case rf.KEYS.END:
144                         e.preventDefault();
145                         this.downBottom();
146                         break;
147 
148                     default:
149                         break;
150                 }
151                 return;
152             },
153 
154             getList: function() {
155                 return this.list;
156             },
157 
158             up: function() {
159                 this.keepingFocus = true;
160                 this.list.setFocus();
161                 var items = this.list.getSelectedItems();
162                 this.list.move(items, -1);
163                 this.encodeHiddenValues();
164             },
165 
166             down: function() {
167                 this.keepingFocus = true;
168                 this.list.setFocus();
169                 var items = this.list.getSelectedItems();
170                 this.list.move(items, 1);
171                 this.encodeHiddenValues();
172             },
173 
174             upTop: function() {
175                 this.keepingFocus = true;
176                 this.list.setFocus();
177                 var selectedItems = this.list.getSelectedItems();
178                 var index = this.list.items.index(selectedItems.first());
179                 this.list.move(selectedItems, -index);
180                 this.encodeHiddenValues();
181             },
182 
183             downBottom: function() {
184                 this.keepingFocus = true;
185                 this.list.setFocus();
186                 var selectedItems = this.list.getSelectedItems();
187                 var index = this.list.items.index(selectedItems.last());
188                 this.list.move(selectedItems, (this.list.items.length -1) - index);
189                 this.encodeHiddenValues();
190             },
191 
192             encodeHiddenValues: function() {
193     			var oldValues = this.hiddenValues.val();
194 				var newValues = this.list.csvEncodeValues();
195 				if (oldValues !== newValues) {
196 					this.hiddenValues.val(newValues);
197 					rf.Event.fire(this, "change" + this.namespace, {oldValues : oldValues, newValues : newValues});
198 				}
199             },
200 
201             toggleButtons: function() {
202                 var list = this.list.__getItems();
203                 if (this.disabled || this.list.getSelectedItems().length === 0) {
204                     this.__disableButton(this.upButton);
205                     this.__disableButton(this.upTopButton);
206                     this.__disableButton(this.downButton);
207                     this.__disableButton(this.downBottomButton);
208                 } else {
209                     if (this.list.items.index(this.list.getSelectedItems().first()) === 0) {
210                         this.__disableButton(this.upButton);
211                         this.__disableButton(this.upTopButton);
212                     } else {
213                         this.__enableButton(this.upButton);
214                         this.__enableButton(this.upTopButton);
215                     }
216                     if (this.list.items.index(this.list.getSelectedItems().last()) === (this.list.items.length - 1)) {
217                         this.__disableButton(this.downButton);
218                         this.__disableButton(this.downBottomButton);
219                     } else {
220                         this.__enableButton(this.downButton);
221                         this.__enableButton(this.downBottomButton);
222                     }
223                 }
224             },
225 
226             __disableButton: function (button) {
227                  if (! button.hasClass('rf-ord-btn-dis')) {
228                     button.addClass('rf-ord-btn-dis')
229                 }
230                 if (! button.attr('disabled')) {
231                     button.attr('disabled', true);
232                 }
233             },
234 
235             __enableButton: function(button) {
236                 if (button.hasClass('rf-ord-btn-dis')) {
237                     button.removeClass('rf-ord-btn-dis')
238                 }
239                 if (button.attr('disabled')) {
240                     button.attr('disabled', false);
241                 }
242             }
243         };
244     })());
245 
246 })(RichFaces.jQuery, window.RichFaces);
247