/*!
 * Custom select plugin for jQuery (zfselect v0.99.1)
 *
 * Author: Valeriy Zavolodko <vals2004@gmail.com>
 * Design: Victoriya Dobrilovskaya <vicere@rambler.ru>
 *
 * Date: 10/24/2011
 * Depends on library: jQuery 1.4+
 * Depends on plugin: jquery.mousewheel.js (for mouse wheel support and for IOS)
 *
 */

(function(jQuery, undefined) {
    function zfSelect()
    {
        this.defaults    = {
            rows:           10,             // num rows visible in drop down
            width:          0,              // width of dropdown (if >0 autosize off)
            maxWidth:       0,              // max width of drop down with autosize
            overflowHidden: true,           //
            optionCallback: null,           // callback for prepare labels of options: function(option){ return option.html() }
            onBeforeOpen:   null,           // call before open dropdown function(drop){ }
            onAfterOpen:    null,           // call after open dropdown function(drop){ }
            onBeforeClose:  null,           // call before close dropdown function(drop){ }
            onAfterClose:   null            // call after close dropdown function(drop){ }

        };

        this._elements         = new Object();
        this._main_template    = '<div id="zf-select-{{id}}" class="zf-select {{multi}} {{classes}}" style="width:{{width}}px;height:{{height}}px;z-index={{z-index}};" tabindex="{{tabindex}}"></div>';
        this._content_template =
            '<div class="select-text" value="{{value}}">{{label}}</div>' +
            '<div class="select-btn"></div>' +
            '<div class="select-drop">' +
                '<div class="select-top">' +
                    '<div class="top-left"></div>' +
                    '<div class="top-right"></div>' +
                    '<div class="top-mid"></div>' +
                '</div>' +
                '<div class="select-mid">' +
                    '<div class="mid-right">' +
                        '<div class="scrollable">' +
                            '<ul></ul>' +
                        '</div>' +
                        '<div class="zf-scroll-track">' +
                            '<div class="zf-scroll-drag">' +
                                '<div class="zf-scroll-drag-top"></div>' +
                                '<div class="zf-scroll-drag-btm"></div>' +
                            '</div>' +
                        '</div>' +
                        '<div class="btup zf-scroll-arrow-top"></div>' +
                        '<div class="btdn zf-scroll-arrow-btm"></div>' +
                    '</div>' +
                '</div>' +
                '<div class="select-btm">' +
                    '<div class="btm-left"></div>' +
                    '<div class="btm-right"></div>' +
                    '<div class="btm-mid"></div>' +
                '</div>' +
            '</div>';
        this._option_template  = '<li title="{{title}}" val="{{value}}" class="{{selected}} {{disabled}} {{optitem}}">{{label}}</li>';
        this._optgroup_template  = '<li title="{{title}}" class="{{disabled}} optgroup">{{label}}</li>';
    };

    jQuery.extend(zfSelect.prototype, {

        moveMouseEvent: null,
        prevMoveMouseEvent: null,

        moveMouseObject: null,          // current scroll object
        moveMouseInterval: null,        // current scroll interval (setInterval)

        touchStartY: null,              // touch started at Y

        init: function(target, settings) {
            // ignore if is not 'select' or without 'id'
            if (!jQuery(target).is('select') || undefined==jQuery(target).attr('id')) {
                return;
            }

            // refresh if already initialized
            if (this._getInst(target)) {
                jQuery.zfselect.refresh(jQuery(target), settings);
                return this._getInst(target);
            }

            var options     = {};
            jQuery.extend(options, this.defaults, settings);
            var select      = jQuery(target);

            var border      = select.css('border');
            select.css('border', '0px');
            select.hide().wrapAll(this._main_template
                .replace(/{{id}}/g,      select.attr('id'))
                .replace(/{{width}}/g,   select.width())
                .replace(/{{height}}/g,  select.attr('multiple') ? select.height() : 'auto')
                .replace(/{{tabindex}}/g,select.prop('tabindex'))
                .replace(/{{multi}}/g,   select.attr('multiple') ? 'zf-multi-select' : '')
                .replace(/{{classes}}/g, undefined!=select.attr('class') ? select.attr('class') : '')
                .replace(/{{z-index}}/g, select.css('z-index'))
            )
            .after(this._content_template
                .replace(/{{id}}/g,      select.attr('id'))
                .replace(/{{value}}/g,   select.val())
                .replace(/{{label}}/g,   select.find('option:selected').text())
            );
            select.css('border', border);

            var newInst = this._newInstance(target, options);
            this._elements[select.attr('id')] = newInst;

            newInst.zfSelect
                .bind('keydown', this._doKeyDown)
                .bind('keypress', this._doKeyPress);
            newInst.zfText
                .bind('click', this._doSelectClick)
                .bind('mousedown', this._doSelectMouseDown)
                .bind('mouseup', this._doSelectMouseUp);
            newInst.zfButton
                .bind('click', this._doSelectClick)
                .bind('mousedown', this._doSelectMouseDown);
            newInst.zfDropDown
                .bind('mousewheel', this._doMouseWheel)
                .bind('touchstart.jsp', this._doTouchStart)
                .bind('click', this._false);
            newInst.zfScrollBar
                .bind('mousedown', this._doBarMouseDown)
                .bind('click', this._false);
            newInst.zfScrollDrag
                .bind('mousedown', this._doMouseDownDrag)
                .bind('touchstart.jsp', this._doTouchStartDrag)
                .bind('click', this._false);
            newInst.zfScrollDown
                .bind('mousedown', this._doMouseArrow)
                .bind('click', this._false);
            newInst.zfScrollUp
                .bind('mousedown', this._doMouseArrow)
                .bind('click', this._false);
            newInst.zfSelect
                .bind('focus', this._doOnFocus);
            newInst.zfSelect
                .bind('blur', this._doOnBlur);
            if (newInst.disabled) newInst.zfSelect.addClass('zf-select-dis');
            if (newInst.multi) {
                newInst.zfScrollPane.height(newInst.zfSelect.height());
                jQuery.zfselect._doShow(select);
            }
            jQuery.zfselect.refresh(newInst.select);
            newInst.oldSelected     = [].concat(newInst.selected);
            return target;
        },

        _getElement: function(element)
        {
            var result  = null;
            switch (element) {
                case 'main':
                    result  = '#' + this.mainId;
                    break;
                case 'text':
                case 'button':
                case 'select':
                case 'options':
                case 'scroll':
                case 'up':
                case 'down':
                case 'drag':
            }
            return jQuery(result);
        },

        _doTouchStartDrag: function(event) {
            var touch   = event.originalEvent.touches[0];
            jQuery.zfselect.touchStartY     = touch.pageY;
            var obj     = jQuery.zfselect._getInst(event.currentTarget);
            if (obj && !jQuery.zfselect.moveMouseObject) {
                jQuery.zfselect._doHideExcept(obj);
                obj.lastDragY                   = touch.clientY;
                jQuery.zfselect.moveMouseObject = obj;
                jQuery.zfselect._disableLiEvents(obj);
                jQuery(document)
                    .bind('touchend.jsp', jQuery.zfselect._doTouchEndDrag)
                    .bind('touchmove.jsp', jQuery.zfselect._doTouchMoveDrag);
                return false;
            }
        },

        _doTouchEndDrag: function(event) {
            var touch   = event.originalEvent.touches[0];
            var obj = jQuery.zfselect.moveMouseObject;
            if (obj) {
                jQuery.zfselect._enableLiEvents(obj);
            }
            jQuery(document)
                .unbind('touchend.jsp', jQuery.zfselect._doTouchEndDrag)
                .unbind('touchmove.jsp', jQuery.zfselect._doTouchMoveDrag);
            jQuery.zfselect.moveMouseObject = null;
        },

        _doTouchMoveDrag: function(event) {
            var touch   = event.originalEvent.touches[0];
            var obj    = jQuery.zfselect.moveMouseObject;
            if (obj) {
                var offset = (obj.lastDragY-touch.clientY);
                obj.lastDragY = touch.clientY;
                jQuery.zfselect.touchStartY     = touch.pageY;
                var height  = obj.zfScrollBar.height();
                var top1    = obj.zfScrollDrag.css('top');
                var height1 = obj.zfScrollDrag.height();
                var pers    = -1;
                if (offset!=0) {
                    var trackTop = obj.zfScrollDrag.attr('top')?parseFloat(obj.zfScrollDrag.attr('top')):parseFloat(obj.zfScrollDrag.css('top'));
                    if (offset<0) {
                        if ((trackTop+Math.abs(offset))>(height-(height1+obj.zfScrollDown.height()))) {
                            offset = 0;
                            pers   = 1;
                        }
                        obj.zfScrollDrag.css('top',(trackTop+Math.abs(offset))+'px').attr('top', trackTop+Math.abs(offset));
                    } else {
                        if ((trackTop-Math.abs(offset))<obj.zfScrollUp.height()) {
                            offset = 0;
                            pers   = 0;
                        }
                        obj.zfScrollDrag.css('top',(trackTop-Math.abs(offset))+'px').attr('top', trackTop-Math.abs(offset));
                    }
                    pers = pers!=-1 ? pers : (parseFloat(obj.zfScrollDrag.css('top'))-obj.zfScrollUp.height())/(height-(obj.zfScrollUp.height()+obj.zfScrollDown.height())-height1);
                    if (pers==Infinity || pers<0) pers=0;
                    if (pers>1) pers=1;
                    obj.zfScrollPane.scrollTop((obj.zfOptions.height()-obj.zfScrollPane.height())*pers+parseInt(obj.zfOptions.css('padding-top')));
                }
                jQuery.zfselect._doUpdateArrows(obj.zfSelect);
                return false;
            }
            jQuery.zfselect.touchStartY     = touch.pageY;
        },

        _doTouchStart: function(event) {
            var touch   = event.originalEvent.touches[0];
            jQuery.zfselect.touchStartY     = touch.pageY;
            var obj     = jQuery.zfselect._getInst(event.currentTarget);
            if (obj && !jQuery.zfselect.moveMouseObject) {
                jQuery.zfselect._doHideExcept(obj);
                obj.lastDragY                   = touch.clientY;
                jQuery.zfselect.moveMouseObject = obj;
                jQuery(document)
                    .bind('touchend.jsp', jQuery.zfselect._doTouchEnd)
                    .bind('touchmove.jsp', jQuery.zfselect._doTouchMove);
            }
        },

        _doTouchEnd: function(event) {
            var touch   = event.originalEvent.touches[0];
            var obj = jQuery.zfselect.moveMouseObject;
            jQuery(document)
                .unbind('touchend.jsp', jQuery.zfselect._doTouchEnd)
                .unbind('touchmove.jsp', jQuery.zfselect._doTouchMove);
            jQuery.zfselect.moveMouseObject = null;
        },

        _doTouchMove: function(event)
        {
            var touch   = event.originalEvent.touches[0];
            var obj    = jQuery.zfselect.moveMouseObject;
            if (obj) {
                obj.lastDragY = touch.clientY;
                event.clientY = touch.clientY;
                var toScroll  = obj.zfScrollBar.height()/(obj.zfOptions.height()/obj.rowHeight);
                var delta     = touch.pageY - jQuery.zfselect.touchStartY;
                jQuery.zfselect.touchStartY     = touch.pageY;
                var direction = delta/Math.abs(delta);
                if (delta!=0) {
                    switch (direction) {
                        case 1:             // up
                            toScrollMin     = parseFloat(obj.zfScrollDrag.attr('top'))-obj.zfScrollUp.height();
                            if (toScroll>toScrollMin) {
                                toScroll    = toScrollMin;
                            }
                            break;
                        case -1:            // down
                            toScrollMin     = obj.zfScrollBar.height()-parseFloat(obj.zfScrollDrag.attr('top'))-obj.zfScrollDrag.height()-obj.zfScrollDown.height();
                            if (toScroll>toScrollMin) {
                                toScroll    = toScrollMin;
                            }
                            break;
                    }
                    event.clientY-= direction*toScroll;
                    jQuery.zfselect._doMouseMoveDrag(event);
                return false;
                }
            }
            jQuery.zfselect.touchStartY     = touch.pageY;
        },

        _enableLiEvents: function(target) {
            var obj = jQuery.zfselect._getInst(target);
            if (obj) {
                jQuery(obj.zfOptions)
                    .bind('mousedown',jQuery.zfselect._doLiMouseDown)
                    .bind('mouseover', jQuery.zfselect._doLiMouseDown);
            }
        },

        _disableLiEvents: function(target) {
            var obj = jQuery.zfselect._getInst(target);
            if (obj) {
                jQuery(obj.zfOptions)
                    .unbind('mousedown',jQuery.zfselect._doLiMouseDown)
                    .unbind('mouseover', jQuery.zfselect._doLiMouseDown);
            }
        },

        _prepareOption: function(option, obj) {
            var label   = option.html();
            if (obj && jQuery.isFunction(obj.optionCallback)) {
                label   = obj.optionCallback(option);
            }
            return jQuery.zfselect._option_template
                .replace(/{{title}}/g,      option.html())
                .replace(/{{label}}/g,      label)
                .replace(/{{value}}/g,      option.val())
                .replace(/{{selected}}/,    (option.is(':selected')?'selected':''))
                .replace(/{{disabled}}/,    (option.is(':disabled')?'disabled':''))
                .replace(/{{optitem}}/,     (option.parent().is('optgroup')?'optitem':''));
        },

        _prepareOptGroup: function(optgroup, obj) {
            var label   = optgroup.attr('label');
            return jQuery.zfselect._optgroup_template
                .replace(/{{title}}/g,      label)
                .replace(/{{disabled}}/,    (optgroup.is(':disabled')?'disabled':''))
                .replace(/{{label}}/g,      label);
        },

        _initOptions: function(obj) {
            var options = '';
            if (obj) {
                obj.selected.length     = 0;
                obj.oldSelected.length  = 0;
                jQuery('option', obj.select).each(function(i, e){
                    var parent  = jQuery(e).parent();
                    if (parent.is('optgroup')) {
                        // need to optimize
                        if (!jQuery('li[title="'+parent.attr('label')+'"]', '<ul>' + options + '</ul>').length) {
                            options += jQuery.zfselect._prepareOptGroup(parent, obj);
                        }
                    }
                    if (jQuery(e).is(':selected')) {
                        obj.selected.push(i);
                    }
                    options += jQuery.zfselect._prepareOption(jQuery(e), obj);
                });
                obj.oldSelected     = [].concat(obj.selected);
                obj.zfOptions.html(options);
            }
        },

        // find instance in container
        _getInst: function(target) {
		    try {
                var select = null;
                if (target['zfSelect'] && target['zfSelect'].is('div.zf-select')) {
                    return target;
                }
                if (jQuery(target).is('div.zf-select')) {
                    select = jQuery(target).find('select');
                } else {
                    select = jQuery(target).parents('div.zf-select').find('select');
                }
                if (select.length) {
    			    return this._elements[select.attr('id')];
                }
		    }
    		catch (err) {
                //
		    }
            return null;
        },

        _getSettings: function(obj) {
            var settings    = {};
            if (obj) {
                jQuery.each(jQuery.zfselect.defaults, function(i, el){
                    settings[i]     = obj[i];
                });
            }
            return settings;
        },

        _setSettings: function(obj, settings) {
            if (obj) {
                var options     = {};
                jQuery.extend(options, jQuery.zfselect.defaults, jQuery.zfselect._getSettings(obj), settings);
                jQuery.each(jQuery.zfselect.defaults, function(i, el){
                    obj[i]  = options[i];
                });
            }
        },

        reinit: function(target, settings) {
            if (target.length>1) {
                jQuery.each(target, function(){
                    jQuery.zfselect.reinit(this, settings);
                });
                return target;
            }

            var obj = jQuery.zfselect._getInst(target);
            var options     = {};
            jQuery.extend(options, jQuery.zfselect.defaults, jQuery.zfselect._getSettings(obj), settings);
            if (obj) {
                jQuery.zfselect.remove(target);
            }
            jQuery.zfselect.init(target, options);
            return target;
        },

        // refresh zfselect from select
        refresh: function(target, settings, force) {
            if (target.length>1) {
                jQuery.each(target, function(){
                    jQuery.zfselect.refresh(this, settings);
                });
                return target;
            }
            if (target['zfSelect'] || !jQuery(target).is('select')) {
                return target;
            }
            var obj = jQuery.zfselect._getInst(target);
            if (obj) {
                if (jQuery('li:not(.optgroup)', obj.zfOptions).length!=jQuery('option', obj.select).length || true==force || obj.force) {
                    obj.force = false;
                    jQuery.zfselect._initOptions(obj);
                }
                if (!obj.multi) {
                    obj.zfText.html(obj.select.find('option:selected').text());
                }

                obj.changed = true;
                obj.zfSelect.removeClass('zf-select-dis');
                obj.disabled = obj.select.is(':disabled');
                if (obj.disabled) obj.zfSelect.addClass('zf-select-dis');

                jQuery.zfselect._setSettings(obj, settings);
                jQuery.zfselect._disableLiEvents(target);
                jQuery.zfselect._doCloneSelect(target);
                obj.shiftSelect = jQuery('li:not(.optgroup).selected:first', obj.zfOptions);
                obj.rows        = jQuery('li', obj.zfOptions).length;
                if (obj.zfDropDown.is(':visible')) {
                    jQuery.zfselect._autoSize(target);
                }
                jQuery.zfselect._enableLiEvents(target);

                return obj.select;
            }
            return target;
        },

        // remove zfselect and restore select
        remove: function(target) {
            if (target.length>1) {
                target.each(function(){
                    jQuery.zfselect.remove(jQuery(this));
                });
                return target;
            }
            var obj = jQuery.zfselect._getInst(target);
            if (obj) {
                if (obj.zfSelect.is(':visible')) obj.select.show();
                var events = obj.select.data('events');
                obj.zfSelect.replaceWith(obj.select);
                if (obj.select.data('events')) {
                    jQuery.each(obj.select.data('events'), function(id, el){
                        obj.select.unbind(id);
                    });
                }
                if (events) {
                    jQuery.each(events, function(id,el){
                        var name = id;
                        jQuery.each(el, function(i, h){
                            obj.select.bind(name, h);
                        });
                    });
                }
                delete jQuery.zfselect._elements[obj.id];
            }
        },

        // simple false function
        _false: function() {
            return false;
        },

        // show drop-down
        _doShow: function(target) {
            var obj = jQuery.zfselect._getInst(target);
            if (obj) {
                jQuery.each(jQuery.zfselect._elements, function(id, object){
                    jQuery.zfselect._doHide(object.zfSelect);
                });
                if (jQuery.isFunction(obj.onBeforeOpen)) {
                    obj.onBeforeOpen.call(obj.select, obj.zfSelect);
                }
                obj.zfDropDown.show();
                obj.zfDropDown.trigger('focus');
                if (!obj.multi) {
                    obj.zfSelect.css('z-index', 9999);
                }
                jQuery.zfselect._doCloneSelect(target);
                jQuery.zfselect._autoSize(target);
                if (!obj.multi) {
                    obj.zfDropDown.css('top',obj.zfText.height() + 'px');
                    //var pageHeight  = document.documentElement.clientHeight;
                    var viewHeight  = window.innerHeight;
                    var pageYScroll = window.pageYOffset;
                    var zfSelectTop     = obj.zfSelect.offset().top;
                    var zfSelectHeight  = obj.zfSelect.height();
                    var zfDropHeight    = obj.zfDropDown.height();
                    if ((viewHeight+pageYScroll)<(zfSelectTop+zfSelectHeight+zfDropHeight)) {
                        if (zfSelectTop>=zfDropHeight) {
                            obj.zfDropDown.css('top', '-' + zfDropHeight + 'px');
                        }
                    }
                    obj.zfDropDown.css('left','0px');
                    //var pageWidth   = document.documentElement.clientWidth;
                    var viewWidth   = window.innerWidth;
                    var pageXScroll = window.pageXOffset;
                    var zfSelectLeft    = obj.zfSelect.offset().left;
                    var zfSelectWidth   = obj.zfSelect.width();
                    var zfDropWidth     = obj.zfDropDown.width();
                    if ((viewWidth+pageXScroll)<(zfSelectLeft+zfDropWidth)) {
                        if (zfSelectLeft>(zfDropWidth-zfSelectWidth)) {
                            obj.zfDropDown.css('left','-' + (zfDropWidth-zfSelectWidth) + 'px');
                        }
                    }
                }
                if (jQuery.isFunction(obj.onAfterOpen)) {
                    obj.onAfterOpen.call(obj.select, obj.zfSelect);
                }
            }
        },

        // hide drop-down
        _doHide: function(target) {
            var obj = jQuery.zfselect._getInst(target);
            if (obj && !obj.multi) {
                if (obj.zfDropDown.is(':visible')){
                    if (jQuery.isFunction(obj.onBeforeClose)) {
                        obj.onBeforeClose.call(obj.select, obj.zfSelect);
                    }
                    obj.zfDropDown.hide();
                    if (jQuery.isFunction(obj.onAfterClose)) {
                        obj.onAfterClose.call(obj.select, obj.zfSelect);
                    }
                    obj.zfSelect.css('z-index', obj.zindex);
                }
            }
        },

        _doHideExcept: function(target) {
            var obj = jQuery.zfselect._getInst(target);
            if (obj) {
                jQuery.each(jQuery.zfselect._elements, function() {
                    if (obj.id!=this.id) {
                        jQuery.zfselect._doHide(this);
                    }
                });
            }
        },

        // autosize width of drop-down
        _autoSize: function(target) {
            var obj = jQuery.zfselect._getInst(target);
            if (obj) {
                if (obj.changed) {
                    if (!obj.multi) {
                        obj.zfDropDown.width(obj.zfSelect.width() - obj.zfScrollBar.width());
                    }

                    jQuery('li', obj.zfOptions).height('auto').css('overflow','auto');
                    obj.zfOptions.append('<li>W</li>');
                    var lastLi = jQuery('li:last', obj.zfOptions);
                    obj.rowHeight       = parseInt(lastLi.height());
                    lastLi.remove();

                    if (!obj.multi) {
                        if (obj.width==0 && obj.overflowHidden) {
                            var liIndex = 0;
                            var dropDownWidth   = obj.zfDropDown.width();
                            var windowWidth     = jQuery(window).width(); 
                            do {
                                var liFlag = false;
                                obj.zfOptions.find('li:ge('+liIndex+')').each(function() {
                                    if (obj.rowHeight!=jQuery(this).height() && jQuery(this).html()!='') {
                                        liFlag  = true;
                                        liIndex = jQuery(this).index();
                                        return false;
                                    }
                                });
                                if (liFlag) {
                                    obj.zfDropDown.width(obj.zfDropDown.width()+10);
                                    dropDownWidth   = obj.zfDropDown.width();
                                }
                            } while (liFlag && dropDownWidth<windowWidth && (obj.maxWidth>0 ? dropDownWidth<obj.maxWidth : true));
                        } else {
                            obj.zfDropDown.width(obj.width);
                        }
                    }
                    if (jQuery.browser.msie && parseInt(jQuery.browser.version)<8){
                        obj.zfDropDown.width(obj.zfDropDown.width()-parseInt(lastLi.css('padding-left'))-parseInt(lastLi.css('padding-right')));
                    }
                    if (obj.overflowHidden) {
                        jQuery('li', obj.zfOptions).height(obj.rowHeight).css('overflow','hidden');
                    }
                    jQuery('li', obj.zfOptions).css('padding-top', 0).css('padding-bottom',0);

                    if (obj.multi) {
                        obj.maxRows = Math.round(obj.zfScrollPane.height()/obj.rowHeight);
                    } else {
                        obj.zfScrollPane.height(Math.min(obj.maxRows, obj.rows) * obj.rowHeight + parseInt(obj.zfOptions.css('padding-top')));
                    }

                    if (obj.zfScrollPane.height()<obj.zfOptions.height()) {
                        if (!obj.multi) {
                            obj.zfDropDown.width(obj.zfDropDown.width()+obj.zfScrollBar.width());
                        }
                        obj.zfScrollBar.height(obj.zfScrollPane.height() + parseInt(obj.zfOptions.css('padding-top')));
                        obj.zfScrollBar.show();
                        obj.zfScrollUp.show();
                        obj.zfScrollDown.show();
                    }
                    else {
                        obj.zfDropDown.width(obj.zfDropDown.width()+obj.zfScrollBar.width());
                        obj.zfOptions.css('padding-right', '0px').find('li').css('padding-right', '0px');
                        obj.zfScrollBar.hide();
                        obj.zfScrollUp.hide();
                        obj.zfScrollDown.hide();
                    }
                    obj.zfDropDown.hide().show();
                    obj.changed     = false;

                }
                jQuery.zfselect._doScrollToLi(obj.zfOptions.find('li:not(.optgroup).selected:first'));
            }
        },

        // change value of zfselect and change styles
        _doChange: function(target, event) {
            var obj = jQuery.zfselect._getInst(target);
            if (obj && jQuery(target).is('li') && !jQuery(target).hasClass('disabled') && !jQuery(target).hasClass('optgroup')) {
                obj.currentSelect = target.length ? jQuery(target) : target.first;
                if (obj.multi) {
                    var targetIndex = obj.zfOptions.find('li:not(.optgroup)').index(target);
                    var arrayIndex  = jQuery.inArray(targetIndex,obj.selected);
                    if (obj.shiftSelect.length==0) obj.shiftSelect = target;
                    var shiftIndex = obj.zfOptions.find('li:not(.optgroup)').index(obj.shiftSelect);
                    var toSelect = {};
                    switch (event.type) {
                        case 'mouseup':                 // click ???
                            if (event.ctrlKey) {
                                if (arrayIndex>-1) {
                                    obj.selected.splice(arrayIndex,1);
                                } else {
                                    obj.selected.push(targetIndex);
                                }
                                obj.shiftSelect = target;
                            } else if (event.shiftKey) {
                                if (jQuery.inArray(targetIndex, obj.selected)<0) {
                                    jQuery(target).removeClass('selected');
                                }
                                if (targetIndex>=shiftIndex) {
                                    toSelect = jQuery('li:not(.optgroup):eq('+shiftIndex+'), li:not(.optgroup):gt('+shiftIndex+'):lt('+(targetIndex-shiftIndex)+')', obj.zfOptions);
                                } else {
                                    toSelect = jQuery('li:not(.optgroup):eq('+targetIndex+'), li:not(.optgroup):gt('+targetIndex+'):lt('+(shiftIndex-targetIndex)+')', obj.zfOptions);
                                }
                            } else {
                                obj.selected.length     = 0;
                                obj.selected.push(targetIndex);
                                obj.shiftSelect         = target;
                            }
                            break;
                        case 'keydown':
                            if (event.shiftKey) {
                                if (targetIndex>shiftIndex) {
                                    toSelect = jQuery('li:not(.optgroup):eq('+shiftIndex+'), li:not(.optgroup):gt('+shiftIndex+'):lt('+(targetIndex-shiftIndex)+')', obj.zfOptions);
                                } else {
                                    toSelect = jQuery('li:not(.optgroup):eq('+targetIndex+'), li:not(.optgroup):gt('+targetIndex+'):lt('+(shiftIndex-targetIndex)+')', obj.zfOptions);
                                }
                            } else {
                                obj.selected.length     = 0;
                                obj.selected.push(targetIndex);
                                obj.shiftSelect         = target;
                            }
                            break;
                        case 'keypress':
                            toSelect = jQuery(target);
                            break;
                    }
                    if (toSelect.length) {
                        obj.selected.length     = 0;
                        toSelect.each(function(i, e){
                            obj.selected.push(obj.zfOptions.find('li:not(.optgroup)').index(e));
                        });
                    }
                } else {
                    obj.selected.length     = 0;
                    obj.selected.push(obj.zfOptions.find('li:not(.optgroup)').index(target));
                }

                jQuery('option:selected', obj.select).each(function(i, e){
                    jQuery.zfselect._removeAttrOriginal.apply(jQuery(e), ['selected']);
                });
                jQuery.each(obj.selected, function(i, e){
                    jQuery.zfselect._attrOriginal.apply(jQuery('option:eq('+ e +')', obj.select), ['selected', 'selected']);
                });
                jQuery.zfselect._doCloneSelect(target);
                jQuery.zfselect._doScrollToLi(target);
                var result = true;
                if (obj.selected.length==obj.oldSelected.length) {
                    result = false;
                    jQuery.each(obj.selected, function(i, e){
                        if (jQuery.inArray(e, obj.oldSelected)<0) {
                            result = true;
                        }
                    });
                }
                obj.oldSelected = [].concat(obj.selected);
                if (result) {
                    obj.changeSent = false;
                    return true;
                }
             }
            return false;
        },

        _doLiScrollMouse: function() {
            if (jQuery.zfselect.moveMouseObject!=null && jQuery.zfselect.moveMouseEvent!=null && !jQuery.zfselect.moveMouseEvent.ctrlKey) {
                if (jQuery.zfselect._isMouseMoved()) {
                    jQuery.zfselect._doDisableSelection();
                }
                var obj     = jQuery.zfselect.moveMouseObject;
                var mouseY      = jQuery.zfselect.moveMouseEvent.pageY;
                var mouseX      = jQuery.zfselect.moveMouseEvent.pageX;
                var paneTop     = obj.zfDropDown.offset().top;
                var paneLeft    = obj.zfDropDown.offset().left;
                var paneHeight  = obj.zfDropDown.height();
                var paneWidth   = obj.zfDropDown.width();
                if (paneLeft<mouseX && (paneLeft+paneWidth)>mouseX) {
                    var current = obj.currentSelect;
                    if ((paneTop+paneHeight)<mouseY) {  // down
                        var nextLi = current;
                        if (nextLi.length) {
                            var lastLi = jQuery('li:last', obj.zfOptions);
                            do {
                                nextLi = nextLi.next();
                                if (nextLi.index()==lastLi.index()) break;
                            } while (nextLi.hasClass('disabled')||nextLi.hasClass('optgroup'));
                        } else {
                            nextLi = jQuery('li:not(.disabled):first', obj.zfOptions);
                        }
                        if (nextLi.length && nextLi.is(':not(.disabled)')) {
                            if (!obj.multi) current.removeClass('selected');
                            nextLi.addClass('selected');
                            obj.currentSelect = nextLi.last();
                            jQuery.zfselect._doScrollToLi(obj.currentSelect);
                        }
                    } else if (paneTop>mouseY) {        // up
                        var nextLi = current;
                        if (nextLi.length) {
                            var lastLi = jQuery('li:first', obj.zfOptions);
                            do {
                                nextLi = nextLi.prev();
                                if (nextLi.index==lastLi.index()) break;
                            } while (nextLi.hasClass('disabled')||nextLi.hasClass('optgroup'));
                        } else {
                            nextLi = jQuery('li:not(.disabled):last', obj.zfOptions);
                        }
                        if (nextLi.length && nextLi.is(':not(.disabled)')) {
                            if (!obj.multi) current.removeClass('selected');
                            nextLi.addClass('selected');
                            obj.currentSelect = nextLi.first();
                            jQuery.zfselect._doScrollToLi(obj.currentSelect);
                        }
                    }
                }
            }
        },

        _mouseIsMoved: false,

        _doMouseMove: function(event) {
            var pe  = jQuery.zfselect.prevMoveMouseEvent   = jQuery.zfselect.moveMouseEvent;
            var ce  = jQuery.zfselect.moveMouseEvent       = event;
            jQuery.zfselect._mouseIsMoved  = (ce && pe && (ce.pageX!=pe.pageX || ce.pageY!=pe.pageY || ce.timeStamp!=pe.timeStamp));
        },

        _isMouseMoved: function() {
            return jQuery.zfselect._mouseIsMoved;
        },

        _doLiMouseUp: function(event) {
            clearInterval(jQuery.zfselect.moveMouseInterval);
            var obj = jQuery.zfselect.moveMouseObject;
            if (obj) {
                var mouseY      = jQuery.zfselect.moveMouseEvent.pageY;
                var mouseX      = jQuery.zfselect.moveMouseEvent.pageX;
                var paneTop     = obj.zfDropDown.offset().top;
                var paneLeft    = obj.zfDropDown.offset().left;
                var paneHeight  = obj.zfDropDown.height();
                var paneWidth   = obj.zfDropDown.width();
                if (obj.multi || paneLeft<mouseX && (paneLeft+paneWidth)>mouseX) {
                    event.shiftKey  = true;
                    obj.changeSent = true;
                    if (!obj.currentSelect.hasClass('disabled')) {
                        jQuery.zfselect._doHide(obj);
                    }
                    if (jQuery.zfselect._doChange(obj.currentSelect, event)) {
                        obj.changeSent = true;
                        obj.select.trigger('change');
                    }
                    jQuery.zfselect.moveMouseObject    = null;
                    obj.select.trigger('click');
                }
                if (paneLeft<mouseX && (paneLeft+paneWidth)>mouseX && paneTop<mouseY && (paneTop+paneHeight)>mouseY) {
                    obj.select.find('option:eq('+obj.select.find('li:eq('+(obj.zfOptions.find(':not(.optgroup)').index(obj.currentSelect))+')')+')').trigger('click');
                }
                jQuery(document).unbind('mouseup', jQuery.zfselect._doLiMouseUp);
                jQuery.zfselect._doEnableSelection();
            }
        },

        _doLiMouseDown: function(event) {
            var obj     = jQuery.zfselect._getInst(event.currentTarget);
            var target  = jQuery(event.target);
            if (obj && target.is('li')) {
                if (obj.multi && event.type=='mousedown') {
                    obj.zfSelect.trigger('focus'); // for IE
                    jQuery.each(jQuery.zfselect._elements, function(id, object){
                        jQuery.zfselect._doHide(object.zfSelect);
                    });
                }
                if (!obj.multi || (event.type=='mousedown' && !event.ctrlKey && !event.shiftKey) ) {
                    jQuery('li', obj.zfOptions).removeClass('selected');
                }
                //if (jQuery.zfselect._isMouseMoved()) {
                    if (!obj.multi || event.type=='mousedown' ) {
                        target.addClass('selected');
                    }
                //}
                if (obj.multi && jQuery.zfselect.moveMouseObject!=null) {
                    var shift    = obj.shiftSelect.index();
                    var current  = target.index();
                    jQuery('li', obj.zfOptions).removeClass('selected');
                    if (shift==current) {
                        jQuery('li:eq('+current+')', obj.zfOptions).addClass('selected');
                    } else if (shift<current) {
                        jQuery('li:eq('+shift+'), li:gt('+(shift)+'):lt('+(current-shift)+')', obj.zfOptions).addClass('selected');
                    } else {
                        jQuery('li:eq('+current+'), li:gt('+(current)+'):lt('+(shift-current)+')', obj.zfOptions).addClass('selected');
                    }

                }
                if (event.type=='mousedown') {
                    if (!event.shiftKey) {
                        obj.shiftSelect = target;
                    }
                    jQuery.zfselect.moveMouseObject    = obj;
                    jQuery.zfselect.moveMouseInterval  = setInterval(jQuery.zfselect._doLiScrollMouse, 150);
                    jQuery(document).bind('mouseup',jQuery.zfselect._doLiMouseUp);
                }
                if (jQuery.zfselect._isMouseMoved()) {
                    obj.currentSelect = target;
                }
            }
        },

        // clone selection
        _doCloneSelect: function(target) {
            var obj = jQuery.zfselect._getInst(target);
            if (obj && jQuery('option', obj.select).length==jQuery('li:not(.optgroup)', obj.zfOptions).length) {
                if (!obj.multi) {
                    obj.zfText.html(jQuery('option:selected', obj.select).text());
                }
                jQuery('li', obj.zfOptions).removeClass('selected');
                obj.selected.length     = 0;
                jQuery('option', obj.select).each(function(i, e){
                    if (jQuery(e).is(':selected')) {
                        obj.selected.push(i);
                        jQuery('li:not(.optgroup):eq(' + i + ')', obj.zfOptions).addClass('selected');
                    }
                });
                jQuery('li', obj.zfOptions).removeClass('disabled');
                jQuery('option', obj.select).each(function(i, e){
                    if (jQuery(e).is(':disabled')) {
                        jQuery('li:not(.optgroup):eq(' + i + ')', obj.zfOptions).addClass('disabled');
                    }
                });
                jQuery('optgroup', obj.select).each(function(i, e){
                    if (jQuery(e).is(':disabled')) {
                        jQuery('li.optgroup:eq(' + i + ')', obj.zfOptions).addClass('disabled');
                    }
                });
            } else {
                jQuery.zfselect.refresh(target);
                // refresh ???
//                throw Exception('select is out of sync');
            }
        },

        // onFocus
        _doOnFocus: function(event) {
            var obj = jQuery.zfselect._getInst(event.currentTarget);
            if (obj && !obj.focus) {
                obj.focus = true;
                jQuery.each(jQuery.zfselect._elements, function(id, el){
                    if (el.id!=obj.id) {
                        el.zfSelect.trigger('blur');
                    }
                });
                obj.zfSelect.addClass(obj.multi ? 'zf-focus-select' : 'zf-select-focus');
                if (!obj.focusSent) {
                    obj.focusSent = true;
                    obj.blurSent  = false;
                    obj.select.trigger('focus');
                }
            }
        },

        // onBlur (unfocus)
        _doOnBlur: function(event) {
            var obj = jQuery.zfselect._getInst(event.currentTarget);
            if (obj && obj.focus) {
                obj.focus = false;
                obj.zfSelect.removeClass(obj.multi ? 'zf-focus-select' : 'zf-select-focus');
                if (!obj.changeSent) {
                    obj.changeSent = true;
                    obj.select.trigger('change');
                }
                if (!obj.blurSent) {
                    obj.blurSent = true;
                    obj.focusSent= false;
                    obj.select.trigger('blur');
                }
            }
        },

        //
        _doSelect: function(event) {
            var obj = jQuery.zfselect._getInst(event.currentTarget);
            if (obj) {
                if (jQuery(this).hasClass('disabled')) return false;
                jQuery.zfselect._doChange(jQuery(event.currentTarget), event);
                if (!obj.multi) jQuery.zfselect._doHide(obj.zfSelect);
                obj.changeSent = true;
                obj.select.trigger('change');
            }
        },

        // create new instance and put into container
        _newInstance: function(target, settings) {
            var id     = jQuery(target).attr('id');
            var zIndex = parseInt(jQuery(target).css('z-index'));
            var options= {};
            jQuery.extend(options, this.defaults, settings);
            var obj = {
                'id':               id,
                'mainId':           'zf-select-' + id,
                'disabled':         jQuery(target).is(':disabled'),
                'multi':            jQuery(target).attr('multiple'),
                'width':            options.width,
                'maxWidth':         options.maxWidth,
                'overflowHidden':   options.overflowHidden,
                'rowHeight':        0,                                                      // will be set on show-autosize
                'rowPaddingTop':    0,
                'rowPaddingBottom': 0,
                'maxRows':          options.rows,
                'rows':             jQuery(target).find('option').length,
                'zindex':           isNaN(zIndex) ? 0 : zIndex,
                'select':           jQuery(target),
                'changeSent':       true,
                'zfSelect':         jQuery('div#zf-select-' + id),
                'zfText':           jQuery('div#zf-select-' + id + ' div.select-text'),
                'zfButton':         jQuery('div#zf-select-' + id + ' div.select-btn'),
                'zfDropDown':       jQuery('div#zf-select-' + id + ' div.select-drop'),
                'zfMiddle':         jQuery('div#zf-select-' + id + ' div.select-mid'),
                'zfOptions':        jQuery('div#zf-select-' + id + ' ul'),
                'zfScrollPane':     jQuery('div#zf-select-' + id + ' div.scrollable'),
                'zfScrollBar':      jQuery('div#zf-select-' + id + ' div.zf-scroll-track'),
                'zfScrollUp':       jQuery('div#zf-select-' + id + ' div.zf-scroll-arrow-top'),
                'zfScrollDown':     jQuery('div#zf-select-' + id + ' div.zf-scroll-arrow-btm'),
                'zfScrollDrag':     jQuery('div#zf-select-' + id + ' div.zf-scroll-drag'),
                'currentDirection': 0,
                'selected':         [],
                'oldSelected':      [],
                'shiftSelect':      {},
                'currentSelect':    {},
                'changed':          false,
                'optionCallback':   options.optionCallback,
                'onBeforeOpen':     options.onBeforeOpen,
                'onAfterOpen':      options.onAfterOpen,
                'onBeforeClose':    options.onBeforeClose,
                'onAfterClose':     options.onAfterClose,
                'get':              jQuery.zfselect._getElement
            };
            return obj;
        },

        // scroll to li(option)
        _doScrollToLi: function(target) {
            var obj = jQuery.zfselect._getInst(target);
            if (obj) {
                if (jQuery(target).is('li')) {
                    var newTop  = jQuery(target).position().top-jQuery(target).parent().position().top;
                    if ((obj.zfScrollPane.height()-(obj.zfOptions.position().top+newTop))<=jQuery(target).height()) {
                        obj.zfScrollPane.scrollTop(newTop+jQuery(target).height()-obj.zfScrollPane.height());
                    } else if ((obj.zfOptions.position().top+newTop)<=0) {
                        obj.zfScrollPane.scrollTop(newTop);
                    }
                }
                jQuery.zfselect._doUpdateSlider(target);
            }
        },

        // update scroll bar after manual scroll
        _doUpdateSlider: function(target) {
            var obj = jQuery.zfselect._getInst(target);
            if (obj && obj.zfScrollBar.is(':visible')) {
                var scrollBarHeight     = obj.zfScrollBar.height()-obj.zfScrollUp.height()-obj.zfScrollDown.height()-obj.zfScrollDrag.height();
                var scrollPaneTop       = obj.zfOptions.position().top;
                var scrollPaneHeight    = obj.zfOptions.height()-obj.zfScrollPane.height();
                obj.zfScrollDrag.css('top', obj.zfScrollUp.height() + (-scrollPaneTop/scrollPaneHeight)*scrollBarHeight);
                jQuery.zfselect._doUpdateArrows(target);
           }
        },

        // update up&down arrows
        _doUpdateArrows: function(target) {
            var obj = jQuery.zfselect._getInst(target);
            if (obj) {
                obj.zfScrollUp.removeClass('zf-scroll-arrow-top-dis');
                if (obj.zfOptions.position().top==0) {
                    obj.zfScrollUp.addClass('zf-scroll-arrow-top-dis');
                }

                obj.zfScrollDown.removeClass('zf-scroll-arrow-btm-dis');
                if (Math.round(-obj.zfOptions.position().top)==(obj.zfOptions.height()-obj.zfScrollPane.height())) {
                    obj.zfScrollDown.addClass('zf-scroll-arrow-btm-dis');
                }
            }
        },

        // if manage keys pressed
        _doKeyDown: function(event) {
            var obj = jQuery.zfselect._getInst(event.currentTarget);
            if (obj && !obj.disabled) {
                var select  = jQuery.zfselect._getInst(event.currentTarget);
                var current = obj.currentSelect.length ? obj.currentSelect : obj.zfOptions.find('li:not(.optgroup).selected:first');
                if (event.keyCode==32 || event.keyCode==13 || (event.altKey && (event.keyCode==40 || event.keyCode==38))) {
                    // Space || Enter || (Alt && (Dn || Up))
                    if (event.keyCode==13 && obj.zfDropDown.is(':visible'))
                    {
                        jQuery.zfselect._doSelect(event);
                    } else {
                        obj.zfText.trigger('click');
                    }
                    return false;
                } else if (event.keyCode==27 || event.keyCode==9) {
                    // Esc || Tab
                    obj.zfDropDown.hide();
                    if (event.keyCode==9) return true;
                    return false;
                } else if (event.keyCode==40) {
                    // Dn
                    var nextLi = current;
                    if (nextLi.length) {
                        var lastLi = jQuery('li:not(.optgroup):not(.disabled):last', obj.zfOptions);
                        do {
                            nextLi = nextLi.next();
                            if (obj.zfOptions.find('li:not(.optgroup)').index(nextLi)==obj.zfOptions.find('li:not(.optgroup)').index(lastLi)) break;
                        } while (nextLi.hasClass('disabled'));
                    } else {
                        nextLi = jQuery('li:not(.optgroup):not(.disabled):first', obj.zfOptions);
                    }
                    jQuery.zfselect._doChange(nextLi.length && !nextLi.hasClass('disabled') ? nextLi : current, event);
                    return false;
                } else if (event.keyCode==38) {
                    // Up
                    var nextLi = current;
                    if (nextLi.length) {
                        var firstLi = jQuery('li:not(.optgroup):not(.disabled):first', obj.zfDropDown);
                        do {
                            nextLi = nextLi.prev();
                            if (obj.zfOptions.find('li:not(.optgroup)').index(nextLi)==obj.zfOptions.find('li:not(.optgroup)').index(firstLi)) break;
                        } while (nextLi.hasClass('disabled'));
                    } else {
                        nextLi = jQuery('li:not(.optgroup):not(.disabled):last', obj.zfOptions);
                    }
                    jQuery.zfselect._doChange(nextLi.length && !nextLi.hasClass('disabled') ? nextLi : current, event);
                    return false;
                } else if (event.keyCode==34) {
                    // PgDn
                    var lastLi = jQuery('li:not(.optgroup):not(.disabled):last', obj.zfOptions);
                    var nextLi = jQuery('li:not(.optgroup):eq('+(obj.zfOptions.find('li:not(.optgroup)').index(current)+obj.maxRows-1)+')', obj.zfOptions);
                    do {
                        if (nextLi.length) {
                            nextLi = nextLi.next();
                        }
                        if (!nextLi.length || obj.zfOptions.find('li:not(.optgroup)').index(nextLi)>=obj.zfOptions.find('li:not(.optgroup)').index(lastLi)) {
                            nextLi  = lastLi;
                            break;
                        }
                    } while (nextLi.hasClass('disabled'));
                    jQuery.zfselect._doChange(nextLi.length && !nextLi.hasClass('disabled') ? nextLi : current, event);
                    return false;
                } else if (event.keyCode==33) {
                    // PgUp
                    var firstLi = jQuery('li:not(.optgroup):not(.disabled):first', obj.zfOptions);
                    var nextLi  = jQuery('li:not(.optgroup):eq('+(obj.zfOptions.find('li:not(.optgroup)').index(current)-obj.maxRows+1)+')', obj.zfOptions);
                    do {
                        if (nextLi.length) {
                            nextLi = nextLi.prev();
                        }
                        if (!nextLi.length || obj.zfOptions.find('li:not(.optgroup)').index(nextLi)<=obj.zfOptions.find('li:not(.optgroup)').index(firstLi)) {
                            nextLi  = firstLi;
                            break;
                        }
                    } while (nextLi.hasClass('disabled'));
                    jQuery.zfselect._doChange(nextLi.length && !nextLi.hasClass('disabled') ? nextLi : current, event);
                    return false;
                } else if (event.keyCode==35) {
                    // End
                    jQuery.zfselect._doChange(jQuery('li:not(.optgroup):not(.disabled):last', obj.zfOptions), event);
                    return false;
                } else if (event.keyCode==36) {
                    // Home
                    jQuery.zfselect._doChange(jQuery('li:not(.optgroup):not(.disabled):first', obj.zfOptions), event);
                    return false;
                }
            }
        },

        _doSelectMouseDown: function(event) {
            var obj = jQuery.zfselect._getInst(event.currentTarget);
            if (obj && !obj.zfDropDown.is(':visible')) {
                obj.select.trigger('mousedown');
            }
        },

        _doSelectMouseUp: function(event) {
            var obj = jQuery.zfselect._getInst(event.currentTarget);
            if (obj && obj.zfDropDown.is(':visible')) {
                obj.select.trigger('mouseup');
            }
        },

        // click on Text or Button
        _doSelectClick: function(event) {
            var obj = jQuery.zfselect._getInst(this);
            if (obj && !obj.disabled) {
                obj.zfSelect.trigger('focus');
                if (obj.zfDropDown.is(':visible')) {
                    jQuery.zfselect._doHide(this);
                    obj.select.trigger('click');
                } else {
                    jQuery.zfselect._doShow(this);
                }
            }
        },

        // down mouse button on ScrollBar down arrow
        _doMouseArrow: function(event) {
            var target  = jQuery(event.currentTarget);
            jQuery(document).bind('mouseup',jQuery.zfselect._doMouseUp);
            var obj = jQuery.zfselect._getInst(event.currentTarget);
            if (obj) {
                jQuery.zfselect._doHideExcept(obj);
                if (target.hasClass('btup')) {  // up
                    obj.currentDirection = -1;
                    obj.zfScrollUp.addClass('zf-scroll-arrow-top-press');
                } else if (target.hasClass('btdn')) {  // down
                    obj.currentDirection = 1;
                    obj.zfScrollDown.addClass('zf-scroll-arrow-btm-press');
                } else {
                    return true;    // ?????
                }
                jQuery.zfselect._disableLiEvents(obj);
                jQuery.zfselect._doDisableSelection();
                jQuery.zfselect.moveMouseObject = obj;
                jQuery.zfselect._doMouseDown();
                jQuery.zfselect.moveMouseInterval = setInterval(jQuery.zfselect._doMouseDown, 150);
                return false;
            }
        },

        // sroll while button of mouse down
        _doMouseDown: function() {
            var obj = jQuery.zfselect.moveMouseObject;
            if (obj) {
                // multiplier ???
                jQuery.zfselect._doScroll(obj, obj.currentDirection*obj.rowHeight);
            }
        },

        // scroll to dirrection up to pics
        _doScroll: function(obj, offset) {
            if (obj) {
                obj.zfScrollPane.scrollTop(offset-obj.zfOptions.position().top);
                jQuery.zfselect._doUpdateSlider(obj.zfSelect);
            }
        },

        // release mouse button after scroll
        _doMouseUp: function(event) {
            clearInterval(jQuery.zfselect.moveMouseInterval);
            var obj = jQuery.zfselect.moveMouseObject;
            if (obj) {
                jQuery.zfselect._enableLiEvents(obj);
                jQuery.zfselect._doEnableSelection();
                obj.zfScrollUp.removeClass('zf-scroll-arrow-top-press');
                obj.zfScrollDown.removeClass('zf-scroll-arrow-btm-press');
            }
            jQuery(document).unbind('mouseup',jQuery.zfselect._doMouseUp);
            jQuery.zfselect.moveMouseObject = null;
        },

        // down mouse on Track
        _doMouseDownDrag: function(event) {
            var obj = jQuery.zfselect._getInst(event.currentTarget);
            if (obj) {
                jQuery.zfselect._doHideExcept(obj);
                obj.lastDragY         = event.clientY;
                jQuery.zfselect.moveMouseObject = obj;
                jQuery.zfselect._disableLiEvents(obj);
                jQuery(document)
                    .bind('mouseup', jQuery.zfselect._doMouseUpDrag)
                    .bind('mousemove', jQuery.zfselect._doMouseMoveDrag);
                return false;
            }
        },

        // release mouse on Track
        _doMouseUpDrag: function(event) {
            var obj = jQuery.zfselect.moveMouseObject;
            if (obj) {
                jQuery.zfselect._enableLiEvents(obj);
            }
            jQuery(document)
                .unbind('mouseup', jQuery.zfselect._doMouseUpDrag)
                .unbind('mousemove', jQuery.zfselect._doMouseMoveDrag);
            jQuery.zfselect.moveMouseObject = null;
        },

        // drag track ????
        _doMouseMoveDrag: function(event) {
            var obj    = jQuery.zfselect.moveMouseObject;
            if (obj) {
                var offset = (obj.lastDragY-event.clientY);
                obj.lastDragY = event.clientY;
                var height  = obj.zfScrollBar.height();
                var top1    = obj.zfScrollDrag.css('top');
                var height1 = obj.zfScrollDrag.height();
                var pers    = -1;
                if (offset!=0) {
                    var trackTop = obj.zfScrollDrag.attr('top')?parseFloat(obj.zfScrollDrag.attr('top')):parseFloat(obj.zfScrollDrag.css('top'));
                    if (offset<0) {
                        if ((trackTop+Math.abs(offset))>(height-(height1+obj.zfScrollDown.height()))) {
                            offset = 0;
                            pers   = 1;
                        }
                        obj.zfScrollDrag.css('top',(trackTop+Math.abs(offset))+'px').attr('top', trackTop+Math.abs(offset));
                    } else {
                        if ((trackTop-Math.abs(offset))<obj.zfScrollUp.height()) {
                            offset = 0;
                            pers   = 0;
                        }
                        obj.zfScrollDrag.css('top',(trackTop-Math.abs(offset))+'px').attr('top', trackTop-Math.abs(offset));
                    }
                    pers = pers!=-1 ? pers : (parseFloat(obj.zfScrollDrag.attr('top'))-obj.zfScrollUp.height())/(height-(obj.zfScrollUp.height()+obj.zfScrollDown.height())-height1);
                    if (pers==Infinity || pers<0) pers=0;
                    if (pers>1) pers=1;
                    obj.zfScrollPane.scrollTop((obj.zfOptions.height()-obj.zfScrollPane.height())*pers+parseInt(obj.zfOptions.css('padding-top')));
                }
                jQuery.zfselect._doUpdateArrows(obj.zfSelect);
                return false;
            }
        },

        _doBarMouseDown: function(event) {
            var obj     = jQuery.zfselect._getInst(event.currentTarget);
            if (obj) {
                jQuery.zfselect._doHideExcept(obj);
                jQuery(document).bind('mouseup',jQuery.zfselect._doBarMouseUp);
                jQuery.zfselect._disableLiEvents(obj);
                jQuery.zfselect._doDisableSelection();
                jQuery.zfselect.moveMouseObject = obj;
                jQuery.zfselect._doBarMouse();
                jQuery.zfselect.moveMouseInterval = setInterval(jQuery.zfselect._doBarMouse, 150);
                return false;
            }
        },

        _doBarMouse: function() {
            var obj = jQuery.zfselect.moveMouseObject;
            if (obj) {
                if (jQuery.zfselect.moveMouseEvent.pageX>obj.zfScrollBar.offset().left
                    && jQuery.zfselect.moveMouseEvent.pageX<(obj.zfScrollBar.offset().left+obj.zfScrollBar.width())
                    && jQuery.zfselect.moveMouseEvent.pageY>obj.zfScrollBar.offset().top
                    && jQuery.zfselect.moveMouseEvent.pageY<(obj.zfScrollBar.offset().top+obj.zfScrollBar.height())
                ) {
                    if (jQuery.zfselect.moveMouseEvent.pageY>obj.zfScrollDrag.offset().top && jQuery.zfselect.moveMouseEvent.pageY<(obj.zfScrollDrag.offset().top+obj.zfScrollDrag.height())) {
                        jQuery.zfselect._doBarMouseUp();
                    } else {
                        delta   = jQuery.zfselect.moveMouseEvent.pageY>obj.zfScrollDrag.offset().top ? 1 : -1;
                        jQuery.zfselect._doScroll(obj, delta*obj.rowHeight*obj.maxRows);
                    }
                }
            }
        },

        _doBarMouseUp: function(event) {
            clearInterval(jQuery.zfselect.moveMouseInterval);
            var obj = jQuery.zfselect.moveMouseObject;
            if (obj) {
                jQuery.zfselect._enableLiEvents(obj);
                jQuery.zfselect._doEnableSelection();
            }
            jQuery(document).unbind('mouseup',jQuery.zfselect._doBarMouseUp);
            jQuery.zfselect.moveMouseObject = null;
        },

        _doMouseWheel: function(event, delta) {
            var obj = jQuery.zfselect._getInst(event.currentTarget);
            var eventTmp    = event.type=='mousewheel' ? event.originalEvent : event.originalEvent.touches[0];
            if (obj) {
                obj.lastDragY = eventTmp.clientY;
                event.clientY = eventTmp.clientY;
                jQuery.zfselect.moveMouseObject = obj;
                var toScroll  = obj.zfScrollBar.height()/(obj.zfOptions.height()/obj.rowHeight);
                if (event.type!='mousewheel') {
                    delta   = eventTmp.pageY - jQuery.zfselect.touchStartY;
                }
                var direction = delta/Math.abs(delta);
                switch (direction) {
                    case 1:             // up
                        toScrollMin     = parseFloat(obj.zfScrollDrag.attr('top'))-obj.zfScrollUp.height();
                        if (toScroll>toScrollMin) {
                            toScroll    = toScrollMin;
                        }
                        break;
                    case -1:            // down
                        toScrollMin     = obj.zfScrollBar.height()-parseFloat(obj.zfScrollDrag.attr('top'))-obj.zfScrollDrag.height()-obj.zfScrollDown.height();
                        if (toScroll>toScrollMin) {
                            toScroll    = toScrollMin;
                        }
                        break;
                }
                event.clientY-= direction*toScroll;
                jQuery.zfselect._doMouseMoveDrag(event);
                jQuery.zfselect.moveMouseObject = null;
                return false;
            }
        },

        keyWait: null,
        keyStack: [],

        _doKeyPress: function(event) {
            var obj = jQuery.zfselect._getInst(event.currentTarget);
            if (!obj || obj.disabled) return true;

            var key, keyChar;
            jQuery.zfselect.keyStack.push(event);
            var keyHandler = function() {
                var str = '';
                var obj = null;
                for ( var a in jQuery.zfselect.keyStack ) {
                    str += String.fromCharCode(jQuery.zfselect.keyStack[a].which);
                    obj = jQuery.zfselect._getInst(jQuery.zfselect.keyStack[a].currentTarget);
                }
                if (str.length==1) {
                    var index = 0;
                    if (obj.selected.length) {
                        index   = obj.selected[0]+1;
                    }
                    var found = false;
                    do {
                        obj.zfOptions.find('li:ge('+index+')').each(function(){
                            if ( jQuery(this).attr('title').substr(0,1).toLowerCase()==str.toLowerCase() ) {
                                if (!jQuery(this).hasClass('disabled')) {
                                    jQuery.zfselect._doChange(jQuery(this), event);
                                    found   = true;
                                    return false;
                                }
                            }
                        });
                        if (!found && index>0) {
                            index   = 0;
                        }
                        else {
                            index   = -1;
                        }
                    } while (!found && index!=-1);
                }
                else {
                    obj.zfOptions.find('li').each(function(){
                        if ( jQuery(this).attr('title').substr(0,str.length).toLowerCase()==str.toLowerCase() ) {
                            if (!jQuery(this).hasClass('disabled')) {
                                jQuery.zfselect._doChange(jQuery(this), event);
                                return false;
                            }
                        }
                    });
                }
                jQuery.zfselect.keyStack = [];
            };
            clearTimeout(jQuery.zfselect.keyWait);
            jQuery.zfselect.keyWait = setTimeout(keyHandler, 500);
        },

        _doExternalClick: function(event) {
            if ((event.clientY<jQuery(window).height())&&(event.clientX<jQuery(window).width())) {
                if (!jQuery.zfselect._getInst(event.target)) {
                    jQuery.each(jQuery.zfselect._elements, function(id, obj){
                        jQuery.zfselect._doHide(obj.zfSelect);
                    });
               }
            }
        },

        externalTouchObj: null,
        externalTouchMove: false,

        _doExternalTouchStart: function(event) {
            var touch   = event.originalEvent.touches[0];
            if ((touch.clientY<jQuery(window).height())&&(touch.clientX<jQuery(window).width())) {
                jQuery.zfselect.externalTouchObj    = jQuery.zfselect._getInst(event.target);
                jQuery.zfselect.externalTouchMove   = false;
            }
        },

        _doExternalTouchMove: function(event) {
            if (!jQuery.zfselect.externalTouchObj) {
                jQuery.zfselect.externalTouchMove   = true;
            }
        },

        _doExternalTouchEnd: function(event) {
            if (!jQuery.zfselect.externalTouchObj && !jQuery.zfselect.externalTouchMove) {
                jQuery.each(jQuery.zfselect._elements, function(id, obj){
                    jQuery.zfselect._doHide(obj.zfSelect);
                });
            }
            jQuery.zfselect.externalTouchObj    = null;
        },

        _disableSelectionFlag: false,

        _doDisableSelection : function() {
            if (!jQuery.zfselect._disableSelectionFlag) {
                jQuery.zfselect._disableSelectionFlag = true;
                if (!jQuery.browser.mozilla) {
                    jQuery('body *').disableSelection();
                }
            }
        },

        _doEnableSelection : function() {
            if (jQuery.zfselect._disableSelectionFlag) {
                jQuery.zfselect._disableSelectionFlag = false;
                if (!jQuery.browser.mozilla) {
                    jQuery('body *').enableSelection();
                }
            }
        },

        _removeOriginal: undefined,
        _remove: function() {
            var result  = null;
            var objects     = [];
            jQuery(this).each(function() {
                if (jQuery(this).is('option')) {
                    var obj = jQuery.zfselect._getInst(this);
                    if (obj) {
                        if (undefined==obj.toRemove) {
                            obj.toRemove    = [];
                        }
                        obj.toRemove.push(jQuery(this).index());
                        if (jQuery.inArray(obj.select, objects)<0) {
                            objects.push(obj.select);
                        }
                    }
                }
            });
            result = jQuery.zfselect._removeOriginal.apply(this);
            jQuery.each(objects, function(id, el){
                var obj = jQuery.zfselect._getInst(el);
                obj.toRemove.sort(function(a,b){return a - b}).reverse();
                jQuery.each(obj.toRemove, function(i, el){
                    obj.zfOptions.find('li:eq('+el+')').remove();
                });
                jQuery.zfselect.refresh(el);
            });
            return result;
        },

        _appendOriginal: undefined,
        _append: function() {
            var result = jQuery.zfselect._appendOriginal.apply(this, arguments);
            var objects     = [];
            jQuery(this).each(function() {
                if (jQuery(this).is('select')) {
                    var obj = jQuery.zfselect._getInst(this);
                    if (obj) {
                        obj.select.find('option:ge('+obj.zfOptions.find('li').length+')').each(function(){
                            obj.zfOptions.append(jQuery.zfselect._prepareOption(jQuery(this)));
                        });
                        if (jQuery.inArray(obj.select, objects)<0) {
                            objects.push(obj.select);
                        }
                    }
                }
            });
            jQuery.each(objects, function(id, el){
                jQuery.zfselect.refresh(el);
            });
            return result;
        },

        _prependOriginal: undefined,
        _prepend: function() {
            var result = jQuery.zfselect._prependOriginal.apply(this, arguments);
            var objects     = [];
            jQuery(this).each(function() {
                if (jQuery(this).is('select')) {
                    var obj = jQuery.zfselect._getInst(this);
                    if (obj) {
                        var baseIndex   = 0;
                        jQuery(obj.select.find('option:lt('+(obj.select.find('option').length-obj.zfOptions.find('li').length)+')').get().reverse()).each(function(){
                            obj.zfOptions.prepend(jQuery.zfselect._prepareOption(jQuery(this)));
                        });
                        if (jQuery.inArray(obj.select, objects)<0) {
                            objects.push(obj.select);
                        }
                    }
                }
            });
            jQuery.each(objects, function(id, el){
                jQuery.zfselect.refresh(el);
            });
            return result;
        },

        _afterOriginal: undefined,
        _after: function() {
            var result = jQuery.zfselect._afterOriginal.apply(this, arguments);
            var objects     = [];
            jQuery(this).each(function() {
                if (jQuery(this).is('option')) {
                    var obj = jQuery.zfselect._getInst(jQuery(this));
                    if (obj) {
                        var baseIndex = jQuery(this).index();
                        var diff      = 0;
                        obj.select.find('option:gt('+jQuery(this).index()+'):lt('+(obj.select.find('option').length-obj.zfOptions.find('li').length)+')').each(function(){
                            obj.zfOptions.find('li:eq('+(baseIndex+diff++)+')').after(jQuery.zfselect._prepareOption(jQuery(this)));
                        });
                        if (jQuery.inArray(obj.select, objects)<0) {
                            objects.push(obj.select);
                        }
                    }
                }
            });
            jQuery.each(objects, function(id, el){
                jQuery.zfselect.refresh(el);
            });
            return result;
        },

        _beforeOriginal: undefined,
        _before: function() {
            var result = jQuery.zfselect._beforeOriginal.apply(this, arguments);
            var objects     = [];
            jQuery(this).each(function() {
                if (jQuery(this).is('option')) {
                    var obj = jQuery.zfselect._getInst(jQuery(this));
                    if (obj) {
                        startIndex = jQuery(this).index()-(obj.select.find('option').length-obj.zfOptions.find('li').length);
                        endIndex   = obj.select.find('option').length-obj.zfOptions.find('li').length-1;
                        obj.select.find('option:eq('+startIndex+'), option:gt('+startIndex+'):lt('+endIndex+')').each(function(){
                            obj.zfOptions.find('li:eq('+(jQuery(this).index())+')').before(jQuery.zfselect._prepareOption(jQuery(this)));
                        });
                        if (jQuery.inArray(obj.select, objects)<0) {
                            objects.push(obj.select);
                        }
                    }
                }
            });
            jQuery.each(objects, function(id, el){
                jQuery.zfselect.refresh(el);
            });
            return result;
        },

        _emptyOriginal: undefined,
        _empty: function() {
            var result = jQuery.zfselect._emptyOriginal.apply(this, arguments);
            var objects = [];
            jQuery(this).each(function() {
                if (jQuery(this).is('select') || jQuery(this).is('option')) {
                    var obj     = jQuery.zfselect._getInst(this);
                    if (obj) {
                        if (jQuery.inArray(obj.select, objects)<0) {
                            objects.push(obj.select);
                        }
                    }
                }
            });
            jQuery.each(objects, function(id, el){
                jQuery.zfselect.refresh(el, {}, true);
            });
            return result;
        },

        _valOriginal: undefined,
        _val: function() {
            var result = jQuery.zfselect._valOriginal.apply(this, arguments);
            if (arguments.length!=0) {
                var objects = [];
                jQuery(this).each(function() {
                    if (jQuery(this).is('select') || jQuery(this).is('option')) {
                        var obj     = jQuery.zfselect._getInst(this);
                        if (obj) {
                            if (jQuery.inArray(obj.select, objects)<0) {
                                obj.force   = true;
                                objects.push(obj.select);
                            }
                        }
                    }
                });
                jQuery.each(objects, function(id, el){
                    jQuery.zfselect.refresh(el);
                });
            }
            return result;
        },

        _htmlOriginal: undefined,
        _html: function() {
            var result = jQuery.zfselect._htmlOriginal.apply(this, arguments);
            if (arguments.length!=0) {
                var objects = [];
                jQuery(this).each(function() {
                    if (jQuery(this).is('select') || jQuery(this).is('option')) {
                        var obj     = jQuery.zfselect._getInst(this);
                        if (obj) {
                            if (jQuery.inArray(obj.select, objects)<0) {
                                objects.push(obj.select);
                            }
                        }
                    }
                });
                jQuery.each(objects, function(id, el){
                    jQuery.zfselect.refresh(el, {}, true);
                });
            }
            return result;
        },

        _attrOriginal: undefined,
        _attr: function() {
            var result = jQuery.zfselect._attrOriginal.apply(this, arguments);
            if (arguments.length>1) {
                var objects = [];
                jQuery(this).each(function() {
                    if (jQuery(this).is('select') || jQuery(this).is('option')) {
                        var obj     = jQuery.zfselect._getInst(this);
                        if (obj) {
                            if (jQuery.inArray(obj.select, objects)<0) {
                                objects.push(obj.select);
                            }
                        }
                    }
                });
                jQuery.each(objects, function(id, el){
                    jQuery.zfselect.refresh(el);
                });
            }
            return result;
        },

        _removeAttrOriginal: undefined,
        _removeAttr: function() {
            var result = jQuery.zfselect._removeAttrOriginal.apply(this, arguments);
            if (arguments.length!=0) {
                var objects = [];
                jQuery(this).each(function() {
                    if (jQuery(this).is('select') || jQuery(this).is('option')) {
                        var obj     = jQuery.zfselect._getInst(this);
                        if (obj) {
                            if (jQuery.inArray(obj.select, objects)<0) {
                                objects.push(obj.select);
                            }
                        }
                    }
                });
                jQuery.each(objects, function(id, el){
                    jQuery.zfselect.refresh(el);
                });
            }
            return result;
        },

        _showOriginal: undefined,
        _show: function() {
            var result = jQuery.zfselect._showOriginal.apply(this, arguments);
            jQuery(this).find('select').each(function(){
                var obj = jQuery.zfselect._getInst(jQuery(this));
                if (obj) {
                    jQuery.zfselect.reinit(obj.select);
                }
            });
            return result;
        },

        _getBrowser: function() {
            return jQuery.browser.mozilla
                ? 'FF'                  // Firefox
                : jQuery.browser.msie
                    ? 'IE'              // Internet Explorer
                    : jQuery.browser.opera
                        ? 'OP'          // Opera
                        : 'WK';         // Chrome, Safari
        },

        _exec: function(target, func, settings) {
            var method  = eval('jQuery.zfselect.'+func);
            if (jQuery.isFunction(method)) {
                return method.call(this,target, settings); 
            }
            //throw new Exception('Unknown method "'+func+'" for zfselect plugin');
        }

    });

    if (undefined==jQuery.fn.zfselect) {
        jQuery.fn.zfselect = function(){
            if (!this.length) {
                return this;
            }
            var funcname    = arguments.length>0 && (typeof(arguments[0])=='string') ? arguments[0] : 'init';
            var settings    = {};
            switch (arguments.length) {
                case 1:
                    if (typeof(arguments[0])=='object') {
                        settings    = arguments[0];
                    }
                    break;
                case 2:
                    if (typeof(arguments[1])=='object') {
                        settings    = arguments[1];
                    }
                    break;
                default:
                    settings    = {};
            }
            return this.each(function(){
                jQuery.zfselect._exec(jQuery(this), funcname, settings);
            });
        };

        jQuery.zfselect = new zfSelect();

        jQuery(document)
            .bind('mousedown',jQuery.zfselect._doExternalClick)
            .bind('touchstart.jsp',jQuery.zfselect._doExternalTouchStart)
            .bind('touchmove.jsp',jQuery.zfselect._doExternalTouchMove)
            .bind('touchend.jsp',jQuery.zfselect._doExternalTouchEnd)
            .bind('mousemove',jQuery.zfselect._doMouseMove)
    }

    if (undefined==jQuery.zfselect._appendOriginal) {
        jQuery.zfselect._appendOriginal = jQuery.fn.append;
        jQuery.fn.append = jQuery.zfselect._append;
    }

    if (undefined==jQuery.zfselect._prependOriginal) {
        jQuery.zfselect._prependOriginal = jQuery.fn.prepend;
        jQuery.fn.prepend = jQuery.zfselect._prepend;
    }

    if (undefined==jQuery.zfselect._afterOriginal) {
        jQuery.zfselect._afterOriginal = jQuery.fn.after;
        jQuery.fn.after = jQuery.zfselect._after;
    }

    if (undefined==jQuery.zfselect._beforeOriginal) {
        jQuery.zfselect._beforeOriginal = jQuery.fn.before;
        jQuery.fn.before = jQuery.zfselect._before;
    }

    if (undefined==jQuery.zfselect._removeOriginal) {
        jQuery.zfselect._removeOriginal = jQuery.fn.remove;
        jQuery.fn.remove = jQuery.zfselect._remove;
    }

    if (undefined==jQuery.zfselect._emptyOriginal) {
        jQuery.zfselect._emptyOriginal = jQuery.fn.empty;
        jQuery.fn.empty = jQuery.zfselect._empty;
    }

    if (undefined==jQuery.zfselect._valOriginal) {
        jQuery.zfselect._valOriginal = jQuery.fn.val;
        jQuery.fn.val = jQuery.zfselect._val;
    }

    if (undefined==jQuery.zfselect._attrOriginal) {
        jQuery.zfselect._attrOriginal = jQuery.fn.attr;
        jQuery.fn.attr = jQuery.zfselect._attr;
    }

    if (undefined==jQuery.zfselect._htmlOriginal) {
        jQuery.zfselect._htmlOriginal = jQuery.fn.html;
        jQuery.fn.html = jQuery.zfselect._html;
    }

    if (undefined==jQuery.zfselect._removeAttrOriginal) {
        jQuery.zfselect._removeAttrOriginal = jQuery.fn.removeAttr;
        jQuery.fn.removeAttr = jQuery.zfselect._removeAttr;
    }

    if (undefined==jQuery.zfselect._showOriginal) {
        jQuery.zfselect._showOriginal = jQuery.fn.show;
        jQuery.fn.show = jQuery.zfselect._show;
    }

    if (undefined==jQuery.fn.prop) {
        jQuery.fn.prop = jQuery.fn.attr;
    }

    if (undefined==jQuery.fn.disableSelection) {
        jQuery.fn.disableSelection = function() {
            this.each(function() {
                var browser = jQuery.zfselect._getBrowser();
                if (browser=='IE' || browser=='WK') {                   // IE, Chrome, Safari
                    this._onselectstart = this.onselectstart;
                    this.onselectstart  = function() { return false; };
                }
                if (browser=='IE' || browser=='OP') {                   // IE, Opera
                    this._unselectable  = this.unselectable;
                    this.unselectable   = "on";
                }
                if (browser=='FF') {                                    // FF
                    this._css   = jQuery(this).css('-moz-user-select');
                    jQuery(this).css('-moz-user-select', 'none');
                }
            });
        }
    }

    if (undefined==jQuery.fn.enableSelection) {
        jQuery.fn.enableSelection = function() {
            this.each(function() {
                var browser = jQuery.zfselect._getBrowser();
                if (browser=='IE' || browser=='WK') {                   // IE, Chrome, Safari
                    if (undefined!=this._onselectstart) {
                        this.onselectstart = this._onselectstart;
                        this._onselectstart= undefined;
                    } else {
                        this.onselectstart = function() {};
                    }
                }
                if (browser=='IE' || browser=='OP') {                   // IE, Opera
                    if (undefined!=this._unselectable) {
                        this.unselectable = this._unselectable;
                        this._unselectable= undefined;
                    } else {
                        this.unselectable = 'off';
                    }
                }
                if (browser=='FF') {                                    // FF
                    if (undefined!=this._css) {
                        jQuery(this).css('-moz-user-select', this._css);
                        this._css   = undefined;
                    } else {
                        jQuery(this).css('-moz-user-select', 'auto');
                    }
                }
            });
        }
    }

})(jQuery);

jQuery.extend(jQuery.expr[':'], {  
    ge: function(e, i, p) {
        return i>=p[3];  
    }  
});
jQuery.extend(jQuery.expr[':'], {  
    gel: function(e, i, p) {
        var r = p[3].split(',');
        return i>=r[0] && i<r[1];  
    }  
});
jQuery.extend(jQuery.expr[':'], {  
    gele: function(e, i, p) {
        var r = p[3].split(',');
        return i>=r[0] && i<=r[1];  
    }  
});


