Search code examples
javascriptruby-on-railsdomprototypejsscriptaculous

Prototype/Scriptaculous: Selecting groups of paragraphs (<p>) by clicking on them


A list of paragraphs (<p>) is given. As soon as the user clicks on paragraph A the class of paragraph A changes to "activated". Now the user selects paragraph B and all the paragraphs between A and B change their class to "activated".

By clicking on B again, only A remains with the class "active".

By clicking on A the class "active" gets removed on all paragraphs between A and B (including A and B).

It shouldn't be possible to "deactivate" any paragraph between A and B. The selection between A and B should always be a uninterrupted list of selected paragraphs.

Can anyone give me a hint on how to realize this with Prototype/Scriptaculous? The application is implemented in Rails, so any hint in RJS would even be more appreciated!


Solution

  • OK, in the meantime and with the help of a coworker I came up with an own answer to this problem:

    <script type="text/javascript">
        // holds paragraph A (first selected paragraph)
        var a_selected = null;
        // holds paragraph B (second selected paragraph)
        var b_selected = null;
        // holds all 'active' paragraphs
        var selected_paras = [];
    
        function class_flipper_init() {
            // reset paragraphs A and B
            a_selected = null;
            b_selected = null;
            var paragraphs = $$("#foobar p");
            paragraphs.each(function(paragraph, index) {
                // if user clicks on a paragraph
                paragraph.observe("click", function(event) {
                    // if A and B are 'active': reset everything.
                    if(b_selected != null) {
                        selected_paras.each(function(i) {
                            toggleStyle(i);
                        })
                        a_selected = null
                        b_selected = null
                        return
                    }
                    // if A is 'active'
                    if(a_selected != null) {
                        // if A is 'active' and selected B is below A:
                        // select all paragraphs between A and B
                        if(a_selected < index) {
                            b_selected = index;
                            for (var i = a_selected + 1; i <= index; i++ ) {
                                toggleStyle(paragraphs[i])
                            }
                        }
                        // if A is 'active' and selected B is above A: 
                        // select all paragraphs between A and B
                        else if(a_selected > index) {
                            b_selected = index;
                            for (var i = a_selected - 1; i >= index; i-- ) {
                                toggleStyle(paragraphs[i])
                            }
                        }
                        // if A == B
                        else {
                            toggleStyle(paragraph)
                            a_selected = null
                        }
                    }
                    // if A is selected
                    else {
                        a_selected = index;
                        toggleStyle(paragraph)
                    }
                });
            });
        }
    
        function toggleStyle(paragraph) {
            // remove active class
            if (paragraph.hasClassName("active")) {
                paragraph.removeClassName("active");
                selected_paras = selected_paras.without(paragraph)
            } 
            // set active class
            else {
                paragraph.addClassName("active");
                selected_paras.push(paragraph)
            }
        }
    </script>
    

    class_flipper_init() is called everytime the page (or in my case a certain partial) is loaded.

    Please don't hesitate to submit a solution written in "pure" RJS or something more elegant. :-)