2017-09-05 14 views
0

私はcacsadeフォームを構築するための良いアイデアを見ています。Railsネストされた複合フォーム

私が探しているのは、フォームymlデータを構築するためのフォームを作成することです。

たとえば、キー値フォームを作成するにはvalueフィールドは文字列またはハッシュまたは配列にすることができます。

config - > Items - > has keyとvalue - >はString、ArrayまたはHashです。

どのようなアイデアですか?

+0

(flare.jsonはJSONファイルをretriveするアクションです)...私は人々が同じことをしたかったために何whith共有するあなたはより具体的な例を提供することはできますか?あなたが求めているのはあまりにも曖昧です。 –

+0

私は何のために構成ファイルのための入れ子になったフォームを作成することですllokingです。 この設定ファイルはymlです。これは次のようになります。 bdd: server1: mysql: 'mariadb' vms: - name: 'test_1' files: 'example' 同じカスケード形式を改造しないでフォームを作成するにはどうすればよいですか。 –

答えて

0

私がしたことは、3djsを使ってグラフを生成し、editabeをノードにしてノードを追加/削除することです。私は

var root; 
treeJSON = d3.json("flare.json", function(error, treeData) { 

// Calculate total nodes, max label length 
var totalNodes = 0; 
var maxLabelLength = 0; 
// variables for drag/drop 
var selectedNode = null; 
var draggingNode = null; 
// panning variables 
var panSpeed = 200; 
var panBoundary = 20; // Within 20px from edges will pan when dragging. 
// Misc. variables 
var i = 0; 
var duration = 750; 
// var root; 

// size of the diagram 
var viewerWidth = $('#d3view').width(); 
var viewerHeight = 800; 

var tree = d3.layout.tree() 
    .size([viewerHeight, viewerWidth]); 

// define a d3 diagonal projection for use by the node paths later on. 
var diagonal = d3.svg.diagonal() 
    .projection(function(d) { 
     return [d.y, d.x]; 
    }); 

// A recursive helper function for performing some setup by walking through all nodes 

function visit(parent, visitFn, childrenFn) { 
    if (!parent) return; 

    visitFn(parent); 

    var children = childrenFn(parent); 
    if (children) { 
     var count = children.length; 
     for (var i = 0; i < count; i++) { 
      visit(children[i], visitFn, childrenFn); 
     } 
    } 
} 

// Call visit function to establish maxLabelLength 
visit(treeData, function(d) { 
    totalNodes++; 
    maxLabelLength = Math.max(d.name.length, maxLabelLength); 

}, function(d) { 
    return d.children && d.children.length > 0 ? d.children : null; 
}); 


// sort the tree according to the node names 

function sortTree() { 
    tree.sort(function(a, b) { 
     return b.name.toLowerCase() < a.name.toLowerCase() ? 1 : -1; 
    }); 
} 
// Sort the tree initially incase the JSON isn't in a sorted order. 
sortTree(); 

// Define the zoom function for the zoomable tree 

function zoom() { 
    $('.btn-form').remove() 
    svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); 
} 


// define the zoomListener which calls the zoom function on the "zoom" event constrained within the scaleExtents 
var zoomListener = d3.behavior.zoom().scaleExtent([0.1, 1.5]).on("zoom", zoom); 

// define the baseSvg, attaching a class for styling and the zoomListener 
var baseSvg = d3.select("#d3view").append("svg") 
    .attr("width", viewerWidth) 
    .attr("height", viewerHeight) 
    .attr("class", "overlay") 
    .call(zoomListener); 

// Function to center node when clicked/dropped so node doesn't get lost when collapsing/moving with large amount of children. 

function centerNode(source) { 
    scale = 0.3;//zoomListener.scale(); 
    x = -source.y0; 
    y = -source.x0; 
    x = x * scale + viewerWidth/20; 
    y = y * scale + viewerHeight/2.5; 
    d3.select('g').transition() 
     .duration(duration) 
     .attr("transform", "translate(" + x + "," + y + ")scale(" + scale + ")"); 
    zoomListener.scale(scale); 
    zoomListener.translate([x, y]); 
} 

// Toggle children function 

function toggleChildren(d) { 
    if (d.children) { 
     d._children = d.children; 
     d.children = null; 
    } else if (d._children) { 
     d.children = d._children; 
     d._children = null; 
    } 
    return d; 
} 

// Toggle children on click. 

function click(d) { 
    if (d3.event.defaultPrevented) return; // click suppressed 
    d = toggleChildren(d); 
    update(d); 
    // centerNode(d); 
} 



function remove_link(d){ 
    a = d3.event 
    a.preventDefault() 
    p = d.parent 
    parent_array = [p] 
    depth = d.depth - 1 
    for(var i=1; i<depth; i++){ 
     parent_1 = p 
     parent_2 = parent_1.parent 
     parent_array.push(parent_2) 
     p = parent_2 
    } 
    parent_array[0].children.splice($.inArray(d, parent_array[0].children), 1) 
    update(d); 
    $('#editme').tree('loadData', [root]); 
} 



function make_editable(d) 
{ 
    // console.log("make_editable", arguments); 
    this 
     .on("mouseover", function() { 
     $('.btn-form').remove(); 
     $('.input-form').remove(); 
     d3.selectAll('text').style('fill', null) 
     d3.select(this).style("fill", "red"); 
     var p = this.parentNode; 
     var xy = this.getBBox(); 
     var p_xy = p.getBBox(); 
     xy.x -= p_xy.x; 
     xy.y -= p_xy.y; 

     xy.x += 25; 
     xy.y -= 50; 

     var el = d3.select(this); 
     var p_el = d3.select(p); 

     var frm = p_el.append("foreignObject"); 
     var inp = frm 
      .attr('class', 'btn-form') 
      .attr("x", xy.x) 
      .attr("y", xy.y) 
      .attr("width", 145) 
      .attr("height", 60) 
      .append("xhtml:form") 
       .append('a').text('Add').attr('class', 'btn btn-primary').attr('style', 'width:50px;height:30px;margin-right:2%;').on('click', add_link) 

     frm.select('form').append('a').text('Remove').attr('class', 'btn btn-danger remove-btn').attr('style', 'width:70px;height:30px;').on('click', remove_link) 
     frm.on('mouseover', function(){ 
      $('.btn-form').closest('g').find('text').attr("fill", 'red'); 
     }) 
      .on('mouseout', function(){ 
       $('.btn-form').closest('g').find('text').attr("fill", null); 
      }) 

     }) 
     .on("mouseout", function() { 
     d3.select(this).style("fill", null); 
     }) 
     .on("click", function(d, event) { 
     e = d3.event; 
     e.preventDefault(); 
     $('.btn-form').remove(); 
     var p = this.parentNode; 
     // console.log(this, arguments); 

     // inject a HTML form to edit the content here... 

     // bug in the getBBox logic here, but don't know what I've done wrong here; 
     // anyhow, the coordinates are completely off & wrong. :-((
     var xy = this.getBBox(); 
     var p_xy = p.getBBox(); 

     xy.x -= p_xy.x; 
     xy.y -= p_xy.y; 

     var el = d3.select(this); 
     var p_el = d3.select(p); 

     var frm = p_el.append("foreignObject"); 

     var inp = frm 
      .attr('class', 'input-form') 
      .attr("x", xy.x) 
      .attr("y", xy.y) 
      .style("z-index", 99999) 
      .attr("width", 300) 
      .attr("height", 25) 
      .append("xhtml:form") 
       .append("input") 
        .attr("value", function() { 
         // nasty spot to place this call, but here we are sure that the <input> tag is available 
         // and is handily pointed at by 'this': 
         this.focus(); 

         return el.text(); 
        }) 
        .attr("style", "width: 110px;") 
        // make the form go away when you jump out (form looses focus) or hit ENTER: 
        .on("blur", function() { 
         // console.log("blur", this, arguments); 

         var txt = inp.node().value; 

         el.text(function(d) { return txt; }); 
         d.name = el.text(); 

         // Note to self: frm.remove() will remove the entire <g> group! Remember the D3 selection logic! 
         p_el.select("foreignObject").remove(); 
        }) 
        .on("keypress", function() { 
         // console.log("keypress", this, arguments); 

         // IE fix 
         if (!d3.event) 
          d3.event = window.event; 

         var e = d3.event; 
         if (e.keyCode == 13) 
         { 
          if (typeof(e.cancelBubble) !== 'undefined') // IE 
           e.cancelBubble = true; 
          if (e.stopPropagation) 
           e.stopPropagation(); 
          e.preventDefault(); 

          var txt = inp.node().value; 
          el.text(function(d) { return txt; }); 
          p_el.attr('data-name', txt); 
          d.name = el.text(); 
          $('#editme').tree('loadData', [root]); 
         } 
        }); 
     }); 
} 


function add_link(d){ 
    d3.event.preventDefault(); 
    var p = $(this).closest('form') 
    var xy = $(this).closest('.btn-form')[0].getBBox(); 


    if($(".add-link").length == 0){ 
     var frm = p.append("<div><input type='text' class='add-link' style='width:130px;'></input></div>"); 
     var inp = frm.on('keypress', function(event){ 
      var e = event; 
      if (e.keyCode == 13) 
      { 
       e.preventDefault(); 

       var txt = $('.add-link').val(); 
       var event = document.createEvent('Event'); 
       event.initEvent('click', true, true); 
       if(d.children){ 
        d.children.push({name: txt}) 
       }else if(d._children){ 
        d._children.push({name: txt}) 

       }else{ 
        d.children = [{name: txt}] 
       } 
       $('text[fill="red"]').attr('fill', null); 
       update(root); 
       $(".btn-form").hide(); 
       $('#editme').tree('loadData', [root]); 
      } 
     }) 
     .on('click', function(event){ event.preventDefault();}) 

     $('.add-link').focus() 
    } 

} 


function update(source) { 
    // Compute the new height, function counts total children of root node and sets tree height accordingly. 
    // This prevents the layout looking squashed when new nodes are made visible or looking sparse when nodes are removed 
    // This makes the layout more consistent. 
    var levelWidth = [1]; 
    var childCount = function(level, n) { 

     if (n.children && n.children.length > 0) { 
      if (levelWidth.length <= level + 1) levelWidth.push(0); 

      levelWidth[level + 1] += n.children.length; 
      n.children.forEach(function(d) { 
       childCount(level + 1, d); 
      }); 
     } 
    }; 
    childCount(0, root); 
    var newHeight = d3.max(levelWidth) * 25; // 25 pixels per line 
    tree = tree.size([newHeight, viewerWidth]); 

    // Compute the new tree layout. 
    var nodes = tree.nodes(root).reverse(), 
     links = tree.links(nodes); 

    // Set widths between levels based on maxLabelLength. 
    nodes.forEach(function(d) { 
     d.y = (d.depth * (maxLabelLength * 10)); //maxLabelLength * 10px 
     // alternatively to keep a fixed scale one can set a fixed depth per level 
     // Normalize for fixed-depth by commenting out below line 
     // d.y = (d.depth * 500); //500px per level. 
    }); 

    // Update the nodes… 
    node = svgGroup.selectAll("g.node") 
     .data(nodes, function(d) { 
      return d.id || (d.id = ++i); 
     }); 

    // Enter any new nodes at the parent's previous position. 
    var nodeEnter = node.enter().append("g") 
     // .call(dragListener) 
     .attr("class", "node") 
     .attr("transform", function(d) { 
      return "translate(" + source.y0 + "," + source.x0 + ")"; 
     }) 
     .on('click', click); 

    nodeEnter.append("circle") 
     .attr('class', 'nodeCircle') 
     .attr("r", 0) 
     .style("fill", function(d) { 
      return d._children ? "lightsteelblue" : "#fff"; 
     }); 

    nodeEnter.append("text") 
     .attr("x", function(d) { 
      return d.children || d._children ? -10 : 10; 
     }) 
     .attr("dy", ".35em") 
     .attr('class', 'nodeText') 
     .attr("text-anchor", function(d) { 
      return d.children || d._children ? "end" : "start"; 
     }) 
     .text(function(d) { 
      return d.name; 
     }) 
     .style("fill-opacity", 0) 
     .call(make_editable); 

    // phantom node to give us mouseover in a radius around it 
    // nodeEnter.append("circle") 
    //  .attr('class', 'ghostCircle') 
    //  .attr("r", 30) 
    //  .attr("opacity", 0.2) // change this to zero to hide the target area 
    // .style("fill", "red") 
    //  .attr('pointer-events', 'mouseover'); 
     // .on("mouseover", function(node) { 
     //  overCircle(node); 
     // }) 
     // .on("mouseout", function(node) { 
     //  outCircle(node); 
     // }); 

    // Update the text to reflect whether node has children or not. 
    node.select('text') 
     .attr("x", function(d) { 
      return d.children || d._children ? -10 : 10; 
     }) 
     .attr("text-anchor", function(d) { 
      return d.children || d._children ? "end" : "start"; 
     }) 
     .text(function(d) { 
      return d.name; 
     }); 

    // Change the circle fill depending on whether it has children and is collapsed 
    node.select("circle.nodeCircle") 
     .attr("r", 4.5) 
     .style("fill", function(d) { 
      return d._children ? "lightsteelblue" : "#fff"; 
     }); 

    // Transition nodes to their new position. 
    var nodeUpdate = node.transition() 
     .duration(duration) 
     .attr("transform", function(d) { 
      return "translate(" + d.y + "," + d.x + ")"; 
     }); 

    // Fade the text in 
    nodeUpdate.select("text") 
     .style("fill-opacity", 1); 

    // Transition exiting nodes to the parent's new position. 
    var nodeExit = node.exit().transition() 
     .duration(duration) 
     .attr("transform", function(d) { 
      return "translate(" + source.y + "," + source.x + ")"; 
     }) 
     .remove(); 

    nodeExit.select("circle") 
     .attr("r", 0); 

    nodeExit.select("text") 
     .style("fill-opacity", 0); 

    // Update the links… 
    var link = svgGroup.selectAll("path.link") 
     .data(links, function(d) { 
      return d.target.id; 
     }); 

    // Enter any new links at the parent's previous position. 
    link.enter().insert("path", "g") 
     .attr("class", "link") 
     .attr("d", function(d) { 
      var o = { 
       x: source.x0, 
       y: source.y0 
      }; 
      return diagonal({ 
       source: o, 
       target: o 
      }); 
     }); 

    // Transition links to their new position. 
    link.transition() 
     .duration(duration) 
     .attr("d", diagonal); 

    // Transition exiting nodes to the parent's new position. 
    link.exit().transition() 
     .duration(duration) 
     .attr("d", function(d) { 
      var o = { 
       x: source.x, 
       y: source.y 
      }; 
      return diagonal({ 
       source: o, 
       target: o 
      }); 
     }) 
     .remove(); 

    // Stash the old positions for transition. 
    nodes.forEach(function(d) { 
     d.x0 = d.x; 
     d.y0 = d.y; 
    }); 
} 

function collapse(d) { 
    if (d.children) { 
     d._children = d.children; 
     d._children.forEach(collapse); 
     d.children = null; 
    } 
} 

function expand(d) { 
    if (d._children) { 
     d.children = d._children; 
     d.children.forEach(expand); 
     d._children = null; 
    }else if(d.children) { 
     d.children.forEach(expand); 
    } 
} 

// Append a group which holds all nodes and which the zoom Listener can act upon. 
var svgGroup = baseSvg.append("g"); 

// Define the root 
root = treeData; 
root.x0 = viewerHeight/2; 
root.y0 = 0; 

// Layout the tree initially and center on the root node. 
update(root); 
centerNode(root); 
}); 
関連する問題