UNPKG

jquery.fancytree

Version:

Fancytree is a JavaScript tree view plugin for jQuery with support for persistence, keyboard, checkboxes, drag'n'drop, and lazy loading.

543 lines (489 loc) 18.9 kB
/*! * jquery.fancytree.fixed.js * * Add fixed colums and headers to ext.table. * (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/) * * Copyright (c) 2008-2017, Martin Wendt (http://wwWendt.de) * * Released under the MIT license * https://github.com/mar10/fancytree/wiki/LicenseInfo * * @version @VERSION * @date @DATE */ ;(function($, window, document, undefined) { "use strict"; /* ***************************************************************************** * Private functions and variables */ $.ui.fancytree.registerExtension({ name: "fixed", version: "0.0.1", // Default options for this extension. options: { fixCol: 1, fixColWidths: null, fixRows: true }, // Overide virtual methods for this extension. // `this` : is this extension object // `this._super`: the virtual function that was overriden (member of prev. extension or Fancytree) treeInit: function(ctx){ this._requireExtension("table", true, true); // 'fixed' requires the table extension to be loaded before itself var _this = this, res = this._superApply(arguments), tree = ctx.tree, options = this.options.fixed, $table = tree.widget.element, fixedColCount = options.fixCols, fixedRowCount = options.fixRows, $tableWrapper = $table.parent().addClass("fancytree-ext-fixed-wrapper"), $topLeftWrapper = $("<div>").addClass("fancytree-fixed-wrapper-tl"), $topRightWrapper = $("<div>").addClass("fancytree-fixed-wrapper-tr"), $bottomLeftWrapper = $("<div>").addClass("fancytree-fixed-wrapper-bl"), $bottomRightWrapper = $("<div>").addClass("fancytree-fixed-wrapper-br"), $topLeftTable = $("<table>").attr("style", $table.attr("style")).attr("class", $table.attr("class")), $topRightTable = $("<table>").attr("style", $table.attr("style")).attr("class", $table.attr("class")), $bottomLeftTable = $("<table>").attr("style", $table.attr("style")).attr("class", $table.attr("class")), $bottomRightTable = $table, $head = $table.find("thead"), // $body = $table.find("tbody"), $colgroup = $table.find("colgroup"), headRowCount = $head.find("tr").length; // remainingHeadRows = headRowCount - fixedRowCount; $table.addClass("fancytree-ext-fixed"); $tableWrapper.addClass("fancytree-fixed-wrapper"); $bottomLeftTable.append($("<tbody>")); if ($colgroup.length) { $colgroup.remove(); } if (typeof fixedRowCount === "boolean") { fixedRowCount = fixedRowCount ? headRowCount : 0; } else { fixedRowCount = Math.max(0, Math.min(fixedRowCount, headRowCount)); } if (fixedRowCount) { $topLeftTable.append($head.clone()); $topRightTable.append($head.clone()); $head.hide(); } // if (remainingHeadRows > 0) { // var $remainingHeadRows = $body.find("tr:lt(" + remainingHeadRows + ")").clone(); // $topLeftTable.append($("<tbody>").append($remainingHeadRows)); // $topRightTable.append($("<tbody>").append($remainingHeadRows.clone())); // } $topLeftTable.find("tr").each(function(idx) { var $tr = $(this); $tr.find("th").slice(fixedColCount).remove(); $tr.find("td").slice(fixedColCount).remove(); }); $topRightTable.find("tr").each(function(idx) { var $tr = $(this); $tr.find("th").slice(0, fixedColCount).addClass("fancytree-fixed-hidden"); $tr.find("td").slice(0, fixedColCount).addClass("fancytree-fixed-hidden"); }); // if (remainingHeadRows < 0) { // var headTrCount = $head.find("tr").length; // $bottomLeftTable.append($head.clone()); // // $bottomLeftTable.find("thead tr:lt(" + (headTrCount + remainingHeadRows) + ")").addClass("hidden").find("td, th").addClass("hidden"); // $bottomRightTable.find("thead tr:lt(" + (headTrCount + remainingHeadRows) + ")").addClass("hidden").find("td, th").addClass("hidden"); // // $topLeftTable.find("thead tr:gt(" + (headTrCount + remainingHeadRows-1) + ")").remove(); // $topRightTable.find("thead tr:gt(" + (headTrCount + remainingHeadRows-1) + ")").remove(); // } else { // $bottomRightTable.find("thead").addClass("hidden").find("tr, th").addClass("hidden"); // $bottomRightTable.find("tbody tr:lt(" + remainingHeadRows + ")").addClass("hidden"); // } this.$fixedWrapper = $tableWrapper; $tableWrapper.append( $topLeftWrapper.append( $topLeftTable ), $topRightWrapper.append( $topRightTable ), $bottomLeftWrapper.append( $bottomLeftTable ), $bottomRightWrapper.append( $bottomRightTable ) ); $.ui.fancytree.overrideMethod(ctx.options, "createNode", function(event, data) { this._super.apply(this, arguments); var node = data.node, $nodeTr = $(node.tr), idx = $nodeTr.index(), $blTableBody = $("div.fancytree-fixed-wrapper-bl table tbody"), $prevLeftNode = $blTableBody.find("tr:eq(" + Math.max(idx - 1, 0) + ")"), $clone = $nodeTr.clone(); if ($prevLeftNode.length) { $prevLeftNode.after($clone); } else { $blTableBody.append($clone); } var span = $clone.find("span.fancytree-node").get(0); node.span = span; $nodeTr.data("fancytree-node-counterpart", $clone); $clone.data("fancytree-node-counterpart", $nodeTr); $clone.find("th").slice(fixedColCount).remove(); $clone.find("td").slice(fixedColCount).remove(); $clone.show(); $nodeTr.find("th").slice(0, fixedColCount).addClass("fancytree-fixed-hidden"); $nodeTr.find("td").slice(0, fixedColCount).addClass("fancytree-fixed-hidden"); }); $tableWrapper.on("click", ".fancytree-fixed-wrapper-bl table tr", function(evt) { var $trLeft = $(this), $trRight = $trLeft.data("fancytree-node-counterpart"), node = $.ui.fancytree.getNode($trRight); if (!node.isActive()) { node.setActive(true); } }).on("mouseenter", ".fancytree-fixed-wrapper-bl table tr, .fancytree-fixed-wrapper-br table tr", function(evt) { var $tr = $(this), $trOther = $tr.data("fancytree-node-counterpart"); $tr.addClass("fancytree-hover"); $trOther.addClass("fancytree-hover"); }).on("mouseleave", ".fancytree-fixed-wrapper-bl table tr, .fancytree-fixed-wrapper-br table tr", function(evt) { var $tr = $(this), $trOther = $tr.data("fancytree-node-counterpart"); $tr.removeClass("fancytree-hover"); $trOther.removeClass("fancytree-hover"); }).on("click", ".fancytree-fixed-wrapper-bl .fancytree-expander", function(evt) { var $trLeft = $(this).closest("tr"), $trRight = $trLeft.data("fancytree-node-counterpart"), node = $.ui.fancytree.getNode($trRight), rootCtx = $.extend({}, ctx, {node: node}); _this.nodeSetExpanded(rootCtx, !node.expanded).done(function(){}); }).on("click", ".fancytree-fixed-wrapper-bl .fancytree-checkbox", function(evt) { var $trLeft = $(this).closest("tr"), $trRight = $trLeft.data("fancytree-node-counterpart"), node = $.ui.fancytree.getNode($trRight); // rootCtx = $.extend({}, ctx, {node: node}); node.setSelected(!node.selected); }); $bottomLeftWrapper.bind("mousewheel DOMMouseScroll", function(event) { var $this = $(this), newScroll = $this.scrollTop(); if (event.originalEvent.wheelDelta) { newScroll -= event.originalEvent.wheelDelta / 2; } else if (event.originalEvent.detail) { newScroll += event.originalEvent.detail * 14; } $this.scrollTop(newScroll); $bottomRightWrapper.scrollTop(newScroll); }); $bottomRightWrapper.scroll(function() { var $this = $(this), scrollLeft = $this.scrollLeft(), scrollTop = $this.scrollTop(); $topLeftWrapper .toggleClass("scrollBorderBottom", scrollTop > 0) .toggleClass("scrollBorderRight", scrollLeft > 0); $topRightWrapper .toggleClass("scrollBorderBottom", scrollTop > 0) .scrollLeft(scrollLeft); $bottomLeftWrapper .toggleClass("scrollBorderRight", scrollLeft > 0) .scrollTop(scrollTop); }); return res; }, treeLoad: function(ctx) { var _this = this, res = this._superApply(arguments); res.done(function() { _this.ext.fixed._adjustLayout(); }); return res; }, /* Called by nodeRender to sync node order with tag order.*/ // nodeFixOrder: function(ctx) { // }, nodeLoadChildren: function(ctx, source) { return this._superApply(arguments); }, nodeRemoveChildMarkup: function(ctx) { var node = ctx.node; var children = node.children; if (children) { for (var i = 0; i < children.length; i++) { var child = children[i]; var $leftTr = $(child.tr).data("fancytree-node-counterpart"); if ($leftTr) { $leftTr.remove(); } } } return this._superApply(arguments); }, nodeRemoveMarkup: function(ctx) { var node = ctx.node, $rightNode = $(node.tr), $leftNode = $rightNode.data("fancytree-node-counterpart"); if ($leftNode) { $leftNode.remove(); } return this._superApply(arguments); }, nodeSetActive: function(ctx, flag, callOpts) { var node = ctx.node, $rightNode = $(node.tr), $leftNode = $rightNode.data("fancytree-node-counterpart"); if ($leftNode) { $leftNode.toggleClass("fancytree-active", flag); $leftNode.toggleClass("fancytree-focused", flag); } var res = this._superApply(arguments); return res; }, nodeSetFocus: function(ctx, flag) { var node = ctx.node, $rightNode = $(node.tr), $leftNode = $rightNode.data("fancytree-node-counterpart"); if ($leftNode) { $leftNode.toggleClass("fancytree-focused", flag); } var res = this._superApply(arguments); return res; }, nodeRender: function(ctx, force, deep, collapsed, _recursive) { var res = this._superApply(arguments); // node = ctx.node, // _this = this, // $rightTr = $(node.tr), // $leftTr = $(node.tr).data("fancytree-node-counterpart"); // if (!$leftTr && this.$fixedWrapper && !node.isRoot()) { // var index = $rightTr.index(); // $leftTr = this.$fixedWrapper.find(".fancytree-fixed-wrapper-bl table tbody tr").eq(index); // if ($leftTr.length) { // $rightTr.data("fancytree-node-counterpart", $leftTr); // $leftTr.data("fancytree-node-counterpart", $rightTr); // } // } // // if ($leftTr) { // $leftTr.attr("class", $rightTr.attr("class")); // _this.ext.fixed._adjustRowLayout($leftTr, $rightTr); // $leftTr.find("td:not(.fancytree-fixed-hidden), th:not(.fancytree-fixed-hidden)").each(function(idx) { // _this.ext.fixed._adjustColumnLayout($(this), $rightTr.find("td").eq(idx)); // }); // } return res; }, nodeRenderTitle: function(ctx, title) { return this._superApply(arguments); }, nodeRenderStatus: function(ctx) { var res = this._superApply(arguments), node = ctx.node, $rightTr = $(node.tr).data("fancytree-node-counterpart"); if ($rightTr) { $rightTr.toggleClass("fancytree-selected", node.selected); $rightTr.toggleClass("fancytree-partsel", node.partsel); } return res; }, nodeSetExpanded: function(ctx, flag, callOpts) { var res, _this = this, node = ctx.node, // fixCols = this.options.fixed.fixCols, $leftTr = $(node.tr).data("fancytree-node-counterpart"); if (!$leftTr) { return this._superApply(arguments); } $leftTr.toggleClass("fancytree-expanded", !!flag); if (flag) { res = this._superApply(arguments); res.done(function() { node.visit(function(child) { var $tr = $(child.tr), $clone = $tr.data("fancytree-node-counterpart"); $clone.toggleClass("fancytree-fixed-hidden", !flag).find("td, th").toggleClass("fancytree-fixed-hidden", !flag); _this.ext.fixed._adjustRowLayout($tr, $clone); if (!child.expanded) { return "skip"; } }); $leftTr.find("td:not(.fancytree-fixed-hidden), th:not(.fancytree-fixed-hidden)").each(function(idx) { _this.ext.fixed._adjustColumnLayout($(this), null); }); _this.ext.fixed._adjustWrapperLayout(); }); } else { node.visit(function(child) { var $tr = $(child.tr), $clone = $tr.data("fancytree-node-counterpart"); if ($clone) { $clone.toggleClass("fancytree-fixed-hidden", !flag).find("td, th").toggleClass("fancytree-fixed-hidden", !flag); _this.ext.fixed._adjustRowLayout($tr, $clone); if (!child.expanded) { return "skip"; } } }); $leftTr.find("td:not(.fancytree-fixed-hidden), th:not(.fancytree-fixed-hidden)").each(function(idx) { _this.ext.fixed._adjustColumnLayout($(this), null); }); _this.ext.fixed._adjustWrapperLayout(); res = this._superApply(arguments); } return res; }, nodeSetStatus: function(ctx, status, message, details) { return this._superApply(arguments); }, treeClear: function(ctx) { var tree = ctx.tree, $table = tree.widget.element, $wrapper = this.$fixedWrapper; $table.find("tr, td, th, thead").removeClass("fancytree-fixed-hidden").css({ "min-width": "auto", "height": "auto" }); $wrapper.append($table); $wrapper.find(".fancytree-fixed-wrapper-tl").remove(); $wrapper.find(".fancytree-fixed-wrapper-tr").remove(); $wrapper.find(".fancytree-fixed-wrapper-bl").remove(); $wrapper.find(".fancytree-fixed-wrapper-br").remove(); return this._superApply(arguments); }, treeRegisterNode: function(ctx, add, node) { return this._superApply(arguments); }, treeDestroy: function(ctx) { var tree = ctx.tree, $table = tree.widget.element, $wrapper = this.$fixedWrapper; $table.find("tr, td, th, thead").removeClass("fancytree-fixed-hidden").css({ "min-width": "auto", "height": "auto" }); $wrapper.append($table); $wrapper.find(".fancytree-fixed-wrapper-tl").remove(); $wrapper.find(".fancytree-fixed-wrapper-tr").remove(); $wrapper.find(".fancytree-fixed-wrapper-bl").remove(); $wrapper.find(".fancytree-fixed-wrapper-br").remove(); return this._superApply(arguments); }, _adjustColumnLayout: function($td1, $td2) { if (!$td2) { var $table = $td1.closest("table"), $tr2 = null, colIdx = $td1.index(), $tableWrapper = $table.parent(), $wrapper = this.$fixedWrapper, $tlWrapper = $wrapper.find("div.fancytree-fixed-wrapper-tl"), $trWrapper = $wrapper.find("div.fancytree-fixed-wrapper-tr"), $blWrapper = $wrapper.find("div.fancytree-fixed-wrapper-bl"), $brWrapper = $wrapper.find("div.fancytree-fixed-wrapper-br"); if ($tableWrapper.is($tlWrapper)) { $tr2 = $blWrapper.find("tr:not(.fancytree-fixed-hidden)").first(); } else if ($tableWrapper.is($trWrapper)) { $tr2 = $brWrapper.find("tr:not(.fancytree-fixed-hidden)").first(); } else if ($tableWrapper.is($blWrapper)) { $tr2 = $tlWrapper.find("tr:not(.fancytree-fixed-hidden)").first(); } else if ($tableWrapper.is($brWrapper)) { $tr2 = $trWrapper.find("tr:not(.fancytree-fixed-hidden)").first(); } $td2 = $tr2.find("td:not(.fancytree-fixed-hidden):eq(" + colIdx + "), th:not(.fancytree-fixed-hidden):eq(" + colIdx + ")"); } $td1.css("min-width", "auto"); $td2.css("min-width", "auto"); var td1Width = $td1.width(), td2Width = $td2.width(), td1OuterWidth = $td1.outerWidth(), td2OuterWidth = $td2.outerWidth(), newWidth = Math.max(td1OuterWidth, td2OuterWidth); $td1.css("min-width", newWidth - (td1OuterWidth - td1Width)); $td2.css("min-width", newWidth - (td2OuterWidth - td2Width)); }, _adjustRowLayout: function($row1, $row2) { if (!$row2) { $row2 = $row1.data("fancytree-node-counterpart"); } $row1.css("height", "auto"); $row2.css("height", "auto"); var row1Height = $row1.outerHeight(), row2Height = $row2.outerHeight(), newHeight = Math.max(row1Height, row2Height); $row1.css("height", newHeight+1); $row2.css("height", newHeight+1); }, _adjustWrapperLayout: function() { var $wrapper = this.$fixedWrapper, $topLeftWrapper = $wrapper.find("div.fancytree-fixed-wrapper-tl"), $topRightWrapper = $wrapper.find("div.fancytree-fixed-wrapper-tr"), $bottomLeftWrapper = $wrapper.find("div.fancytree-fixed-wrapper-bl"), $bottomRightWrapper = $wrapper.find("div.fancytree-fixed-wrapper-br"), $topLeftTable = $topLeftWrapper.find("table"), $topRightTable = $topRightWrapper.find("table"), $bottomLeftTable = $bottomLeftWrapper.find("table"), // $bottomRightTable = $bottomRightWrapper.find("table"), wrapperWidth = $wrapper.width(), wrapperHeight = $wrapper.height(), // fixedWidth = Math.min(wrapperWidth, Math.max($topLeftTable.outerWidth(), $bottomLeftTable.outerWidth())), fixedWidth = Math.min(wrapperWidth, Math.max($topLeftTable.outerWidth(), $bottomLeftTable.get(0).scrollWidth)), fixedHeight = Math.min(wrapperHeight, Math.max($topLeftTable.height(), $topRightTable.height())), vScrollbar = $bottomRightWrapper.get(0).scrollHeight > (wrapperHeight - fixedHeight), hScrollbar = $bottomRightWrapper.get(0).scrollWidth > (wrapperWidth - fixedWidth); $topLeftWrapper.css({ width: fixedWidth, height: fixedHeight }); $topRightWrapper.css({ width: wrapperWidth - fixedWidth - (vScrollbar ? 17 : 0), height: fixedHeight, left: fixedWidth }); $bottomLeftWrapper.css({ width: fixedWidth, height: vScrollbar ? wrapperHeight - fixedHeight - (hScrollbar ? 17 : 0) : "auto", top: fixedHeight }); $bottomRightWrapper.css({ width: wrapperWidth - fixedWidth, height: vScrollbar ? wrapperHeight - fixedHeight : "auto", top: fixedHeight, left: fixedWidth }); }, _adjustLayout: function() { var _this = this, $wrapper = this.$fixedWrapper, $topLeftTable = $wrapper.find("div.fancytree-fixed-wrapper-tl table"), $topRightTable = $wrapper.find("div.fancytree-fixed-wrapper-tr table"), $bottomLeftTable = $wrapper.find("div.fancytree-fixed-wrapper-bl table"), $bottomRightTable = $wrapper.find("div.fancytree-fixed-wrapper-br table"); $topLeftTable.find("tr").each(function(idx) { var $row2 = $topRightTable.find("tr:eq(" + idx + ")"); _this.ext.fixed._adjustRowLayout($(this), $row2); }); $bottomLeftTable.find("tr").each(function(idx) { var $row2 = $bottomRightTable.find("tbody").find("tr:eq(" + idx + ")"); _this.ext.fixed._adjustRowLayout($(this), $row2); }); $topLeftTable.find("tr:first-child").find("td, th").each(function(idx) { var $bottomTr = $bottomLeftTable.find("tr:first-child"), $td2 = $bottomTr.find("td:not(.fancytree-fixed-hidden):eq(" + idx + "), th:not(.fancytree-fixed-hidden):eq(" + idx + ")"); _this.ext.fixed._adjustColumnLayout($(this), $td2); }); $topRightTable.find("tr:first-child").find("th:not(.fancytree-fixed-hidden)").each(function(idx) { var $bottomTr = $bottomRightTable.find("tbody tr:first-child:not(.fancytree-fixed-hidden)"), $td2 = $bottomTr.find("td:not(.fancytree-fixed-hidden):eq(" + idx + "), th:not(.fancytree-fixed-hidden):eq(" + idx + ")"); _this.ext.fixed._adjustColumnLayout($(this), $td2); }); _this.ext.fixed._adjustWrapperLayout(); } /*, treeSetFocus: function(ctx, flag) { // alert("treeSetFocus" + ctx.tree.$container); ctx.tree.$container.focus(); $.ui.fancytree.focusTree = ctx.tree; }*/ }); }(jQuery, window, document));