<commit_before>// repaint
function Repaint(){
    $("#whiteboard").resize(function(){
        jsPlumb.repaintEverything();
    });
}
// drag
function DragEl(el){
    jsPlumb.draggable($(el) ,{
        containment:"#whiteboard"
    });
}

// JsPlumb Config
var color = "gray",
    exampleColor = "#00f",
    arrowCommon = { foldback:0.7, fillStyle:color, width:14 };

jsPlumb.importDefaults({
    Connector : [ "Bezier", { curviness:63 } ],
    /*Overlays: [
     [ "Arrow", { location:0.7 }, arrowCommon ],
     ]*/
});

var nodeDropOptions = {
    activeClass:"dragActive"
};

var bottomConnectorOptions = {
    endpoint:"Rectangle",
    paintStyle:{ width:25, height:21, fillStyle:'#666' },
    isSource:true,
    connectorStyle : { strokeStyle:"#666" },
    isTarget:false,
    maxConnections:20
};

var endpointOptions = {
    isTarget:true,
    endpoint:"Dot",
    paintStyle:{
        fillStyle:"gray"
    },
    dropOptions: nodeDropOptions,
    maxConnections:1
};

var groupOptions = {
    isTarget:true,
    endpoint:"Dot",
    paintStyle:{
        fillStyle:"gray"
    },
    dropOptions: nodeDropOptions,
    maxConnections:1
};

var generatedCartridgeEndpointOptions = {
    isTarget:false,
    endpoint:"Dot",
    paintStyle:{
        fillStyle:"gray"
    },
    dropOptions: '',
    maxConnections:1
};

var generatedGroupOptions = {
    isTarget:false,
    endpoint:"Dot",
    paintStyle:{
        fillStyle:"gray"
    },
    dropOptions: nodeDropOptions,
    maxConnections:1
};

jsPlumb.ready(function() {
    //create application level block
    jsPlumb.addEndpoint('group-base', {
        anchor:"BottomCenter"
    }, bottomConnectorOptions);
});

