Created
September 3, 2015 05:37
-
-
Save deitch/a941f551b3d2582b691d to your computer and use it in GitHub Desktop.
jstreegrid patch test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* http://github.com/deitch/jstree-grid | |
* | |
* This plugin handles adding a grid to a tree to display additional data | |
* | |
* Licensed under the MIT license: | |
* http://www.opensource.org/licenses/mit-license.php | |
* | |
* Works only with jstree version >= 3.0.0 | |
* | |
* $Date: 2015-06-016 $ | |
* $Revision: 3.2.3 $ | |
*/ | |
/*jslint nomen:true */ | |
/*jshint unused:vars */ | |
/*global navigator, document, jQuery, define */ | |
/* AMD support added by jochenberger per https://github.com/deitch/jstree-grid/pull/49 | |
* | |
*/ | |
(function (factory) { | |
if (typeof define === 'function' && define.amd) { | |
// AMD. Register as an anonymous module. | |
define(['jquery', 'jstree'], factory); | |
} else { | |
// Browser globals | |
factory(jQuery); | |
} | |
}(function ($) { | |
var renderAWidth, renderATitle, getIndent, htmlstripre, findLastClosedNode, BLANKRE = /^\s*$/g, | |
IDREGEX = /[\\:&!^|()\[\]<>@*'+~#";,= \/${}%]/g, | |
SPECIAL_TITLE = "_DATA_", LEVELINDENT = 24, bound = false, styled = false, GRIDCELLID_PREFIX = "jsgrid_",GRIDCELLID_POSTFIX = "_col"; | |
/*jslint regexp:true */ | |
htmlstripre = /<\/?[^>]+>/gi; | |
/*jslint regexp:false */ | |
getIndent = function(node,tree) { | |
var div, i, li, width; | |
// did we already save it for this tree? | |
tree._gridSettings = tree._gridSettings || {}; | |
if (tree._gridSettings.indent > 0) { | |
width = tree._gridSettings.indent; | |
} else { | |
// create a new div on the DOM but not visible on the page | |
div = $("<div></div>"); | |
i = node.prev("i"); | |
li = i.parent(); | |
// add to that div all of the classes on the tree root | |
div.addClass(tree.get_node("#",true).attr("class")); | |
// move the li to the temporary div root | |
li.appendTo(div); | |
// attach to the body quickly | |
div.appendTo($("body")); | |
// get the width | |
width = i.width() || LEVELINDENT; | |
// detach the li from the new div and destroy the new div | |
li.detach(); | |
div.remove(); | |
// save it for the future | |
tree._gridSettings.indent = width; | |
} | |
return(width); | |
}; | |
findLastClosedNode = function (tree,id) { | |
// first get our node | |
var ret, node = tree.get_node(id), children = node.children; | |
// is it closed? | |
if (!children || children.length <= 0 || !node.state.opened) { | |
ret = id; | |
} else { | |
ret = findLastClosedNode(tree,children[children.length-1]); | |
} | |
return(ret); | |
}; | |
renderAWidth = function(node,tree) { | |
var depth, width, | |
fullWidth = parseInt(tree.settings.grid.columns[0].width,10) + parseInt(tree._gridSettings.treeWidthDiff,10); | |
// need to use a selector in jquery 1.4.4+ | |
depth = tree.get_node(node).parents.length; | |
width = fullWidth - depth*getIndent(node,tree); | |
// the following line is no longer needed, since we are doing this inside a <td> | |
//a.css({"vertical-align": "top", "overflow":"hidden"}); | |
return(fullWidth); | |
}; | |
renderATitle = function(node,t,tree) { | |
var a = node.get(0).tagName.toLowerCase() === "a" ? node : node.children("a"), title, col = tree.settings.grid.columns[0]; | |
// get the title | |
title = ""; | |
if (col.title) { | |
if (col.title === SPECIAL_TITLE) { | |
title = tree.get_text(t); | |
} else if (t.attr(col.title)) { | |
title = t.attr(col.title); | |
} | |
} | |
// strip out HTML | |
title = title.replace(htmlstripre, ''); | |
if (title) { | |
a.attr("title",title); | |
} | |
}; | |
$.jstree.defaults.grid = { | |
width: 25 | |
}; | |
$.jstree.plugins.grid = function(options,parent) { | |
this._initialize = function () { | |
if (!this._initialized) { | |
var s = this.settings.grid || {}, styles, container = this.element, gridparent = container.parent(), i, | |
gs = this._gridSettings = { | |
columns : s.columns || [], | |
treeClass : "jstree-grid-col-0", | |
context: s.contextmenu || false, | |
columnWidth : s.width, | |
defaultConf : {"*display":"inline","*+display":"inline"}, | |
isThemeroller : !!this._data.themeroller, | |
treeWidthDiff : 0, | |
resizable : s.resizable, | |
indent: 0 | |
}, cols = gs.columns, treecol = 0; | |
// find which column our tree shuld go in | |
for (i=0;i<s.columns.length;i++) { | |
if (s.columns[i].tree) { | |
// save which column it was | |
treecol = i; | |
// do not check any others | |
break; | |
} | |
} | |
this.treecol = treecol; | |
var msie = /msie/.test(navigator.userAgent.toLowerCase()); | |
if (msie) { | |
var version = parseFloat(navigator.appVersion.split("MSIE")[1]); | |
if (version < 8) { | |
gs.defaultConf.display = "inline"; | |
gs.defaultConf.zoom = "1"; | |
} | |
} | |
// set up the classes we need | |
if (!styled) { | |
styled = true; | |
styles = [ | |
'.jstree-grid-cell {vertical-align: top; overflow:hidden;margin-left:0;position:relative;width: 100%;padding-left:7px;white-space: nowrap;}', | |
'.jstree-grid-cell span {margin-right:0px;margin-right:0px;*display:inline;*+display:inline;white-space: nowrap;}', | |
'.jstree-grid-separator {position:relative; height:24px; float:right;margin-left: -2px; border-width: 0 2px 0 0; *display:inline; *+display:inline; margin-right:0px;width:0px;}', | |
'.jstree-grid-header-cell {overflow: hidden; white-space: nowrap;padding: 1px 3px 2px 5px;}', | |
'.jstree-grid-header-themeroller {border: 0; padding: 1px 3px;}', | |
'.jstree-grid-header-regular {background-color: #EBF3FD;}', | |
'.jstree-grid-resizable-separator {cursor: col-resize;}', | |
'.jstree-grid-separator-regular {border-color: #d0d0d0; border-style: solid;}', | |
'.jstree-grid-cell-themeroller {border: none !important; background: transparent !important;}', | |
'.jstree-grid-table {table-layout: fixed; width: 100%;}', | |
'.jstree-grid-width-auto {width:auto;display:block;}', | |
'.jstree-grid-col-0 {width: 100%;}' | |
]; | |
$('<style type="text/css">'+styles.join("\n")+'</style>').appendTo("head"); | |
} | |
this.table = $("<table></table>").addClass("jstree-grid-table"); | |
this.gridWrapper = $("<div></div>").addClass("jstree-grid-wrapper").appendTo(gridparent).append(this.table); | |
this.dataRow = $("<tr></tr>"); | |
this.headerRow = $("<tr></tr>"); | |
this.colgroup = $("<colgroup></colgroup>"); | |
this.table.append(this.colgroup); | |
this.table.append(this.headerRow); | |
this.table.append(this.dataRow); | |
// create the data columns | |
for (i=0;i<cols.length;i++) { | |
this.dataRow.append($("<td></td>").addClass("jstree-grid-cell")); | |
} | |
this.dataRow.children("td:eq("+treecol+")").append(container); | |
this._initialized = true; | |
} | |
}; | |
this.init = function (el,options) { | |
parent.init.call(this,el,options); | |
this._initialize(); | |
}; | |
this.bind = function () { | |
parent.bind.call(this); | |
this._initialize(); | |
this.element | |
.on("move_node.jstree create_node.jstree clean_node.jstree change_node.jstree", $.proxy(function (e, data) { | |
var target = this.get_node(data || "#",true); | |
this._prepare_grid(target); | |
}, this)) | |
.on("delete_node.jstree",$.proxy(function (e,data) { | |
if (data.node.id !== undefined) { | |
var dataRow = this.dataRow, removeNodes = [data.node.id], i; | |
// add children to remove list | |
if (data.node && data.node.children_d) { | |
removeNodes = removeNodes.concat(data.node.children_d); | |
} | |
for (i=0;i<removeNodes.length;i++) { | |
dataRow.find("div."+GRIDCELLID_PREFIX+removeNodes[i]+GRIDCELLID_POSTFIX).remove(); | |
} | |
} | |
}, this)) | |
.on("close_node.jstree",$.proxy(function (e,data) { | |
this._hide_grid(data.node); | |
}, this)) | |
.on("open_node.jstree",$.proxy(function (e,data) { | |
}, this)) | |
.on("load_node.jstree",$.proxy(function (e,data) { | |
}, this)) | |
.on("loaded.jstree", $.proxy(function (e) { | |
this._prepare_headers(); | |
this.element.trigger("loaded_grid.jstree"); | |
}, this)) | |
.on("ready.jstree",$.proxy(function (e,data) { | |
// find the line-height of the first known node | |
var lh = this.element.find("li a:first").css("line-height"); | |
$('<style type="text/css">td.jstree-grid-cell {line-height: '+lh+'}</style>').appendTo("head"); | |
// add container classes to the wrapper | |
this.gridWrapper.addClass(this.element.attr("class")); | |
},this)) | |
.on("move_node.jstree",$.proxy(function(e,data){ | |
var node = data.new_instance.element; | |
//renderAWidth(node,this); | |
// check all the children, because we could drag a tree over | |
node.find("li > a").each($.proxy(function(i,elm){ | |
//renderAWidth($(elm),this); | |
},this)); | |
},this)) | |
.on("hover_node.jstree",$.proxy(function(node,selected,event){ | |
var id = selected.node.id; | |
if (this._hover_node !== null && this._hover_node !== undefined) { | |
this.dataRow.find("."+GRIDCELLID_PREFIX+this._hover_node+GRIDCELLID_POSTFIX).removeClass("jstree-hovered"); | |
} | |
this._hover_node = id; | |
this.dataRow.find("."+GRIDCELLID_PREFIX+id+GRIDCELLID_POSTFIX).addClass("jstree-hovered"); | |
},this)) | |
.on("dehover_node.jstree",$.proxy(function(node,selected,event){ | |
var id = selected.node.id; | |
this._hover_node = null; | |
this.dataRow.find("."+GRIDCELLID_PREFIX+id+GRIDCELLID_POSTFIX).removeClass("jstree-hovered"); | |
},this)) | |
.on("select_node.jstree",$.proxy(function(node,selected,event){ | |
var id = selected.node.id; | |
this.dataRow.find("."+GRIDCELLID_PREFIX+id+GRIDCELLID_POSTFIX).addClass("jstree-clicked"); | |
this.get_node(selected.node.id,true).children("div.jstree-grid-cell").addClass("jstree-clicked"); | |
},this)) | |
.on("deselect_node.jstree",$.proxy(function(node,selected,event){ | |
var id = selected.node.id; | |
this.dataRow.find("."+GRIDCELLID_PREFIX+id+GRIDCELLID_POSTFIX).removeClass("jstree-clicked"); | |
},this)) | |
.on("deselect_all.jstree",$.proxy(function(node,selected,event){ | |
// get all of the ids that were unselected | |
var ids = selected.node || [], i; | |
for (i=0;i<ids.length;i++) { | |
this.dataRow.find("."+GRIDCELLID_PREFIX+ids[i]+GRIDCELLID_POSTFIX).removeClass("jstree-clicked"); | |
} | |
},this)) | |
.on("search.jstree", $.proxy(function (e, data) { | |
// search sometimes filters, so we need to hide all of the appropriate grid cells as well, and show only the matches | |
var dataRow = this.dataRow; | |
if(this._data.search.som) { | |
if(data.nodes.length) { | |
// hide all of the grid cells | |
dataRow.find('div.jstree-grid-cell').hide(); | |
// show only those that match | |
data.nodes.add(data.nodes.parentsUntil(".jstree")).filter(".jstree-node").each(function (i,node) { | |
var id = node.id; | |
if (id) { | |
dataRow.find("."+GRIDCELLID_PREFIX+id+GRIDCELLID_POSTFIX).show(); | |
} | |
}); | |
} | |
} | |
return true; | |
}, this)) | |
; | |
if (this._gridSettings.isThemeroller) { | |
this.element | |
.on("select_node.jstree",$.proxy(function(e,data){ | |
data.rslt.obj.children("a").nextAll("div").addClass("ui-state-active"); | |
},this)) | |
.on("deselect_node.jstree deselect_all.jstree",$.proxy(function(e,data){ | |
data.rslt.obj.children("a").nextAll("div").removeClass("ui-state-active"); | |
},this)) | |
.on("hover_node.jstree",$.proxy(function(e,data){ | |
data.rslt.obj.children("a").nextAll("div").addClass("ui-state-hover"); | |
},this)) | |
.on("dehover_node.jstree",$.proxy(function(e,data){ | |
data.rslt.obj.children("a").nextAll("div").removeClass("ui-state-hover"); | |
},this)); | |
} | |
}; | |
// tear down the tree entirely | |
this.teardown = function() { | |
var gw = this.gridWrapper, container = this.element, gridparent = gw.parent(); | |
container.detach(); | |
gw.remove(); | |
gridparent.append(container); | |
parent.teardown.call(this); | |
}; | |
// clean the grid in case of redraw or refresh entire tree | |
this._clean_grid = function (target,id) { | |
var dataRow = this.dataRow; | |
if (target) { | |
dataRow.find("div."+GRIDCELLID_PREFIX+id+GRIDCELLID_POSTFIX).remove(); | |
} else { | |
// get all of the `div` children in all of the `td` in dataRow except for :first (that is the tree itself) and remove | |
dataRow.children("td:gt(0)").find("div").remove(); | |
} | |
}; | |
// prepare the headers | |
this._prepare_headers = function() { | |
var header, i, col, gs = this._gridSettings,cols = gs.columns || [], width, defaultWidth = gs.columnWidth, resizable = gs.resizable || false, | |
cl, ccl, val, margin, last, tr = gs.isThemeroller, classAdd = (tr?"themeroller":"regular"), puller, | |
hasHeaders = false, gridparent = this.gridparent, colgroup, | |
conf = gs.defaultConf, isClickedSep = false, oldMouseX = 0, newMouseX = 0, | |
currentTree = null, colNum = 0, toResize = {}, clickedSep = null, borPadWidth = 0, totalWidth = 0; | |
// save the original parent so we can reparent on destroy | |
this.parent = gridparent; | |
// set up the wrapper, if not already done | |
header = this.headerRow; | |
header.addClass((tr?"ui-widget-header ":"")+"jstree-grid-header jstree-grid-header-"+classAdd); | |
colgroup = this.colgroup; | |
// create the headers | |
for (i=0;i<cols.length;i++) { | |
col = $("<col/>"); | |
col.appendTo(colgroup); | |
cl = cols[i].headerClass || ""; | |
ccl = cols[i].columnClass || ""; | |
val = cols[i].header || ""; | |
if (val) {hasHeaders = true;} | |
width = cols[i].width || defaultWidth; | |
borPadWidth = tr ? 1+6 : 2+8; // account for the borders and padding | |
width -= borPadWidth; | |
margin = i === 0 ? 3 : 0; | |
col.css({width:width}); | |
last = $("<th></th>").css(conf).css({"margin-left": margin}).addClass((tr?"ui-widget-header ":"")+"jstree-grid-header jstree-grid-header-cell jstree-grid-header-"+classAdd+" "+cl+" "+ccl).html(val).appendTo(header); | |
totalWidth += last.outerWidth(); | |
puller = $("<div class='jstree-grid-separator jstree-grid-separator-"+classAdd+(tr ? " ui-widget-header" : "")+(resizable? " jstree-grid-resizable-separator":"")+"'> </div>").appendTo(last); | |
} | |
// get rid of last puller | |
puller.remove(); | |
last.addClass((tr?"ui-widget-header ":"")+"jstree-grid-header jstree-grid-header-last jstree-grid-header-"+classAdd); | |
// if there is no width given for the last column, do it via automatic | |
if (cols[cols.length-1].width === undefined) { | |
totalWidth -= width; | |
col.css({width:"auto"}); | |
last.addClass("jstree-grid-width-auto").next(".jstree-grid-separator").remove(); | |
} | |
if (hasHeaders) { | |
// save the offset of the div from the body | |
gs.divOffset = header.parent().offset().left; | |
gs.header = header; | |
} else { | |
this.headerRow.css("display","none"); | |
} | |
if (!bound && resizable) { | |
bound = true; | |
$(document).mouseup(function () { | |
var i, ref, cols, widths, headers, w; | |
if (isClickedSep) { | |
ref = $.jstree.reference(currentTree); | |
cols = ref.settings.grid.columns; | |
headers = colgroup.children("col"); | |
widths = []; | |
if (isNaN(colNum) || colNum < 0) { ref._gridSettings.treeWidthDiff = currentTree.find("ins:eq(0)").width() + currentTree.find("a:eq(0)").width() - ref._gridSettings.columns[0].width; } | |
isClickedSep = false; | |
for (i=0;i<cols.length;i++) { | |
w = parseFloat(headers[i].style.width); | |
widths[i] = {w: w, r: i===colNum }; | |
ref._gridSettings.columns[i].width = w; | |
} | |
currentTree.trigger("resize_column.jstree-grid", widths); | |
} | |
}).mousemove(function (e) { | |
if (isClickedSep) { | |
newMouseX = e.clientX; | |
var diff = newMouseX - oldMouseX, | |
oldPrevHeaderInner, oldNextHeaderInner, | |
oldPrevColWidth, oldNextColWidth, newPrevColWidth, | |
newNextColWidth; | |
if (diff !== 0){ | |
oldPrevHeaderInner = toResize.prevHeader.width(); | |
oldNextHeaderInner = toResize.nextHeader.width(); | |
oldPrevColWidth = parseFloat(toResize.prevCol.css("width")); | |
oldNextColWidth = parseFloat(toResize.nextCol.css("width")); | |
// make sure that diff cannot be beyond the left/right limits | |
diff = diff < 0 ? Math.max(diff,-oldPrevHeaderInner) : Math.min(diff,oldNextHeaderInner); | |
newPrevColWidth = (oldPrevColWidth+diff)+"px"; | |
newNextColWidth = (oldNextColWidth-diff)+"px"; | |
// only do this if we are not shrinking past 0 on left or right - and limit it to that amount | |
if ((diff < 0 && oldPrevHeaderInner > 0) || (diff > 0 && oldNextHeaderInner > 0)) { | |
toResize.prevCol.width(newPrevColWidth); | |
if (!toResize.nextHeader.hasClass("jstree-grid-width-auto")) { | |
toResize.nextCol.width(newNextColWidth); | |
} | |
oldMouseX = newMouseX; | |
} | |
} | |
} | |
}); | |
header.on("selectstart", ".jstree-grid-resizable-separator", function () { return false; }) | |
.on("mousedown", ".jstree-grid-resizable-separator", function (e) { | |
var headerWrapper; | |
clickedSep = $(this); | |
isClickedSep = true; | |
currentTree = clickedSep.closest(".jstree-grid-wrapper").find(".jstree"); | |
oldMouseX = e.clientX; | |
colNum = clickedSep.closest("th").prevAll("th").length; | |
toResize.prevCol = colgroup.children("col:eq("+colNum+")"); | |
toResize.nextCol = toResize.prevCol.next("col"); | |
toResize.prevHeader = clickedSep.closest("th"); | |
toResize.nextHeader = toResize.prevHeader.next("th"); | |
// the max rightmost position we will allow is the right-most of the wrapper minus a buffer (10) | |
headerWrapper = clickedSep.parent(); | |
return false; | |
}); | |
} | |
}; | |
/* | |
* Override redraw_node to correctly insert the grid | |
*/ | |
this.redraw_node = function(obj, deep, is_callback, force_render) { | |
// first allow the parent to redraw the node | |
obj = parent.redraw_node.call(this, obj, deep, is_callback, force_render); | |
// next prepare the grid | |
if(obj) { | |
this._prepare_grid(obj); | |
} | |
return obj; | |
}; | |
this.refresh = function () { | |
this._clean_grid(); | |
return parent.refresh.apply(this,arguments); | |
}; | |
this._hide_grid = function (node) { | |
var dataRow = this.dataRow, children = node && node.children_d ? node.children_d : [], i; | |
// go through each column, remove all children with the correct ID name | |
for (i=0;i<children.length;i++) { | |
dataRow.find("td div."+GRIDCELLID_PREFIX+children[i]+GRIDCELLID_POSTFIX).remove(); | |
} | |
}; | |
this.holdingCells = {}; | |
this.getHoldingCells = function (obj,col,hc) { | |
var ret = $(), children = obj.children||[], child, i; | |
// run through each child, render it, and then render its children recursively | |
for (i=0;i<children.length;i++) { | |
child = GRIDCELLID_PREFIX+children[i]+GRIDCELLID_POSTFIX+col; | |
if (hc[child] && obj.state.opened) { | |
ret = ret.add(hc[child]).add(this.getHoldingCells(this.get_node(children[i]),col,hc)); | |
//delete hc[child]; | |
} | |
} | |
return(ret); | |
}; | |
/** | |
* put a grid cell in edit mode (input field to edit the data) | |
* @name edit(obj, col) | |
* @param {mixed} obj | |
* @param {obj} col definition | |
* @param {element} cell element, either span or wrapping div | |
*/ | |
this._edit = function (obj, col, element) { | |
if(!obj) { return false; } | |
if (element) { | |
element = $(element); | |
if (element.prop("tagName").toLowerCase() === "div") { | |
element = element.children("span:first"); | |
} | |
} else { | |
// need to find the element - later | |
return false; | |
} | |
var rtl = this._data.core.rtl, | |
w = this.element.width(), | |
t = obj.data[col.value], | |
h1 = $("<"+"div />", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body"), | |
h2 = $("<"+"input />", { | |
"value" : t, | |
"class" : "jstree-rename-input", | |
"css" : { | |
"padding" : "0", | |
"border" : "1px solid silver", | |
"box-sizing" : "border-box", | |
"display" : "inline-block", | |
"height" : (this._data.core.li_height) + "px", | |
"lineHeight" : (this._data.core.li_height) + "px", | |
"width" : "150px" // will be set a bit further down | |
}, | |
"blur" : $.proxy(function () { | |
var v = h2.val(); | |
// save the value if changed | |
if(v === "" || v === t) { | |
v = t; | |
} else { | |
obj.data[col.value] = v; | |
this.element.trigger('update_cell.jstree-grid',{node:obj, col:col.value, value:v, old:t}); | |
this._prepare_grid(this.get_node(obj,true)); | |
} | |
h2.remove(); | |
element.show(); | |
}, this), | |
"keydown" : function (event) { | |
var key = event.which; | |
if(key === 27) { | |
this.value = t; | |
} | |
if(key === 27 || key === 13 || key === 37 || key === 38 || key === 39 || key === 40 || key === 32) { | |
event.stopImmediatePropagation(); | |
} | |
if(key === 27 || key === 13) { | |
event.preventDefault(); | |
this.blur(); | |
} | |
}, | |
"click" : function (e) { e.stopImmediatePropagation(); }, | |
"mousedown" : function (e) { e.stopImmediatePropagation(); }, | |
"keyup" : function (event) { | |
h2.width(Math.min(h1.text("pW" + this.value).width(),w)); | |
}, | |
"keypress" : function(event) { | |
if(event.which === 13) { return false; } | |
} | |
}), | |
fn = { | |
fontFamily : element.css('fontFamily') || '', | |
fontSize : element.css('fontSize') || '', | |
fontWeight : element.css('fontWeight') || '', | |
fontStyle : element.css('fontStyle') || '', | |
fontStretch : element.css('fontStretch') || '', | |
fontVariant : element.css('fontVariant') || '', | |
letterSpacing : element.css('letterSpacing') || '', | |
wordSpacing : element.css('wordSpacing') || '' | |
}; | |
element.hide(); | |
element.parent().append(h2); | |
h2.css(fn).width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select(); | |
}; | |
this._prepare_grid = function (obj) { | |
var gs = this._gridSettings, c = gs.treeClass, _this = this, t, cols = gs.columns || [], width, tr = gs.isThemeroller, | |
tree = this.element, | |
classAdd = (tr?"themeroller":"regular"), img, objData = this.get_node(obj), | |
defaultWidth = gs.columnWidth, conf = gs.defaultConf, cellClickHandler = function (tree,node,val,col,t) { | |
return function(e) { | |
node = tree.find("#"+node.attr("id")); | |
node.children(".jstree-anchor").trigger("click.jstree",e); | |
tree.trigger("select_cell.jstree-grid", [{value: val,column: col.header,node: node,grid:$(this),sourceName: col.value}]); | |
}; | |
}, cellRightClickHandler = function (tree,node,val,col,t) { | |
return function (e) { | |
if (gs.context) { | |
e.preventDefault(); | |
$.vakata.context.show(this,{ 'x' : e.pageX, 'y' : e.pageY },{ | |
"edit":{label:"Edit","action": function (data) { | |
var obj = t.get_node(node); | |
_this._edit(obj,col,e.target); | |
}} | |
}); | |
} | |
}; | |
}, | |
i, val, cl, wcl, ccl, a, last, valClass, wideValClass, span, paddingleft, title, gridCellName, gridCellParentId, gridCellParent, | |
gridCellPrev, gridCellPrevId, gridCellNext, gridCellNextId, gridCellChild, gridCellChildId, | |
col, content, tmpWidth, dataRow = this.dataRow, dataCell, lid = objData.id, | |
peers = this.get_node(objData.parent).children, | |
// find my position in the list of peers. "peers" is the list of everyone at my level under my parent, in order | |
pos = jQuery.inArray(lid,peers), | |
hc = this.holdingCells, rendered = false, closed; | |
// get our column definition | |
t = $(obj); | |
// find the a children | |
a = t.children("a"); | |
if (a.length === 1) { | |
closed = !objData.state.opened; | |
gridCellName = GRIDCELLID_PREFIX+lid+GRIDCELLID_POSTFIX; | |
gridCellName = gridCellName.replace(IDREGEX,'\\$&'); | |
gridCellParentId = objData.parent === "#" ? null : GRIDCELLID_PREFIX+objData.parent+GRIDCELLID_POSTFIX; | |
a.addClass(c); | |
//renderAWidth(a,_this); | |
renderATitle(a,t,_this); | |
last = a; | |
for (i=0;i<cols.length;i++) { | |
if (this.treecol === i) { | |
continue; | |
} | |
col = cols[i]; | |
dataCell = dataRow.children("td:eq("+i+")"); | |
// get the cellClass, the wideCellClass, and the columnClass | |
cl = col.cellClass || ""; | |
wcl = col.wideCellClass || ""; | |
ccl = col.columnClass || ""; | |
// add a column class to the dataCell | |
dataCell.addClass(ccl); | |
// get the contents of the cell - value could be a string or a function | |
if (col.value !== undefined && col.value !== null) { | |
if (typeof(col.value) === "function") { | |
val = col.value(objData); | |
} else if (objData.data !== null && objData.data !== undefined && objData.data[col.value] !== undefined) { | |
val = objData.data[col.value]; | |
} else { | |
val = ""; | |
} | |
} else { | |
val = ""; | |
} | |
// put images instead of text if needed | |
if (col.images) { | |
img = col.images[val] || col.images["default"]; | |
if (img) {content = img[0] === "*" ? '<span class="'+img.substr(1)+'"></span>' : '<img src="'+img+'">';} | |
} else { content = val; } | |
// content cannot be blank, or it messes up heights | |
if (content === undefined || content === null || BLANKRE.test(content)) { | |
content = " "; | |
} | |
// get the valueClass | |
valClass = col.valueClass && objData.data !== null && objData.data !== undefined ? objData.data[col.valueClass] || "" : ""; | |
if (valClass && col.valueClassPrefix && col.valueClassPrefix !== "") { | |
valClass = col.valueClassPrefix + valClass; | |
} | |
// get the wideValueClass | |
wideValClass = col.wideValueClass && objData.data !== null && objData.data !== undefined ? objData.data[col.wideValueClass] || "" : ""; | |
if (wideValClass && col.wideValueClassPrefix && col.wideValueClassPrefix !== "") { | |
wideValClass = col.wideValueClassPrefix + wideValClass; | |
} | |
// get the title | |
title = col.title && objData.data !== null && objData.data !== undefined ? objData.data[col.title] || "" : ""; | |
// strip out HTML | |
title = title.replace(htmlstripre, ''); | |
// get the width | |
paddingleft = 7; | |
width = col.width || defaultWidth; | |
width = tmpWidth || (width - paddingleft); | |
last = dataCell.children("div#"+gridCellName+i); | |
if (!last || last.length < 1) { | |
last = $("<div></div>"); | |
$("<span></span>").appendTo(last); | |
last.attr("id",gridCellName+i); | |
last.addClass(gridCellName); | |
} | |
// we need to put it in the dataCell - after the parent, but the position matters | |
// if we have no parent, then we are one of the root nodes, but still need to look at peers | |
// if we are first, i.e. pos === 0, we go right after the parent; | |
// if we are not first, and our previous peer (one before us) is closed, we go right after the previous peer cell | |
// if we are not first, and our previous peer is opened, then we have to find its youngest & lowest closed child (incl. leaf) | |
// | |
// probably be much easier to go *before* our next one | |
// but that one might not be drawn yet | |
// here is the logic for jstree drawing: | |
// it draws peers from first to last or from last to first | |
// it draws children before a parent | |
// | |
// so I can rely on my *parent* not being drawn, but I cannot rely on my previous peer or my next peer being drawn | |
// so we do the following: | |
// 1- We are the first child: install after the parent | |
// 2- Our previous peer is already drawn: install after the previous peer | |
// 3- Our previous peer is not drawn, we have a child that is drawn: install right before our first child | |
// 4- Our previous peer is not drawn, we have no child that is drawn, our next peer is drawn: install right before our next peer | |
// 5- Our previous peer is not drawn, we have no child that is drawn, our next peer is not drawn: install right after parent | |
gridCellPrevId = GRIDCELLID_PREFIX+ (pos <=0 ? objData.parent : findLastClosedNode(this,peers[pos-1])) +GRIDCELLID_POSTFIX+i; | |
gridCellPrev = dataCell.find("div#"+gridCellPrevId); | |
gridCellNextId = GRIDCELLID_PREFIX+ (pos >= peers.length-1 ? "NULL" : peers[pos+1]) +GRIDCELLID_POSTFIX+i; | |
gridCellNext = dataCell.find("div#"+gridCellNextId); | |
gridCellChildId = GRIDCELLID_PREFIX+ (objData.children && objData.children.length > 0 ? objData.children[0] : "NULL") +GRIDCELLID_POSTFIX+i; | |
gridCellChild = dataCell.find("div#"+gridCellChildId); | |
gridCellParent = dataCell.find("div#"+gridCellParentId+i); | |
// if our parent is already drawn, then we put this in the right order under our parent | |
if (gridCellParentId) { | |
if (gridCellParent && gridCellParent.length > 0) { | |
if (gridCellPrev && gridCellPrev.length > 0) { | |
last.insertAfter(gridCellPrev); | |
} else if (gridCellChild && gridCellChild.length > 0) { | |
last.insertBefore(gridCellChild); | |
} else if (gridCellNext && gridCellNext.length > 0) { | |
last.insertBefore(gridCellNext); | |
} else { | |
last.insertAfter(gridCellParent); | |
} | |
rendered = true; | |
} else { | |
rendered = false; | |
} | |
// always put it in the holding cells, and then sort when the parent comes in, in case parent is (re)drawn later | |
hc[gridCellName+i] = last; | |
} else { | |
if (gridCellPrev && gridCellPrev.length > 0) { | |
last.insertAfter(gridCellPrev); | |
} else if (gridCellChild && gridCellChild.length > 0) { | |
last.insertBefore(gridCellChild); | |
} else if (gridCellNext && gridCellNext.length > 0) { | |
last.insertBefore(gridCellNext); | |
} else { | |
last.appendTo(dataCell); | |
} | |
rendered = true; | |
} | |
// do we have any children waiting for this cell? walk down through the children/grandchildren/etc tree | |
if (rendered) { | |
last.after(this.getHoldingCells(objData,i,hc)); | |
} | |
// need to make the height of this match the line height of the tree. How? | |
span = last.children("span"); | |
// create a span inside the div, so we can control what happens in the whole div versus inside just the text/background | |
span.addClass(cl+" "+valClass).html(content); | |
last = last.css(conf).addClass("jstree-grid-cell jstree-grid-cell-"+classAdd+" "+wcl+ " " + wideValClass + (tr?" ui-state-default":"")).addClass("jstree-grid-col-"+i); | |
// add click handler for clicking inside a grid cell | |
last.click(cellClickHandler(tree,t,val,col,this)); | |
last.on("contextmenu",cellRightClickHandler(tree,t,val,col,this)); | |
if (title) { | |
span.attr("title",title); | |
} | |
} | |
last.addClass("jstree-grid-cell-last"+(tr?" ui-state-default":"")); | |
// if there is no width given for the last column, do it via automatic | |
if (cols[cols.length-1].width === undefined) { | |
last.addClass("jstree-grid-width-auto").next(".jstree-grid-separator").remove(); | |
} | |
} | |
this.element.css({'overflow-y':'auto !important'}); | |
}; | |
// clean up holding cells | |
this.holdingCells = {}; | |
// need to do alternating background colors or borders | |
}; | |
})); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment