﻿(function($, $$) { //shiftKey ctrlKey altKey
    var _selectedClass = 'selected';
    var _selectabled = 'selectabled';

    function selected(row, e, self) {
        if (e.ctrlKey) {
            $(row).addClass(_selectedClass);
        } else if (e.shiftKey) {
            var rows = $('tBody > tr.' + _selectabled, self.context);
            var pos = -1, eos = -1;
            for (var i = 0; i < rows.length; i++) {
                if (pos == -1 && $(rows[i]).hasClass(_selectedClass)) {
                    pos = i;
                }

                if (eos == -1 && rows[i] == row) {
                    eos = i;
                }

                if (pos > -1 && eos > -1) {
                    break;
                }
            }
            if (pos < eos) {
                while (++pos <= eos) {
                    $(rows[pos]).addClass(_selectedClass);
                }
            } else if (pos > eos) {
                while (eos < pos) {
                    $(rows[eos++]).addClass(_selectedClass);
                }
            }
        } else {
            var row = $(row);
            if (!row.hasClass(_selectedClass)) {
                $('tBody > tr.' + _selectabled, self.context).removeClass(_selectedClass);
                row.addClass(_selectedClass);
            } else {
                row.toggleClass(_selectedClass);
            }
        }
    }

    $$.extend({
        selectable: function(context, options) {
            var context = context ? $(context) : $('table.selectable');
            var o = context.data(_selectabled);
            if (o) {
                o.refresh();
                return o;
            } else {
                return new $$.selectable.fn.init(context, options);
            }
        }
    });

    $$.selectable.fn = $$.selectable.prototype = {
        init: function(context, options) {
            this.options = options = options || {};
            this.context = context;
            this.refresh();
            context.data(_selectabled, this);
            return this;
        },
        refresh: function(row) {
            var self = this;
            if (row) {
                var row = $(row);
                if (!row.hasClass(_selectabled)) {
                    row.addClass(_selectabled).bind('click', function(e) {
                        selected(this, e, self);
                    });
                }
            } else {
                this.context.each(function() {
                    var table = this;
                    $('tbody > tr[class!=' + _selectabled + ']', table).addClass(_selectabled).bind('click', function(e) {
                        selected(this, e, self);
                    });
                }).bind('selectstart', function(e) {
                    if (e.shiftKey || e.ctrlKey)
                        return false;
                    else
                        return true;
                }).filter(function() {
                    return ($(this).find('input[type=text]').length == 0);
                }).css('MozUserSelect', 'none').attr('unselectable', 'on');
            }
        },
        remove: function() {
            $('tbody > tr.' + _selectedClass, this.context).remove();
            return this;
        }
    };

    $$.selectable.fn.init.prototype = $$.selectable.fn;

})(jQuery, cvv);