estimancy/projestimate

View on GitHub
app/views/projects/_show_project_tree_history.html.erb

Summary

Maintainability
Test Coverage
<div id="project_history_actions" style="margin-bottom: 50px;" xmlns="http://www.w3.org/1999/html">
  <div class="project_history">
    <h4>
      <%= hidden_field_tag :select_at_least_one_project, I18n.t(:select_at_least_one_project) %>

      <span style="color:#23A4FF; float: left; margin-left: 0px; margin-right: 10px;">Estimation Actions : </span>
      <%  %>
      <%= link_to '', '', :class => 'node_link_to button_attribute_tooltip icon-pencil pull-left', :id => 'edit_node_path', :title => I18n.t('edit'), :remote => true %>
      <%= link_to '', '', :class => 'node_link_to button_attribute_tooltip icon-star pull-left', :id => 'activate_node_path', :title => I18n.t('button_activate_project'), :remote => true %>
      <%= link_to '', '', :class => 'node_link_to button_attribute_tooltip icon-ok-circle pull-left', :id => 'promote_node_path', :title => I18n.t('button_commit_project'), :remote => true %>
      <%= link_to('', '', :class => 'node_link_to button_attribute_tooltip fa fa-code-fork pull-left', :id => 'set_checkout_version_path', style: "margin-top:4px;", :title => I18n.t('button_checkout_project'), remote: true, :confirm => (I18n.t(:confirm_new_branch_project_checkout) unless @project.is_childless?)) %>
      <%= link_to '', '', :class => 'node_link_to button_attribute_tooltip icon-info pull-left', :id => 'find_use_projects_from_history', :project_id => @project.id, :title => I18n.t('button_find_use'), :remote => true %>
      <%= link_to '', '', :class => 'node_link_to button_attribute_tooltip icon-copy pull-left', :id => 'duplicate_node_path', :title => I18n.t('button_duplicate_project'), :remote => true %>
      <%= link_to '', '', :class => 'node_link_to button_attribute_tooltip icon-trash pull-left', :style => 'color:red', :id => 'delete_node_path', :title => I18n.t('delete'), :remote => true %>
    </h4>
  </div>
</div>

<div id="container">
  <div id="center-container">
    <div id="infovis" class="infovis_project_history"></div>
  </div>
  <div id="log"></div>
</div>


<script>

    var labelType, useGradients, nativeTextSupport, animate;

    (function() {
        var ua = navigator.userAgent,
                iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
                typeOfCanvas = typeof HTMLCanvasElement,
                nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
                textSupport = nativeCanvasSupport
                        && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
        //I'm setting this based on the fact that ExCanvas provides text support for IE
        //and that as of today iPhone/iPad current text support is lame
        labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
        nativeTextSupport = labelType == 'Native';
        useGradients = nativeCanvasSupport;
        animate = !(iStuff || !nativeCanvasSupport);
    })();

    var Log = {
        elem: false,
        write: function(text){
            if (!this.elem)
                this.elem = document.getElementById('log');
            this.elem.innerHTML = text;
            this.elem.style.left = (450 - this.elem.offsetWidth / 2) + 'px';
        }
    };

