META-INF.resources.primefaces.organigram.organigram.js Maven / Gradle / Ivy
PrimeFaces.widget.Organigram = PrimeFaces.widget.BaseWidget.extend({
init: function(cfg) {
this._super(cfg);
this.draw();
},
draw : function() {
this.source = this.jq.children('ul');
this.target = this.jq.children('div');
this.target.empty();
this.drawNode(this.source.find('li:first').data("rowkey"), this.source.find('li:first'), this.target, 0, 0);
this.setupSelection();
this.setupDragAndDrop();
this.setupControls();
},
setupSelection : function() {
var widget = this;
var selectableNodes = this.target.find(".ui-organigram-node.selectable");
selectableNodes.on("click", function() {
widget.selectNode(widget, $(this), "select");
});
if (this.cfg.autoScrollToSelection === true) {
this.scrollToSelection();
}
},
selectNode : function(widget, node, event) {
if (!node.hasClass("selected")) {
widget.target.find(".ui-organigram-node.selected").removeClass("selected");
node.addClass("selected");
if (widget.hasBehavior(event)) {
var options = {
params: [
{ name: widget.id + "_selectNode", value: node.data("rowkey") }
]
};
widget.cfg.behaviors[event].call(widget, options);
}
}
},
setupDragAndDrop : function() {
var widget = this;
var nodes = this.target.find(".ui-organigram-node");
var draggableNodes = nodes.filter(".draggable");
var droppableNodes = nodes.filter(".droppable");
var initialDragPosition = {
x: 0,
y: 0
};
draggableNodes.draggable({
zIndex: 100,
opacity: 0.7,
cursor: "move",
helper: "clone",
distance: 60,
revert: "invalid",
revertDuration: 200,
snapMode: "inner",
// overwrite start/drag to support browser scaling/zooming
start: function(event) {
initialDragPosition.x = event.clientX;
initialDragPosition.y = event.clientY;
},
drag: function(event, ui) {
var original = ui.originalPosition;
var zoomFactor = 1.0;
if (widget.zoomFactor) {
zoomFactor = widget.zoomFactor;
}
ui.position = {
left: (event.clientX - initialDragPosition.x + original.left) / zoomFactor,
top: (event.clientY - initialDragPosition.y + original.top ) / zoomFactor
};
}
});
droppableNodes.droppable({
accept: ".ui-organigram-node.draggable",
activeClass: "drag-active",
hoverClass: "drop-hover"
});
// drop & drop happens in the target dom
// but moving the actual nodes happens in the source li/ul dom
// after dropping, we redraw the organigram from the source
droppableNodes.bind("drop", function (event, ui) {
// lookup target node in source DOM
var targetId = $(this).data("rowkey");
var targetLi = widget.source.find("li").filter(function () {
return $(this).data("rowkey") === targetId;
});
var targetUl = targetLi.children("ul");
// lookup source node in source DOM
var sourceId = ui.draggable.data("rowkey");
var sourceLi = widget.source.find("li").filter(function () {
return $(this).data("rowkey") === sourceId;
});
var sourceUl = sourceLi.parent("ul");
// ignore the current drop?
var ignore = false;
// ignore moving to the current parent
if (sourceLi.data("parent-rowkey") === targetId)
{
ignore = true;
}
// ignore moving to the direct child
if (targetLi.data("parent-rowkey") === sourceId)
{
ignore = true;
}
// ignore moving to childs
targetLi.parents().each(function() {
if ($(this).data("parent-rowkey") === sourceId) {
ignore = true;
return false;
}
});
if (ignore) {
return false;
}
// add new children
if (targetUl.length > 0) {
targetUl.append(sourceLi);
}
else {
targetLi.append("
");
targetLi.children("ul").append(sourceLi);
}
// remove children if empty
if (sourceUl.children().length === 0) {
sourceUl.remove();
}
// add "leaf" class if the last item was removed from the parent
var oldParent = widget.source.find("li").filter(function () {
return $(this).data("rowkey") === sourceLi.data("parent-rowkey");
});
if (oldParent.children("ul").length === 0) {
oldParent.addClass("leaf");
}
// remove leave class if a node was added to a leaf node
targetLi.removeClass("leaf");
// update parent
sourceLi.data("parent-rowkey", targetId);
sourceLi.attr("data-parent-rowkey", targetId);
// call behavior
if (widget.hasBehavior("dragdrop")) {
var options = {
params: [
{ name: widget.id + "_dragNode", value: sourceId },
{ name: widget.id + "_dropNode", value: targetId }
]
};
widget.cfg.behaviors["dragdrop"].call(widget, options);
}
widget.redraw = true;
});
// redraw from source after drop
draggableNodes.bind("dragstop", function (event, ui) {
// redraw only if the item was dropped successfully
if (widget.redraw) {
widget.draw();
widget.redraw = false;
}
});
},
/**
* Setup global controls.
* Currently zoom-in and zoom-out.
*/
setupControls : function() {
var widget = this;
if (this.cfg.zoom) {
this.jq.children(".controls").remove();
var controls = $("").appendTo(this.jq);
var controlsTable = $("
").appendTo(controls);
if (!this.zoomFactor) {
this.zoomFactor = 1.0;
}
else {
this.zoom(this.zoomFactor);
}
var zoomIn = $(" ").appendTo(controlsTable);
zoomIn.on("click", function() {
widget.zoomFactor += 0.1;
widget.zoom(widget.zoomFactor);
});
var zoomOut = $(" ").appendTo(controlsTable);
zoomOut.on("click", function() {
widget.zoomFactor -= 0.1;
widget.zoom(widget.zoomFactor);
});
}
},
/**
* Applies css zoom/scale to the target DOM.
*
* @param {type} zoom The zoom factor. (e.g. 1.0 or 0.5)
*/
zoom : function(zoom) {
var element = this.target.find(">:first-child");
// avoid both zoom and transform in IE, otherwise it will be zoomed * 2
if (PrimeFaces.env.isIE()) {
element.css("zoom", zoom);
}
else {
element.css("-moz-transform", "scale(" + zoom + ")");
element.css("-moz-transform-origin", "0 0");
element.css("-o-transform", "scale(" + zoom + ")");
element.css("-o-transform-origin", "0 0");
element.css("-webkit-transform", "scale(" + zoom + ")");
element.css("-webkit-transform-origin", "0 0");
element.css("transform", "scale(" + zoom + ")");
element.css("transform-origin", "0 0");
}
},
drawNode : function(parentRowKey, nodeSource, appendTo, level) {
var childNodes = nodeSource.children("ul:first").children("li");
var isLastLevel = childNodes.length === 0;
// clone node content - ignore subnodes
var nodeContent = nodeSource.clone()
.children("ul,li")
.remove()
.end()
.html();
var node = $("");
// copy class and style from source
node.attr("class", nodeSource.attr("class"));
node.attr("style", nodeSource.attr("style"));
// styling
node.addClass("ui-organigram-node");
node.addClass("level-" + level);
// set metadata
node.attr("data-level", level);
node.attr("data-rowkey", nodeSource.data("rowkey"));
node.attr("data-parent-rowkey", parentRowKey);
// top icons
var topIconContainer = $("").appendTo(node);
if (nodeSource.data("icon")) {
var icon = $("").appendTo(topIconContainer);
icon.addClass(nodeSource.data("icon"));
var iconPos = nodeSource.data("icon-pos");
if (iconPos && (iconPos === "left" || iconPos === "right")) {
icon.addClass(nodeSource.data("icon-pos"));
}
}
// content
node.append(nodeContent);
// bottom icons
var bottomIconContainer = $("").appendTo(node);
// we don't need to render a table in the last level as it can't have further childs
if (isLastLevel) {
appendTo.append(node);
}
else if (childNodes.length > 0) {
var table = $("
").appendTo(appendTo);
var row = $(" ").appendTo(table);
var leafChildNodes = childNodes.filter(".leaf:not(.skip-leaf)");
var nonLeafChildNodes = childNodes.filter(":not(.leaf),.skip-leaf");
var childNodeCount = nonLeafChildNodes.length;
if (leafChildNodes && leafChildNodes.length > 0) {
childNodeCount += 1;
}
var cell = $(" ").appendTo(row);
cell.append(node);
this.addExpander(nodeSource, node, bottomIconContainer);
this.drawLines(childNodeCount, table);
this.drawChildNodes(nodeSource.data("rowkey"), leafChildNodes, nonLeafChildNodes, table, level);
// handle initial collapsed state
if (nodeSource.hasClass("collapsed")) {
var collapsedIcon = "ui-icon-plusthick";
if (nodeSource.data("collapsed-icon")) {
collapsedIcon = nodeSource.data("collapsed-icon");
}
var expandedIcon = "ui-icon-minusthick";
if (nodeSource.data("expanded-icon")) {
expandedIcon = nodeSource.data("expanded-icon");
}
// hide childs
row.nextAll("tr").hide();
// switch expander icons
node.find(".expander").removeClass(expandedIcon).addClass(collapsedIcon);
}
else {
if (!nodeSource.hasClass("expanded")) {
node.addClass("expanded");
}
}
}
},
addExpander : function(nodeSource, node, bottomIconContainer) {
if (node.hasClass("collapsible")) {
var collapsedIcon = nodeSource.data("collapsed-icon") ? nodeSource.data("collapsed-icon") : "ui-icon-plusthick";
var expandedIcon = nodeSource.data("expanded-icon") ? nodeSource.data("expanded-icon") : "ui-icon-minusthick";
var initialIcon = node.hasClass("collapsed") ? collapsedIcon : expandedIcon;
var widget = this;
var expander = $(" ").appendTo(bottomIconContainer);
expander.click(function (e) {
// reinit dom references - they are lost sometimes
var expander = $(this);
var node = expander.closest(".ui-organigram-node");
var row = node.closest("tr");
if (node.hasClass("collapsed")) {
node.removeClass("collapsed").addClass("expanded");
expander.removeClass(collapsedIcon).addClass(expandedIcon);
row.nextAll("tr").show();
// maintain state in source
nodeSource.removeClass("collapsed");
// call behavior
if (widget.hasBehavior("expand")) {
var options = {
params: [
{ name: widget.id + "_expandNode", value: node.data("rowkey") }
]
};
widget.cfg.behaviors["expand"].call(widget, options);
}
}
else {
node.removeClass("expanded").addClass("collapsed");
expander.removeClass(expandedIcon).addClass(collapsedIcon);
row.nextAll("tr").hide();
// maintain state in source
nodeSource.addClass("collapsed");
// call behavior
if (widget.hasBehavior("collapse")) {
var options = {
params: [
{ name: widget.id + '_collapseNode', value: node.data("rowkey") }
]
};
widget.cfg.behaviors["collapse"].call(widget, options);
}
}
// avoid bubbling to the parent select click handler
e.stopPropagation();
});
}
},
drawLines : function(childNodeCount, table) {
// draw vertical row
var verticalColspan = childNodeCount * 2;
var verticalRow = $(" ").appendTo(table);
var verticalCell = $(" ").appendTo(verticalRow);
verticalCell.append($(""));
// draw horizontal row/cells
var horizontalRow = $(" ").appendTo(table);
for (var i = 0; i < childNodeCount; i++) {
horizontalRow.append($(" "));
horizontalRow.append($(" "));
}
// remove the line from the first and last cell
horizontalRow.find("td:first").removeClass("top");
horizontalRow.find("td:last").removeClass("top");
},
drawChildNodes : function(parentRowKey, leafChildNodes, nonLeafChildNodes, table, level) {
var row = $(" ").appendTo(table);
// draw leaf nodes in a different way
if (leafChildNodes && leafChildNodes.length > 0) {
var cell = $(" ").appendTo(row);
var leafTable = $("
").appendTo(cell);
for (var j = 0; j < leafChildNodes.length; j++) {
// add connector line
if (j !== 0 && this.cfg.leafNodeConnectorHeight > 0) {
leafTable.append($(" "));
}
var leafRow = $(" ").appendTo(leafTable);
var leafCell = $(" ").appendTo(leafRow);
var childNode = $(leafChildNodes[j]);
this.drawNode(parentRowKey, childNode, leafCell, level + 1);
}
}
// draw normal nodes
for (var i = 0; i < nonLeafChildNodes.length; i++) {
var cell = $(" ").appendTo(row);
var childNode = $(nonLeafChildNodes[i]);
this.drawNode(parentRowKey, childNode, cell, level + 1);
}
},
hasBehavior: function(event) {
if (this.cfg.behaviors) {
return this.cfg.behaviors[event] !== undefined;
}
return false;
},
// contextMenu integration
bindContextMenu : function(menuWidget, targetWidget, targetId, cfg) {
var selector = targetId + " .ui-organigram-node.selectable",
event = cfg.event + ".organigram";
if (cfg.nodeType) {
selector += "." + cfg.nodeType;
}
$(document).off(event, selector).on(event, selector, null, function(e) {
targetWidget.selectNode(targetWidget, $(this), "contextmenu");
menuWidget.show(e);
});
},
scrollToSelection : function() {
var selection = this.target.find(".ui-organigram-node.selected");
if (selection.length > 0) {
var offset = selection.offset();
this.target.animate({
scrollTop: offset.top ,
scrollLeft: offset.left
},{
easing: 'easeInCirc'
},1000);
}
}
});
© 2015 - 2024 Weber Informatics LLC | Privacy Policy