├── .gitignore ├── LICENSE ├── README.md ├── doc ├── appendTreetable.html ├── depthFirst.html ├── makeData.js ├── makeTree.html ├── renderTree.html ├── style.css ├── tree.js ├── treeTable.html └── version.html ├── favicon ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── browserconfig.xml ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── mstile-150x150.png ├── safari-pinned-tab.svg └── site.webmanifest ├── index.html ├── release └── 1.0 │ └── treeTable.js ├── style └── simple.css └── treeTable.js /.gitignore: -------------------------------------------------------------------------------- 1 | /.project 2 | /.settings/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Matthias Cullmann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [jsTreeTable](https://culmat.github.io/jsTreeTable/) 2 | 3 | jsTreeTable is a clone of [jQuery treetable](https://ludo.cubicphuse.nl/jquery-treetable/). 4 | I wrote it, because integrating the original with Atlassian products was too complicated. 5 | This version is very light weight and provides some helper functions for dynamic tables. 6 | 7 | ## Features 8 | 9 | * unobtrusive 10 | * light weigth 11 | * self contained: no external images, css ... 12 | * helper functions for dynamic tables 13 | * [jQuery treetable](https://ludo.cubicphuse.nl/jquery-treetable/) compatible 14 | 15 | ## Requirements 16 | Some version of [jQuery](https://jquery.com/), i.e. 17 | 18 | ```html 19 | 20 | ``` 21 | 22 | If you want to use the [slider](#slider) function, some version of [jQuery UI](https://jqueryui.com/), i.e. 23 | 24 | ```html 25 | 26 | 27 | ``` 28 | 29 | jsTreeTable HEAD 30 | ```html 31 | 32 | ``` 33 | or [any release](https://github.com/culmat/jsTreeTable/tree/gh-pages/release). 34 | 35 | ```html 36 | 37 | ``` 38 | 39 | jsTreeTable registers itself under the variable *com_github_culmat_jsTreeTable*. 40 | You will want to declare a short hand alias or, if no conflicts exist register all methods in the scope of your choice: 41 | 42 | ```javascript 43 | // define a short hand 44 | var jsTT = com_github_culmat_jsTreeTable 45 | alert(jsTT.jsTreeTable) 46 | 47 | // register on the window object 48 | com_github_culmat_jsTreeTable.register(this) 49 | alert(jsTreeTable) 50 | 51 | ``` 52 | 53 | 54 | ## Providing data 55 | Either provide pre rendered tables ([see treeTable Example](doc/treeTable.html))... 56 | ```html 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
Parent
Child
65 | ``` 66 | ... or dynamically create the table from any data structure, e.g. JSON obtained by an AJAX call. 67 | See [makeTree](#maketree) API. 68 | 69 | ## API 70 | 71 | ### depthFirst 72 | 73 | Traverses a tree depth first, applying a given function to each node. 74 | 75 | ```javascript 76 | function depthFirst(tree, func, childrenAttr) 77 | ``` 78 | 79 | paramter | description | required | default 80 | --- | --- | --- | --- 81 | tree | the tree data as array of roots | X | 82 | func | the function to apply recursivly | X | 83 | childrenAttr | the attribute used to recursivly dig into the tree| | 'children' 84 | **Returns** the input parameter tree. 85 | 86 | [Example](https://culmat.github.io/jsTreeTable/doc/depthFirst.html) 87 | 88 | ### makeTree 89 | 90 | Transform a flat data structure into a hierarchical tree structure using id and parent attributes. 91 | 92 | ```javascript 93 | function makeTree (data, idAttr, refAttr, childrenAttr) 94 | ``` 95 | 96 | paramter | description | required | default 97 | --- | --- | --- | --- 98 | data | the flat data as array | X | 99 | idAttr | the attribute used to identify a node | | 'id' 100 | refAttr | the attribute used by the children to reference their parent | | 'parent' 101 | childrenAttr | the attribute used to build the hierarchical tree structure| | 'children' 102 | **Returns** an array of tree roots. 103 | 104 | [Example](https://culmat.github.io/jsTreeTable/doc/makeTree.html) 105 | 106 | ### renderTree 107 | 108 | Renders a tree data structure into a DOM table with CSS class *jsTT*, setting the following attributes 109 | 110 | * data-tt-id 111 | * data-tt-level 112 | * data-tt-isnode / data-tt-isleaf 113 | * data-tt-parent-id 114 | 115 | ```javascript 116 | function renderTree(tree, childrenAttr, idAttr, attrs, renderer, tableAttributes) 117 | ``` 118 | 119 | paramter | description | required | default 120 | --- | --- | --- | --- 121 | tree | the tree data | X | 122 | childrenAttr | the attribute used to navigate the hierarchical tree structure| | 'children' 123 | idAttr | the attribute used to identify a node | | 'id' 124 | attrs | a map of attribute names and labels to be rendered | all attributes except the childrenAttr e.g. {id: 'Name' , yob : 'Born in'} | 125 | renderer | a rendreing function for custom rendering | | 126 | tableAttributes | additional table attributes (ie id or class). Can be useful for styling. The css class *jsTT* will always be added. | | 127 | 128 | **Returns** an html table as javascript object. 129 | 130 | [Example](https://culmat.github.io/jsTreeTable/doc/renderTree.html) 131 | 132 | ### attr2attr 133 | 134 | A simple helper funtion that copies attributes from javascript objects onto the DOM. 135 | ```javascript 136 | function attr2attr(nodes, attrs) 137 | ``` 138 | 139 | paramter | description | required | default 140 | --- | --- | --- | --- 141 | nodes | an array of nodes to process | X | 142 | attrs | an array of attribute names | X | 143 | **Returns** the input parameter nodes 144 | 145 | ### treeTable 146 | 147 | Adds functions to expand / collapse a tree table. 148 | Styling needs to be done externally. 149 | 150 | ```javascript 151 | function treeTable(table) 152 | ``` 153 | 154 | paramter | description | required | default 155 | --- | --- | --- | --- 156 | table | the table dom node with data-tt-* attributes | X | 157 | 158 | **Returns** the input parameter nodes 159 | 160 | [Example](https://culmat.github.io/jsTreeTable/doc/treeTable.html) 161 | 162 | ### appendTreetable 163 | 164 | ```javascript 165 | function (tree, options) 166 | ``` 167 | 168 | paramter | description | required | default 169 | --- | --- | --- | --- 170 | tree | the tree data | X | 171 | options | see below | | 172 | 173 | option | description | required | default 174 | --- | --- | --- | --- 175 | idAttr | the attribute used to identify a node | | 'id' 176 | childrenAttr | the attribute used to navigate the hierarchical tree structure| | 'children' 177 | controls | controls you want to add to the top of the table | | 178 | mountPoint | where to append the table into the DOM | | $('body') 179 | depthFirst | funtion to be applied prior to rendering see [depthFirst](#depthfirst)| | 180 | renderer | see [renderTree](#rendertree) | | 181 | renderedAttr |see [renderTree](#rendertree) | | 182 | tableAttributes | see [renderTree](#rendertree) | | 183 | replaceContent | wether to empty the mount point before appending, useful for activity indicators | | false 184 | initialExpandLevel | 1 .. infinity | | 185 | slider | wether to display an expand slider control | | false 186 | 187 | 188 | **Returns** an html table as javascript object obtained by calling [renderTree](#rendertree) 189 | 190 | [Example](https://culmat.github.io/jsTreeTable/doc/appendTreetable.html) 191 | 192 | ### jsTreeTable 193 | 194 | A property holding the version of jsTreeTable 195 | 196 | ```javascript 197 | alert(com_github_culmat_jsTreeTable.jsTreeTable) 198 | ``` 199 | 200 | [Example](https://culmat.github.io/jsTreeTable/doc/version.html) 201 | 202 | ## Source 203 | 204 | [Github project](https://github.com/culmat/jsTreeTable/) 205 | 206 | ## Alternatives 207 | 208 | [SlickGrid](https://wiki.github.com/mleibman/SlickGrid) 209 | 210 | [jQuery treetable](https://ludo.cubicphuse.nl/jquery-treetable/) 211 | 212 | 213 | -------------------------------------------------------------------------------- /doc/appendTreetable.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | appendTreetable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 41 | 42 | 43 | 44 | 45 |
46 |
// Go ahed and play ... 47 | 48 | function enrich(node) { 49 | var desc = 0 50 | var childCount = 0 51 | if (node['children']) { 52 | $.each(node['children'], function(i, child) { 53 | desc += child['descendants'] + 1 54 | }) 55 | childCount = node['children'].length 56 | } 57 | node['descendants'] = desc 58 | node['childCount'] = childCount 59 | } 60 | 61 | function renderItem(tr, item){ 62 | tr.append($('<td>' + item.name.toUpperCase() + '</td>')) 63 | tr.append($('<td colspan="5"><a " href="https://en.wikipedia.org/wiki/'+item.geb+'" target="inWikipedia" >' + item.geb + '</a></td>')) 64 | } 65 | 66 | var options = { 67 | mountPoint : $('#container'), 68 | idAttr : 'name', 69 | renderedAttr : { 70 | name : 'Name', 71 | childCount : '# Children', 72 | descendants : '# Descendants', 73 | geb : 'Year of birth' 74 | }, 75 | depthFirst : enrich, 76 | replaceContent : true, 77 | tableAttributes : { 78 | // class : 'orange' 79 | }, 80 | slider :true, 81 | initialExpandLevel : 4, 82 | //renderer : renderItem, 83 | controls : [ 84 | //$('<button onclick="alert(jsTreeTable)">Show version</button>'), 85 | //$('<span>Just some text</span>') 86 | ] 87 | } 88 | 89 | appendTreetable(makeTree(makeData(), 'name'), options)
90 | 91 |
92 |
93 | table loading 95 |
96 |
97 | 98 | 101 | 102 | 103 | 104 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /doc/depthFirst.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | depthFirst 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /doc/makeData.js: -------------------------------------------------------------------------------- 1 | function makeData() { 2 | return [ { 3 | name : 'Harold', 4 | geb : 1933, 5 | parent : 'Robert' 6 | }, { 7 | name : 'Robert', 8 | geb : 1903, 9 | parent : 'John' 10 | }, { 11 | name : 'Thomas', 12 | geb : 2008, 13 | parent : 'Mathew' 14 | }, { 15 | name : 'Mathew', 16 | geb : 1977, 17 | parent : 'Harold' 18 | }, { 19 | name : 'Andrew', 20 | geb : 1974, 21 | parent : 'Harold' 22 | }, { 23 | name : 'Kate', 24 | geb : 2008, 25 | parent : 'Mathew' 26 | }, { 27 | name : 'Walter', 28 | geb : 1900, 29 | parent : 'John' 30 | }, { 31 | name : 'Michelle', 32 | geb : 2028, 33 | parent : 'Thomas' 34 | }, { 35 | name : 'James', 36 | geb : 2026, 37 | parent : 'Kate' 38 | } ] 39 | } 40 | -------------------------------------------------------------------------------- /doc/makeTree.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | makeTree 7 | 8 | 9 | 20 | 21 | 22 | 23 |
24 | 25 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /doc/renderTree.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | renderTree 7 | 8 | 9 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /doc/style.css: -------------------------------------------------------------------------------- 1 | #toc { 2 | position: fixed; 3 | top: 70px; 4 | left: 0px; 5 | width: 200px; 6 | padding: 10px; 7 | } 8 | 9 | .navbar { 10 | width: 222px; 11 | } 12 | .navbar #headline { 13 | margin-left: 20px; 14 | } 15 | 16 | body { 17 | background-image:url("data:image/svg+xml;utf8,"); 18 | background-repeat: repeat-y; 19 | background-position: right top; 20 | background-attachment: scroll; 21 | 22 | } 23 | 24 | .toc-h2 { 25 | padding-left: 0px; 26 | } 27 | .toc-h3 { 28 | padding-left: 15px; 29 | } 30 | .toc-h4 { 31 | padding-left: 30px; 32 | } 33 | #toc-list{ 34 | list-style-type:none; 35 | } 36 | #toc-list a{ 37 | text-decoration: none; 38 | } 39 | #toc-list li:HOVER{ 40 | border-right: 2px solid #ccc; 41 | } 42 | 43 | #chart { 44 | left: 0; 45 | position: fixed; 46 | top: 0px; 47 | width: 50%; 48 | height: 100%; 49 | z-index:-10; 50 | } 51 | 52 | #content{ 53 | margin-left: 250px; 54 | padding-left: 20px; 55 | margin-top: 10px; 56 | width: 70%; 57 | background-color: white; 58 | opacity: 0.95; 59 | } 60 | 61 | /* SVG styling */ 62 | svg { 63 | width: 840px; 64 | height: 600px; 65 | font-family: helvetica, sans-serif; 66 | } 67 | 68 | path, line { 69 | stroke: #777; 70 | } -------------------------------------------------------------------------------- /doc/tree.js: -------------------------------------------------------------------------------- 1 | /* D3 Tree */ 2 | /* Copyright 2013 Peter Cook (@prcweb); Licensed MIT */ 3 | 4 | // Tree configuration 5 | var branches = []; 6 | var seed = {i: 0, x: 320, y: 600, a: 0.3, l: 130, d:0}; // a = angle, l = length, d = depth 7 | var da = 0.5; // Angle delta 8 | var dl = 0.8; // Length delta (factor) 9 | var ar = 0.7; // Randomness 10 | var maxDepth = 9; 11 | 12 | // Tree creation functions 13 | function branch(b) { 14 | var end = endPt(b), daR, newB; 15 | 16 | branches.push(b); 17 | 18 | if (b.d === maxDepth) 19 | return; 20 | 21 | // Left branch 22 | daR = ar * Math.random() - ar * 0.5; 23 | newB = { 24 | i: branches.length, 25 | x: end.x, 26 | y: end.y, 27 | a: b.a - da + daR, 28 | l: b.l * dl, 29 | d: b.d + 1, 30 | parent: b.i 31 | }; 32 | branch(newB); 33 | 34 | // Right branch 35 | daR = ar * Math.random() - ar * 0.5; 36 | newB = { 37 | i: branches.length, 38 | x: end.x, 39 | y: end.y, 40 | a: b.a + da + daR, 41 | l: b.l * dl, 42 | d: b.d + 1, 43 | parent: b.i 44 | }; 45 | branch(newB); 46 | } 47 | 48 | function regenerate(initialise) { 49 | branches = []; 50 | branch(seed); 51 | initialise ? create() : update(); 52 | } 53 | 54 | function endPt(b) { 55 | // Return endpoint of branch 56 | var x = b.x + b.l * Math.sin( b.a ); 57 | var y = b.y - b.l * Math.cos( b.a ); 58 | return {x: x, y: y}; 59 | } 60 | 61 | 62 | // D3 functions 63 | function x1(d) {return d.x;} 64 | function y1(d) {return d.y;} 65 | function x2(d) {return endPt(d).x;} 66 | function y2(d) {return endPt(d).y;} 67 | function highlightParents(d) { 68 | var colour = d3.event.type === 'mouseover' ? 'green' : '#777'; 69 | var depth = d.d; 70 | for(var i = 0; i <= depth; i++) { 71 | d3.select('#id-'+parseInt(d.i)).style('stroke', colour); 72 | d = branches[d.parent]; 73 | } 74 | } 75 | 76 | function create() { 77 | d3.select('svg') 78 | .selectAll('line') 79 | .data(branches) 80 | .enter() 81 | .append('line') 82 | .attr('x1', x1) 83 | .attr('y1', y1) 84 | .attr('x2', x2) 85 | .attr('y2', y2) 86 | .style('stroke-width', function(d) {return parseInt(maxDepth + 1 - d.d) + 'px';}) 87 | .attr('id', function(d) {return 'id-'+d.i;}) 88 | .on('mouseover', highlightParents) 89 | .on('mouseout', highlightParents); 90 | } 91 | 92 | function update() { 93 | d3.select('svg') 94 | .selectAll('line') 95 | .data(branches) 96 | .transition() 97 | .attr('x1', x1) 98 | .attr('y1', y1) 99 | .attr('x2', x2) 100 | .attr('y2', y2); 101 | } 102 | 103 | d3.selectAll('.regenerate') 104 | .on('click', regenerate); 105 | 106 | regenerate(true); 107 | 108 | function iter() { 109 | regenerate() 110 | setTimeout("iter()", 30*1000) 111 | } 112 | 113 | setTimeout("iter()", 5*1000) 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /doc/treeTable.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | renderTree 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
namearea (km²)
America
North America
South America
Argentina2766890
Bolivia1098580
Brazil8511965
Para1247689
57 | 58 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /doc/version.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | depthFirst 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/culmat/jsTreeTable/5a1c6ee5b26fec70be4dbaa4f31842b27879f718/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/culmat/jsTreeTable/5a1c6ee5b26fec70be4dbaa4f31842b27879f718/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/culmat/jsTreeTable/5a1c6ee5b26fec70be4dbaa4f31842b27879f718/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/culmat/jsTreeTable/5a1c6ee5b26fec70be4dbaa4f31842b27879f718/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/culmat/jsTreeTable/5a1c6ee5b26fec70be4dbaa4f31842b27879f718/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/culmat/jsTreeTable/5a1c6ee5b26fec70be4dbaa4f31842b27879f718/favicon/favicon.ico -------------------------------------------------------------------------------- /favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/culmat/jsTreeTable/5a1c6ee5b26fec70be4dbaa4f31842b27879f718/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /favicon/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 805 | 807 | 809 | 811 | 813 | 814 | 816 | 818 | 820 | 822 | 831 | 832 | 833 | -------------------------------------------------------------------------------- /favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | jsTreeTable 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 34 | 35 | 36 |
37 | 38 | 39 |
40 | 41 | 42 | 66 | 67 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /release/1.0/treeTable.js: -------------------------------------------------------------------------------- 1 | var com_github_culmat_jsTreeTable = (function(){ 2 | 3 | function depthFirst(tree, func, childrenAttr) { 4 | childrenAttr = childrenAttr || 'children' 5 | function i_depthFirst(node) { 6 | if (node[childrenAttr]) { 7 | $.each(node[childrenAttr], function(i, child) { 8 | i_depthFirst(child) 9 | }) 10 | } 11 | func(node) 12 | } 13 | $.each(tree, function(i, root) { 14 | i_depthFirst(root) 15 | }) 16 | return tree 17 | } 18 | 19 | /* 20 | * make a deep copy of the object 21 | */ 22 | function copy(data){ 23 | return JSON.parse(JSON.stringify(data)) 24 | } 25 | 26 | function makeTree (data, idAttr, refAttr, childrenAttr) { 27 | var data_tmp = data 28 | idAttr = idAttr || 'id' 29 | refAttr = refAttr || 'parent' 30 | childrenAttr = childrenAttr || 'children' 31 | 32 | var byName = [] 33 | $.each(data_tmp, function(i, entry) { 34 | byName[entry[idAttr]] = entry 35 | }) 36 | var tree = [] 37 | $.each(data_tmp, function(i, entry) { 38 | var parents = entry[refAttr] 39 | if(!$.isArray(parents)){ 40 | parents = [parents] 41 | } 42 | if(parents.length == 0){ 43 | tree.push(entry) 44 | } else { 45 | var inTree = false; 46 | $.each(parents, function(i,parentID){ 47 | var parent = byName[parentID] 48 | if (parent) { 49 | if (!parent[childrenAttr]) { 50 | parent[childrenAttr] = [] 51 | } 52 | if($.inArray(entry, parent[childrenAttr])< 0) 53 | parent[childrenAttr].push(entry) 54 | inTree = true 55 | } 56 | }) 57 | if(!inTree){ 58 | tree.push(entry) 59 | } 60 | } 61 | }) 62 | return tree 63 | } 64 | 65 | function renderTree(tree, childrenAttr, idAttr, attrs, renderer, tableAttributes) { 66 | childrenAttr = childrenAttr || 'children' 67 | idAttr = idAttr || 'id' 68 | tableAttributes = tableAttributes || {} 69 | var maxLevel = 0; 70 | var ret = [] 71 | 72 | var table = $("") 73 | $.each(tableAttributes, function(key, value){ 74 | if(key == 'class' && value != 'jsTT') { 75 | table.addClass(value) 76 | } else { 77 | table.attr(key, value) 78 | } 79 | }) 80 | var thead = $("") 81 | var tr = $("") 82 | var tbody = $("") 83 | 84 | table.append(thead) 85 | thead.append(tr) 86 | table.append(tbody) 87 | if (attrs) { 88 | $.each(attrs, function(attr, desc) { 89 | $(tr).append($('')) 90 | }) 91 | } else { 92 | $(tr).append($('')) 93 | $.each(tree[0], function(key, value) { 94 | if (key != childrenAttr && key != idAttr) 95 | $(tr).append($('')) 96 | }) 97 | } 98 | 99 | function render(node, parent) { 100 | var tr = $("") 101 | $(tr).attr('data-tt-id', node[idAttr]) 102 | $(tr).attr('data-tt-level', node['data-tt-level']) 103 | if(!node[childrenAttr] || node[childrenAttr].length == 0) 104 | $(tr).attr('data-tt-isleaf', true) 105 | else 106 | $(tr).attr('data-tt-isnode', true) 107 | if (parent) { 108 | $(tr).attr('data-tt-parent-id', parent[idAttr]) 109 | } 110 | if (renderer) { 111 | renderer($(tr), node) 112 | }else if (attrs) { 113 | $.each(attrs, function(attr, desc) { 114 | $(tr).append($('')) 115 | }) 116 | } else { 117 | $(tr).append($('')) 118 | $.each(node, function(key, value) { 119 | if (key != childrenAttr && key != idAttr && key != 'data-tt-level') 120 | $(tr).append($('')) 121 | }) 122 | } 123 | tbody.append(tr) 124 | } 125 | 126 | function i_renderTree(subTree, childrenAttr, level, parent) { 127 | maxLevel = Math.max(maxLevel, level) 128 | $.each(subTree, function(i, node) { 129 | node['data-tt-level'] = level 130 | render(node, parent) 131 | if (node[childrenAttr]) { 132 | $.each(node[childrenAttr], function(i, child) { 133 | i_renderTree([ child ], childrenAttr, level + 1, node) 134 | }) 135 | } 136 | }) 137 | } 138 | i_renderTree(tree, childrenAttr, 1) 139 | if (tree[0]) 140 | tree[0].maxLevel = maxLevel 141 | return table 142 | } 143 | 144 | function attr2attr(nodes, attrs){ 145 | $.each(nodes, function(i, node) { 146 | $.each(attrs, function(j, at) { 147 | node[at] = $(node).attr(at) 148 | }) 149 | }) 150 | return nodes 151 | } 152 | 153 | function treeTable(table){ 154 | table.addClass('jsTT') 155 | table.expandLevel = function (n) { 156 | $("tr[data-tt-level]", table).each(function(index) { 157 | var level = parseInt($(this).attr('data-tt-level')) 158 | if (level > n-1) { 159 | this.trCollapse(true) 160 | } else if (level == n-1){ 161 | this.trExpand(true) 162 | } 163 | }) 164 | } 165 | function getLevel(node){ 166 | var level = node.attr('data-tt-level') 167 | if(level != undefined ) return parseInt(level) 168 | var parentID = node.attr('data-tt-parent-id') 169 | if( parentID == undefined){ 170 | return 0 171 | } else { 172 | return getLevel($('tr[data-tt-id="'+parentID+'"]', table).first()) + 1 173 | } 174 | } 175 | $("tr[data-tt-id]", table).each(function(i,node){ 176 | node = $(node) 177 | node.attr('data-tt-level', getLevel(node)) 178 | }) 179 | var dat = $("tr[data-tt-level]", table).get() 180 | $.each(dat, function(j, d) { 181 | d.trChildrenVisible = true 182 | d.trChildren = [] 183 | }) 184 | dat = attr2attr(dat, ['data-tt-id', 'data-tt-parent-id']) 185 | dat = makeTree(dat, 'data-tt-id', 'data-tt-parent-id', 'trChildren') 186 | 187 | var imgExpand = "data:image/png;base64,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" 188 | var imgCollapse = "data:image/png;base64,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" 189 | $("tr[data-tt-level]", table).each(function(index, tr) { 190 | var level = $(tr).attr('data-tt-level') 191 | var td = $("td",tr).first() 192 | if(tr.trChildren.length>0){ 193 | td.prepend($('')) 194 | } else { 195 | td.prepend($('')) 196 | } 197 | td.prepend($('')) 198 | td.css('white-space','nowrap') 199 | tr.trExpand = function(changeState){ 200 | if(this.trChildren.length < 1) return 201 | if(changeState) { 202 | this.trChildrenVisible = true 203 | $('#state', this).get(0).src= imgCollapse 204 | } 205 | var doit = changeState || this.trChildrenVisible 206 | $.each(this.trChildren, function(i, ctr) { 207 | if(doit) $(ctr).css('display', 'table-row') 208 | ctr.trExpand() 209 | }) 210 | } 211 | tr.trCollapse = function(changeState){ 212 | if(this.trChildren.length < 1) return 213 | if(changeState) { 214 | this.trChildrenVisible = false 215 | $('#state', this).get(0).src= imgExpand 216 | } 217 | $.each(this.trChildren, function(i, ctr) { 218 | $(ctr).css('display', 'none') 219 | ctr.trCollapse() 220 | }) 221 | } 222 | $(tr).click(function() { 223 | this.trChildrenVisible ? this.trCollapse(true) : this.trExpand(true) 224 | }) 225 | }) 226 | return table 227 | } 228 | 229 | 230 | function appendTreetable(tree, options) { 231 | function inALine(nodes) { 232 | var tr = $('') 233 | $.each(nodes, function(i, node){ 234 | tr.append($('
' + desc + '' + idAttr + '' + key + '
' + node[attr] + '' + node[idAttr] + '' + value + '
').append(node)) 235 | }) 236 | return $('').append(tr) 237 | 238 | } 239 | options = options || {} 240 | options.idAttr = (options.idAttr || 'id') 241 | options.childrenAttr = (options.childrenAttr || 'children') 242 | var controls = (options.controls || []) 243 | 244 | if (!options.mountPoint) 245 | options.mountPoint = $('body') 246 | 247 | if (options.depthFirst) 248 | depthFirst(tree, options.depthFirst, options.childrenAttr) 249 | var rendered = renderTree(tree, options.childrenAttr, options.idAttr, 250 | options.renderedAttr, options.renderer, options.tableAttributes) 251 | 252 | treeTable(rendered) 253 | if (options.replaceContent) { 254 | options.mountPoint.html('') 255 | } 256 | var initialExpandLevel = options.initialExpandLevel ? parseInt(options.initialExpandLevel) : -1 257 | initialExpandLevel = Math.min(initialExpandLevel, tree[0].maxLevel) 258 | rendered.expandLevel(initialExpandLevel) 259 | if(options.slider){ 260 | var slider = $('
') 261 | slider.width('200px') 262 | slider.slider({ 263 | min : 1, 264 | max : tree[0].maxLevel, 265 | range : "min", 266 | value : initialExpandLevel, 267 | slide : function(event, ui) { 268 | rendered.expandLevel(ui.value) 269 | } 270 | }) 271 | controls = [slider].concat(options.controls) 272 | } 273 | 274 | if(controls.length >0){ 275 | options.mountPoint.append(inALine(controls)) 276 | } 277 | options.mountPoint.append(rendered) 278 | return rendered 279 | } 280 | 281 | return { 282 | depthFirst : depthFirst, 283 | makeTree : makeTree, 284 | renderTree : renderTree, 285 | attr2attr : attr2attr, 286 | treeTable : treeTable, 287 | appendTreetable : appendTreetable, 288 | jsTreeTable : '1.0', 289 | register : function(target){ 290 | $.each(this, function(key, value){ if(key != 'register') target[key] = value}) 291 | } 292 | } 293 | })(); -------------------------------------------------------------------------------- /style/simple.css: -------------------------------------------------------------------------------- 1 | 2 | table.jsTT { 3 | margin-top: 10px; 4 | border-collapse: collapse; 5 | table-layout: fixed; 6 | border: 1px solid #686a66; 7 | } 8 | 9 | table.jsTT th { 10 | background-color: #9a9c97; 11 | color: white; 12 | border: 1px solid #686a66; 13 | padding-left: 8px; 14 | padding-right: 8px; 15 | text-align: left; 16 | } 17 | 18 | table.jsTT td { 19 | position: static; 20 | border-left: 1px solid #999; 21 | border-right: 1px solid #999; 22 | padding-left: 8px; 23 | padding-right: 8px; 24 | } 25 | 26 | table.jsTT tr[data-tt-level="1"] td:first-child { 27 | background-color: #c6c9c3; 28 | } 29 | 30 | table.jsTT tr[data-tt-level="2"] td:first-child { 31 | background-color: #dbdfd8; 32 | } 33 | 34 | table.jsTT tr[data-tt-level="3"] td:first-child { 35 | background-color: #f1f2f0; 36 | } 37 | 38 | table.jsTT tr:hover td { 39 | font-style: italic; 40 | border-bottom: 1px solid #999; 41 | } 42 | 43 | table.jsTT tr:hover td:first-child { 44 | font-style: inherit; 45 | border-bottom: inherit; 46 | } 47 | -------------------------------------------------------------------------------- /treeTable.js: -------------------------------------------------------------------------------- 1 | var com_github_culmat_jsTreeTable = (function(){ 2 | 3 | function depthFirst(tree, func, childrenAttr) { 4 | childrenAttr = childrenAttr || 'children' 5 | function i_depthFirst(node) { 6 | if (node[childrenAttr]) { 7 | $.each(node[childrenAttr], function(i, child) { 8 | i_depthFirst(child) 9 | }) 10 | } 11 | func(node) 12 | } 13 | $.each(tree, function(i, root) { 14 | i_depthFirst(root) 15 | }) 16 | return tree 17 | } 18 | 19 | /* 20 | * make a deep copy of the object 21 | */ 22 | function copy(data){ 23 | return JSON.parse(JSON.stringify(data)) 24 | } 25 | 26 | function makeTree (data, idAttr, refAttr, childrenAttr) { 27 | var data_tmp = data 28 | idAttr = idAttr || 'id' 29 | refAttr = refAttr || 'parent' 30 | childrenAttr = childrenAttr || 'children' 31 | 32 | var byName = [] 33 | $.each(data_tmp, function(i, entry) { 34 | byName[entry[idAttr]] = entry 35 | }) 36 | var tree = [] 37 | $.each(data_tmp, function(i, entry) { 38 | var parents = entry[refAttr] 39 | if(!$.isArray(parents)){ 40 | parents = [parents] 41 | } 42 | if(parents.length == 0){ 43 | tree.push(entry) 44 | } else { 45 | var inTree = false; 46 | $.each(parents, function(i,parentID){ 47 | var parent = byName[parentID] 48 | if (parent) { 49 | if (!parent[childrenAttr]) { 50 | parent[childrenAttr] = [] 51 | } 52 | if($.inArray(entry, parent[childrenAttr])< 0) 53 | parent[childrenAttr].push(entry) 54 | inTree = true 55 | } 56 | }) 57 | if(!inTree){ 58 | tree.push(entry) 59 | } 60 | } 61 | }) 62 | return tree 63 | } 64 | 65 | function renderTree(tree, childrenAttr, idAttr, attrs, renderer, tableAttributes) { 66 | childrenAttr = childrenAttr || 'children' 67 | idAttr = idAttr || 'id' 68 | tableAttributes = tableAttributes || {} 69 | var maxLevel = 0; 70 | var ret = [] 71 | 72 | var table = $("
") 73 | $.each(tableAttributes, function(key, value){ 74 | if(key == 'class' && value != 'jsTT') { 75 | table.addClass(value) 76 | } else { 77 | table.attr(key, value) 78 | } 79 | }) 80 | var thead = $("") 81 | var tr = $("") 82 | var tbody = $("") 83 | 84 | table.append(thead) 85 | thead.append(tr) 86 | table.append(tbody) 87 | if (attrs) { 88 | $.each(attrs, function(attr, desc) { 89 | $(tr).append($('')) 90 | }) 91 | } else { 92 | $(tr).append($('')) 93 | $.each(tree[0], function(key, value) { 94 | if (key != childrenAttr && key != idAttr) 95 | $(tr).append($('')) 96 | }) 97 | } 98 | 99 | function render(node, parent) { 100 | var tr = $("") 101 | $(tr).attr('data-tt-id', node[idAttr]) 102 | $(tr).attr('data-tt-level', node['data-tt-level']) 103 | if(!node[childrenAttr] || node[childrenAttr].length == 0) 104 | $(tr).attr('data-tt-isleaf', true) 105 | else 106 | $(tr).attr('data-tt-isnode', true) 107 | if (parent) { 108 | $(tr).attr('data-tt-parent-id', parent[idAttr]) 109 | } 110 | if (renderer) { 111 | renderer($(tr), node) 112 | } else if (attrs) { 113 | $.each(attrs, function(attr, desc) { 114 | $(tr).append($('')) 115 | }) 116 | } else { 117 | $(tr).append($('')) 118 | $.each(node, function(key, value) { 119 | if (key != childrenAttr && key != idAttr && key != 'data-tt-level') 120 | $(tr).append($('')) 121 | }) 122 | } 123 | tbody.append(tr) 124 | } 125 | 126 | function i_renderTree(subTree, childrenAttr, level, parent) { 127 | maxLevel = Math.max(maxLevel, level) 128 | $.each(subTree, function(i, node) { 129 | node['data-tt-level'] = level 130 | render(node, parent) 131 | if (node[childrenAttr]) { 132 | $.each(node[childrenAttr], function(i, child) { 133 | i_renderTree([ child ], childrenAttr, level + 1, node) 134 | }) 135 | } 136 | }) 137 | } 138 | i_renderTree(tree, childrenAttr, 1) 139 | if (tree[0]) 140 | tree[0].maxLevel = maxLevel 141 | return table 142 | } 143 | 144 | function attr2attr(nodes, attrs){ 145 | $.each(nodes, function(i, node) { 146 | $.each(attrs, function(j, at) { 147 | node[at] = $(node).attr(at) 148 | }) 149 | }) 150 | return nodes 151 | } 152 | 153 | function treeTable(table){ 154 | table.addClass('jsTT') 155 | table.expandLevel = function (n) { 156 | $("tr[data-tt-level]", table).each(function(index) { 157 | var level = parseInt($(this).attr('data-tt-level')) 158 | if (level > n-1) { 159 | this.trCollapse(true) 160 | } else if (level == n-1){ 161 | this.trExpand(true) 162 | } 163 | }) 164 | } 165 | function getLevel(node){ 166 | var level = node.attr('data-tt-level') 167 | if(level != undefined ) return parseInt(level) 168 | var parentID = node.attr('data-tt-parent-id') 169 | if( parentID == undefined){ 170 | return 0 171 | } else { 172 | return getLevel($('tr[data-tt-id="'+parentID+'"]', table).first()) + 1 173 | } 174 | } 175 | $("tr[data-tt-id]", table).each(function(i,node){ 176 | node = $(node) 177 | node.attr('data-tt-level', getLevel(node)) 178 | }) 179 | var dat = $("tr[data-tt-level]", table).get() 180 | $.each(dat, function(j, d) { 181 | d.trChildrenVisible = true 182 | d.trChildren = [] 183 | }) 184 | dat = attr2attr(dat, ['data-tt-id', 'data-tt-parent-id']) 185 | dat = makeTree(dat, 'data-tt-id', 'data-tt-parent-id', 'trChildren') 186 | 187 | var imgExpand = "data:image/png;base64,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" 188 | var imgCollapse = "data:image/png;base64,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" 189 | $("tr[data-tt-level]", table).each(function(index, tr) { 190 | var level = $(tr).attr('data-tt-level') 191 | var td = $("td",tr).first() 192 | if(tr.trChildren.length>0){ 193 | td.prepend($('')) 194 | } else { 195 | td.prepend($('')) 196 | } 197 | td.prepend($('')) 198 | td.css('white-space','nowrap') 199 | tr.trExpand = function(changeState){ 200 | if(this.trChildren.length < 1) return 201 | if(changeState) { 202 | this.trChildrenVisible = true 203 | $('#state', this).get(0).src= imgCollapse 204 | } 205 | var doit = changeState || this.trChildrenVisible 206 | $.each(this.trChildren, function(i, ctr) { 207 | if(doit) $(ctr).css('display', 'table-row') 208 | ctr.trExpand() 209 | }) 210 | } 211 | tr.trCollapse = function(changeState){ 212 | if(this.trChildren.length < 1) return 213 | if(changeState) { 214 | this.trChildrenVisible = false 215 | $('#state', this).get(0).src= imgExpand 216 | } 217 | $.each(this.trChildren, function(i, ctr) { 218 | $(ctr).css('display', 'none') 219 | ctr.trCollapse() 220 | }) 221 | } 222 | $(tr).click(function() { 223 | this.trChildrenVisible ? this.trCollapse(true) : this.trExpand(true) 224 | }) 225 | }) 226 | return table 227 | } 228 | 229 | 230 | function appendTreetable(tree, options) { 231 | function inALine(nodes) { 232 | var tr = $('') 233 | $.each(nodes, function(i, node){ 234 | tr.append($('
' + desc + '' + idAttr + '' + key + '
' + node[attr] + '' + node[idAttr] + '' + value + '
').append(node)) 235 | }) 236 | return $('').append(tr) 237 | 238 | } 239 | options = options || {} 240 | options.idAttr = (options.idAttr || 'id') 241 | options.childrenAttr = (options.childrenAttr || 'children') 242 | var controls = (options.controls || []) 243 | 244 | if (!options.mountPoint) 245 | options.mountPoint = $('body') 246 | 247 | if (options.depthFirst) 248 | depthFirst(tree, options.depthFirst, options.childrenAttr) 249 | var rendered = renderTree(tree, options.childrenAttr, options.idAttr, 250 | options.renderedAttr, options.renderer, options.tableAttributes) 251 | 252 | treeTable(rendered) 253 | if (options.replaceContent) { 254 | options.mountPoint.html('') 255 | } 256 | var initialExpandLevel = options.initialExpandLevel ? parseInt(options.initialExpandLevel) : -1 257 | initialExpandLevel = Math.min(initialExpandLevel, tree[0].maxLevel) 258 | rendered.expandLevel(initialExpandLevel) 259 | if(options.slider){ 260 | var slider = $('
') 261 | slider.width('200px') 262 | slider.slider({ 263 | min : 1, 264 | max : tree[0].maxLevel, 265 | range : "min", 266 | value : initialExpandLevel, 267 | slide : function(event, ui) { 268 | rendered.expandLevel(ui.value) 269 | } 270 | }) 271 | controls = [slider].concat(options.controls) 272 | } 273 | 274 | if(controls.length >0){ 275 | options.mountPoint.append(inALine(controls)) 276 | } 277 | options.mountPoint.append(rendered) 278 | return rendered 279 | } 280 | 281 | return { 282 | depthFirst : depthFirst, 283 | makeTree : makeTree, 284 | renderTree : renderTree, 285 | attr2attr : attr2attr, 286 | treeTable : treeTable, 287 | appendTreetable : appendTreetable, 288 | jsTreeTable : 'HEAD', 289 | register : function(target){ 290 | $.each(this, function(key, value){ if(key != 'register') target[key] = value}) 291 | } 292 | } 293 | })(); --------------------------------------------------------------------------------