Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plugin for jQuery Text-editor style selection?

What I'm trying to achieve is to use jQuery to mimic the behavior of the text-selection functionality you see in a typical text-editor, except instead of selecting text, I want to select multiple rows of <div>s. However, so far the only "selection" plugins I've found for jQuery operate based on a rectangular lasso model. In particular, I'm using the jQueryUI selectable plugin. To see what I'm talking about, consider the following 2 images:

Default jQueryUI "selectable" plugin behavior

Ideal plugin behavior (sans the lasso) http://img709.imageshack.us/img709/5664/selectableidealthumb.png

You can also go here to play with this exact example. Does anybody know of a plugin that achieves this? That would save me from proceeding to hack or hack around this plugin to get what I want...

P/S: In my app each row will contain up to 150 or so divs, and each div will have a few divs within it. I have tried hand-rolling my own selectable but it was slow even when dealing with just a single line. I'm currently using this plugin because its much more performant than what I wrote.

like image 727
Suan Avatar asked Dec 20 '25 00:12

Suan


1 Answers

Maybe this could be optimized somehow and yet I have tested it in Chrome only, but I think it will work in other browsers too. There is no need of jQuery UI for this, it's hand made ;)

$(function() {
    var selectableLi = $('#selectable li');
    selectableLi.mousedown(function(){
        var startIndex, endIndex, mouseUpOnLi = false;

        // When dragging starts, remove classes active and hover
        selectableLi.removeClass('active hover');

        // Give the element where dragging starts a class
        $(this).addClass('active');

        // Save the start index
        startIndex = $(this).index();

        // Bind mouse up event 
        selectableLi.bind('mouseup', function(){

            // Mouse up is on a li-element
            mouseUpOnLi = true;
            $(this).addClass('active');

            // Remove the events for mouseup, mouseover and mouseout
            selectableLi.unbind('mouseup mouseover mouseout');

            // Store the end index
            endIndex = $(this).index();

            // Swap values if endIndex < startindex
            if(endIndex < startIndex){
                var tmp = startIndex;
                startIndex = endIndex;
                endIndex = tmp;                 
            }

            // Give the selected elements a colour
            for(i=startIndex; i<=endIndex; i++){
                $(selectableLi[i]).addClass('active');
            }

        }).bind('mouseover', function(){
            // Give elements a hover class when hovering
            $(this).addClass('hover');
        }).bind('mouseout', function(){
            // Remove the hover class when mouse moves out the li
            $(this).removeClass('hover');
        });

        $(document).bind('mouseup', function(e){
            // When mouse up is outside a li-element
            if(!mouseUpOnLi){
                selectableLi.removeClass('active');
            }
            $(this).unbind('mouseup');
        });
    }).attr("unselectable","on").css("MozUserSelect","none").bind("selectstart",function(){return false});
});

I've got an example online. Note that items don't have a background colour when selecting; I think this will give a better performance.


UPDATE - Example 2

I updated it so the selection is visible while selecting:

var selectableLi;

function colourSelected(a, b, Class){
    selectableLi.removeClass(Class);
    // Swap values if a > b
    if(a > b){
        var tmp = a;
        a = b;
        b = tmp;                    
    }

    // Give the selected elements a colour
    for(i=a; i<=b; i++){
        $(selectableLi[i]).addClass(Class);
    }       
}

$(function() {
    selectableLi = $('#selectable li');
    selectableLi.mousedown(function(){
        var startIndex, endIndex, mouseUpOnLi = false;

        // When dragging starts, remove classes active and hover
        selectableLi.removeClass('active hover');

        // Give the element where dragging starts a class
        $(this).addClass('active');

        // Save the start index
        startIndex = $(this).index();

        // Bind mouse up event 
        selectableLi.bind('mouseup', function(){

            // Mouse up is on a li-element
            mouseUpOnLi = true;
            $(this).addClass('active');

            // Remove the events for mouseup, mouseover and mouseout
            selectableLi.unbind('mouseup mouseover mouseout');

            colourSelected(startIndex, $(this).index(), 'active');

        }).bind('mouseover mouseout', function(){
            // Give elements a hover class when hovering
            colourSelected(startIndex, $(this).index(), 'hover');
        });

        $(document).bind('mouseup', function(e){
            // When mouse up is outside a li-element
            if(!mouseUpOnLi){
                selectableLi.removeClass('active hover');
            }
            $(this).unbind('mouseup');
            selectableLi.unbind('mouseover mouseout');
        });
    }).attr("unselectable","on").css("MozUserSelect","none").bind("selectstart",function(){return false});
});

Again, maybe this code could be optimized somehow for performance.

like image 61
Harmen Avatar answered Dec 22 '25 14:12

Harmen