# Source: orderingList.js

    (function ($, rf) {

        rf.ui = rf.ui || {};

        /**
         * Backing object for rich:orderingList
         *
         * @extends RichFaces.BaseComponent
         * @memberOf! RichFaces.ui
         * @constructs RichFaces.ui.OrderingList
         *
         * @param id
         * @param options
         */
        rf.ui.OrderingList = function(id, options) {
            var mergedOptions = $.extend({}, defaultOptions, options);
            $super.constructor.call(this, id, mergedOptions);
            this.namespace = this.namespace || "." + rf.Event.createNamespace(this.name, this.id);
            this.attachToDom();
            mergedOptions['scrollContainer'] = $(document.getElementById(id + "Scroll"));
            mergedOptions['parentContainer'] = $(document.getElementById(id + "Items"));
            this.orderingList = $(document.getElementById(id));
            this.list = new rf.ui.ListMulti(id+ "List", mergedOptions);
            var hiddenId = mergedOptions['hiddenId'] ===null ? id + "SelValue" : mergedOptions['hiddenId'];
            this.hiddenValues = $(document.getElementById(hiddenId));
            this.selectItemCss = mergedOptions['selectItemCss'];
            this.disabled = mergedOptions.disabled;

            this.upButton = $('.rf-ord-up', this.orderingList);
            this.upButton.bind("click", $.proxy(this.up, this));
            this.upTopButton = $('.rf-ord-up-tp', this.orderingList);
            this.upTopButton.bind("click", $.proxy(this.upTop, this));
            this.downButton = $('.rf-ord-dn', this.orderingList);
            this.downButton.bind("click", $.proxy(this.down, this));
            this.downBottomButton = $('.rf-ord-dn-bt', this.orderingList);
            this.downBottomButton.bind("click", $.proxy(this.downBottom, this));

            this.focused = false;
            this.keepingFocus = false;
            bindFocusEventHandlers.call(this, mergedOptions);

            if (mergedOptions['onmoveitems'] && typeof mergedOptions['onmoveitems'] == 'function') {
                rf.Event.bind(this.list, "moveitems", mergedOptions['onmoveitems']);
            }
            rf.Event.bind(this.list, "moveitems", $.proxy(this.toggleButtons, this));

            rf.Event.bind(this.list, "selectItem", $.proxy(this.toggleButtons, this));
            rf.Event.bind(this.list, "unselectItem", $.proxy(this.toggleButtons, this));

            rf.Event.bind(this.list, "keydown" + this.list.namespace, $.proxy(this.__keydownHandler, this));

            if (options['onchange'] && typeof options['onchange'] == 'function') {
                rf.Event.bind(this, "change" + this.namespace, options['onchange']);
            }

            // TODO: Is there a "Richfaces way" of executing a method after page load?
            $(document).ready($.proxy(this.toggleButtons, this));
        };
        rf.BaseComponent.extend(rf.ui.OrderingList);
        var $super = rf.ui.OrderingList.$super;

        var defaultOptions = {
            defaultLabel: "",
            itemCss: "rf-ord-opt",
            selectItemCss: "rf-ord-sel",
            listCss: "rf-ord-lst-cord",
            clickRequiredToSelect: true,
            disabled : false,
            hiddenId : null
        };

        var bindFocusEventHandlers = function (options) {
            if (options['onfocus'] && typeof options['onfocus'] == 'function') {
                rf.Event.bind(this, "listfocus" + this.namespace, options['onfocus']);
            }
            if (options['onblur'] && typeof options['onblur'] == 'function') {
                rf.Event.bind(this, "listblur" + this.namespace, options['onblur']);
            }

            var focusEventHandlers = {};
            focusEventHandlers["listfocus" + this.list.namespace] = $.proxy(this.__focusHandler, this);
            focusEventHandlers["listblur" + this.list.namespace] = $.proxy(this.__blurHandler, this);
            rf.Event.bind(this.list, focusEventHandlers, this);

            focusEventHandlers = {};
            focusEventHandlers["focus" + this.namespace] = $.proxy(this.__focusHandler, this);
            focusEventHandlers["blur" + this.namespace] = $.proxy(this.__blurHandler, this);
            rf.Event.bind(this.upButton, focusEventHandlers, this);
            rf.Event.bind(this.upTopButton, focusEventHandlers, this);
            rf.Event.bind(this.downButton, focusEventHandlers, this);
            rf.Event.bind(this.downBottomButton, focusEventHandlers, this);
        };

        $.extend(rf.ui.OrderingList.prototype, (function () {

            return {
                name : "ordList",
                defaultLabelClass : "rf-ord-dflt-lbl",

                getName: function() {
                    return this.name;
                },
                getNamespace: function() {
                    return this.namespace;
                },

                __focusHandler: function(e) {
                    this.keepingFocus = this.focused;
                    if (! this.focused) {
                        this.focused = true;
                        rf.Event.fire(this, "listfocus" + this.namespace, e);
                    }
                },

                __blurHandler: function(e) {
                    var that = this;
                    this.timeoutId = window.setTimeout(function() {
                        if (!that.keepingFocus) { // If no other orderingList "sub" component has grabbed the focus during the timeout
                            that.focused = false;
                            rf.Event.fire(that, "listblur" + that.namespace, e);
                        }
                        that.keepingFocus = false;
                    }, 200);
                },

                __keydownHandler: function(e) {
                    if (e.isDefaultPrevented()) return;
                    if (! e.metaKey) return;

                    var code;
                    if (e.keyCode) {
                        code = e.keyCode;
                    } else if (e.which) {
                        code = e.which;
                    }

                    switch (code) {
                        case rf.KEYS.DOWN:
                            e.preventDefault();
                            this.down();
                            break;

                        case rf.KEYS.UP:
                            e.preventDefault();
                            this.up();
                            break;

                        case rf.KEYS.HOME:
                            e.preventDefault();
                            this.upTop();
                            break;

                        case rf.KEYS.END:
                            e.preventDefault();
                            this.downBottom();
                            break;

                        default:
                            break;
                    }
                    return;
                },

                /**
                 * Get the backing object of the list
                 *
                 * @method
                 * @name RichFaces.ui.OrderingList#getList
                 * @return {ListMulti} list
                 */
                getList: function() {
                    return this.list;
                },

                /**
                 * Move the selected elements one step up
                 *
                 * @method
                 * @name RichFaces.ui.OrderingList#up
                 */
                up: function() {
                    this.keepingFocus = true;
                    this.list.setFocus();
                    var items = this.list.getSelectedItems();
                    this.list.move(items, -1);
                    this.encodeHiddenValues();
                },

                /**
                 * Move the selected elements one step down
                 *
                 * @method
                 * @name RichFaces.ui.OrderingList#down
                 */
                down: function() {
                    this.keepingFocus = true;
                    this.list.setFocus();
                    var items = this.list.getSelectedItems();
                    this.list.move(items, 1);
                    this.encodeHiddenValues();
                },

                /**
                 * Move the selected elements to the top of the list
                 *
                 * @method
                 * @name RichFaces.ui.OrderingList#upTop
                 */
                upTop: function() {
                    this.keepingFocus = true;
                    this.list.setFocus();
                    var selectedItems = this.list.getSelectedItems();
                    var index = this.list.items.index(selectedItems.first());
                    this.list.move(selectedItems, -index);
                    this.encodeHiddenValues();
                },

                /**
                 * Move the selected elements to the bottom of the list
                 *
                 * @method
                 * @name RichFaces.ui.OrderingList#downBottom
                 */
                downBottom: function() {
                    this.keepingFocus = true;
                    this.list.setFocus();
                    var selectedItems = this.list.getSelectedItems();
                    var index = this.list.items.index(selectedItems.last());
                    this.list.move(selectedItems, (this.list.items.length -1) - index);
                    this.encodeHiddenValues();
                },

                encodeHiddenValues: function() {
        			var oldValues = this.hiddenValues.val();
    				var newValues = this.list.csvEncodeValues();
    				if (oldValues !== newValues) {
    					this.hiddenValues.val(newValues);
    					rf.Event.fire(this, "change" + this.namespace, {oldValues : oldValues, newValues : newValues});
    				}
                },

                /**
                 * Update the state of the buttons based on the current state
                 *
                 * @method
                 * @name RichFaces.ui.OrderingList#toggleButtons
                 */
                toggleButtons: function() {
                    var list = this.list.__getItems();
                    if (this.disabled || this.list.getSelectedItems().length === 0) {
                        this.__disableButton(this.upButton);
                        this.__disableButton(this.upTopButton);
                        this.__disableButton(this.downButton);
                        this.__disableButton(this.downBottomButton);
                    } else {
                        if (this.list.items.index(this.list.getSelectedItems().first()) === 0) {
                            this.__disableButton(this.upButton);
                            this.__disableButton(this.upTopButton);
                        } else {
                            this.__enableButton(this.upButton);
                            this.__enableButton(this.upTopButton);
                        }
                        if (this.list.items.index(this.list.getSelectedItems().last()) === (this.list.items.length - 1)) {
                            this.__disableButton(this.downButton);
                            this.__disableButton(this.downBottomButton);
                        } else {
                            this.__enableButton(this.downButton);
                            this.__enableButton(this.downBottomButton);
                        }
                    }
                },

                /**
                 * Focus the list
                 *
                 * @method
                 * @name RichFaces.ui.OrderingList#focus
                 */
                focus: function () {
                    this.list.setFocus();
                },

                __disableButton: function (button) {
                     if (! button.hasClass('rf-ord-btn-dis')) {
                        button.addClass('rf-ord-btn-dis')
                    }
                    if (! button.attr('disabled')) {
                        button.attr('disabled', true);
                    }
                },

                __enableButton: function(button) {
                    if (button.hasClass('rf-ord-btn-dis')) {
                        button.removeClass('rf-ord-btn-dis')
                    }
                    if (button.attr('disabled')) {
                        button.attr('disabled', false);
                    }
                }
            };
        })());

    })(RichFaces.jQuery, window.RichFaces);