var cartridgeCounter=0;
//add cartridge to editor
function addJsplumbCartridge(idname, cartridgeCounter) {

    var Div = $('
').attr({'id':cartridgeCounter+'-'+idname, 'data-type':'cartridge', 'data-ctype':idname } )
        .attr('data-toggle', 'tooltip')
        .attr('title',idname)
        .appendTo('#whiteboard');
    $(Div).append(''+idname+'');
    $(Div).addClass('stepnode');
    jsPlumb.addEndpoint($(Div), {
        anchor: "TopCenter"
    }, endpointOptions);
    DragEl($(Div));
    Repaint();
}

//add group to editor
function addJsplumbGroup(cartridgeCounter) {

    var div = $('
').attr({'id':cartridgeCounter+'-group','data-type':'group','data-ctype':''})
        .addClass('input-false')
        .addClass('stepnode')
        .attr('data-toggle', 'tooltip')
        .attr('title','Group')
        .appendTo('#whiteboard');
    $(div).append('Group');
    $(div).append('

');
    jsPlumb.addEndpoint($(div), {
        anchor:"BottomCenter"
    }, bottomConnectorOptions);

    jsPlumb.addEndpoint($(div), {
        anchor: "TopCenter"
    }, groupOptions);
    DragEl($(div));
    Repaint();
}

//create cartridge list
var cartridgeListHtml='';
function generateCartridges(data){
    if(data.length == 0){
        cartridgeListHtml = 'No Cartridges found..';
    }else{
        for(var cartridge in data){
            var cartridgeData = data[cartridge];
            cartridgeListHtml += '
'
                + cartridgeData.displayName+
                '
'
        }
    }

    //append cartridge into html content
    $('#cartridge-list').append(cartridgeListHtml);
}

//node positioning algo with dagre js
function dagrePosition(){
    // construct dagre graph from JsPlumb graph
    var g = new dagre.graphlib.Graph();
    g.setGraph({ranksep:'80'});
    g.setDefaultEdgeLabel(function() { return {}; });
    var nodes = $(".stepnode");

    for (var i = 0; i < nodes.length; i++) {
        var n = nodes[i];
        g.setNode(n.id, {width: 52, height: 52});
    }
    var edges = jsPlumb.getAllConnections();
    for (var i = 0; i < edges.length; i++) {
        var c = edges[i];
        g.setEdge(c.source.id,c.target.id );
    }
    // calculate the layout (i.e. node positions)
    dagre.layout(g);

    // Applying the calculated layout
    g.nodes().forEach(function(v) {
        $("#" + v).css("left", g.node(v).x + "px");
        $("#" + v).css("top", g.node(v).y + "px");
    });
    jsPlumb.repaintEverything();
}

function genGroupJSON(collector, connections){
    //generate raw data tree from connections
    var collector = collector || {};

    var rawtree = [];

    //get base-node data
    var groupBase = $('#group-base').attr('data-generated');
    if(groupBase){
        var groupBaseJSON =  JSON.parse(decodeURIComponent(groupBase));
        collector = groupBaseJSON;
    }
    //create empty nodes for group and cartridges
    collector['groups']=[];
    collector['cartridges']=[];

    $.each(connections, function (idx, connection) {
        var dataType = $('#'+connection.targetId).attr('data-type');
        var dataGenerated  = $('#'+connection.targetId).attr('data-generated');
        var jsonContent;
        if(dataGenerated != undefined){
            var jsonContent = JSON.parse(decodeURIComponent(dataGenerated));
        }else{

            var jsonContent = {cname: $('#'+connection.targetId).attr('data-ctype')};
        }
        rawtree.push({
            parent: connection.sourceId,
            content: jsonContent,
            dtype: dataType,
            id: connection.targetId
        });

    });

    //generate heirache by adding json and extra info
    var nodes = [];
    var toplevelNodes = [];
    var lookupList = {};

    for (var i = 0; i < rawtree.length; i++) {
        var n = rawtree[i].content;
        if(rawtree[i].dtype == 'cartridge'){
            n.id =  rawtree[i].id;
            n.parent_id = ((rawtree[i].parent == 'group-base') ? 'group-base': rawtree[i].parent);
            n.dtype =rawtree[i].dtype;
        }else if(rawtree[i].dtype == 'group'){
            n.id =  rawtree[i].id;
            n.parent_id = ((rawtree[i].parent == 'group-base') ? 'group-base': rawtree[i].parent);
            n.dtype =rawtree[i].dtype;
            n.groups = [];
            n.cartridges =[];
        }

        lookupList[n.id] = n;
        nodes.push(n);

        if (n.parent_id == 'group-base' && rawtree[i].dtype == 'cartridge') {
            collector['cartridges'].push(n.cname);
        }else if(n.parent_id == 'group-base' && rawtree[i].dtype == 'group'){
            collector['groups'].push(n);
        }

    }

    //merge any root level stuffs
    for (var i = 0; i < nodes.length; i++) {
        var n = nodes[i];
        if (!(n.parent_id == 'group-base') && n.dtype == 'cartridge') {
            lookupList[n.parent_id]['cartridges'] = lookupList[n.parent_id]['cartridges'].concat([n.cname]);
        }else if(!(n.parent_id == 'group-base') && n.dtype == 'group'){
            lookupList[n.parent_id]['groups'] = lookupList[n.parent_id]['groups'].concat([n]);
        }
    }

    //cleanup JSON, remove extra items added to object level
    function traverse(o) {
        for (var i in o) {
            if(i == 'id' || i == 'parent_id' || i == 'dtype'){
                delete o[i];
            }else if(i == 'groups' && o[i].length == 0){
                delete o[i];
            }
            if (o[i] !== null && typeof(o[i])=="object") {
                //going on step down in the object tree!!
                traverse(o[i]);
            }
        }
    }

    traverse(collector);

    return collector;

}

var groupBlockTemplate = {
    "$schema": "http://json-schema.org/draft-04/schema#",
    "id": "root",
    "title":" ",
    "type": "object",
    "options": {
        "disable_properties": true,
        "disable_collapse": true
    },
    "properties": {
        "name": {
            "id": "root/name",
            "type": "string",
            "title": "Group Name: "
        },
        "groupScalingEnabled": {
            "id": "root/groupScalingEnabled",
            "type": "boolean",
            "title": "Group Scaling Enabled: "
        },
        "dependencies": {
            "id": "root/dependencies",
            "type": "object",
            "title": "Dependencies: ",
            "options": {
                "disable_properties": true
            },
            "properties": {
                "startupOrders": {
                    "id": "root/dependencies/startupOrders",
                    "type": "array",
                    "title": "Startup Orders: ",
                    "items": {
                        "id": "root/dependencies/startupOrders/0",
                        "type": "string",
                        "title": "Startup Order "
                    }
                },
                "scalingDependants": {
                    "id": "root/dependencies/scalingDependants",
                    "type": "array",
                    "title": "Scaling Dependants: ",
                    "items": {
                        "id": "root/dependencies/scalingDependants/0",
                        "type": "string",
                        "title": "Scaling Dependant "
                    }
                },
                "terminationBehaviour": {
                    "id": "root/dependencies/terminationBehaviour",
                    "type": "string",
                    "title": "Termination Behavior: ",
                    "enum": ["terminate-none","terminate-dependents","terminate-all"]
                },
                "required": [
                    "startupOrders",
                    "scalingDependants",
                    "terminationBehaviour"
                ]
            }
        },
        "required": [
            "name",
            "groupScalingEnabled",
            "dependencies"
        ]
    }
};

var groupBlockDefault = {
    "name": "",
    "groupScalingEnabled": "true",
    "dependencies": {
        "startupOrders": [
            "cartridge.type, group.name"
        ],
        "scalingDependants": [
            "cartridge.type, group.name"
        ],
        "terminationBehaviour": "terminate-all"
    }
};

// Document ready events
$(document).ready(function(){

    $('#deploy').on('click', function(){
        var  payload = genGroupJSON({}, jsPlumb.getConnections());
        var btn = $(this);
        var formtype = 'groups';
        btn.html(" Adding...");
        $.ajax({
            type: "POST",
            url: caramel.context + "/controllers/configure/configure_requests.jag",
            dataType: 'json',
            data: { "formPayload": JSON.stringify(payload), "formtype": formtype },
            success: function (data) {
                if (data.status == 'error') {
                    var n = noty({text: data.message, layout: 'bottomRight', type: 'error'});
                } else if (data.status == 'warning') {
                    var n = noty({text: data.message, layout: 'bottomRight', type: 'warning'});
                } else {
                    var n = noty({text: data.message, layout: 'bottomRight', type: 'success'});
                    window.setTimeout(function(){
                        window.location.href = '../';
                    }, 1500);
                }
            }
        })
            .always(function () {
                btn.html('Add Cartridge Group Definition');
            });

    });

    //*******************Adding JSON editor *************//
    JSONEditor.defaults.theme = 'bootstrap3';
    JSONEditor.defaults.iconlib = 'fontawesome4';
    JSONEditor.defaults.show_errors = "always";
    var editor, blockId = 'group-base';

    // Initialize the editor
    editor = new JSONEditor(document.getElementById('general-data'), {
        ajax: false,
        disable_edit_json: true,
        schema: groupBlockTemplate,
        format: "grid",
        startval: groupBlockDefault
    });

    DragEl(".stepnode");
    Repaint();

    function tabData(node){

        blockId = node.attr('id');
        var blockType = node.attr('data-type');
        var startval;
        if(blockType == 'group'){
            if(node.attr('data-generated')) {
                startval = JSON.parse(decodeURIComponent(node.attr('data-generated')));
            }else{
                startval = groupBlockDefault;
            }

            $('#general-data').html('');

            // Initialize the editor
            editor = new JSONEditor(document.getElementById('general-data'), {
                ajax: false,
                disable_edit_json: true,
                schema: groupBlockTemplate,
                format: "grid",
                startval: startval
            });
        }

    }

    $('#whiteboard').on('click', '.stepnode', function(){
        tabData($(this))
    });

    $('#whiteboard').on('dblclick', '.stepnode', function(){
        var target = $('#group-data-scroll');
        if( target.length ) {
            event.preventDefault();
            $('html, body').animate({
                scrollTop: target.offset().top - 140
            }, 1000);
        }
    });

    //get component JSON data
    $('#component-info-update').on('click', function(){
        $('#'+blockId).attr('data-generated', encodeURIComponent(JSON.stringify(editor.getValue())));
        $('#'+blockId).removeClass('input-false');
        $('#'+blockId).find('div>i').removeClass('fa-exclamation-circle').addClass('fa-check-circle-o').css('color','#2ecc71');
        if(blockId == 'group-base'){
            $('#deploy').prop("disabled", false);
        }

    });

    //get create cartridge list
    generateCartridges(cartridgeList);

    //handle single click for cartridge
    $('#cartridge-list').on('click', ".block-cartridge", function(){
        $('.description-section').html($(this).attr('data-info'));
    });
    //handle double click for cartridge
    $('#cartridge-list').on('dblclick', ".block-cartridge", function(){
        addJsplumbCartridge($(this).attr('id'),cartridgeCounter);
        //reposition after cartridge add
        dagrePosition();
        //increase global count for instances
        cartridgeCounter++;
    });

    //handle single click for groups
    $('#group-list').on('click', ".block-group", function(){

    });
    //handle double click event for groups
    $('#group-list').on('dblclick', ".block-group", function(){

        addJsplumbGroup(cartridgeCounter);
        //reposition after group add
        dagrePosition();
        //increase global count for instances
        cartridgeCounter++;
    });

    //reposition on click event on editor
    $('.reposition').on('click', function(){
        dagrePosition();
    });

});

//bootstrap tooltip added
$(function () {
    $('[data-toggle="tooltip"]').tooltip();
})
<commit_msg>improve tabs on cartridge editor<commit_after>// repaint
function Repaint(){
    $("#whiteboard").resize(function(){
        jsPlumb.repaintEverything();
    });
}
// drag
function DragEl(el){
    jsPlumb.draggable($(el) ,{
        containment:"#whiteboard"
    });
}

// JsPlumb Config
var color = "gray",
    exampleColor = "#00f",
    arrowCommon = { foldback:0.7, fillStyle:color, width:14 };

jsPlumb.importDefaults({
    Connector : [ "Bezier", { curviness:63 } ],
    /*Overlays: [
     [ "Arrow", { location:0.7 }, arrowCommon ],
     ]*/
});

var nodeDropOptions = {
    activeClass:"dragActive"
};

var bottomConnectorOptions = {
    endpoint:"Rectangle",
    paintStyle:{ width:25, height:21, fillStyle:'#666' },
    isSource:true,
    connectorStyle : { strokeStyle:"#666" },
    isTarget:false,
    maxConnections:20
};

var endpointOptions = {
    isTarget:true,
    endpoint:"Dot",
    paintStyle:{
        fillStyle:"gray"
    },
    dropOptions: nodeDropOptions,
    maxConnections:1
};

var groupOptions = {
    isTarget:true,
    endpoint:"Dot",
    paintStyle:{
        fillStyle:"gray"
    },
    dropOptions: nodeDropOptions,
    maxConnections:1
};

var generatedCartridgeEndpointOptions = {
    isTarget:false,
    endpoint:"Dot",
    paintStyle:{
        fillStyle:"gray"
    },
    dropOptions: '',
    maxConnections:1
};

var generatedGroupOptions = {
    isTarget:false,
    endpoint:"Dot",
    paintStyle:{
        fillStyle:"gray"
    },
    dropOptions: nodeDropOptions,
    maxConnections:1
};

jsPlumb.ready(function() {
    //create application level block
    jsPlumb.addEndpoint('group-base', {
        anchor:"BottomCenter"
    }, bottomConnectorOptions);
});

var cartridgeCounter=0;
//add cartridge to editor
function addJsplumbCartridge(idname, cartridgeCounter) {

    var Div = $('
').attr({'id':cartridgeCounter+'-'+idname, 'data-type':'cartridge', 'data-ctype':idname } )
        .attr('data-toggle', 'tooltip')
        .attr('title',idname)
        .appendTo('#whiteboard');
    $(Div).append(''+idname+'');
    $(Div).addClass('stepnode');
    jsPlumb.addEndpoint($(Div), {
        anchor: "TopCenter"
    }, endpointOptions);
    DragEl($(Div));
    Repaint();
}

//add group to editor
function addJsplumbGroup(cartridgeCounter) {

    var div = $('
').attr({'id':cartridgeCounter+'-group','data-type':'group','data-ctype':''})
        .addClass('input-false')
        .addClass('stepnode')
        .attr('data-toggle', 'tooltip')
        .attr('title','Group')
        .appendTo('#whiteboard');
    $(div).append('Group');
    $(div).append('

');
    jsPlumb.addEndpoint($(div), {
        anchor:"BottomCenter"
    }, bottomConnectorOptions);

    jsPlumb.addEndpoint($(div), {
        anchor: "TopCenter"
    }, groupOptions);
    DragEl($(div));
    Repaint();
}

//create cartridge list
var cartridgeListHtml='';
function generateCartridges(data){
    if(data.length == 0){
        cartridgeListHtml = 'No Cartridges found..';
    }else{
        for(var cartridge in data){
            var cartridgeData = data[cartridge];
            cartridgeListHtml += '
'
                + cartridgeData.displayName+
                '
'
        }
    }

    //append cartridge into html content
    $('#cartridge-list').append(cartridgeListHtml);
}

//node positioning algo with dagre js
function dagrePosition(){
    // construct dagre graph from JsPlumb graph
    var g = new dagre.graphlib.Graph();
    g.setGraph({ranksep:'80'});
    g.setDefaultEdgeLabel(function() { return {}; });
    var nodes = $(".stepnode");

    for (var i = 0; i < nodes.length; i++) {
        var n = nodes[i];
        g.setNode(n.id, {width: 52, height: 52});
    }
    var edges = jsPlumb.getAllConnections();
    for (var i = 0; i < edges.length; i++) {
        var c = edges[i];
        g.setEdge(c.source.id,c.target.id );
    }
    // calculate the layout (i.e. node positions)
    dagre.layout(g);

    // Applying the calculated layout
    g.nodes().forEach(function(v) {
        $("#" + v).css("left", g.node(v).x + "px");
        $("#" + v).css("top", g.node(v).y + "px");
    });
    jsPlumb.repaintEverything();
}

function genGroupJSON(collector, connections){
    //generate raw data tree from connections
    var collector = collector || {};

    var rawtree = [];

    //get base-node data
    var groupBase = $('#group-base').attr('data-generated');
    if(groupBase){
        var groupBaseJSON =  JSON.parse(decodeURIComponent(groupBase));
        collector = groupBaseJSON;
    }
    //create empty nodes for group and cartridges
    collector['groups']=[];
    collector['cartridges']=[];

    $.each(connections, function (idx, connection) {
        var dataType = $('#'+connection.targetId).attr('data-type');
        var dataGenerated  = $('#'+connection.targetId).attr('data-generated');
        var jsonContent;
        if(dataGenerated != undefined){
            var jsonContent = JSON.parse(decodeURIComponent(dataGenerated));
        }else{

            var jsonContent = {cname: $('#'+connection.targetId).attr('data-ctype')};
        }
        rawtree.push({
            parent: connection.sourceId,
            content: jsonContent,
            dtype: dataType,
            id: connection.targetId
        });

    });

    //generate heirache by adding json and extra info
    var nodes = [];
    var toplevelNodes = [];
    var lookupList = {};

    for (var i = 0; i < rawtree.length; i++) {
        var n = rawtree[i].content;
        if(rawtree[i].dtype == 'cartridge'){
            n.id =  rawtree[i].id;
            n.parent_id = ((rawtree[i].parent == 'group-base') ? 'group-base': rawtree[i].parent);
            n.dtype =rawtree[i].dtype;
        }else if(rawtree[i].dtype == 'group'){
            n.id =  rawtree[i].id;
            n.parent_id = ((rawtree[i].parent == 'group-base') ? 'group-base': rawtree[i].parent);
            n.dtype =rawtree[i].dtype;
            n.groups = [];
            n.cartridges =[];
        }

        lookupList[n.id] = n;
        nodes.push(n);

        if (n.parent_id == 'group-base' && rawtree[i].dtype == 'cartridge') {
            collector['cartridges'].push(n.cname);
        }else if(n.parent_id == 'group-base' && rawtree[i].dtype == 'group'){
            collector['groups'].push(n);
        }

    }

    //merge any root level stuffs
    for (var i = 0; i < nodes.length; i++) {
        var n = nodes[i];
        if (!(n.parent_id == 'group-base') && n.dtype == 'cartridge') {
            lookupList[n.parent_id]['cartridges'] = lookupList[n.parent_id]['cartridges'].concat([n.cname]);
        }else if(!(n.parent_id == 'group-base') && n.dtype == 'group'){
            lookupList[n.parent_id]['groups'] = lookupList[n.parent_id]['groups'].concat([n]);
        }
    }

    //cleanup JSON, remove extra items added to object level
    function traverse(o) {
        for (var i in o) {
            if(i == 'id' || i == 'parent_id' || i == 'dtype'){
                delete o[i];
            }else if(i == 'groups' && o[i].length == 0){
                delete o[i];
            }
            if (o[i] !== null && typeof(o[i])=="object") {
                //going on step down in the object tree!!
                traverse(o[i]);
            }
        }
    }

    traverse(collector);

    return collector;

}

var groupBlockTemplate = {
    "$schema": "http://json-schema.org/draft-04/schema#",
    "id": "root",
    "title":" ",
    "type": "object",
    "options": {
        "disable_properties": true,
        "disable_collapse": true
    },
    "properties": {
        "name": {
            "id": "root/name",
            "type": "string",
            "title": "Group Name: "
        },
        "groupScalingEnabled": {
            "id": "root/groupScalingEnabled",
            "type": "boolean",
            "title": "Group Scaling Enabled: "
        },
        "dependencies": {
            "id": "root/dependencies",
            "type": "object",
            "title": "Dependencies: ",
            "options": {
                "disable_properties": true
            },
            "properties": {
                "startupOrders": {
                    "id": "root/dependencies/startupOrders",
                    "type": "array",
                    "title": "Startup Orders: ",
                    "format":"tabs",
                    "items": {
                        "id": "root/dependencies/startupOrders/0",
                        "type": "string",
                        "title": "Order"
                    }
                },
                "scalingDependants": {
                    "id": "root/dependencies/scalingDependants",
                    "type": "array",
                    "title": "Scaling Dependants: ",
                    "format":"tabs",
                    "items": {
                        "id": "root/dependencies/scalingDependants/0",
                        "type": "string",
                        "title": "Dependant"
                    }
                },
                "terminationBehaviour": {
                    "id": "root/dependencies/terminationBehaviour",
                    "type": "string",
                    "title": "Termination Behavior: ",
                    "enum": ["terminate-none","terminate-dependents","terminate-all"]
                },
                "required": [
                    "startupOrders",
                    "scalingDependants",
                    "terminationBehaviour"
                ]
            }
        },
        "required": [
            "name",
            "groupScalingEnabled",
            "dependencies"
        ]
    }
};

var groupBlockDefault = {
    "name": "",
    "groupScalingEnabled": "true",
    "dependencies": {
        "startupOrders": [
            "cartridge.type, group.name"
        ],
        "scalingDependants": [
            "cartridge.type, group.name"
        ],
        "terminationBehaviour": "terminate-all"
    }
};

// Document ready events
$(document).ready(function(){

    $('#deploy').on('click', function(){
        var  payload = genGroupJSON({}, jsPlumb.getConnections());
        var btn = $(this);
        var formtype = 'groups';
        btn.html(" Adding...");
        $.ajax({
            type: "POST",
            url: caramel.context + "/controllers/configure/configure_requests.jag",
            dataType: 'json',
            data: { "formPayload": JSON.stringify(payload), "formtype": formtype },
            success: function (data) {
                if (data.status == 'error') {
                    var n = noty({text: data.message, layout: 'bottomRight', type: 'error'});
                } else if (data.status == 'warning') {
                    var n = noty({text: data.message, layout: 'bottomRight', type: 'warning'});
                } else {
                    var n = noty({text: data.message, layout: 'bottomRight', type: 'success'});
                    window.setTimeout(function(){
                        window.location.href = '../';
                    }, 1500);
                }
            }
        })
            .always(function () {
                btn.html('Add Cartridge Group Definition');
            });

    });

    //*******************Adding JSON editor *************//
    JSONEditor.defaults.theme = 'bootstrap3';
    JSONEditor.defaults.iconlib = 'fontawesome4';
    JSONEditor.defaults.show_errors = "always";
    var editor, blockId = 'group-base';

    // Initialize the editor
    editor = new JSONEditor(document.getElementById('general-data'), {
        ajax: false,
        disable_edit_json: true,
        schema: groupBlockTemplate,
        format: "grid",
        startval: groupBlockDefault
    });

    DragEl(".stepnode");
    Repaint();

    function tabData(node){

        blockId = node.attr('id');
        var blockType = node.attr('data-type');
        var startval;
        if(blockType == 'group'){
            if(node.attr('data-generated')) {
                startval = JSON.parse(decodeURIComponent(node.attr('data-generated')));
            }else{
                startval = groupBlockDefault;
            }

            $('#general-data').html('');

            // Initialize the editor
            editor = new JSONEditor(document.getElementById('general-data'), {
                ajax: false,
                disable_edit_json: true,
                schema: groupBlockTemplate,
                format: "grid",
                startval: startval
            });
        }

    }

    $('#whiteboard').on('click', '.stepnode', function(){
        tabData($(this))
    });

    $('#whiteboard').on('dblclick', '.stepnode', function(){
        var target = $('#group-data-scroll');
        if( target.length ) {
            event.preventDefault();
            $('html, body').animate({
                scrollTop: target.offset().top - 140
            }, 1000);
        }
    });

    //get component JSON data
    $('#component-info-update').on('click', function(){
        $('#'+blockId).attr('data-generated', encodeURIComponent(JSON.stringify(editor.getValue())));
        $('#'+blockId).removeClass('input-false');
        $('#'+blockId).find('div>i').removeClass('fa-exclamation-circle').addClass('fa-check-circle-o').css('color','#2ecc71');
        if(blockId == 'group-base'){
            $('#deploy').prop("disabled", false);
        }

    });

    //get create cartridge list
    generateCartridges(cartridgeList);

    //handle single click for cartridge
    $('#cartridge-list').on('click', ".block-cartridge", function(){
        $('.description-section').html($(this).attr('data-info'));
    });
    //handle double click for cartridge
    $('#cartridge-list').on('dblclick', ".block-cartridge", function(){
        addJsplumbCartridge($(this).attr('id'),cartridgeCounter);
        //reposition after cartridge add
        dagrePosition();
        //increase global count for instances
        cartridgeCounter++;
    });

    //handle single click for groups
    $('#group-list').on('click', ".block-group", function(){

    });
    //handle double click event for groups
    $('#group-list').on('dblclick', ".block-group", function(){

        addJsplumbGroup(cartridgeCounter);
        //reposition after group add
        dagrePosition();
        //increase global count for instances
        cartridgeCounter++;
    });

    //reposition on click event on editor
    $('.reposition').on('click', function(){
        dagrePosition();
    });

});

//bootstrap tooltip added
$(function () {
    $('[data-toggle="tooltip"]').tooltip();
})
<|endoftext|>


<commit_before>define(function(require, exports, module) {
	module.exports = Backbone.View.extend({
		tagName: 'div',
		className: 'modal modal-fixed-footer',
		template: '

',
		initialize: function(options) {
			$(this.el).html(this.template);
			$('body').append(this.el);
		},
		render: function() {},
		show: function(msg) {
			$(this.el).find('.modal-content').text(msg);
			$(this.el).openModal({
				dismissible: true, // Modal can be dismissed by clicking outside of the modal
				opacity: .5, // Opacity of modal background
				in_duration: 300, // Transition in duration
				out_duration: 200, // Transition out duration
				ready: function() { alert('Ready'); }, // Callback for Modal open
				complete: function() { alert('Closed'); } // Callback for Modal close
			});
		}
	});
});<commit_msg>修改MaterializeModal控件，完成alert和confirm<commit_after>define(function(require, exports, module) {
	var MButton = require('button');
	var Modal = Backbone.View.extend({
		tagName: 'div',
		className: 'modal modal-fixed-footer',
		template: '

',
		initialize: function(options) {
			var self = this;
			options = options || {};
			var defaults = {
				title: 'Dialog',
				message: '',
				buttons: [],
				dismissible: true,
				opacity: .5,
				in_duration: 300,
				out_duration: 200,
				autodestroy: true
			};
			var config = {
				dismissible: options.dismissible==undefined ? defaults.dismissible : options.dismissible,
				opacity: options.opacity || defaults.opacity,
				in_duration: options.in_duration || defaults.in_duration,
				out_duration: options.out_duration || defaults.out_duration,
				ready: _.isFunction(options.onOpen) ? options.onOpen : defaults.onOpen,
				complete: _.isFunction(options.onClosed) ? options.onClosed : defaults.onClosed
			}
			this.autodestroy = options.autodestroy==undefined ? defaults.autodestroy : options.autodestroy;
			var el = $(this.el);
			el.html(this.template);
			el.find('.modal-header').html(options.title || defaults.title);
			el.find('.modal-body').html(options.message || defaults.message);
			if(options.buttons && options.buttons.length > 0) {
				for(var i in options.buttons) {
					var btn = new MButton({
						modal: self,
						label: options.buttons[i].label,
						action: options.buttons[i].action
					});
					el.find('.modal-footer').append(btn.render().el);
				}
			}
			$('body').append(this.el);
			$(this.el).openModal(config);
		},
		close: function() {
			$(this.el).closeModal();
			if(this.autodestroy) this.remove();
		}
	});

	module.exports = {
		alert: function(message, title, label) {
			var modal = new Modal({
				title: title,
				message: message,
				buttons: [{
					label: label,
					action: function(modal) {
						modal.close();
					}
				}]
			});
		},
		confirm: function(options) {
			options = options || {};
			var modal = new Modal({
				title: options.title || 'Confirm',
				message: options.message || '?',
				buttons: [{
					label: options.btnCancelLabel || 'Cancel',
					action: function(modal) {
						if(options.callback && _.isFunction(options.callback)) {
							options.callback(false);
						}
						modal.close();
					}
				}, {
					label: options.btnOKLabel || 'OK',
					action: function(modal) {
						if(options.callback && _.isFunction(options.callback)) {
							options.callback(true);
						}
						modal.close();
					}
				}]
			});
		}
	};

});<|endoftext|>


<commit_before>//
//   Copyright 2015 Ilkka Oksanen <iao@iki.fi>
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing,
//   software distributed under the License is distributed on an "AS
//   IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//   express or implied.  See the License for the specific language
//   governing permissions and limitations under the License.
//

'use strict';

const redis = require('../lib/redis').createClient(),
      socketIo = require('socket.io'),
      co = require('co'),
      uuid = require('uid2'),
      requestController = require('../controllers/request'),
      log = require('../lib/log'),
      friends = require('../models/friends'),
      settings = require('../models/settings'),
      alerts = require('../lib/alert'),
      conf = require('../lib/conf'),
      notification = require('../lib/notification'),
      courier = require('../lib/courier').create();

let networks = null;

exports.setup = function(server) {
    let io = socketIo(server);

    io.on('connection', function(socket) {
        let userId = null;
        let sessionId = null;
        let state = 'connected'; // connected, authenticated, disconnected

        socket.on('init', function(data) {
            co(function*() {
                if (sessionId) {
                    socket.emit('terminate', {
                        code: 'MULTIPLE_INITS',
                        reason: 'INIT event can be send only once per socket.io connection.'
                    });
                    yield end('Multiple inits.');
                    return;
                }

                let ts = Math.round(Date.now() / 1000);
                let secret = data.secret;

                userId = data.userId;

                if (!userId || !secret) {
                    log.info('Invalid init socket.io message.');
                    socket.emit('terminate', {
                        code: 'INVALID_INIT',
                        reason: 'Invalid init event.'
                    });
                    yield end('Invalid init.');
                    return;
                }

                let userRecord = yield redis.hgetall(`user:${userId}`);

                if (!(userRecord &&
                    userRecord.secretExpires > ts &&
                    userRecord.secret === secret &&
                    userRecord.inuse === 'true')) {
                    log.info(userId, 'Init message with incorrect or expired secret.');
                    socket.emit('terminate', {
                        code: 'INVALID_SECRET',
                        reason: 'Invalid or expired secret.'
                    });
                    yield end('Invalid secret.');
                    return;
                }

                state = 'authenticated';
                sessionId = uuid(15);

                let maxBacklogMsgs = checkBacklogParameterBounds(data.maxBacklogMsgs);
                let cachedUpto = isInteger(data.cachedUpto) ? data.cachedUpto : 0;

                socket.emit('initok', {
                    sessionId: sessionId,
                    maxBacklogMsgs: maxBacklogMsgs
                });

                log.info(userId, `New session init: ${sessionId}, client: ${data.clientName}`);
                log.info(userId, `maxBacklogMsgs: ${maxBacklogMsgs}, cachedUpto: ${cachedUpto}`);

                yield redis.run('initSession', userId, sessionId, maxBacklogMsgs, cachedUpto, ts);

                yield settings.sendSet(userId, sessionId);
                yield friends.sendFriends(userId, sessionId);
                yield friends.sendFriendConfirm(userId, sessionId);
                yield friends.informStateChange(userId, 'login');
                yield alerts.sendAlerts(userId, sessionId);
                yield sendNetworkList(userId, sessionId);

                // Check if the user was away too long
                courier.callNoWait('ircparser', 'reconnectifinactive', { userId: userId });

                // Event loop
                while (1) {
                    let loopTs = Math.round(Date.now() / 1000);
                    yield redis.zadd('sessionlastheartbeat', loopTs, userId + ':' + sessionId);

                    let ntfs = yield notification.receive(userId, sessionId, 60);

                    if (state !== 'authenticated') {
                        break;
                    }

                    for (let ntf of ntfs) {
                        if (ntf.id !== 'MSG') {
                            log.info(userId,
                                `Emitted ${ntf.id}. SesId: ${sessionId}, [${JSON.stringify(ntf)}]`);
                        }

                        socket.emit('ntf', ntf);
                    }
                }
            })();
        });

        socket.on('req', function(data, cb) {
            co(function*() {
                if (state !== 'authenticated') {
                    yield end('Request arrived before init.');
                    return;
                }

                let resp = yield requestController(userId, sessionId, data);

                if (cb) {
                    cb(resp); // Send the response as Socket.io acknowledgment.
                }
            })();
        });

        socket.on('disconnect', function() {
            co(function*() {
                yield end('Socket.io disconnect.');
            })();
        });

        function *end(reason) {
            if (state !== 'disconnected') {
                socket.disconnect();
                state = 'disconnected';

                let sessionIdExplained = `${sessionId} ` || '';
                log.info(userId, `Session ${sessionIdExplained}ended. Reason: ${reason}`);

                if (sessionId) {
                    let last = yield redis.run('deleteSession', userId, sessionId);

                    if (last) {
                        yield friends.informStateChange(userId, 'logout');
                    }
                }
            }
        }
    });
};

function *sendNetworkList(userId, sessionId) {
    networks = networks || (yield redis.smembers('networklist'));

    yield notification.send(userId, sessionId, {
        id: 'NETWORKS',
        networks: networks
    });
}

function checkBacklogParameterBounds(value) {
    let minAllowedBacklog = conf.get('session:min_backlog');
    let maxAllowedBacklog = conf.get('session:max_backlog');

    if (!isInteger(value)) {
        value = maxAllowedBacklog;
    } else if (value < minAllowedBacklog) {
        value = minAllowedBacklog;
    } else if (value > maxAllowedBacklog) {
        value = maxAllowedBacklog;
    }

    return value;
}

function isInteger(x) {
    return (typeof x === 'number') && (x % 1 === 0);
}
<commit_msg>Add quit method to socket controller<commit_after>//
//   Copyright 2015 Ilkka Oksanen <iao@iki.fi>
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing,
//   software distributed under the License is distributed on an "AS
//   IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//   express or implied.  See the License for the specific language
//   governing permissions and limitations under the License.
//

'use strict';

const redis = require('../lib/redis').createClient(),
      socketIo = require('socket.io'),
      co = require('co'),
      uuid = require('uid2'),
      requestController = require('../controllers/request'),
      log = require('../lib/log'),
      friends = require('../models/friends'),
      settings = require('../models/settings'),
      alerts = require('../lib/alert'),
      conf = require('../lib/conf'),
      notification = require('../lib/notification'),
      courier = require('../lib/courier').create();

let io = socketIo(server);
let networks = null;
let clientSocketList = [];

exports.setup = function(server) {
    io.on('connection', function(socket) {
        let userId = null;
        let sessionId = null;
        let state = 'connected'; // connected, authenticated, disconnected

        clientSocketList.push(socket);

        socket.on('init', function(data) {
            co(function*() {
                if (sessionId) {
                    socket.emit('terminate', {
                        code: 'MULTIPLE_INITS',
                        reason: 'INIT event can be send only once per socket.io connection.'
                    });
                    yield end('Multiple inits.');
                    return;
                }

                let ts = Math.round(Date.now() / 1000);
                let secret = data.secret;

                userId = data.userId;

                if (!userId || !secret) {
                    log.info('Invalid init socket.io message.');
                    socket.emit('terminate', {
                        code: 'INVALID_INIT',
                        reason: 'Invalid init event.'
                    });
                    yield end('Invalid init.');
                    return;
                }

                let userRecord = yield redis.hgetall(`user:${userId}`);

                if (!(userRecord &&
                    userRecord.secretExpires > ts &&
                    userRecord.secret === secret &&
                    userRecord.inuse === 'true')) {
                    log.info(userId, 'Init message with incorrect or expired secret.');
                    socket.emit('terminate', {
                        code: 'INVALID_SECRET',
                        reason: 'Invalid or expired secret.'
                    });
                    yield end('Invalid secret.');
                    return;
                }

                state = 'authenticated';
                sessionId = uuid(15);

                let maxBacklogMsgs = checkBacklogParameterBounds(data.maxBacklogMsgs);
                let cachedUpto = isInteger(data.cachedUpto) ? data.cachedUpto : 0;

                socket.emit('initok', {
                    sessionId: sessionId,
                    maxBacklogMsgs: maxBacklogMsgs
                });

                log.info(userId, `New session init: ${sessionId}, client: ${data.clientName}`);
                log.info(userId, `maxBacklogMsgs: ${maxBacklogMsgs}, cachedUpto: ${cachedUpto}`);

                yield redis.run('initSession', userId, sessionId, maxBacklogMsgs, cachedUpto, ts);

                yield settings.sendSet(userId, sessionId);
                yield friends.sendFriends(userId, sessionId);
                yield friends.sendFriendConfirm(userId, sessionId);
                yield friends.informStateChange(userId, 'login');
                yield alerts.sendAlerts(userId, sessionId);
                yield sendNetworkList(userId, sessionId);

                // Check if the user was away too long
                courier.callNoWait('ircparser', 'reconnectifinactive', { userId: userId });

                // Event loop
                while (1) {
                    let loopTs = Math.round(Date.now() / 1000);
                    yield redis.zadd('sessionlastheartbeat', loopTs, userId + ':' + sessionId);

                    let ntfs = yield notification.receive(userId, sessionId, 60);

                    if (state !== 'authenticated') {
                        break;
                    }

                    for (let ntf of ntfs) {
                        if (ntf.id !== 'MSG') {
                            log.info(userId,
                                `Emitted ${ntf.id}. SesId: ${sessionId}, [${JSON.stringify(ntf)}]`);
                        }

                        socket.emit('ntf', ntf);
                    }
                }
            })();
        });

        socket.on('req', function(data, cb) {
            co(function*() {
                if (state !== 'authenticated') {
                    yield end('Request arrived before init.');
                    return;
                }

                let resp = yield requestController(userId, sessionId, data);

                if (cb) {
                    cb(resp); // Send the response as Socket.io acknowledgment.
                }
            })();
        });

        socket.on('disconnect', function() {
            co(function*() {
                yield end('Socket.io disconnect.');
            })();
        });

        function *end(reason) {
            if (state !== 'disconnected') {
                clientSocketList.splice(clientSocketList.indexOf(socket), 1);
                socket.disconnect(true);

                state = 'disconnected';

                let sessionIdExplained = `${sessionId} ` || '';
                log.info(userId, `Session ${sessionIdExplained}ended. Reason: ${reason}`);

                if (sessionId) {
                    let last = yield redis.run('deleteSession', userId, sessionId);

                    if (last) {
                        yield friends.informStateChange(userId, 'logout');
                    }
                }
            }
        }
    });
};

exports.quit = function() {
    log.info('Closing all socket.io connections');

    io.httpServer.close();
    terminateClientConnections();

    yield redis.quit();
    courier.quit();
};

function *sendNetworkList(userId, sessionId) {
    networks = networks || (yield redis.smembers('networklist'));

    yield notification.send(userId, sessionId, {
        id: 'NETWORKS',
        networks: networks
    });
}

function checkBacklogParameterBounds(value) {
    let minAllowedBacklog = conf.get('session:min_backlog');
    let maxAllowedBacklog = conf.get('session:max_backlog');

    if (!isInteger(value)) {
        value = maxAllowedBacklog;
    } else if (value < minAllowedBacklog) {
        value = minAllowedBacklog;
    } else if (value > maxAllowedBacklog) {
        value = maxAllowedBacklog;
    }

    return value;
}

function terminateClientConnections() {
    clientSocketList.forEach(function(socket) {
        socket.disconnect(true);
    });
}

function isInteger(x) {
    return (typeof x === 'number') && (x % 1 === 0);
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015 IBM Corp. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* global _:true, Cookies:true*/
/* eslint no-unused-vars: "warn"*/
'use strict';

var resize = require('./demo.js').resize;
var scrollToElement = require('./demo.js').scrollToElement;

/*
 * Setups the "Try Out" and "Test" panels.
 * It connects listeners to the DOM elements in the panel to allow
 * users to select an existing image or upload a file.
 * @param params.panel {String} The panel name that will be use to locate the DOM elements.
 */

function setupUse(params) {
  var panel = params.panel || 'use';
  console.log('setupUse()', panel);

  // panel ids
  var pclass = '.' + panel + '--';
  var pid = '#' + panel + '--';

  // jquery elements we are using
  var $loading = $(pclass + 'loading');
  var $result = $(pclass + 'output');
  var $error = $(pclass + 'error');
  var $errorMsg = $(pclass + 'error-message');
  var $tbody = $(pclass + 'output-tbody');
  var $image = $(pclass + 'output-image');
  var $urlInput = $(pclass + 'url-input');
  var $imageDataInput = $(pclass + 'image-data-input');
  var $radioImages = $(pclass + 'example-radio');
  var $invalidImageUrl = $(pclass + 'invalid-image-url').hide();
  var $invalidUrl = $(pclass + 'invalid-url').show();
  var $dropzone = $(pclass + 'dropzone');
  var $fileupload = $(pid + 'fileupload');
  var $outputData = $(pclass + 'output-data');

  /*
   * Resets the panel
   */
  function reset() {
    $loading.hide();
    $result.hide();
    $error.hide();
    resetPasteUrl();
    $urlInput.val('');
    $tbody.empty();
    $outputData.empty();
    $('.dragover').removeClass('dragover');
  }

  // init reset
  reset();

  function processImage() {
    reset();
    $loading.show();
    scrollToElement($loading);
  }

  /*
   * Shows the result from classifing an image
   */
  function showResult(results) {
    $loading.hide();
    $error.hide();

    if (!results || !results.images || !results.images[0]) {
      showError('Error processing the request, please try again later.');
      return;
    }

    if (results.images[0].error) {
      var error = results.images[0].error;
      if (error.description && error.description.indexOf('Individual size limit exceeded') === 0) {
        showError('The file size exceeds the limit allowed. The maximum file size is 2 MB.');
        return;
      } else if (results.images[0].error.error_id === 'input_error') {
        showError("We couldn't not retrieve that URL, please check your URL and try again.");
        return;
      }
    }

    // populate table
    renderTable(results);
    $result.show();

    // check if there are results or not
    if (!$('.classes-table').is(':visible') &&
        !$('.faces-table').is(':visible') &&
        !$('.words-table').is(':visible') &&
        !results.classifier_ids) {
      $('.classes-table').after(
        $('
')
        .html('No matching classifiers found.'));
    }

    var outputImage = document.querySelector('.use--output-image');
    if (outputImage && (outputImage.height > outputImage.width)) {
      $(outputImage).addClass('landscape');
    }
    scrollToElement($result);
  }

  function showError(message) {
    $error.show();
    $errorMsg.html(message);
    console.log($error, $errorMsg);
  }

  function _error(xhr, responseMessage) {
    $loading.hide();
    var message = responseMessage || 'Error classifying the image';
    if (xhr && xhr.responseJSON) {
      message = xhr.responseJSON.error;
    }
    showError(message);
  }

  /*
   * submit event
   */
  function classifyImage(imgPath, imageData) {
    processImage();
    if (imgPath !== '') {
      $image.attr('src', imgPath);
      $urlInput.val(imgPath);
    }

    $imageDataInput.val(imageData);

    // Grab all form data
    $.post('/api/classify', $(pclass + 'form').serialize())
      .done(showResult)
      .error(function(error) {
        $loading.hide();
        console.log(error);

        if (error.status === 429) {
          showError('You have entered too many requests at once. Please try again later.');
        } else if (error.responseJSON && error.responseJSON.error) {
          showError('We had a problem classifying that image because ' + error.responseJSON.error);
        } else {
          showError('The demo is not available right now.
We are working on ' +
              'getting this back up and running soon.');
        }
      });
  }

  /*
   * Prevent default form submission
   */
  $fileupload.submit(false);

  /*
   * Radio image submission
   */
  $radioImages.click(function() {
    console.log('clicked');
    resetPasteUrl();
    var imgPath = $(this).next('label').find('img').attr('src');
    classifyImage(imgPath);
    $urlInput.val('');
  });

  /*
   * Image url submission
   */
  $urlInput.keypress(function(e) {
    var url = $(this).val();
    var self = $(this);

    if (e.keyCode === 13) {
      $invalidUrl.hide();
      $invalidImageUrl.hide();
      resetPasteUrl();
      classifyImage(url);
      self.blur();
    }

    $(self).focus();
  });

  function resetPasteUrl() {
    $urlInput.removeClass(panel + '--url-input_error');
    $invalidUrl.hide();
    $invalidImageUrl.hide();
  }
  /**
   * Jquery file upload configuration
   * See details: https://github.com/blueimp/jQuery-File-Upload
   */
  $fileupload.fileupload({
    dataType: 'json',
    dropZone: $dropzone,
    acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
    add: function(e, data) {
      data.url = '/api/classify';
      if (data.files && data.files[0]) {
        $error.hide();

        processImage();
        var reader = new FileReader();
        reader.onload = function() {
          var image = new Image();
          image.src = reader.result;
          image.onload = function() {
            $image.attr('src', this.src);
            classifyImage('', resize(image, 2048));
          };
          image.onerror = function() {
            _error(null, 'Error loading the image file. I can only work with images.');
          };
        };
        reader.readAsDataURL(data.files[0]);
      }
    },
    error: _error,
    done: function(e, data) {
      showResult(data.result);
    }
  });

  $(document).on('dragover', function() {
    $(pclass + 'dropzone label').addClass('dragover');
    $('form#use--fileupload').addClass('dragover');
  });

  $(document).on('dragleave', function() {
    $(pclass + 'dropzone label').removeClass('dragover');
    $('form#use--fileupload').removeClass('dragover');
  });

  function roundScore(score) {
    return Math.round(score * 100) / 100;
  }

  function slashesToArrows(typeHierarchy) {
    var results = typeHierarchy;
    results = results.replace(/^\/|\/$/g, ''); // trim first / and last /
    results = results.replace(/\//g, ' > ');  // change slashes to >'s
    return results;
  }

  function lookupInMap(mapToCheck, kind, token, defaultValue) {
    var res = mapToCheck[kind][token];
    if (res) {
      return res;
    } else {
      return defaultValue;
    }
  }

  function getAndParseCookieName(cookieName, defaultValue) {
    var res = Cookies.get(cookieName);
    if (res) {
      return JSON.parse(res);
    } else {
      return defaultValue;
    }
  }

  function renderTable(results) {
    $('.' + panel + '--mismatch').remove();

    if (results.images && results.images.length > 0) {
      if (results.images[0].resolved_url) {
        $image.attr('src', results.images[0].resolved_url);
      }
    }

    // eslint-disable-next-line camelcase
    var useResultsTable_template = useResultsTableTemplate.innerHTML;

    var classNameMap = getAndParseCookieName('classNameMap', {});
    var bundle = getAndParseCookieName('bundle', {});

    // classes
    if ((results.images &&
      results.images[0].classifiers &&
      results.images[0].classifiers.length > 0 &&
      results.images[0].classifiers[0].classes !== 'undefined') &&
      results.images[0].classifiers[0].classes.length > 0) {
      var classesModel = (function() {
        var classes = results.images[0].classifiers[0].classes.map(function(item) {
          return {
            name: results.classifier_ids ? lookupInMap(classNameMap, bundle.kind, item.class, item.class) : item.class,
            score: roundScore(item.score),
            type_hierarchy: item.type_hierarchy ? slashesToArrows(item.type_hierarchy) : false
          };
        });

        return {
          resultCategory: 'Classes',
          data: classes
        };
      })();

      // $('.classes-table').show();
      $outputData.append(_.template(useResultsTable_template, {
        items: classesModel
      }));
    } else if (results.classifier_ids) {
      var classes = bundle.names[0];
      if (bundle.names.length > 1) {
        classes = bundle.names.slice(0, -1).join(', ') + ' or ' + bundle.names.slice(-1);
      }
      $('.classes-table').html('
This image is not a match for ' + bundle.name + ': ' + classes + '.
');
      $('.classes-table').show();
    } else {
      $('.classes-table').hide();
    }

    // faces
    if ((typeof results.images[0].faces !== 'undefined') && (results.images[0].faces.length > 0)) {
      var facesModel = (function() {
        var identities = [];
        var faces = results.images[0].faces.reduce(function(acc, facedat) {
          // gender
          acc.push({
            name: facedat.gender.gender.toLowerCase(),
            score: roundScore(facedat.gender.score)
          });

          // age
          acc.push({
            name: 'age ' + facedat.age.min + ' - ' + facedat.age.max,
            score: roundScore(facedat.age.score)
          });

          // identity
          if (typeof facedat.identity !== 'undefined') {
            identities.push({
              name: facedat.identity.name,
              score: roundScore(facedat.identity.score),
              type_hierarchy: facedat.identity.type_hierarchy ? slashesToArrows(facedat.identity.type_hierarchy) : false
            });
          }
          return acc;
        }, []);

        return {
          resultCategory: 'Faces',
          identities: identities,
          data: faces
        };
      })();

      console.log(facesModel);

      // $('.faces-table').show();
      $outputData.append(_.template(useResultsTable_template, {
        items: facesModel
      }));
    } else {
      $('.faces-table').hide();
    }

    // words
    if ((typeof results.images[0].words !== 'undefined') && (results.images[0].words.length > 0)) {
      var wordsModel = (function() {
        var words = results.images[0].words.map(function(item) {
          return {
            name: item.word,
            score: roundScore(item.score)
          };
        });
        return {
          resultCategory: 'Words',
          data: words
        };
      })();

      // $('.words-table').show();
      $outputData.append(_.template(useResultsTable_template, {
        items: wordsModel
      }));
    } else {
      $('.words-table').hide();
    }

    $(document).on('click', '.results-table--input-no', function() {
      $(this).parent().hide();
      $(this).parent().parent().find('.results-table--feedback-thanks').show();
      $(this).parent().parent().addClass('results-table--feedback-wowed');
      var originalElement = $(this);
      setTimeout(function() {
        originalElement.parent().show();
        originalElement.parent().parent().find('.results-table--feedback-thanks').hide();
        originalElement.parent().parent().removeClass('results-table--feedback-wowed');
      },2000);
    });

    $(document).on('click', '.results-table--input-yes', function() {
      $(this).parent().hide();
      $(this).parent().parent().find('.results-table--feedback-thanks').show();
      $(this).parent().parent().addClass('results-table--feedback-wowed');
      var originalElement = $(this);
      setTimeout(function() {
        originalElement.parent().show();
        originalElement.parent().parent().find('.results-table--feedback-thanks').hide();
        originalElement.parent().parent().removeClass('results-table--feedback-wowed');
      },2000);
    });
  }
}

module.exports = setupUse;
<commit_msg>eslint fixes<commit_after>/**
 * Copyright 2015 IBM Corp. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* global _:true, Cookies:true*/
/* eslint no-unused-vars: "warn"*/
'use strict';

var resize = require('./demo.js').resize;
var scrollToElement = require('./demo.js').scrollToElement;

/*
 * Setups the "Try Out" and "Test" panels.
 * It connects listeners to the DOM elements in the panel to allow
 * users to select an existing image or upload a file.
 * @param params.panel {String} The panel name that will be use to locate the DOM elements.
 */

function setupUse(params) {
  var panel = params.panel || 'use';
  console.log('setupUse()', panel);

  // panel ids
  var pclass = '.' + panel + '--';
  var pid = '#' + panel + '--';

  // jquery elements we are using
  var $loading = $(pclass + 'loading');
  var $result = $(pclass + 'output');
  var $error = $(pclass + 'error');
  var $errorMsg = $(pclass + 'error-message');
  var $tbody = $(pclass + 'output-tbody');
  var $image = $(pclass + 'output-image');
  var $urlInput = $(pclass + 'url-input');
  var $imageDataInput = $(pclass + 'image-data-input');
  var $radioImages = $(pclass + 'example-radio');
  var $invalidImageUrl = $(pclass + 'invalid-image-url').hide();
  var $invalidUrl = $(pclass + 'invalid-url').show();
  var $dropzone = $(pclass + 'dropzone');
  var $fileupload = $(pid + 'fileupload');
  var $outputData = $(pclass + 'output-data');

  /*
   * Resets the panel
   */
  function reset() {
    $loading.hide();
    $result.hide();
    $error.hide();
    resetPasteUrl();
    $urlInput.val('');
    $tbody.empty();
    $outputData.empty();
    $('.dragover').removeClass('dragover');
  }

  // init reset
  reset();

  function processImage() {
    reset();
    $loading.show();
    scrollToElement($loading);
  }

  /*
   * Shows the result from classifing an image
   */
  function showResult(results) {
    $loading.hide();
    $error.hide();

    if (!results || !results.images || !results.images[0]) {
      showError('Error processing the request, please try again later.');
      return;
    }

    if (results.images[0].error) {
      var error = results.images[0].error;
      if (error.description && error.description.indexOf('Individual size limit exceeded') === 0) {
        showError('The file size exceeds the limit allowed. The maximum file size is 2 MB.');
        return;
      } else if (results.images[0].error.error_id === 'input_error') {
        showError("We couldn't not retrieve that URL, please check your URL and try again.");
        return;
      }
    }

    // populate table
    renderTable(results);
    $result.show();

    // check if there are results or not
    if (!$('.classes-table').is(':visible') &&
        !$('.faces-table').is(':visible') &&
        !$('.words-table').is(':visible') &&
        !results.classifier_ids) {
      $('.classes-table').after(
        $('
')
        .html('No matching classifiers found.'));
    }

    var outputImage = document.querySelector('.use--output-image');
    if (outputImage && (outputImage.height > outputImage.width)) {
      $(outputImage).addClass('landscape');
    }
    scrollToElement($result);
  }

  function showError(message) {
    $error.show();
    $errorMsg.html(message);
    console.log($error, $errorMsg);
  }

  function _error(xhr, responseMessage) {
    $loading.hide();
    var message = responseMessage || 'Error classifying the image';
    if (xhr && xhr.responseJSON) {
      message = xhr.responseJSON.error;
    }
    showError(message);
  }

  /*
   * submit event
   */
  function classifyImage(imgPath, imageData) {
    processImage();
    if (imgPath !== '') {
      $image.attr('src', imgPath);
      $urlInput.val(imgPath);
    }

    $imageDataInput.val(imageData);

    // Grab all form data
    $.post('/api/classify', $(pclass + 'form').serialize())
      .done(showResult)
      .error(function(error) {
        $loading.hide();
        console.log(error);

        if (error.status === 429) {
          showError('You have entered too many requests at once. Please try again later.');
        } else if (error.responseJSON && error.responseJSON.error) {
          showError('We had a problem classifying that image because ' + error.responseJSON.error);
        } else {
          showError('The demo is not available right now.
We are working on ' +
              'getting this back up and running soon.');
        }
      });
  }

  /*
   * Prevent default form submission
   */
  $fileupload.submit(false);

  /*
   * Radio image submission
   */
  $radioImages.click(function() {
    console.log('clicked');
    resetPasteUrl();
    var imgPath = $(this).next('label').find('img').attr('src');
    classifyImage(imgPath);
    $urlInput.val('');
  });

  /*
   * Image url submission
   */
  $urlInput.keypress(function(e) {
    var url = $(this).val();
    var self = $(this);

    if (e.keyCode === 13) {
      $invalidUrl.hide();
      $invalidImageUrl.hide();
      resetPasteUrl();
      classifyImage(url);
      self.blur();
    }

    $(self).focus();
  });

  function resetPasteUrl() {
    $urlInput.removeClass(panel + '--url-input_error');
    $invalidUrl.hide();
    $invalidImageUrl.hide();
  }
  /**
   * Jquery file upload configuration
   * See details: https://github.com/blueimp/jQuery-File-Upload
   */
  $fileupload.fileupload({
    dataType: 'json',
    dropZone: $dropzone,
    acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
    add: function(e, data) {
      data.url = '/api/classify';
      if (data.files && data.files[0]) {
        $error.hide();

        processImage();
        var reader = new FileReader();
        reader.onload = function() {
          var image = new Image();
          image.src = reader.result;
          image.onload = function() {
            $image.attr('src', this.src);
            classifyImage('', resize(image, 2048));
          };
          image.onerror = function() {
            _error(null, 'Error loading the image file. I can only work with images.');
          };
        };
        reader.readAsDataURL(data.files[0]);
      }
    },
    error: _error,
    done: function(e, data) {
      showResult(data.result);
    }
  });

  $(document).on('dragover', function() {
    $(pclass + 'dropzone label').addClass('dragover');
    $('form#use--fileupload').addClass('dragover');
  });

  $(document).on('dragleave', function() {
    $(pclass + 'dropzone label').removeClass('dragover');
    $('form#use--fileupload').removeClass('dragover');
  });

  function roundScore(score) {
    return Math.round(score * 100) / 100;
  }

  function slashesToArrows(typeHierarchy) {
    var results = typeHierarchy;
    results = results.replace(/^\/|\/$/g, ''); // trim first / and last /
    results = results.replace(/\//g, ' > ');  // change slashes to >'s
    return results;
  }

  function lookupInMap(mapToCheck, kind, token, defaultValue) {
    var res = mapToCheck[kind][token];
    if (res) {
      return res;
    } else {
      return defaultValue;
    }
  }

  function getAndParseCookieName(cookieName, defaultValue) {
    var res = Cookies.get(cookieName);
    if (res) {
      return JSON.parse(res);
    } else {
      return defaultValue;
    }
  }

  function renderTable(results) {
    $('.' + panel + '--mismatch').remove();

    if (results.images && results.images.length > 0) {
      if (results.images[0].resolved_url) {
        $image.attr('src', results.images[0].resolved_url);
      }
    }

    // eslint-disable-next-line camelcase
    var useResultsTable_template = useResultsTableTemplate.innerHTML;

    var classNameMap = getAndParseCookieName('classNameMap', {});
    var bundle = getAndParseCookieName('bundle', {});

    // classes
    if ((results.images &&
      results.images[0].classifiers &&
      results.images[0].classifiers.length > 0 &&
      results.images[0].classifiers[0].classes !== 'undefined') &&
      results.images[0].classifiers[0].classes.length > 0) {
      var classesModel = (function() {
        var classes = results.images[0].classifiers[0].classes.map(function(item) {
          return {
            name: results.classifier_ids ? lookupInMap(classNameMap, bundle.kind, item.class, item.class) : item.class,
            score: roundScore(item.score),
            type_hierarchy: item.type_hierarchy ? slashesToArrows(item.type_hierarchy) : false
          };
        });

        return {
          resultCategory: 'Classes',
          data: classes
        };
      })();

      // $('.classes-table').show();
      $outputData.append(_.template(useResultsTable_template, {
        items: classesModel
      }));
    } else if (results.classifier_ids) {
      var classes = bundle.names[0];
      if (bundle.names.length > 1) {
        classes = bundle.names.slice(0, -1).join(', ') + ' or ' + bundle.names.slice(-1);
      }
      $('.classes-table').html('
This image is not a match for ' + bundle.name + ': ' + classes + '.
');
      $('.classes-table').show();
    } else {
      $('.classes-table').hide();
    }

    // faces
    if ((typeof results.images[0].faces !== 'undefined') && (results.images[0].faces.length > 0)) {
      var facesModel = (function() {
        var identities = [];
        var faces = results.images[0].faces.reduce(function(acc, facedat) {
          // gender
          acc.push({
            name: facedat.gender.gender.toLowerCase(),
            score: roundScore(facedat.gender.score)
          });

          // age
          acc.push({
            name: 'age ' + facedat.age.min + ' - ' + facedat.age.max,
            score: roundScore(facedat.age.score)
          });

          // identity
          if (typeof facedat.identity !== 'undefined') {
            identities.push({
              name: facedat.identity.name,
              score: roundScore(facedat.identity.score),
              type_hierarchy: facedat.identity.type_hierarchy ? slashesToArrows(facedat.identity.type_hierarchy) : false
            });
          }
          return acc;
        }, []);

        return {
          resultCategory: 'Faces',
          identities: identities,
          data: faces
        };
      })();

      console.log(facesModel);

      // $('.faces-table').show();
      $outputData.append(_.template(useResultsTable_template, {
        items: facesModel
      }));
    } else {
      $('.faces-table').hide();
    }

    // words
    if ((typeof results.images[0].words !== 'undefined') && (results.images[0].words.length > 0)) {
      var wordsModel = (function() {
        var words = results.images[0].words.map(function(item) {
          return {
            name: item.word,
            score: roundScore(item.score)
          };
        });
        return {
          resultCategory: 'Words',
          data: words
        };
      })();

      // $('.words-table').show();
      $outputData.append(_.template(useResultsTable_template, {
        items: wordsModel
      }));
    } else {
      $('.words-table').hide();
    }

    $(document).on('click', '.results-table--input-no', function() {
      $(this).parent().hide();
      $(this).parent().parent().find('.results-table--feedback-thanks').show();
      $(this).parent().parent().addClass('results-table--feedback-wowed');
      var originalElement = $(this);
      setTimeout(function() {
        originalElement.parent().show();
        originalElement.parent().parent().find('.results-table--feedback-thanks').hide();
        originalElement.parent().parent().removeClass('results-table--feedback-wowed');
      }, 2000);
    });

    $(document).on('click', '.results-table--input-yes', function() {
      $(this).parent().hide();
      $(this).parent().parent().find('.results-table--feedback-thanks').show();
      $(this).parent().parent().addClass('results-table--feedback-wowed');
      var originalElement = $(this);
      setTimeout(function() {
        originalElement.parent().show();
        originalElement.parent().parent().find('.results-table--feedback-thanks').hide();
        originalElement.parent().parent().removeClass('results-table--feedback-wowed');
      }, 2000);
    });
  }
}

module.exports = setupUse;
<|endoftext|>


<commit_before>import context from '../../context';

/**
 * Obtaining and installing external HTML.
 * @module xblocks/dom/outerHTML
 */
export default (function () {

    let container = context.document.createElementNS('http://www.w3.org/1999/xhtml', '_');
    let getter;
    let setter;

    if (container.hasOwnProperty('outerHTML')) {
        getter = function () {
            return this.outerHTML;
        };

        setter = function (html) {
            this.outerHTML = html;
        };

    } else {
        const serializer = context.XMLSerializer && (new context.XMLSerializer());
        const xmlns = /\sxmlns=\"[^\"]+\"/;

        if (serializer) {
            getter = function () {
                return serializer.serializeToString(this).replace(xmlns, '');
            };

        } else {
            getter = function () {
                container.appendChild(this.cloneNode(false));
                const html = container.innerHTML.replace('><', `>${this.innerHTML}<`);
                container.innerHTML = '';
                return html;
            };
        }

        setter = function (html) {
            let node = this;
            let parent = node.parentNode;
            let child;

            if (!parent) {
                context.DOMException.code = context.DOMException.NOT_FOUND_ERR;
                throw context.DOMException;
            }

            container.innerHTML = html;

            while ((child = container.firstChild)) {
                parent.insertBefore(child, node);
            }

            parent.removeChild(node);
        };
    }

    return {
        /** @alias module:xblocks/dom/outerHTML.get */
        'get': getter,
        /** @alias module:xblocks/dom/outerHTML.set */
        'set': setter
    };

}());
<commit_msg>updated documentation<commit_after>import context from '../../context';

/**
 * Obtaining and installing external HTML.
 * @module xblocks/dom/outerHTML
 */
export default (function () {

    let container = context.document.createElementNS('http://www.w3.org/1999/xhtml', '_');
    let getter;
    let setter;

    if (container.hasOwnProperty('outerHTML')) {
        getter = function () {
            return this.outerHTML;
        };

        setter = function (html) {
            this.outerHTML = html;
        };

    } else {
        const serializer = context.XMLSerializer && (new context.XMLSerializer());
        const xmlns = /\sxmlns=\"[^\"]+\"/;

        if (serializer) {
            getter = function () {
                return serializer.serializeToString(this).replace(xmlns, '');
            };

        } else {
            getter = function () {
                container.appendChild(this.cloneNode(false));
                const html = container.innerHTML.replace('><', `>${this.innerHTML}<`);
                container.innerHTML = '';
                return html;
            };
        }

        setter = function (html) {
            let node = this;
            let parent = node.parentNode;
            let child;

            if (!parent) {
                context.DOMException.code = context.DOMException.NOT_FOUND_ERR;
                throw context.DOMException;
            }

            container.innerHTML = html;

            while ((child = container.firstChild)) {
                parent.insertBefore(child, node);
            }

            parent.removeChild(node);
        };
    }

    return {
        /**
         * Obtaining external HTML.
         * @alias module:xblocks/dom/outerHTML.get
         * @function
         * @returns {string}
         */
        'get': getter,

        /**
         * Installing external HTML.
         * @alias module:xblocks/dom/outerHTML.set
         * @function
         * @param {string} html
         */
        'set': setter
    };

}());
<|endoftext|>


<commit_before>/*jshint multistr: true */

'use strict';

var $ = require('jquery'),
    PulsarSortableComponent = require('../../../js/PulsarSortableComponent');

describe('PulsarSortableComponent', function () {
    beforeEach(function () {

        this.$html = $('');
        this.$body = $('').appendTo(this.$html);
        this.$markup = $('\

\

\
        <button data-toggle="dropdown" class="btn dropdown__toggle">\
            Actions \
            \
        </button>\

\

 New Filter
\

 Random Option
\

\

 Delete
\

\

\

\

\

\
                foo	\
                	\
                <input type="checkbox" class="form__control checkbox">	\

\

\
                foo	\
                	\

\

\

\

\
').appendTo(this.$html);

        this.$table = this.$html.find('.table');
        this.$rowOne = this.$html.find('.qa-row-one');
        this.$rowTwo = this.$html.find('.qa-row-two');
        this.$moveUp = this.$html.find('[data-move="up"]');
        this.$moveDown = this.$html.find('[data-move="down"]');

        this.pulsarSortable = new PulsarSortableComponent(this.$html);
    });

    describe('The sortable table', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
        });

        it('should have row one at index 0', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(0);
        });

        it('should have row two at index 1', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(1);
        });
    });

    describe('Clicking a move control in row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$moveUp.click();
        });

        it('should hide the move links', function () {
            expect(this.$html.find('.qa-row-one [data-move="up"]').hasClass('hide')).to.be.true;
        });

        it('should add the success icon', function () {
            expect(this.$html.find('.qa-row-one [data-move="up"]').parent().find('.icon-ok-sign').length).to.equal(1);
        });

        it('should remove the success icon after a delay', function () {
            setTimeout(function (){
                expect(this.$html.find('.qa-row-one [data-move="up"]').parent().find('.js-sortable-moved').length).to.equal(0);
            }, 1000);
        });

        it('should show the move links after a delay', function () {
            setTimeout(function (){
                expect(this.$html.find('.qa-row-one [data-move="up"]').hasClass('hide')).to.be.false;
            }, 2250);
        });
    });

    describe('Clicking the move down control on row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$rowOne.find('[data-move="down"]').click();
        });

        it('should move the row down one position', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(1);
        });

        it('should move the other row up one position', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(0);
        });
    });

    describe('Clicking the move up control on row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$rowOne.find('[data-move="up"]').click();
        });

        it('should move the row up one position', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(0);
        });

        it('should move the other row down one position', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(1);
        });
    });

    describe('Selecting a table row', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.click();
        });

        afterEach(function () {
            this.actionsBadgeStub.restore();
        });

        it('should add class "is-selected"', function () {
            expect(this.$rowOne.hasClass('is-selected')).to.be.true;
        });

        it('should toggle the row\'s checkbox', function () {
            expect(this.$rowOne.find('.checkbox').first().prop('checked')).to.be.true;
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });

        it('should add a badge to "Actions" dropdown', function () {
            expect(this.$html.find('.has-badges .dropdown__toggle .badge').is(':visible')).to.be.true;
        });

        it('should have the word "item" in the Delete dadge', function () {
            expect(this.$html.find('.has-badges .dropdown__menu li:last-child a').text().indexOf("item") > 1).to.be.true;
        });
    });

    describe('Deselecting a table row', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.addClass('is-selected');
            this.$rowOne.find('.checkbox').first().prop('checked', true);
            this.$rowOne.click();
        });

        it('should add class "is-selected"', function () {
            expect(this.$rowOne.hasClass('is-selected')).to.be.false;
        });

        it('should toggle the row\'s checkbox', function () {
            expect(this.$rowOne.find('.checkbox').first().prop('checked')).to.be.false;
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });
    });

    describe('When a row is already selected and another row is selected afterwords,', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.click();
            this.$rowTwo.click();
        });

        afterEach(function () {
            this.actionsBadgeStub.restore();
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });

        it('should increase the number of selected items in the "Actions" dropdown badges', function () {
            expect(this.$html.find('.has-badges .dropdown__toggle .badge').html()).to.equal(2);
        });

        it('should have the word "items" in the Delete dadge', function () {
            expect(this.$html.find('.has-badges .dropdown__menu li:last-child a').text().indexOf("items") > 1).to.be.true;
        });
    });
});
<commit_msg>Improve Test DOM Structure, Add Another Checkbox<commit_after>/*jshint multistr: true */

