﻿/*
* --------------------------------------------------------------------
* jQuery-Plugin - select
* by Scott Jehl, scott@filamentgroup.com
* http://www.filamentgroup.com
* 
* Copyright (c) 2009 Filament Group, Inc
* Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
*  
* --------------------------------------------------------------------
*/

(function($) {

    $.widget("ui.select", $.extend({}, $.ui.mouse, {
        _init: function() {
            var self = this, o = this.options;
            var that = this;
            this._mouseInit();

            //quick array of button and menu id's
            this.ids = this._genId();

            //create menu button wrapper
            this.newelement = $('<a class="ui-select" tabindex="0" id="' + this.ids[0] + '" href="#" aria-haspopup="true" aria-owns="' + this.ids[1] + '"></a>').insertAfter(this.element);

            //menu icon
            this.selectIcon = $('<span class="ui-select-icon"></span>').prependTo(this.newelement);

            //click toggle for menu visibility
            this.newelement.click(function() {
                that._closeOthers();
                that._toggle();
                return false;
            })
		.bind('mouseover focus', function() { $(this).addClass('ui-select-focus'); })
		.bind('mouseout blur', function() { $(this).removeClass('ui-select-focus'); });

            //document click closes menu
            $(document).click(function() {
                that.close();
            });

            //change event on original select
            this.element
			.click(function() { this._refreshValue(); })
			.focus(function() { this.newelement.focus(); });



            //create menu portion, append to body
            this.list = $('<ul class="ui-select-menu" role="menu" aria-labelledby="' + this.ids[0] + '" id="' + this.ids[1] + '"></ul>').appendTo('body');

            //get select element option data	
            var s_options = this._selectOptions();
            //original select width
            var selectWidth = this.element.width();
            //write li's
            for (var i in s_options) {
                var thisLi = $('<li><a href="#" tabindex="-1" role="option" aria-selected="false">' + s_options[i].text + '</a></li>')
				.data('index', i)
				.data('optionClasses', s_options[i].classes)
				.addClass(s_options[i].classes)
				.click(function() {
				    that.value($(this).data('index'));
				})
				.bind('mouseover focus', function() { $(this).addClass('ui-select-item-focus'); })
				.bind('mouseout blur', function() { $(this).removeClass('ui-select-item-focus'); })

				.appendTo(this.list);
            }

            //set menu button width
            this.newelement.width((o.width) ? o.width : selectWidth);
            //set menu width to either menuWidth option value, width option value, or select width 
            if (o.style == 'dropdown') { this.list.width((o.menuWidth) ? o.menuWidth : ((o.width) ? o.width : selectWidth)); }
            else { this.list.width((o.menuWidth) ? o.menuWidth : ((o.width) ? o.width - o.handleWidth : selectWidth - o.handleWidth)); }

            //transfer menu click to menu button
            this.list.click(function() {
                that.newelement.trigger('click');
                return false;
            })
		.keydown(function(event) {
		    var ret = true;

		    switch (event.keyCode) {
		        case $.ui.keyCode.UP:
		        case $.ui.keyCode.RIGHT:
		            ret = false;
		            if ($(event.target).parents('li:eq(0)').prev().size() > 0) {
		                $(event.target).blur().parents('li:eq(0)').prev().find('a:eq(0)').focus();
		            }
		            break;
		        case $.ui.keyCode.DOWN:
		        case $.ui.keyCode.LEFT:
		            ret = false;
		            if ($(event.target).parents('li:eq(0)').next().size() > 0) {
		                $(event.target).blur().parents('li:eq(0)').next().find('a:eq(0)').focus();
		            }
		            break;
		        case $.ui.keyCode.TAB:
		            ret = true;
		            that.close();
		            break;
		    }
		    return ret;
		});

            //select style
            if (o.style == 'dropdown') {
                this.newelement
				.addClass("ui-select-dropdown");
                this.list
				.addClass("ui-select-menu-dropdown");
            }
            else {
                this.newelement
				.addClass("ui-select-popup");
                this.list
				.addClass("ui-select-menu-popup");
            }

            this.newelement.prepend('<span class="ui-select-status">' + s_options[this._selectedIndex()].text + '</span>');

            //hide original select element
            if (o.hideElement) {
                this.element.hide();
            }

            //update value 
            if (o.value) { this.value(o.value); }
            else { this._refreshValue(); }
            this._setData("value", this._selectedIndex());
        },

        destroy: function() {
            this.newelement.remove();
            this.element.show();
            this._mouseDestroy();

        },

        _closeOthers: function() {
            $('.ui-select-open').not(this.list).removeClass('ui-select-open');
        },

        _genId: function(type) {
            var num = Math.round(Math.random() * 1000);
            return [this.element.attr('id') + '_' + 'button' + '_' + num, this.element.attr('id') + '_' + 'menu' + '_' + num];
        },

        open: function() {
            this._refreshPosition();
            this.list
			.appendTo('body')
			.addClass('ui-select-open')
			.find('li:eq(' + this._selectedIndex() + ') a').focus();
            return this.element;
        },

        close: function() {
            this.list.removeClass('ui-select-open');
            return this.element;
        },

        _toggle: function() {
            if (this.list.is('.ui-select-open')) { this.close(); }
            else { this.open(); }
        },

        _formatText: function(text) {
            var o = this.options;
            var newText = text;
            if (o.format) {
                for (var i in o.format) {
                    newText = newText.replace(o.format[i].find, o.format[i].rep);
                }
            }
            return newText;
        },

        _selectedIndex: function() {
            return this.element[0].selectedIndex;
        },

        _selectOptions: function() {
            var opts = [];
            var that = this;
            this.element.find('option').each(function(i) {
                opts.push({
                    value: jQuery(this).attr('value'),
                    text: that._formatText(jQuery(this).text()),
                    selected: (i == that._selectedIndex()),
                    classes: jQuery(this).attr('class')
                });
            });
            return opts;
        },

        _change: function(event, index) {
            //alert(this.element[0].id);
            $('#' + this.element[0].id).change();
            var uiHash = {
                value: this.value()
            };
            this._trigger("change", event, uiHash);
        },

        value: function(newValue) {
            if (arguments.length) {
                this._setData("value", newValue);
                this.element[0].selectedIndex = newValue;
                this._refreshValue();
                this._refreshPosition();
                this._change(null, 0);
            }
            return this._value();
        },

        _setData: function(key, value) {
            $.widget.prototype._setData.apply(this, arguments);
            this._refreshValue();

        },

        _value: function() {
            var val = this.options.value;
            return val;
        },


        _refreshValue: function() {
            this.list.find('.ui-select-item-selected').removeClass("ui-select-item-selected").find('a').attr('aria-selected', 'false');
            this.list.find('li').eq(this._selectedIndex()).addClass("ui-select-item-selected").find('a').attr('aria-selected', 'true');

            //toggle any class brought in from option
            var currentOptionClasses = this.newelement.data('optionClasses') ? this.newelement.data('optionClasses') : "";
            var newOptionClasses = this.list.find('li.ui-select-item-selected').data('optionClasses') ? this.list.find('li.ui-select-item-selected').data('optionClasses') : "";
            this.newelement
		.removeClass(currentOptionClasses)
		.data('optionClasses', newOptionClasses)
		.addClass(newOptionClasses)
		.find('.ui-select-status').html(this.list.find('li').eq(this._selectedIndex()).find('a').html());
        },

        _refreshPosition: function(offsetTop, offsetLeft) {
            var topOffset = offsetTop || 0;
            var leftOffset = offsetLeft || 0;

            var menuHeight = this.list.height();
            var sHeight = this.list[0].scrollHeight;

            //set left value
            this.list.css('left', this.newelement.offset().left);

            //set top value
            this.list.find('li:lt(' + this._selectedIndex() + ')').each(function() {
                topOffset -= $(this).height();
            });

            var menuTop = this.newelement.offset().top;

            if (this.newelement.is('.ui-select-popup')) {
                menuTop += topOffset;
                this.list.css('top', menuTop);
            }
            else {
                menuTop += this.newelement.height();
                this.list.css('top', menuTop);
            }
            var availHeight = $(window).height();
        }
    }));

    $.extend($.ui.select, {
        getter: "value",
        version: "@VERSION",
        eventPrefix: "select",
        defaults: {
            value: null, //set selected value to an index (accepts index number)
            hideElement: true, //hide original select element
            style: 'dropdown', //also avail: 'popup'
            width: null, //defaults to select width
            menuWidth: null, //sets menu body separately. number value or 'widest' 
            handleWidth: 20, //width that the icon arrow block will hang off the edge in a 'popup' style menu
            format: null //array of objects with find and rep properties. Each will run in order and perform find/replace formatting. 
            //for example: format: [{find:/^([a-zA-Z0-9 ]+)\-/g, rep: '<span class="header">$1</span>'}
        }
    });

})(jQuery);


//default format option for zoomin
$.ui.select.defaults.format = [
	{ find: /^([^\-]+) \- /g, rep: '<span class="header">$1</span>' },
	{ find: /([^\|><]+) \| /g, rep: '<span class="line">$1</span>' },
	{ find: /([^\|><]+)$/g, rep: '<span class="line">$1</span>' }
];