//    function init(){
       //Init data from Rails project history data
       // FOr ex. var json = {"id":"301","name":"ggg","title":"ggg","version":"1.0","data":{},"children":[{"id":"305","name":"ggg","title":"ggg","version":"1.0-1.0","data":{},"children":[]},{"id":"304","name":"ggg","title":"ggg","version":"1.1","data":{},"children":[{"id":"306","name":"ggg","title":"ggg","version":"1.2","data":{},"children":[{"id":"30","name":"moi","title":"moi","version":"1.2","data":{},"children":[]}]}]}]};
       var json = $("#project_tree_id").data("project_tree");
        //end

        //init Spacetree
        //Create a new ST instance
        var st = new $jit.ST({
            //id of viz container element
            injectInto: 'infovis',
            //set orientation
            orientation: 'left',
            //set duration for the animation
            duration: 0, //800,
            //set animation transition type
            transition: $jit.Trans.Quart.easeInOut,
            //set distance between node and its children
            levelDistance: 50,
            //set the maximum depth/level to show in the Tree
            levelsToShow: 9999,

            //offsetWidth: 100,

            onComplete: function () {
                var LastnodeTop = 0;
                var LastnodeLeft = 0;
                $("div.node").each(function () {
                    var pos = $(this).position();
                    if (pos.top > LastnodeTop)
                        LastnodeTop = pos.top;
                    if (pos.left > LastnodeLeft)
                    LastnodeLeft = pos.left;
                });

                var LastnodeTopStr = LastnodeTop.toString();
                var LastnodeLeftStr = LastnodeLeft.toString();
                LastnodeTopStr = LastnodeTopStr.substring(0, 4);
                LastnodeLeftStr = LastnodeLeftStr.substring(0, 4);
                var LastnodeTopInt = parseInt(LastnodeTopStr) + 100;
                var LastnodeLeftInt = parseInt(LastnodeLeftStr) + 100;

//                $("#center-container").attr("style", "height:" + LastnodeTopInt + "px");
//                $("#center-container").attr("style", "width:" + LastnodeLeftInt + "px");
                var treeRoot = st.root;

            },

            //enable panning
            Navigation: {
                enable:true,
                panning:true
            },
            //set node and edge styles
            //set overridable=true for styling individual
            //nodes or edges
            Node: {
                height: 75, //20,
                width: 60,
                type: 'circle', //'rectangle',
                color: '#aaa',
                overridable: true
            },

            Edge: {
                type: 'bezier',
                overridable: true
            },

            onBeforeCompute: function(node){
                //Log.write("loading " + node.name);
            },

            onAfterCompute: function(){
                //Log.write("Project: Title");
            },

            //This method is called on DOM label creation.
            //Use this method to add event handlers and styles to
            //your node.
            onCreateLabel: function(label, node){
                label.id = node.id;
                //label.innerHTML = node.name;

                //Display node version and state
                var version_maxi_length = 16;
                var node_version = "";
                if (node.name.length > version_maxi_length)
                    node_version = node.name.substring(0, 16) + "...";
                else
                    node_version = node.name;

                var display = node_version;
                var data = node.data;

                var my_check_box = document.createElement('input');
                my_check_box.type = 'checkbox';
                my_check_box.name = 'checkbox_'+node.id;
                my_check_box.id = 'checkbox_'+node.id;
                my_check_box.value = node.id;
                my_check_box.className = 'tree_node_checkbox';
                my_check_box.dataset['node_state'] = node.data.state;

                var state = document.createElement('Label');
                state.type = 'text';
                state.innerText = capitaliseFirstLetter(node.data.state).replace('_', ' ');

                display += "<br>";
                label.innerHTML = display;
                label.appendChild(state);
                label.appendChild(my_check_box);

                //Current project is styled in bold
                if ( node.id == $('#current_showed_project_id').val()){
                    label.innerHTML = "<b style='font-weight: bold; color: #990000;'>"+ label.innerHTML +"</b>";
                }

                //Enable/disable some actions according to the checked node
                label.onclick = function(){
                    var counter = 0,
                        checkout_counter = 0,
                        i = 0;
                    var states_to_confirm = {checkpoint: "checkpoint", released: "released", rejected: "rejected"};
                    var states_to_checkout = {checkpoint: "checkpoint", released: "released"};
                    var checkbox_objects = document.getElementsByClassName('tree_node_checkbox');
                    // loop through all collected checkbox objects
                    for (i = 0; i < checkbox_objects.length; i++) {
                        // if input object is checkbox and checkbox is checked then ... for promote
                        if (checkbox_objects[i].dataset['node_state'] in states_to_confirm && checkbox_objects[i].checked === true) {
                            // ... increase counter
                            counter++;
                        }
                        //For checkout button
                        if ( !(checkbox_objects[i].dataset['node_state'] in states_to_checkout) && checkbox_objects[i].checked === true ) {
                            // ... increase checkout counter
                            checkout_counter++;
                        }
                    }
                    //Get promote link_to
                    var promote_button = document.getElementById('promote_node_path');
                    if(counter > 0){
                        promote_button.disabled = true;
                        $('#promote_node_path').removeClass('icon-ok-circle');
                    }
                    else{
                        promote_button.disabled = false;
                        $('#promote_node_path').addClass('icon-ok-circle');
                    }

                    //Get checkout link_to
                    var checkout_button = document.getElementById('checkout_node_path');
                    if(checkout_counter > 0){
                        checkout_button.disabled = true;
                        $('#checkout_node_path').removeClass('icon-step-forward');
                    }
                    else{
                        checkout_button.disabled = false;
                        $('#checkout_node_path').addClass('icon-step-forward');
                    }
                };

//                label.onclick = function(){
//                    if(normal.checked) {
//                    //if(node.checked) {
//                        alert($("#checkbox_"+node.id).val());
//                        st.onClick(node.id);
//                    } else {
//                        //alert($(this));
//                        st.setRoot(node.id, 'animate');
//                    }
//                };


                //set label styles
                var style = label.style;
                style.width = 60 + 'px';
                style.height = 17 + 'px';
                style.cursor = 'pointer';
                style.color = '#333';
                style.fontSize = '0.9em'; /*'0.8em';*/
                style.textAlign= 'center';
                style.paddingTop = '3px';
                style.fontWeight = 'bold';
            },

            //For displaying Tooltips
            Tips: {
                enable: true,
                type: 'HTML',
                offsetX: 10,
                offsetY: 10,
                onShow: function (tip, node)
                {
                    tip.innerHTML = getToolTip(node);
                }
            },

            //This method is called right before plotting
            //a node. It's useful for changing an individual node
            //style properties before plotting it.
            //The data properties prefixed with a dollar
            //sign will override the global node style properties.
            onBeforePlotNode: function(node){
                //add some color to the nodes in the path between the
                //root node and the selected node.
                if (node.selected) {
                    node.data.$color = "#ff7";
                }
                else {
                    delete node.data.$color;
                    //if the node belongs to the last plotted level
                    if(!node.anySubnode("exist")) {
                        //count children number
                        var count = 0;
                        node.eachSubnode(function(n) { count++; });
                        //assign a node color based on
                        //how many children it has
                        node.data.$color = ['#aaa', '#baa', '#caa', '#daa', '#eaa', '#faa'][count];
                    }
                }
            },

            //This method is called right before plotting
            //an edge. It's useful for changing an individual edge
            //style properties before plotting it.
            //Edge data proprties prefixed with a dollar sign will
            //override the Edge global style properties.
            onBeforePlotLine: function(adj){
                if (adj.nodeFrom.selected && adj.nodeTo.selected) {
                    adj.data.$color = "#eed";
                    adj.data.$lineWidth = 3;
                }
                else {
                    delete adj.data.$color;
                    delete adj.data.$lineWidth;
                }
            }
        });

       var infovis_canvas = document.getElementById("infovis-canvas");
       var infovis_label = document.getElementById("infovis-label");
       var infovis_canvas_widget = document.getElementById("infovis-canvaswidget");