'use strict';

var $ = require('jquery'),
    PulsarSortableComponent = require('../../../js/PulsarSortableComponent');

describe('PulsarSortableComponent', function () {
    beforeEach(function () {

        this.$html = $('

').appendTo('html');
        this.$body = $('

').appendTo(this.$html);
        this.$markup = $('\

\

\
        <button data-toggle="dropdown" class="btn dropdown__toggle">\
            Actions \
            \
        </button>\

\

 New Filter
\

 Random Option
\

\

 Delete
\

\

\

\

\

\
                foo	\
                	\
                <input type="checkbox" class="form__control checkbox">	\

\

\
                foo	\
                	\
                <input type="checkbox" class="form__control checkbox">	\

\

\

\

\
').appendTo(this.$body);

        this.$table = this.$html.find('.table');
        this.$rowOne = this.$html.find('.qa-row-one');
        this.$rowTwo = this.$html.find('.qa-row-two');
        this.$moveUp = this.$html.find('[data-move="up"]');
        this.$moveDown = this.$html.find('[data-move="down"]');

        this.pulsarSortable = new PulsarSortableComponent(this.$html);
    });

    describe('The sortable table', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
        });

        it('should have row one at index 0', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(0);
        });

        it('should have row two at index 1', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(1);
        });
    });

    describe('Clicking a move control in row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$moveUp.click();
        });

        it('should hide the move links', function () {
            expect(this.$html.find('.qa-row-one [data-move="up"]').hasClass('hide')).to.be.true;
        });

        it('should add the success icon', function () {
            expect(this.$html.find('.qa-row-one [data-move="up"]').parent().find('.icon-ok-sign').length).to.equal(1);
        });

        it('should remove the success icon after a delay', function () {
            setTimeout(function (){
                expect(this.$html.find('.qa-row-one [data-move="up"]').parent().find('.js-sortable-moved').length).to.equal(0);
            }, 1000);
        });

        it('should show the move links after a delay', function () {
            setTimeout(function (){
                expect(this.$html.find('.qa-row-one [data-move="up"]').hasClass('hide')).to.be.false;
            }, 2250);
        });
    });

    describe('Clicking the move down control on row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$rowOne.find('[data-move="down"]').click();
        });

        it('should move the row down one position', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(1);
        });

        it('should move the other row up one position', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(0);
        });
    });

    describe('Clicking the move up control on row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$rowOne.find('[data-move="up"]').click();
        });

        it('should move the row up one position', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(0);
        });

        it('should move the other row down one position', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(1);
        });
    });

    describe('Selecting a table row', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.click();
        });

        afterEach(function () {
            this.actionsBadgeStub.restore();
        });

        it('should add class "is-selected"', function () {
            expect(this.$rowOne.hasClass('is-selected')).to.be.true;
        });

        it('should toggle the row\'s checkbox', function () {
            expect(this.$rowOne.find('.checkbox').first().prop('checked')).to.be.true;
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });

        it('should add a badge to "Actions" dropdown', function () {
            expect(this.$html.find('.has-badges .dropdown__toggle .badge').is(':visible')).to.be.true;
        });

        it('should have the word "item" in the Delete dadge', function () {
            expect(this.$html.find('.has-badges .dropdown__menu li:last-child a').text().indexOf("item") > 1).to.be.true;
        });
    });

    describe('Deselecting a table row', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.addClass('is-selected');
            this.$rowOne.find('.checkbox').first().prop('checked', true);
            this.$rowOne.click();
        });

        it('should add class "is-selected"', function () {
            expect(this.$rowOne.hasClass('is-selected')).to.be.false;
        });

        it('should toggle the row\'s checkbox', function () {
            expect(this.$rowOne.find('.checkbox').first().prop('checked')).to.be.false;
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });
    });

    describe('When a row is already selected and another row is selected afterwords,', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.click();
            this.$rowTwo.click();
        });

        afterEach(function () {
            this.actionsBadgeStub.restore();
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });

        it('should increase the number of selected items in the "Actions" dropdown badges', function () {
            expect(this.$html.find('.has-badges .dropdown__toggle .badge').html()).to.equal(2);
        });

        it('should have the word "items" in the Delete dadge', function () {
            expect(this.$html.find('.has-badges .dropdown__menu li:last-child a').text().indexOf("items") > 1).to.be.true;
        });
    });
});
<|endoftext|>