").append(keyrow).append(valrow).append(clearrow));
}
var tooltip = $("
").attr("class", "xtrace-tooltip");
appendRow("ID", d.get_id(), tooltip);
appendRow("NumReports", d.get_node_ids().length, tooltip);
appendRow("NumLabels", Object.keys(d.get_labels()).length, tooltip);
return tooltip.outerHTML();
});
return tooltip;
}
var Tooltip = function(gravity) {
if (gravity==null)
gravity = $.fn.tipsy.autoWE;
var tooltip = function(selection) {
selection.each(function(d) {
$(this).tipsy({
gravity: gravity,
html: true,
title: function() { return title(d); },
opacity: 1
});
});
}
var title = function(d) { return ""; };
tooltip.hide = function() { $(".tipsy").remove(); }
tooltip.title = function(_) { if (arguments.length==0) return title; title = _; return tooltip; }
return tooltip;
}
var d3LineageContextMenu = function(graph, graphSVG) {
var onMenuOpen = function(d) {
handlers.open.call(this, d);
}
var onMenuClose = function(d) {
handlers.close.call(this, d);
}
var onMenuClick = function(d) {
if (d.operation=="viewcode") {
var url;
url = g_currentData.nodes[this.__data__]['git_location'];
if (url){
window.open(url);
}
}
}
var onOptionMouseOver = function(d) {
var items = [];
if (d.operation=="hideselected") {
items = graphSVG.selectAll(".node.selected").data();
}
if (d.operation=="hideunselected") {
var items = graphSVG.selectAll(".node").filter(function(d) {
return !d3.select(this).classed("selected");
}).data();
}
if (d.operation=="hidethis") {
items = d3.select(this).data();
}
if (d.operation=="hidefield" || d.operation=="selectfield") {
var fieldname = d.fieldname;
var value = d.value;
items = graph.getVisibleNodes().filter(function(node) {
return node.report && node.report[fieldname] && node.report[fieldname][0]==value;
});
}
if (d.operation=="invertselection") {
var items = graphSVG.selectAll(".node").filter(function(d) {
return !d3.select(this).classed("selected");
}).data();
}
if (d.operation=="selectall") {
items = graph.getVisibleNodes();
}
if (d.operation=="selectneighbours") {
var item = d3.select(this).data()[0];
items = item.getVisibleParents().concat(item.getVisibleChildren());
items.push(item);
}
if (d.operation=="selectpath") {
items = getEntirePathNodes(d3.select(this).data()[0]);
}
handlers.hovernodes.call(this, items);
}
var onOptionMouseOut = function(d) {
onMenuClose(d);
handlers.hovernodes.call(this, []);
}
var ctxmenu = ContextMenu().on("open", onMenuOpen)
.on("close", onMenuClose)
.on("click", onMenuClick);
//.on("mouseover", onOptionMouseOver)
//.on("mouseout", onOptionMouseOut);
var menu = function(selection) {
menu.hide.call(this, selection);
selection.each(function(d) {
var items = [];
var data;
data = g_currentData.nodes[d];
if (data['git_location']){
items.push({
"operation": "viewcode",
"name": "View source code on git"
});
}
items.push({
"operation": "selectall",
"name": "Select all"
});
items.push({
"operation": "selectneighbours",
"name": "Select neighbours"
});
items.push({
"operation": "selectpath",
"name": "Select path"
});
ctxmenu.call(this, items);
d3.select(this).classed("hascontextmenu", true);
});
}
menu.hide = function(selection) {
d3.select(this).selectAll(".hascontextmenu").each(function(d) {
$(this).unbind("contextmenu");
})
d3.select(this).selectAll(".context-menu").remove();
}
var onhide = function(nodes, selectionname) {}
var handlers = {
"hidenodes": function() {},
"selectnodes": function() {},
"hovernodes": function() {},
"open": function() {},
"close": function() {}
}
menu.on = function(event, _) {
if (!handlers.hasOwnProperty(event)) return menu;
if (arguments.length==1) return handlers[event];
handlers[event] = _;
return menu;
}
return menu;
}
var CompareGraphContextMenu = function() {
var onMenuOpen = function(d) {
handlers.open.call(this, d);
}
var onMenuClick = function(d) {
if (d.operation=="viewthis") {
handlers.view.call(this, d3.select(this).datum());
}
if (d.operation=="removeselected") {
handlers.hide.call(this, d3.selectAll(".node.selected").data());
}
if (d.operation=="clusterselected") {
handlers.hide.call(this, d3.selectAll(".node").filter(function(d) {
return !d3.select(this).classed("selected");
}).data());
}
if (d.operation=="compareselected") {
handlers.compare.call(this, d3.selectAll(".node.selected").data());
}
if (d.operation=="comparetoselected") {
var ds = d3.selectAll(".node.selected").data().concat(d3.select(this).data());
handlers.compare.call(this, ds);
}
}
var ctxmenu = ContextMenu().on("click", onMenuClick)
.on("open", onMenuOpen);
var menu = function(selection) {
menu.hide.call(this, selection);
selection.each(function(d) {
var items = [];
items.push({
"operation": "viewthis",
"name": "View execution graph"
})
var selected = selection.filter(".selected");
if (!selected.empty() && (selection[0].length - selected[0].length) > 1) {
items.push({
"operation": "removeselected",
"name": "Remove selected from the clustering"
});
}
if (selected[0].length > 1) {
items.push({
"operation": "clusterselected",
"name": "Re-cluster using selected"
});
}
if (selected[0].length == 2) {
items.push({
"operation": "compareselected",
"name": "Compare graphs of selected"
});
}
if (selected[0].length == 1) {
if (selected.datum() != d3.select(this).datum()) {
items.push({
"operation": "comparetoselected",
"name": "Compare graph of this to selected"
});
}
}
ctxmenu.call(this, items);
d3.select(this).classed("hascontextmenu", true);
});
}
menu.hide = function(selection) {
d3.select(this).selectAll(".hascontextmenu").each(function(d) {
$(this).unbind("contextmenu");
})
d3.select(this).selectAll(".context-menu").remove();
}
var handlers = {
"open": function() {},
"view": function() {},
"hide": function() {},
"compare": function() {}
}
menu.on = function(event, _) {
if (!handlers.hasOwnProperty(event)) return menu;
if (arguments.length==1) return handlers[event];
handlers[event] = _;
return menu;
}
return menu;
}
var ContextMenu = function() {
var idseed = 0;
var menu = function(ds) {
var attach = this;
// Create the menu items
var menu = {};
for (var i = 0; i < ds.length; i++) {
var item = ds[i];
var itemname = name.call(this, item);
menu[itemname] = {
"click": menuClick(attach, item, i),
"mouseover": menuMouseOver(attach, item, i),
"mouseout": menuMouseOut(attach, item, i)
};
}
// Set the options
var options = {
"disable_native_context_menu": true,
"showMenu": function() { handlers.open.call(attach, ds); },
"hideMenu": function() { handlers.close.call(attach, ds); }
}
// Attach the context menu to this element
$(attach).contextMenu('context-menu'+(idseed++), menu, options);
}
// Stupid javascript
var menuClick = function(attach,d, i) {
return function() {
handlers.click.call(attach, d, i);
}
}
// Stupid stupid javascript
var menuMouseOver = function(attach, d, i) {
return function() {
handlers.mouseover.call(attach, d, i);
}
}
// Stupid stupid stupid javascript
var menuMouseOut = function(attach, d, i) {
return function() {
handlers.mouseout.call(attach, d, i);
}
}
var name = function(d) { return d.name; }
var handlers = {
"click": function() {},
"open": function() {},
"close": function() {},
"mouseover": function() {},
"mouseout": function() {},
}
menu.name = function(_) { if (arguments.length==0) return name; name = _; return menu; }
menu.on = function(event, _) {
if (!handlers[event]) return menu;
if (arguments.length==1) return handlers[event];
handlers[event] = _;
return menu;
}
return menu;
}