$(function () {
setSideMenu("sidebar_menu_product", "sidebar_menu_product_jira_connect");
});
$(function () {
jsTreeBuild();
});
/* -------------------------------- jstree 설정 ------------------------------- */
function jsTreeBuild() {
console.log("href: " + $(location).attr("href"));
console.log("protocol: " + $(location).attr("protocol"));
console.log("host: " + $(location).attr("host"));
console.log("pathname: " + $(location).attr("pathname"));
console.log("search: " + $(location).attr("search"));
console.log("hostname: " + $(location).attr("hostname"));
console.log("port: " + $(location).attr("port"));
var isDevelopingToRoute = "/auth-user";
$("#demo")
.bind("before.jstree", function (e, data) {
$("#alog").append(data.func + " ");
$("li:not([rel='drive']).jstree-open > a > .jstree-icon").css(
"background-image",
"url(http://www.a-rms.net/313devgrp/reference/jquery-plugins/jstree-v.pre1.0/themes/toolbar_open.png)"
);
$("li:not([rel='drive']).jstree-closed > a > .jstree-icon").css(
"background-image",
"url(http://www.a-rms.net/313devgrp/reference/jquery-plugins/jstree-v.pre1.0/themes/ic_explorer.png)"
);
})
.jstree({
// List of active plugins
plugins: [
"themes",
"json_data",
"ui",
"crrm",
"cookies",
"dnd",
"search",
"types",
"hotkeys",
"contextmenu",
"checkbox",
],
themes: { theme: ["lightblue4"] },
//contextmenu
contextmenu: {
items: {
// Could be a function that should return an object like this one
create: {
separator_before: true,
separator_after: true,
label: "Create",
action: false,
submenu: {
create_file: {
seperator_before: false,
seperator_after: false,
label: "File",
action: function (obj) {
this.create(obj, "last", {
attr: {
rel: "default",
},
});
},
},
create_folder: {
seperator_before: false,
seperator_after: false,
label: "Folder",
action: function (obj) {
this.create(obj, "last", {
attr: {
rel: "folder",
},
});
},
},
},
},
ccp: {
separator_before: false,
separator_after: true,
label: "Edit",
action: false,
submenu: {
cut: {
seperator_before: false,
seperator_after: false,
label: "Cut",
action: function (obj) {
this.cut(obj, "last", {
attr: {
rel: "default",
},
});
},
},
paste: {
seperator_before: false,
seperator_after: false,
label: "Paste",
action: function (obj) {
this.paste(obj, "last", {
attr: {
rel: "folder",
},
});
},
},
changeType: {
seperator_before: false,
seperator_after: false,
label: "Change Type",
submenu: {
toFile: {
seperator_before: false,
seperator_after: false,
label: "toFile",
action: function (obj) {
this.set_type("default");
},
},
toFolder: {
seperator_before: false,
seperator_after: false,
label: "toFolder",
action: function (obj) {
this.set_type("folder");
},
},
},
},
},
},
},
},
// I usually configure the plugin that handles the data first
// This example uses JSON as it is most common
json_data: {
// This tree is ajax enabled - as this is most common, and maybe a bit more complex
// All the options are almost the same as jQuery's AJAX (read the docs)
ajax: {
// the URL to fetch the data
url: isDevelopingToRoute + "/api/arms/pdservice/getChildNode.do",
// the `data` function is executed in the instance's scope
// the parameter is the node being loaded
// (may be -1, 0, or undefined when loading the root nodes)
data: function (n) {
// the result is fed to the AJAX request `data` option
console.log(n);
return {
c_id: n.attr
? n.attr("id").replace("node_", "").replace("copy_", "")
: 1,
};
},
success: function (n) {
jSuccess("Product(service) Data Load Complete");
},
},
},
// Configuring the search plugin
search: {
// As this has been a common question - async search
// Same as above - the `ajax` config option is actually jQuery's AJAX object
ajax: {
url: isDevelopingToRoute + "/api/arms/pdservice/searchNode.do",
// You get the search string as a parameter
data: function (str) {
return {
searchString: str,
};
},
success: function (n) {
jSuccess("search data complete");
},
},
},
// Using types - most of the time this is an overkill
// read the docs carefully to decide whether you need types
types: {
// I set both options to -2, as I do not need depth and children count checking
// Those two checks may slow jstree a lot, so use only when needed
max_depth: -2,
max_children: -2,
// I want only `drive` nodes to be root nodes
// This will prevent moving or creating any other type as a root node
valid_children: ["drive"],
types: {
// The default type
default: {
// I want this type to have no children (so only leaf nodes)
// In my case - those are files
valid_children: "none",
// If we specify an icon for the default type it WILL OVERRIDE the theme icons
icon: {
image: "../dist/js/jstree-v.pre1.0/themes/attibutes.png",
},
},
// The `folder` type
folder: {
// can have files and other folders inside of it, but NOT `drive` nodes
valid_children: ["default", "folder"],
icon: {
image: "../dist/js/jstree-v.pre1.0/themes/ic_explorer.png",
},
},
// The `drive` nodes
drive: {
// can have files and folders inside, but NOT other `drive` nodes
valid_children: ["default", "folder"],
icon: {
image: "../dist/js/jstree-v.pre1.0/themes/home.png",
},
// those prevent the functions with the same name to be used on `drive` nodes
// internally the `before` event is used
start_drag: false,
move_node: false,
delete_node: false,
remove: false,
},
},
},
// UI & core - the nodes to initially select and open will be overwritten by the cookie plugin
// the UI plugin - it handles selecting/deselecting/hovering nodes
ui: {
// this makes the node with ID node_4 selected onload
initially_select: ["node_4"],
},
// the core plugin - not many options here
core: {
// just open those two nodes up
// as this is an AJAX enabled tree, both will be downloaded from the server
initially_open: ["node_2", "node_3"],
},
})
.bind("create.jstree", function (e, data) {
$.post(
isDevelopingToRoute + "/api/arms/pdservice/addNode.do",
{
ref: data.rslt.parent.attr("id").replace("node_", "").replace("copy_", ""),
c_position: data.rslt.position,
c_title: data.rslt.name,
c_type: data.rslt.obj.attr("rel"),
},
function (r) {
if (r.status) {
$(data.rslt.obj).attr("id", "node_" + r.id);
jNotify("Notification : Add Node, Complete !");
} else {
$.jstree.rollback(data.rlbk);
}
if (typeof Chat != "undefined") {
Chat.sendMessage(
"노드를 추가했습니다. 추가된 노드의 아이디는 " + r.id,
function (data) {
console.log(data);
}
);
}
jsTreeBuild();
}
);
})
.bind("remove.jstree", function (e, data) {
data.rslt.obj.each(function () {
$.ajax({
async: false,
type: "POST",
url: isDevelopingToRoute + "/api/arms/pdservice/removeNode.do",
data: {
c_id: this.id.replace("node_", "").replace("copy_", ""),
},
success: function (r) {
jNotify("Notification : Remove Node, Complete !");
if (typeof Chat != "undefined") {
Chat.sendMessage(
"노드를 삭제했습니다. 삭제된 노드의 아이디는 " + r.c_id,
function (data) {
console.log(data);
}
);
}
jsTreeBuild();
},
});
});
})
.bind("rename.jstree", function (e, data) {
$.post(
isDevelopingToRoute + "/api/arms/pdservice/alterNode.do",
{
c_id: data.rslt.obj.attr("id").replace("node_", "").replace("copy_", ""),
c_title: data.rslt.new_name,
c_type: data.rslt.obj.attr("rel"),
},
function (r) {
if (!r.status) {
$.jstree.rollback(data.rlbk);
}
jSuccess("Rename Node Complete");
if (typeof Chat != "undefined") {
Chat.sendMessage(
"노드를 변경했습니다. 변경된 노드의 아이디는 " + r.c_id,
function (data) {
console.log(data);
}
);
}
jsTreeBuild();
}
);
})
.bind("set_type.jstree", function (e, data) {
$.post(
isDevelopingToRoute + "/api/arms/pdservice/alterNodeType.do",
{
c_id: data.rslt.obj.attr("id").replace("node_", "").replace("copy_", ""),
c_title: data.rslt.new_name,
c_type: data.rslt.obj.attr("rel"),
},
function (r) {
jSuccess("Node Type Change");
if (typeof Chat != "undefined") {
Chat.sendMessage(
"노드를 변경했습니다. 변경된 노드의 아이디는 " + r.c_id,
function (data) {
console.log(data);
}
);
}
jsTreeBuild();
}
);
})
.bind("move_node.jstree", function (e, data) {
data.rslt.o.each(function (i) {
$.ajax({
async: false,
type: "POST",
url: isDevelopingToRoute + "/api/arms/pdservice/moveNode.do",
data: {
c_id: $(this).attr("id").replace("node_", "").replace("copy_", ""),
ref:
data.rslt.cr === -1
? 1
: data.rslt.np.attr("id").replace("node_", "").replace("copy_", ""),
c_position: data.rslt.cp + i,
c_title: data.rslt.name,
copy: data.rslt.cy ? 1 : 0,
multiCounter: i,
},
success: function (r) {
if (r.status) {
$.jstree.rollback(data.rlbk);
} else {
$(data.rslt.oc).attr("id", "node_" + r.id);
if (data.rslt.cy && $(data.rslt.oc).children("UL").length) {
data.inst.refresh(data.inst._get_parent(data.rslt.oc));
}
}
jNotify("Notification : Move Node Complete !");
if (typeof Chat != "undefined") {
Chat.sendMessage(
"노드가 이동되었습니다. 이동된 노드의 아이디는 " + r.c_id,
function (data) {
console.log(data);
}
);
}
jsTreeBuild();
},
});
});
})
.bind("select_node.jstree", function (event, data) {
// `data.rslt.obj` is the jquery extended node that was clicked
if ($.isFunction(jsTreeClick)) {
console.log(data.rslt.obj.attr("localName"));
jsTreeClick(data.rslt.obj.attr("id"), data.rslt.obj.text());
}
});
$("#mmenu input, #mmenu button").click(function () {
switch (this.id) {
case "add_default":
case "add_folder":
$("#demo").jstree("create", null, "last", {
attr: {
rel: this.id.toString().replace("add_", ""),
},
});
break;
case "search":
$("#demo").jstree("search", document.getElementById("text").value);
break;
case "text":
break;
default:
$("#demo").jstree(this.id);
break;
}
});
}
$(function () {
jstreeDataTableReload();
$(".dataTables_length").find("select:eq(0)").addClass("darkBack");
$(".dataTables_length").find("select:eq(0)").css("min-height", "30px");
//min-height: 30px;
$("body").find("[aria-controls='jstreeTable']").css("width", "100px");
});
// --- 데이터 테이블 설정 --- //
function jstreeDataTableReload() {
console.log("href: " + $(location).attr("href"));
console.log("protocol: " + $(location).attr("protocol"));
console.log("host: " + $(location).attr("host"));
console.log("pathname: " + $(location).attr("pathname"));
console.log("search: " + $(location).attr("search"));
console.log("hostname: " + $(location).attr("hostname"));
console.log("port: " + $(location).attr("port"));
var isDevelopingToRoute = "/auth-user";
var tempDataTable = $("#jstreeTable").DataTable({
ajax: {
url: isDevelopingToRoute + "/api/arms/pdjira/getMonitor.do",
dataSrc: "",
},
destroy: true,
processing: true,
responsive: true,
select: {
style: "multi",
},
columns: [
{ data: "c_id" },
{ data: "c_parentid" },
{ data: "c_position" },
{ data: "c_left" },
{ data: "c_right" },
{ data: "c_level" },
{ data: "c_title" },
{ data: "c_type" },
{ data: "c_pdjira_detail" },
{ data: "c_pdjira_con_name" },
{ data: "c_pdjira_con_user" },
{ data: "c_pdjira_con_pass" },
{ data: "c_pdjira_con_token" },
{ data: "c_pdjira_con_jql" },
{ data: "jiraConPassMode" },
],
});
$("#jstreeTable tbody").on("click", "tr", function () {
var data = tempDataTable.row(this).data();
console.log(data);
//alert( 'You clicked on '+ data.c_title +'\'s row' );
});
}
/* ---------------------------------------- d3 config ------------------------------------ */
/* d3 */
var treeData = {
name: "product service name",
type: "Product(service)",
children: [
{
name: "Visualization",
type: "Jira JQL",
children: [
{
name: "test",
type: "Jira JQL",
},
],
},
],
};
//treeJSON = d3.json(flare_data, 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
//edit 313devops
//var viewerWidth = $(document).width();
//var viewerHeight = $(document).height();
var viewerWidth = $("#tree-container").outerHeight();
var viewerHeight = 295;
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();
// TODO: Pan function, can be better implemented.
function pan(domNode, direction) {
var speed = panSpeed;
if (panTimer) {
clearTimeout(panTimer);
translateCoords = d3.transform(svgGroup.attr("transform"));
if (direction == "left" || direction == "right") {
translateX =
direction == "left"
? translateCoords.translate[0] + speed
: translateCoords.translate[0] - speed;
translateY = translateCoords.translate[1];
} else if (direction == "up" || direction == "down") {
translateX = translateCoords.translate[0];
translateY =
direction == "up"
? translateCoords.translate[1] + speed
: translateCoords.translate[1] - speed;
}
scaleX = translateCoords.scale[0];
scaleY = translateCoords.scale[1];
scale = zoomListener.scale();
svgGroup
.transition()
.attr(
"transform",
"translate(" + translateX + "," + translateY + ")scale(" + scale + ")"
);
d3
.select(domNode)
.select("g.node")
.attr("transform", "translate(" + translateX + "," + translateY + ")");
zoomListener.scale(zoomListener.scale());
zoomListener.translate([translateX, translateY]);
panTimer = setTimeout(function () {
pan(domNode, speed, direction);
}, 50);
}
}
// Define the zoom function for the zoomable tree
function zoom() {
//edit 313devops
svgGroup.attr(
"transform",
"translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"
);
//svgGroup.attr("transform", "translate(" + "221,79" + ")scale(" + 1.5 + ")");
}
// define the zoomListener which calls the zoom function on the "zoom" event constrained within the scaleExtents
var zoomListener = d3.behavior.zoom().scaleExtent([0.1, 3]).on("zoom", zoom);
function initiateDrag(d, domNode) {
draggingNode = d;
d3.select(domNode).select(".ghostCircle").attr("pointer-events", "none");
d3.selectAll(".ghostCircle").attr("class", "ghostCircle show");
d3.select(domNode).attr("class", "node activeDrag");
svgGroup.selectAll("g.node").sort(function (a, b) {
// select the parent and sort the path's
if (a.id != draggingNode.id)
return 1; // a is not the hovered element, send "a" to the back
else return -1; // a is the hovered element, bring "a" to the front
});
// if nodes has children, remove the links and nodes
if (nodes.length > 1) {
// remove link paths
links = tree.links(nodes);
nodePaths = svgGroup
.selectAll("path.link")
.data(links, function (d) {
return d.target.id;
})
.remove();
// remove child nodes
nodesExit = svgGroup
.selectAll("g.node")
.data(nodes, function (d) {
return d.id;
})
.filter(function (d, i) {
if (d.id == draggingNode.id) {
return false;
}
return true;
})
.remove();
}
// remove parent link
parentLink = tree.links(tree.nodes(draggingNode.parent));
svgGroup
.selectAll("path.link")
.filter(function (d, i) {
if (d.target.id == draggingNode.id) {
return true;
}
return false;
})
.remove();
dragStarted = null;
}
// define the baseSvg, attaching a class for styling and the zoomListener
var baseSvg = d3
.select("#tree-container")
.append("svg")
.attr("width", viewerWidth)
.attr("height", viewerHeight)
.attr("class", "overlay")
.call(zoomListener);
// Define the drag listeners for drag/drop behaviour of nodes.
dragListener = d3.behavior
.drag()
.on("dragstart", function (d) {
if (d == root) {
return;
}
dragStarted = true;
nodes = tree.nodes(d);
d3.event.sourceEvent.stopPropagation();
// it's important that we suppress the mouseover event on the node being dragged. Otherwise it will absorb the mouseover event and the underlying node will not detect it d3.select(this).attr('pointer-events', 'none');
})
.on("drag", function (d) {
if (d == root) {
return;
}
if (dragStarted) {
domNode = this;
initiateDrag(d, domNode);
}
// get coords of mouseEvent relative to svg container to allow for panning
relCoords = d3.mouse($("svg").get(0));
if (relCoords[0] < panBoundary) {
panTimer = true;
pan(this, "left");
} else if (relCoords[0] > $("svg").width() - panBoundary) {
panTimer = true;
pan(this, "right");
} else if (relCoords[1] < panBoundary) {
panTimer = true;
pan(this, "up");
} else if (relCoords[1] > $("svg").height() - panBoundary) {
panTimer = true;
pan(this, "down");
} else {
try {
clearTimeout(panTimer);
} catch (e) {}
}
d.x0 += d3.event.dy;
d.y0 += d3.event.dx;
var node = d3.select(this);
node.attr("transform", "translate(" + d.y0 + "," + d.x0 + ")");
updateTempConnector();
})
.on("dragend", function (d) {
if (d == root) {
return;
}
domNode = this;
if (selectedNode) {
// now remove the element from the parent, and insert it into the new elements children
var index = draggingNode.parent.children.indexOf(draggingNode);
if (index > -1) {
draggingNode.parent.children.splice(index, 1);
}
if (
typeof selectedNode.children !== "undefined" ||
typeof selectedNode._children !== "undefined"
) {
if (typeof selectedNode.children !== "undefined") {
selectedNode.children.push(draggingNode);
} else {
selectedNode._children.push(draggingNode);
}
} else {
selectedNode.children = [];
selectedNode.children.push(draggingNode);
}
// Make sure that the node being added to is expanded so user can see added node is correctly moved
expand(selectedNode);
sortTree();
endDrag();
} else {
endDrag();
}
});
function endDrag() {
selectedNode = null;
d3.selectAll(".ghostCircle").attr("class", "ghostCircle");
d3.select(domNode).attr("class", "node");
// now restore the mouseover event or we won't be able to drag a 2nd time
d3.select(domNode).select(".ghostCircle").attr("pointer-events", "");
updateTempConnector();
if (draggingNode !== null) {
update(root);
centerNode(draggingNode);
draggingNode = null;
}
}
// Helper functions for collapsing and expanding nodes.
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;
}
}
var overCircle = function (d) {
selectedNode = d;
updateTempConnector();
};
var outCircle = function (d) {
selectedNode = null;
updateTempConnector();
};
// Function to update the temporary connector indicating dragging affiliation
var updateTempConnector = function () {
var data = [];
if (draggingNode !== null && selectedNode !== null) {
// have to flip the source coordinates since we did this for the existing connectors on the original tree
data = [
{
source: {
x: selectedNode.y0,
y: selectedNode.x0,
},
target: {
x: draggingNode.y0,
y: draggingNode.x0,
},
},
];
}
var link = svgGroup.selectAll(".templink").data(data);
link
.enter()
.append("path")
.attr("class", "templink")
.attr("d", d3.svg.diagonal())
.attr("pointer-events", "none");
link.attr("d", d3.svg.diagonal());
link.exit().remove();
};
// 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 = zoomListener.scale();
x = -source.y0;
y = -source.x0;
x = x * scale + viewerWidth / 2;
y = y * scale + viewerHeight / 2;
//edit 313devops
x = $("#tree-container").outerWidth() / 3;
y = $("#tree-container").outerHeight() / 3;
scale = 1.4;
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 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);
nodeEnter
.append("text")
.attr("x", function (d) {
return -15;
})
.attr("y", function (d) {
return 15;
})
.text(function (d) {
return d.type;
})
.on("click", function (d) {
window.location = d.url;
})
.style("font-size", "8px");
// 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;
});
}
// 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);
/* --------------------------- multi select & slim scroll ---------------------------------- */
$(function () {
//multiselect
$(".searchable").multiSelect({
selectableHeader:
"",
selectionHeader:
"",
afterInit: function (ms) {
var that = this,
$selectableSearch = that.$selectableUl.prev(),
$selectionSearch = that.$selectionUl.prev(),
selectableSearchString =
"#" +
that.$container.attr("id") +
" .ms-elem-selectable:not(.ms-selected)",
selectionSearchString =
"#" + that.$container.attr("id") + " .ms-elem-selection.ms-selected";
that.qs1 = $selectableSearch
.quicksearch(selectableSearchString)
.on("keydown", function (e) {
if (e.which === 40) {
that.$selectableUl.focus();
return false;
}
});
that.qs2 = $selectionSearch
.quicksearch(selectionSearchString)
.on("keydown", function (e) {
if (e.which == 40) {
that.$selectionUl.focus();
return false;
}
});
},
afterSelect: function (value, text) {
this.qs1.cache();
this.qs2.cache();
d3Update();
},
afterDeselect: function (value, text) {
this.qs1.cache();
this.qs2.cache();
d3Update();
},
});
//slim scroll
$(".ms-list").slimscroll();
});
/* ----------------------- click action ------------------------- */
function d3Update() {
if (
typeof treeData.children == "undefined" ||
treeData.children == "" ||
treeData.children == null
) {
console.log("it is not inner element");
treeData.children = [];
} else {
treeData.children.splice(0, treeData.children.length);
}
$("#sampleMultiTest :selected").each(function () {
item = {};
item["name"] = this.text;
item["type"] = "Jira JQL";
treeData.children.push(item);
});
update(root);
}
function jsTreeClick(selectedNodeID, selectedNodeText) {
treeData.name = selectedNodeText;
update(root);
}