Search code examples
jquery-ui-tabsstate-machinejsplumb

jsplumb state machine on multiple tabs


I am designing a web page for state machine and I am using jsplumb state machine. I want to draw this state machine on multiple tabs. Tabs are created dynamically using 'New' button

<div id="tabs">
    <ul>
        <li>
            <a href="#Untitled-1">Untitled-1</a>
            <span class="ui-icon ui-icon-close"></span>
        </li>
    </ul>
    <div id="Untitled-1" class="content">
        <div id="Untitled-1-content" class="fsm">
        </div> 
    </div>
</div>

In the div area of class 'fsm', state machine is drawn dynamically by dragging state machine(SM) blocks and dropping it in 'fsm' div. If there are multiple tabs, after dropping SM block in fsm div, it is draggable in fsm div only on 1st tab and not in another tabs. For example, if there are 2 tabs, I can re-position SM blocks only in 1st tab, on 2nd tab when I start dragging SM block, it disappears from fsm div and its left-top coordinates become negative.

This is the code for fsm div -

$("div.fsm").droppable({
    accept: ".cTemp, .rTemp",
    hoverClass: "ui-state-hover",
    drop: function (event, ui) {
        var draggable = $(ui.draggable[0]);
        if (draggable.attr("class").indexOf("rTemp") > -1) {
            $("<div class='rBase'  id='rect" + rectI + "'></div>").text("rect" + rectI).appendTo(this);
            $("#rect" + rectI).append("<div class='ep'></div>").appendTo(this);
            $("#rect" + rectI).addClass("draggable");                  

            jsPlumb.draggable($(".rBase"),{containment: ".fsm", zIndex: 30});
        } else if (draggable.attr("class").indexOf("cTemp") > -1) {
            $("<div class='cBase' id='circle" + circleI + "'></div>").text("circle" + circleI).appendTo(this);
            $("#circle" + circleI).append("<div class='ep'></div>").appendTo(this);
            $("#circle" + circleI).addClass("draggable");

        jsPlumb.draggable($(".cBase"),{containment: ".fsm", zIndex: 30});

       }

       jsPlumbDemo.init();
}

});

This might be because fsm div is created dynamically or there are more than 1 fsm divs. What would be the best option to handle this multitab situation ?

I tried to remove fsm div from all tabs except the active tab then it works. I can drag SM blocks from tab content even if there are more than 1 tabs since there is only 1 fsm div. But then I have to add fsm div back again to the tab when I switch to that tab. Then which is the best way to save the tab's content before switching to any other tab and load it back when that tab is opened ?

To give my background, this is my first time to work on jquery/jsplumb so detailed explanation is very much appreciated.


Solution

  • Here is a couple of comments

    1. You can use the Jquery command hasClass() instead of attr("class")indexOf
    2. To handle tabs I guess you are using the Jquery command tabs() ? in that case you don't need to save anything.
    3. As far as your dropping issue is concerned you should use the appendTo: property in the draggable() parameters specifying which div they are supposed to be dropped to. You can change the target tab by reacting to the jquery tab select event this way

      $("#tabs").tabs({ select: function(event, ui) { // Your code } });

    You can play with this fiddle I made for you

    http://jsfiddle.net/webaba/sy9PJ/

    $(document).ready(function () {
    
        // Calls custom select tab function, scroll down for implementation
        selectTab(1);
    
        // Block models are made draggable
        function selectTab(tabIndex) {
            var tabName = '#tab'+tabIndex;
            $(".model").draggable({
                appendTo: tabName,
                helper: 'clone'
            });
        }
    
        // Tabs div is formatted as tabs by jquery
        $("#tabs").tabs({
            select: function (event, ui) {
                selectTab(ui.index + 1);
            }
        });
    
        //Sets canvas as droppable
        $(".tab").droppable({
    
            accept: ".model",
            drop: function (event, ui) {
                var newBlock = ui.helper.clone();
                $(newBlock).removeClass("model").addClass("block");
                $(this).append($(newBlock));
                $(newBlock).draggable({containment:$(this)});  
                return true;
            }
        });
    });
    

    and the html

    <body>
        <div id="container">
            <div id="library">
                <div class="model type1" type="1">Block1</div>
                <div class="model type2" type="2">Block2</div>
            </div>
            <div id="tabs">
                <ul>
                    <li><a href="#tab1">Tab1</a>
                    </li>
                    <li><a href="#tab2">Tab2</a>
                    </li>
                    <li><a href="#tab3">Tab3</a>
                    </li>
                </ul>
                <div id="tab1" class="tab">Tab1</div>
                <div id="tab2" class="tab">Tab2</div>
                <div id="tab3" class="tab">Tab3</div>
            </div>
        </div>
    </body>
    

    and the CSS

    #container {
        width:100%;
        height:300px;
    }
    #tabs {
        height:300px;
        width:70%;
        float:right;
        border:1px solid black;
    }
    .tab{
        height:100%;
        border:1px dotted blue;
    }
    #library {
        border:1px solid black;
        width:20%;
        height:300px;
        float:left;
    }
    .type1 {
        width:50px;
        height:50px;
        border:1px solid green;
    }
    .type2 {
        width:50px;
        height:20px;
        border:1px solid red;
    }