//       infovis_canvas.style.left =  "-300px";
//       infovis_label.style.left =  "-300px";

        //load json data
        st.loadJSON(json);
        //compute node positions and layout
        st.compute();
        //optional: make a translation of the tree
        st.geom.translate(new $jit.Complex(-200, 0), "current");
        //emulate a click on the root node.
        ///st.onClick(st.root);
        //Add offset on the Tree Root
        st.onClick(st.root, {
            Move: {
                offsetX: 400,
                offsetY: 100
            }
        });
        //end

       //Added by me
       //st.each(st, function(node){
//       $jit.json.each(json, function(node){
//           st.addEvent(node, 'click', function(){ alert('hello'); });
//       });
       //end added by me

        //Add event handlers to switch spacetree orientation.
        var top = $jit.id('r-top'),
                left = $jit.id('r-left'),
                bottom = $jit.id('r-bottom'),
                right = $jit.id('r-right'),
                normal = $jit.id('s-normal');


        function changeHandler() {
            if(this.checked) {
                top.disabled = bottom.disabled = right.disabled = left.disabled = true;
                st.switchPosition(this.value, "animate", {
                    onComplete: function(){
                        top.disabled = bottom.disabled = right.disabled = left.disabled = false;
                    }
                });
            }
        };

        top.onchange = left.onchange = bottom.onchange = right.onchange = changeHandler;
        //end

//    };  // END init

       //Function that display Tooltips
       function getToolTip(node){
           return node.data.title + "-" + node.name;
       }

        function capitaliseFirstLetter(string)
        {
          return string.charAt(0).toUpperCase() + string.slice(1);
        }

</script>