/** * JQuery Organisation Chart Plugin. * * Author: Mark Lee * Copyright (C)2013-2015 Caprica Software Limited * http://www.capricasoftware.co.uk * * Contributions by: Paul Lautman * * This software is licensed under the Creative Commons Attribution-ShareAlike 3.0 License, * see here for license terms: * * http://creativecommons.org/licenses/by-sa/3.0 */ (function($) { $.fn.orgChart = function(options) { var opts = $.extend({}, $.fn.orgChart.defaults, options); return this.each(function() { var $chartSource = $(this); // Clone the source list hierarchy so levels can be non-destructively removed if needed // before creating the chart $this = $chartSource.clone(); if (opts.levels > -1) { $this.find("ul").andSelf().filter(function() {return $chartSource.parents("ul").length+1 > opts.levels;}).remove(); } // Store the original element $this.data("chart-source", $chartSource); // Build the chart... var $container = $("
"); if (opts.interactive) { $container.addClass("interactive"); } // The chart may be sourced from either a "ul", or an "li" element... var $root; if ($this.is("ul")) { $root = $this.find("li:first"); } else if ($this.is("li")) { $root = $this; } if ($root) { buildNode($root, $container, 0, 0, opts); // Special case for any hyperlink anchor in the chart to prevent the click on the node itself from propagating $container.find("div.node a").click(function(evt) { evt.stopImmediatePropagation(); }); if(opts.replace) { opts.container.empty(); } opts.container.append($container); } }); }; $.fn.orgChart.defaults = { container : $("body"), depth : -1, levels : -1, showLevels : -1, stack : false, chartClass : "orgChart", hoverClass : "hover", nodeText : function($node) {return $node.clone().children("ul,li").remove().end().html();}, interactive: false, fade : false, speed : "slow", nodeClicked: function($node) {}, copyClasses: true, copyData : true, copyStyles : true, copyTitle : true, replace : true }; function buildNode($node, $appendTo, level, index, opts) { var $table = $(""); var $tbody = $(""); // Make this node... var $nodeRow = $("").addClass("nodes"); var $nodeCell = $("").addClass("lines"); var $downLineCell = $("
").addClass("node").attr("colspan", 2); var $childNodes = $node.children("ul:first").children("li"); if ($childNodes.length > 1) { $nodeCell.attr("colspan", $childNodes.length*2); } var $adjunct = $node.children("adjunct").eq(0); if ($adjunct.length > 0) { var $adjunctDiv = $("
").addClass("adjunct node").addClass("level"+level).addClass("node"+index).addClass("level"+level+"-node"+index).append(opts.nodeText($adjunct)); $adjunctDiv.appendTo($nodeCell); var $linkDiv = $("
").addClass("adjunct-link"); $linkDiv.appendTo($nodeCell); $adjunct.remove(); } var $heading = $("

").html(opts.nodeText($node)); var $nodeDiv = $("
").addClass("node").addClass("level"+level).addClass("node"+index).addClass("level"+level+"-node"+index).append($heading); // Copy classes from the source list to the chart node if (opts.copyClasses) { $nodeDiv.addClass($node.attr("class")); } // Copy data from the source list to the chart node if (opts.copyData) { $nodeDiv.data($node.data()); } // Copy CSS styles from the source list to the chart node if (opts.copyStyles) { $nodeDiv.attr("style", $node.attr("style")); } // Copy the title attribute from the source list to the chart node if (opts.copyTitle) { $nodeDiv.attr("title", $node.attr("title")); } $nodeDiv.data("orgchart-level", level).data("orgchart-node", $node); $nodeCell.append($nodeDiv); $nodeRow.append($nodeCell); $tbody.append($nodeRow); $nodeDiv.click(function() { var $this = $(this); opts.nodeClicked($this.data("orgchart-node"), $this); if (opts.interactive) { var $row = $this.closest("tr"); if ($row.next("tr").is(":visible")) { if (opts.fade) { $row.nextAll("tr").fadeOut(opts.speed); } else { $row.nextAll("tr").hide(); } $this.removeClass("shownChildren").addClass("hiddenChildren"); } else { $this.removeClass("hiddenChildren").addClass("shownChildren"); if (opts.fade) { $row.nextAll("tr").fadeIn(opts.speed); } else { $row.nextAll("tr").show(); } } } }); if ($childNodes.length > 0) { if (opts.depth == -1 || level+1 < opts.depth) { var $downLineRow = $("

").attr("colspan", $childNodes.length*2); $downLineRow.append($downLineCell); var $downLineTable = $(""); $downLineTable.append(""); var $downLineLine = $("").addClass("lines x"); var $downLeft = $("").addClass("lines v"); $childNodes.each(function() { var $left = $(""); $childNodes.each(function(index) { var $td = $("
").addClass("line left"); var $downRight = $("").addClass("line right"); $downLineLine.append($downLeft).append($downRight); $downLineTable.children("tbody").append($downLineLine); $downLineCell.append($downLineTable); $tbody.append($downLineRow); if ($childNodes.length > 0) { $nodeDiv.addClass("hasChildren"); if (opts.showLevels == -1 || level < opts.showLevels-1) { $nodeDiv.addClass("shownChildren"); } else { $nodeDiv.addClass("hiddenChildren"); } if (opts.interactive) { $nodeDiv.hover(function() {$(this).addClass(opts.hoverClass);}, function() {$(this).removeClass(opts.hoverClass)}); } } // Recursively make child nodes... var $linesRow = $("
").addClass("line left top"); var $right = $("").addClass("line right top"); $linesRow.append($left).append($right); }); $linesRow.find("td:first").removeClass("top"); $linesRow.find("td:last").removeClass("top"); $tbody.append($linesRow); var $childNodesRow = $("
"); $td.attr("colspan", 2); buildNode($(this), $td, level+1, index, opts); $childNodesRow.append($td); }); $tbody.append($childNodesRow); } else if (opts.stack) { var $stackNodes = $childNodes.clone(); var $list = $("
    ").append($stackNodes).addClass("level"+level).addClass("node"+index).addClass("level"+level+"-node"+index); var $stackContainer = $("
    ").append($list); $nodeDiv.after($stackContainer); } } if (opts.showLevels > -1 && level >= opts.showLevels-1) { $nodeRow.nextAll("tr").hide(); } $table.append($tbody); $appendTo.append($table); }; })(jQuery);