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
JavaScript
/*!
* 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));