├── .bowerrc
├── .gitattributes
├── .gitignore
├── .jshintrc
├── .travis.yml
├── CHANGELOG.md
├── Gruntfile.js
├── LICENSE
├── README.md
├── app.js
├── bower.json
├── dist
├── bootstrap-treeview.min.css
└── bootstrap-treeview.min.js
├── package.json
├── public
├── css
│ └── bootstrap-treeview.css
├── example-dom.html
├── index.html
└── js
│ └── bootstrap-treeview.js
├── screenshot
└── default.PNG
├── src
├── css
│ └── bootstrap-treeview.css
└── js
│ └── bootstrap-treeview.js
└── tests
├── README.md
├── lib
├── blanket.min.js
├── bootstrap-treeview.css
├── bootstrap-treeview.js
├── jquery.js
├── qunit-1.12.0.css
└── qunit-1.12.0.js
├── tests.html
└── tests.js
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "public/bower_components"
3 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | public/bower_components/
3 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | // Details: https://github.com/victorporof/Sublime-JSHint#using-your-own-jshintrc-options
3 | // Example: https://github.com/jshint/jshint/blob/master/examples/.jshintrc
4 | // Documentation: http://www.jshint.com/docs/
5 | "browser": true,
6 | "esnext": true,
7 | "globals": { $: false, jQuery: false, "console": false},
8 | "globalstrict": true,
9 | "quotmark": "single",
10 | "smarttabs": true,
11 | "trailing": true,
12 | "undef": true,
13 | "unused": true
14 | }
15 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - "0.11"
5 | - "0.10"
6 |
7 | before_script:
8 | - npm install -g grunt-cli
9 | - npm install
10 | - bower install
11 |
12 | script: grunt test --verbose --force
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 | This project adheres to [Semantic Versioning](http://semver.org/).
4 |
5 | ## v1.2.0 - 9th May, 2015
6 |
7 | ### New Features
8 |
9 | - Disable nodes, allow a tree node to disabled (not selectable, expandable or checkable)
10 |
11 | - Added node state property `disabled` to set a node initial state
12 |
13 | - Methods `disableAll`, `disableNode`, `enableAll`, `enableNode` and `toggleNodeDisabled` added to control state programmatically
14 |
15 | - Events `nodeDisabled` and `nodeEnabled`
16 |
17 | - Checkable nodes, allows a tree node to be checked or unchecked.
18 |
19 | - Added node state property `checked` to set a node initial state
20 |
21 | - Pass option `{showCheckbox: true}` to initialize tree view with checkboxes
22 |
23 | - Use options `checkedIcon` and `uncheckedIcon` to configure checkbox icons
24 |
25 | - Methods `checkAll`, `checkNode`, `uncheckAll`, `uncheckNode` and `toggleNodeChecked` to control state programmatically
26 |
27 | - Events `nodeChecked` and `nodeUnchecked`
28 |
29 | - New option + node property `selectedIcon` to support displaying different icons when a node is selected.
30 |
31 | - New search option `{ revealResults : true | false }` which when set to true will automatically expand the tree view to reveal matching nodes
32 |
33 | - New method `revealNode` which expands the tree view to reveal a given node
34 |
35 | - New methods to retrieve nodes by state : `getSelected`, `getUnselected`, `getExpanded`, `getCollapsed`, `getChecked`, `getUnchecked`, `getDisabled` and `getEnabled`
36 |
37 |
38 | ### Changes
39 | - Removed nodeIcon by default, by popular demand. Use `{nodeIcon: 'glyphicon glyphicon-stop'}` in initial options to add a node icon.
40 |
41 | - Search behaviour, by default search will the expand tree view and reveal results. Alternatively pass `{revealResults:false}`
42 |
43 | - Method collapseNode accepts new option `{ ignoreChildren: true | false }`. The default is false, passing true will leave child nodes uncollapsed
44 |
45 |
46 | ### Bug Fixes
47 | - Remove unnecessary render in clearSearch when called from search
48 |
49 | - Child nodes should collapse by default on collapseNode
50 |
51 | - Incorrect expand collapse icon displayed when nodes array is empty
52 |
53 |
54 |
55 |
56 | ## v1.1.0 - 29th March, 2015
57 |
58 | ### New Features
59 |
60 | - Added node state properties `expanded` and `selected` so a node's intial state can be set
61 |
62 | - New get methods `getNode`, `getParent` and `getSiblings` for retrieving nodes and their immediate relations
63 |
64 | - New select methods `selectNode`, `unselectNode` and `toggleNodeSelected`
65 |
66 | - Adding `nodeUnselected` event
67 |
68 | - New global option `multiSelect` which allows multiple nodes to hold the selected state, default is false
69 |
70 | - New expand collapse methods `expandAll`, `collapseAll`, `expandNode`, `collapseNode` and `toggleNodeExpanded`
71 |
72 | - Adding events `nodeExpanded` and `nodeCollapsed`
73 |
74 | - New methods `search` and `clearSearch` which allow you to query the tree view for nodes based on a `text` value
75 |
76 | - Adding events `searchComplete` and `searchCleared`
77 |
78 | - New global options `highlightSearchResults`, `searchResultColor` and `searchResultBackColor` for configuring how search results are displayed
79 |
80 |
81 |
82 |
83 | ## v1.0.2 - 6th February, 2015
84 |
85 | ### Changes
86 | - jQuery dependency version updated in Bower
87 |
88 | ### Bug Fixes
89 | - Events not unbound when re-initialised
90 |
91 | - CSS selectors too general, affecting other page elements
92 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | grunt.initConfig({
3 | pkg: grunt.file.readJSON('package.json'), // the package file to use
4 |
5 | uglify: {
6 | files: {
7 | expand: true,
8 | flatten: true,
9 | src: 'src/js/*.js',
10 | dest: 'dist',
11 | ext: '.min.js'
12 | }
13 | },
14 |
15 | cssmin: {
16 | minify: {
17 | expand: true,
18 | cwd: 'src/css',
19 | src: ['*.css', '!*.min.css'],
20 | dest: 'dist',
21 | ext: '.min.css'
22 | }
23 | },
24 |
25 | qunit: {
26 | all: ['tests/*.html']
27 | },
28 |
29 | watch: {
30 | files: ['tests/*.js', 'tests/*.html', 'src/**'],
31 | tasks: ['default']
32 | },
33 |
34 | copy: {
35 | main: {
36 | files: [
37 | // copy dist to tests
38 | // { expand: true, cwd: 'dist', src: '*', dest: 'tests/lib/' },
39 | { expand: true, cwd: 'src/css', src: '*', dest: 'tests/lib/' },
40 | { expand: true, cwd: 'src/js', src: '*', dest: 'tests/lib/' },
41 | // copy latest libs to tests
42 | { expand: true, cwd: 'public/bower_components/jquery', src: 'jquery.js', dest: 'tests/lib/' },
43 | { expand: true, cwd: 'public/bower_components/bootstrap-datepicker/js', src: 'bootstrap-datepicker.js', dest: 'tests/lib/' },
44 | // copy src to example
45 | { expand: true, cwd: 'src/css', src: '*', dest: 'public/css/' },
46 | { expand: true, cwd: 'src/js', src: '*', dest: 'public/js/' }
47 | ]
48 | }
49 | }
50 | });
51 |
52 | // load up your plugins
53 | grunt.loadNpmTasks('grunt-contrib-uglify');
54 | grunt.loadNpmTasks('grunt-contrib-cssmin');
55 | grunt.loadNpmTasks('grunt-contrib-qunit');
56 | grunt.loadNpmTasks('grunt-contrib-watch');
57 | grunt.loadNpmTasks('grunt-contrib-copy');
58 |
59 | // register one or more task lists (you should ALWAYS have a "default" task list)
60 | grunt.registerTask('default', ['uglify','cssmin', 'copy', 'qunit', 'watch']);
61 | grunt.registerTask('test', 'qunit');
62 | };
63 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Bootstrap Tree View
2 |
3 | ---
4 |
5 | 
6 | [](https://www.npmjs.com/package/bootstrap-treeview)
7 | [](https://travis-ci.org/jonmiles/bootstrap-treeview)
8 |
9 | A simple and elegant solution to displaying hierarchical tree structures (i.e. a Tree View) while leveraging the best that Twitter Bootstrap has to offer.
10 |
11 | 
12 |
13 | ## Dependencies
14 |
15 | Where provided these are the actual versions bootstrap-treeview has been tested against.
16 |
17 | - [Bootstrap v3.3.4 (>= 3.0.0)](http://getbootstrap.com/)
18 | - [jQuery v2.1.3 (>= 1.9.0)](http://jquery.com/)
19 |
20 |
21 | ## Getting Started
22 |
23 | ### Install
24 |
25 | You can install using bower (recommended):
26 |
27 | ```javascript
28 | $ bower install bootstrap-treeview
29 | ```
30 |
31 | or using npm:
32 |
33 | ```javascript
34 | $ npm install bootstrap-treeview
35 | ```
36 |
37 | or [download](https://github.com/jonmiles/bootstrap-treeview/releases/tag/v1.2.0) manually.
38 |
39 |
40 |
41 | ### Usage
42 |
43 | Add the following resources for the bootstrap-treeview to function correctly.
44 |
45 | ```html
46 |
47 |
48 |
49 |
50 |
51 |
52 | ```
53 |
54 | The component will bind to any existing DOM element.
55 |
56 | ```html
57 |
58 | ```
59 |
60 | Basic usage may look something like this.
61 |
62 | ```javascript
63 | function getTree() {
64 | // Some logic to retrieve, or generate tree structure
65 | return data;
66 | }
67 |
68 | $('#tree').treeview({data: getTree()});
69 | ```
70 |
71 |
72 | ## Data Structure
73 |
74 | In order to define the hierarchical structure needed for the tree it's necessary to provide a nested array of JavaScript objects.
75 |
76 | Example
77 |
78 | ```javascript
79 | var tree = [
80 | {
81 | text: "Parent 1",
82 | nodes: [
83 | {
84 | text: "Child 1",
85 | nodes: [
86 | {
87 | text: "Grandchild 1"
88 | },
89 | {
90 | text: "Grandchild 2"
91 | }
92 | ]
93 | },
94 | {
95 | text: "Child 2"
96 | }
97 | ]
98 | },
99 | {
100 | text: "Parent 2"
101 | },
102 | {
103 | text: "Parent 3"
104 | },
105 | {
106 | text: "Parent 4"
107 | },
108 | {
109 | text: "Parent 5"
110 | }
111 | ];
112 | ```
113 |
114 | At the lowest level a tree node is a represented as a simple JavaScript object. This one required property `text` will build you a tree.
115 |
116 | ```javascript
117 | {
118 | text: "Node 1"
119 | }
120 | ```
121 |
122 | If you want to do more, here's the full node specification
123 |
124 | ```javascript
125 | {
126 | text: "Node 1",
127 | icon: "glyphicon glyphicon-stop",
128 | selectedIcon: "glyphicon glyphicon-stop",
129 | color: "#000000",
130 | backColor: "#FFFFFF",
131 | href: "#node-1",
132 | selectable: true,
133 | state: {
134 | checked: true,
135 | disabled: true,
136 | expanded: true,
137 | selected: true
138 | },
139 | tags: ['available'],
140 | nodes: [
141 | {},
142 | ...
143 | ]
144 | }
145 | ```
146 |
147 | ### Node Properties
148 |
149 | The following properties are defined to allow node level overrides, such as node specific icons, colours and tags.
150 |
151 | #### text
152 | `String` `Mandatory`
153 |
154 | The text value displayed for a given tree node, typically to the right of the nodes icon.
155 |
156 | #### icon
157 | `String` `Optional`
158 |
159 | The icon displayed on a given node, typically to the left of the text.
160 |
161 | For simplicity we directly leverage [Bootstraps Glyphicons support](http://getbootstrap.com/components/#glyphicons) and as such you should provide both the base class and individual icon class separated by a space.
162 |
163 | By providing the base class you retain full control over the icons used. If you want to use your own then just add your class to this icon field.
164 |
165 | #### selectedIcon
166 | `String` `Optional`
167 |
168 | The icon displayed on a given node when selected, typically to the left of the text.
169 |
170 | #### color
171 | `String` `Optional`
172 |
173 | The foreground color used on a given node, overrides global color option.
174 |
175 | #### backColor
176 | `String` `Optional`
177 |
178 | The background color used on a given node, overrides global color option.
179 |
180 | #### href
181 | `String` `Optional`
182 |
183 | Used in conjunction with global enableLinks option to specify anchor tag URL on a given node.
184 |
185 | #### selectable
186 | `Boolean` `Default: true`
187 |
188 | Whether or not a node is selectable in the tree. False indicates the node should act as an expansion heading and will not fire selection events.
189 |
190 | #### state
191 | `Object` `Optional`
192 | Describes a node's initial state.
193 |
194 | #### state.checked
195 | `Boolean` `Default: false`
196 |
197 | Whether or not a node is checked, represented by a checkbox style glyphicon.
198 |
199 | #### state.disabled
200 | `Boolean` `Default: false`
201 |
202 | Whether or not a node is disabled (not selectable, expandable or checkable).
203 |
204 | #### state.expanded
205 | `Boolean` `Default: false`
206 |
207 | Whether or not a node is expanded i.e. open. Takes precedence over global option levels.
208 |
209 | #### state.selected
210 | `Boolean` `Default: false`
211 |
212 | Whether or not a node is selected.
213 |
214 | #### tags
215 | `Array of Strings` `Optional`
216 |
217 | Used in conjunction with global showTags option to add additional information to the right of each node; using [Bootstrap Badges](http://getbootstrap.com/components/#badges)
218 |
219 | ### Extendible
220 |
221 | You can extend the node object by adding any number of additional key value pairs that you require for your application. Remember this is the object which will be passed around during selection events.
222 |
223 |
224 |
225 | ## Options
226 |
227 | Options allow you to customise the treeview's default appearance and behaviour. They are passed to the plugin on initialization, as an object.
228 |
229 | ```javascript
230 | // Example: initializing the treeview
231 | // expanded to 5 levels
232 | // with a background color of green
233 | $('#tree').treeview({
234 | data: data, // data is not optional
235 | levels: 5,
236 | backColor: 'green'
237 | });
238 | ```
239 | You can pass a new options object to the treeview at any time but this will have the effect of re-initializing the treeview.
240 |
241 | ### List of Options
242 |
243 | The following is a list of all available options.
244 |
245 | #### data
246 | Array of Objects. No default, expects data
247 |
248 | This is the core data to be displayed by the tree view.
249 |
250 | #### backColor
251 | String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: inherits from Bootstrap.css.
252 |
253 | Sets the default background color used by all nodes, except when overridden on a per node basis in data.
254 |
255 | #### borderColor
256 | String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: inherits from Bootstrap.css.
257 |
258 | Sets the border color for the component; set showBorder to false if you don't want a visible border.
259 |
260 | #### checkedIcon
261 | String, class names(s). Default: "glyphicon glyphicon-check" as defined by [Bootstrap Glyphicons](http://getbootstrap.com/components/#glyphicons)
262 |
263 | Sets the icon to be as a checked checkbox, used in conjunction with showCheckbox.
264 |
265 | #### collapseIcon
266 | String, class name(s). Default: "glyphicon glyphicon-minus" as defined by [Bootstrap Glyphicons](http://getbootstrap.com/components/#glyphicons)
267 |
268 | Sets the icon to be used on a collapsible tree node.
269 |
270 | #### color
271 | String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: inherits from Bootstrap.css.
272 |
273 | Sets the default foreground color used by all nodes, except when overridden on a per node basis in data.
274 |
275 | #### emptyIcon
276 | String, class name(s). Default: "glyphicon" as defined by [Bootstrap Glyphicons](http://getbootstrap.com/components/#glyphicons)
277 |
278 | Sets the icon to be used on a tree node with no child nodes.
279 |
280 | #### enableLinks
281 | Boolean. Default: false
282 |
283 | Whether or not to present node text as a hyperlink. The href value of which must be provided in the data structure on a per node basis.
284 |
285 | #### expandIcon
286 | String, class name(s). Default: "glyphicon glyphicon-plus" as defined by [Bootstrap Glyphicons](http://getbootstrap.com/components/#glyphicons)
287 |
288 | Sets the icon to be used on an expandable tree node.
289 |
290 | #### highlightSearchResults
291 | Boolean. Default: true
292 |
293 | Whether or not to highlight search results.
294 |
295 | #### highlightSelected
296 | Boolean. Default: true
297 |
298 | Whether or not to highlight the selected node.
299 |
300 | #### levels
301 | Integer. Default: 2
302 |
303 | Sets the number of hierarchical levels deep the tree will be expanded to by default.
304 |
305 | #### multiSelect
306 | Boolean. Default: false
307 |
308 | Whether or not multiple nodes can be selected at the same time.
309 |
310 | #### nodeIcon
311 | String, class name(s). Default: "glyphicon glyphicon-stop" as defined by [Bootstrap Glyphicons](http://getbootstrap.com/components/#glyphicons)
312 |
313 | Sets the default icon to be used on all nodes, except when overridden on a per node basis in data.
314 |
315 | #### onhoverColor
316 | String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: '#F5F5F5'.
317 |
318 | Sets the default background color activated when the users cursor hovers over a node.
319 |
320 | #### selectedIcon
321 | String, class name(s). Default: "glyphicon glyphicon-stop" as defined by [Bootstrap Glyphicons](http://getbootstrap.com/components/#glyphicons)
322 |
323 | Sets the default icon to be used on all selected nodes, except when overridden on a per node basis in data.
324 |
325 | #### searchResultBackColor
326 | String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: undefined, inherits.
327 |
328 | Sets the background color of the selected node.
329 |
330 | #### searchResultColor
331 | String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: '#D9534F'.
332 |
333 | Sets the foreground color of the selected node.
334 |
335 | #### selectedBackColor
336 | String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: '#428bca'.
337 |
338 | Sets the background color of the selected node.
339 |
340 | #### selectedColor
341 | String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: '#FFFFFF'.
342 |
343 | Sets the foreground color of the selected node.
344 |
345 | #### showBorder
346 | Boolean. Default: true
347 |
348 | Whether or not to display a border around nodes.
349 |
350 | #### showCheckbox
351 | Boolean. Default: false
352 |
353 | Whether or not to display checkboxes on nodes.
354 |
355 | #### showIcon
356 | Boolean. Default: true
357 |
358 | Whether or not to display a nodes icon.
359 |
360 | #### showTags
361 | Boolean. Default: false
362 |
363 | Whether or not to display tags to the right of each node. The values of which must be provided in the data structure on a per node basis.
364 |
365 | #### uncheckedIcon
366 | String, class names(s). Default: "glyphicon glyphicon-unchecked" as defined by [Bootstrap Glyphicons](http://getbootstrap.com/components/#glyphicons)
367 |
368 | Sets the icon to be as an unchecked checkbox, used in conjunction with showCheckbox.
369 |
370 |
371 | ## Methods
372 |
373 | Methods provide a way of interacting with the plugin programmatically. For example, expanding a node is possible via the expandNode method.
374 |
375 | You can invoke methods in one of two ways, using either:
376 |
377 | #### 1. The plugin's wrapper
378 |
379 | The plugin's wrapper works as a proxy for accessing the underlying methods.
380 |
381 | ```javascript
382 | $('#tree').treeview('methodName', args)
383 | ```
384 | > Limitation, multiple arguments must be passed as an array of arguments.
385 |
386 | #### 2. The treeview directly
387 |
388 | You can get an instance of the treeview using one of the two following methods.
389 |
390 | ```javascript
391 | // This special method returns an instance of the treeview.
392 | $('#tree').treeview(true)
393 | .methodName(args);
394 |
395 | // The instance is also saved in the DOM elements data,
396 | // and accessible using the plugin's id 'treeview'.
397 | $('#tree').data('treeview')
398 | .methodName(args);
399 | ```
400 | > A better approach, if you plan a lot of interaction.
401 |
402 | ### List of Methods
403 |
404 | The following is a list of all available methods.
405 |
406 | #### checkAll(options)
407 |
408 | Checks all tree nodes
409 |
410 | ```javascript
411 | $('#tree').treeview('checkAll', { silent: true });
412 | ```
413 |
414 | Triggers `nodeChecked` event; pass silent to suppress events.
415 |
416 | #### checkNode(node | nodeId, options)
417 |
418 | Checks a given tree node, accepts node or nodeId.
419 |
420 | ```javascript
421 | $('#tree').treeview('checkNode', [ nodeId, { silent: true } ]);
422 | ```
423 |
424 | Triggers `nodeChecked` event; pass silent to suppress events.
425 |
426 | #### clearSearch()
427 |
428 | Clear the tree view of any previous search results e.g. remove their highlighted state.
429 |
430 | ```javascript
431 | $('#tree').treeview('clearSearch');
432 | ```
433 |
434 | Triggers `searchCleared` event
435 |
436 | #### collapseAll(options)
437 |
438 | Collapse all tree nodes, collapsing the entire tree.
439 |
440 | ```javascript
441 | $('#tree').treeview('collapseAll', { silent: true });
442 | ```
443 |
444 | Triggers `nodeCollapsed` event; pass silent to suppress events.
445 |
446 | #### collapseNode(node | nodeId, options)
447 |
448 | Collapse a given tree node and it's child nodes. If you don't want to collapse the child nodes, pass option `{ ignoreChildren: true }`.
449 |
450 | ```javascript
451 | $('#tree').treeview('collapseNode', [ nodeId, { silent: true, ignoreChildren: false } ]);
452 | ```
453 |
454 | Triggers `nodeCollapsed` event; pass silent to suppress events.
455 |
456 | #### disableAll(options)
457 |
458 | Disable all tree nodes
459 |
460 | ```javascript
461 | $('#tree').treeview('disableAll', { silent: true });
462 | ```
463 |
464 | Triggers `nodeDisabled` event; pass silent to suppress events.
465 |
466 | #### disableNode(node | nodeId, options)
467 |
468 | Disable a given tree node, accepts node or nodeId.
469 |
470 | ```javascript
471 | $('#tree').treeview('disableNode', [ nodeId, { silent: true } ]);
472 | ```
473 |
474 | Triggers `nodeDisabled` event; pass silent to suppress events.
475 |
476 | #### enableAll(options)
477 |
478 | Enable all tree nodes
479 |
480 | ```javascript
481 | $('#tree').treeview('enableAll', { silent: true });
482 | ```
483 |
484 | Triggers `nodeEnabled` event; pass silent to suppress events.
485 |
486 | #### enableNode(node | nodeId, options)
487 |
488 | Enable a given tree node, accepts node or nodeId.
489 |
490 | ```javascript
491 | $('#tree').treeview('enableNode', [ nodeId, { silent: true } ]);
492 | ```
493 |
494 | Triggers `nodeEnabled` event; pass silent to suppress events.
495 |
496 | #### expandAll(options)
497 |
498 | Expand all tree nodes. Optionally can be expanded to any given number of levels.
499 |
500 | ```javascript
501 | $('#tree').treeview('expandAll', { levels: 2, silent: true });
502 | ```
503 |
504 | Triggers `nodeExpanded` event; pass silent to suppress events.
505 |
506 | #### expandNode(node | nodeId, options)
507 |
508 | Expand a given tree node, accepts node or nodeId. Optionally can be expanded to any given number of levels.
509 |
510 | ```javascript
511 | $('#tree').treeview('expandNode', [ nodeId, { levels: 2, silent: true } ]);
512 | ```
513 |
514 | Triggers `nodeExpanded` event; pass silent to suppress events.
515 |
516 | #### getCollapsed()
517 |
518 | Returns an array of collapsed nodes e.g. state.expanded = false.
519 |
520 | ```javascript
521 | $('#tree').treeview('getCollapsed', nodeId);
522 | ```
523 |
524 | #### getDisabled()
525 |
526 | Returns an array of disabled nodes e.g. state.disabled = true.
527 |
528 | ```javascript
529 | $('#tree').treeview('getDisabled', nodeId);
530 | ```
531 |
532 | #### getEnabled()
533 |
534 | Returns an array of enabled nodes e.g. state.disabled = false.
535 |
536 | ```javascript
537 | $('#tree').treeview('getEnabled', nodeId);
538 | ```
539 |
540 | #### getExpanded()
541 |
542 | Returns an array of expanded nodes e.g. state.expanded = true.
543 |
544 | ```javascript
545 | $('#tree').treeview('getExpanded', nodeId);
546 | ```
547 |
548 | #### getNode(nodeId)
549 |
550 | Returns a single node object that matches the given node id.
551 |
552 | ```javascript
553 | $('#tree').treeview('getNode', nodeId);
554 | ```
555 |
556 | #### getParent(node | nodeId)
557 |
558 | Returns the parent node of a given node, if valid otherwise returns undefined.
559 |
560 | ```javascript
561 | $('#tree').treeview('getParent', node);
562 | ```
563 |
564 | #### getSelected()
565 |
566 | Returns an array of selected nodes e.g. state.selected = true.
567 |
568 | ```javascript
569 | $('#tree').treeview('getSelected', nodeId);
570 | ```
571 |
572 | #### getSiblings(node | nodeId)
573 |
574 | Returns an array of sibling nodes for a given node, if valid otherwise returns undefined.
575 |
576 | ```javascript
577 | $('#tree').treeview('getSiblings', node);
578 | ```
579 |
580 | #### getUnselected()
581 |
582 | Returns an array of unselected nodes e.g. state.selected = false.
583 |
584 | ```javascript
585 | $('#tree').treeview('getUnselected', nodeId);
586 | ```
587 |
588 | #### remove()
589 |
590 | Removes the tree view component. Removing attached events, internal attached objects, and added HTML elements.
591 |
592 | ```javascript
593 | $('#tree').treeview('remove');
594 | ```
595 |
596 | #### revealNode(node | nodeId, options)
597 |
598 | Reveals a given tree node, expanding the tree from node to root.
599 |
600 | ```javascript
601 | $('#tree').treeview('revealNode', [ nodeId, { silent: true } ]);
602 | ```
603 |
604 | Triggers `nodeExpanded` event; pass silent to suppress events.
605 |
606 | #### search(pattern, options)
607 |
608 | Searches the tree view for nodes that match a given string, highlighting them in the tree.
609 |
610 | Returns an array of matching nodes.
611 |
612 | ```javascript
613 | $('#tree').treeview('search', [ 'Parent', {
614 | ignoreCase: true, // case insensitive
615 | exactMatch: false, // like or equals
616 | revealResults: true, // reveal matching nodes
617 | }]);
618 | ```
619 |
620 | Triggers `searchComplete` event
621 |
622 | #### selectNode(node | nodeId, options)
623 |
624 | Selects a given tree node, accepts node or nodeId.
625 |
626 | ```javascript
627 | $('#tree').treeview('selectNode', [ nodeId, { silent: true } ]);
628 | ```
629 |
630 | Triggers `nodeSelected` event; pass silent to suppress events.
631 |
632 | #### toggleNodeChecked(node | nodeId, options)
633 |
634 | Toggles a nodes checked state; checking if unchecked, unchecking if checked.
635 |
636 | ```javascript
637 | $('#tree').treeview('toggleNodeChecked', [ nodeId, { silent: true } ]);
638 | ```
639 |
640 | Triggers either `nodeChecked` or `nodeUnchecked` event; pass silent to suppress events.
641 |
642 | #### toggleNodeDisabled(node | nodeId, options)
643 |
644 | Toggles a nodes disabled state; disabling if enabled, enabling if disabled.
645 |
646 | ```javascript
647 | $('#tree').treeview('toggleNodeDisabled', [ nodeId, { silent: true } ]);
648 | ```
649 |
650 | Triggers either `nodeDisabled` or `nodeEnabled` event; pass silent to suppress events.
651 |
652 | #### toggleNodeExpanded(node | nodeId, options)
653 |
654 | Toggles a nodes expanded state; collapsing if expanded, expanding if collapsed.
655 |
656 | ```javascript
657 | $('#tree').treeview('toggleNodeExpanded', [ nodeId, { silent: true } ]);
658 | ```
659 |
660 | Triggers either `nodeExpanded` or `nodeCollapsed` event; pass silent to suppress events.
661 |
662 | #### toggleNodeSelected(node | nodeId, options)
663 |
664 | Toggles a node selected state; selecting if unselected, unselecting if selected.
665 |
666 | ```javascript
667 | $('#tree').treeview('toggleNodeSelected', [ nodeId, { silent: true } ]);
668 | ```
669 |
670 | Triggers either `nodeSelected` or `nodeUnselected` event; pass silent to suppress events.
671 |
672 | #### uncheckAll(options)
673 |
674 | Uncheck all tree nodes.
675 |
676 | ```javascript
677 | $('#tree').treeview('uncheckAll', { silent: true });
678 | ```
679 |
680 | Triggers `nodeUnchecked` event; pass silent to suppress events.
681 |
682 | #### uncheckNode(node | nodeId, options)
683 |
684 | Uncheck a given tree node, accepts node or nodeId.
685 |
686 | ```javascript
687 | $('#tree').treeview('uncheckNode', [ nodeId, { silent: true } ]);
688 | ```
689 |
690 | Triggers `nodeUnchecked` event; pass silent to suppress events.
691 |
692 | #### unselectNode(node | nodeId, options)
693 |
694 | Unselects a given tree node, accepts node or nodeId.
695 |
696 | ```javascript
697 | $('#tree').treeview('unselectNode', [ nodeId, { silent: true } ]);
698 | ```
699 |
700 | Triggers `nodeUnselected` event; pass silent to suppress events.
701 |
702 | ## Events
703 |
704 | Events are provided so that your application can respond to changes in the treeview's state. For example, if you want to update a display when a node is selected use the `nodeSelected` event.
705 |
706 | You can bind to any event defined below by either using an options callback handler, or the standard jQuery .on method.
707 |
708 | Example using options callback handler:
709 |
710 | ```javascript
711 | $('#tree').treeview({
712 | // The naming convention for callback's is to prepend with `on`
713 | // and capitalize the first letter of the event name
714 | // e.g. nodeSelected -> onNodeSelected
715 | onNodeSelected: function(event, data) {
716 | // Your logic goes here
717 | });
718 | ```
719 |
720 | and using jQuery .on method
721 |
722 | ```javascript
723 | $('#tree').on('nodeSelected', function(event, data) {
724 | // Your logic goes here
725 | });
726 | ```
727 |
728 | ### List of Events
729 |
730 | `nodeChecked (event, node)` - A node is checked.
731 |
732 | `nodeCollapsed (event, node)` - A node is collapsed.
733 |
734 | `nodeDisabled (event, node)` - A node is disabled.
735 |
736 | `nodeEnabled (event, node)` - A node is enabled.
737 |
738 | `nodeExpanded (event, node)` - A node is expanded.
739 |
740 | `nodeSelected (event, node)` - A node is selected.
741 |
742 | `nodeUnchecked (event, node)` - A node is unchecked.
743 |
744 | `nodeUnselected (event, node)` - A node is unselected.
745 |
746 | `searchComplete (event, results)` - After a search completes
747 |
748 | `searchCleared (event, results)` - After search results are cleared
749 |
750 |
751 |
752 | ## Copyright and Licensing
753 | Copyright 2013 Jonathan Miles
754 |
755 | Licensed under the Apache License, Version 2.0 (the "License");
756 | you may not use this file except in compliance with the License.
757 | You may obtain a copy of the License at
758 |
759 | Unless required by applicable law or agreed to in writing, software
760 | distributed under the License is distributed on an "AS IS" BASIS,
761 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
762 | See the License for the specific language governing permissions and
763 | limitations under the License.
764 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Module dependencies.
4 | */
5 |
6 | var express = require('express');
7 | var http = require('http');
8 | var path = require('path');
9 |
10 | var app = express();
11 |
12 | // all environments
13 | app.set('port', process.env.PORT || 3000);
14 | app.use(express.favicon());
15 | app.use(express.logger('dev'));
16 | app.use(express.json());
17 | app.use(express.urlencoded());
18 | app.use(express.methodOverride());
19 | app.use(express.static(path.join(__dirname, '/public')));
20 | app.use(express.static(path.join(__dirname, '/tests')));
21 |
22 | // development only
23 | if ('development' == app.get('env')) {
24 | app.use(express.errorHandler());
25 | }
26 |
27 | http.createServer(app).listen(app.get('port'), function(){
28 | console.log('Express server listening on port ' + app.get('port'));
29 | });
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap-treeview",
3 | "description": "Tree View for Twitter Bootstrap",
4 | "version": "1.2.0",
5 | "homepage": "https://github.com/jonmiles/bootstrap-treeview",
6 | "main": [
7 | "dist/bootstrap-treeview.min.js",
8 | "dist/bootstrap-treeview.min.css"
9 | ],
10 | "keywords": [
11 | "twitter",
12 | "bootstrap",
13 | "tree",
14 | "treeview",
15 | "tree-view",
16 | "navigation",
17 | "javascript",
18 | "jquery",
19 | "jquery-plugin"
20 | ],
21 | "ignore": [
22 | "**/.*",
23 | "node_modules",
24 | "bower_components",
25 | "test",
26 | "tests"
27 | ],
28 | "dependencies": {
29 | "jquery": ">= 1.9.0",
30 | "bootstrap": ">= 3.0.0"
31 | },
32 | "devDependencies": {}
33 | }
34 |
--------------------------------------------------------------------------------
/dist/bootstrap-treeview.min.css:
--------------------------------------------------------------------------------
1 | .treeview .list-group-item{cursor:pointer}.treeview span.indent{margin-left:10px;margin-right:10px}.treeview span.icon{width:12px;margin-right:5px}.treeview .node-disabled{color:silver;cursor:not-allowed}
--------------------------------------------------------------------------------
/dist/bootstrap-treeview.min.js:
--------------------------------------------------------------------------------
1 | !function(a,b,c,d){"use strict";var e="treeview",f={};f.settings={injectStyle:!0,levels:2,expandIcon:"glyphicon glyphicon-plus",collapseIcon:"glyphicon glyphicon-minus",emptyIcon:"glyphicon",nodeIcon:"",selectedIcon:"",checkedIcon:"glyphicon glyphicon-check",uncheckedIcon:"glyphicon glyphicon-unchecked",color:d,backColor:d,borderColor:d,onhoverColor:"#F5F5F5",selectedColor:"#FFFFFF",selectedBackColor:"#428bca",searchResultColor:"#D9534F",searchResultBackColor:d,enableLinks:!1,highlightSelected:!0,highlightSearchResults:!0,showBorder:!0,showIcon:!0,showCheckbox:!1,showTags:!1,multiSelect:!1,onNodeChecked:d,onNodeCollapsed:d,onNodeDisabled:d,onNodeEnabled:d,onNodeExpanded:d,onNodeSelected:d,onNodeUnchecked:d,onNodeUnselected:d,onSearchComplete:d,onSearchCleared:d},f.options={silent:!1,ignoreChildren:!1},f.searchOptions={ignoreCase:!0,exactMatch:!1,revealResults:!0};var g=function(b,c){return this.$element=a(b),this.elementId=b.id,this.styleId=this.elementId+"-style",this.init(c),{options:this.options,init:a.proxy(this.init,this),remove:a.proxy(this.remove,this),getNode:a.proxy(this.getNode,this),getParent:a.proxy(this.getParent,this),getSiblings:a.proxy(this.getSiblings,this),getSelected:a.proxy(this.getSelected,this),getUnselected:a.proxy(this.getUnselected,this),getExpanded:a.proxy(this.getExpanded,this),getCollapsed:a.proxy(this.getCollapsed,this),getChecked:a.proxy(this.getChecked,this),getUnchecked:a.proxy(this.getUnchecked,this),getDisabled:a.proxy(this.getDisabled,this),getEnabled:a.proxy(this.getEnabled,this),selectNode:a.proxy(this.selectNode,this),unselectNode:a.proxy(this.unselectNode,this),toggleNodeSelected:a.proxy(this.toggleNodeSelected,this),collapseAll:a.proxy(this.collapseAll,this),collapseNode:a.proxy(this.collapseNode,this),expandAll:a.proxy(this.expandAll,this),expandNode:a.proxy(this.expandNode,this),toggleNodeExpanded:a.proxy(this.toggleNodeExpanded,this),revealNode:a.proxy(this.revealNode,this),checkAll:a.proxy(this.checkAll,this),checkNode:a.proxy(this.checkNode,this),uncheckAll:a.proxy(this.uncheckAll,this),uncheckNode:a.proxy(this.uncheckNode,this),toggleNodeChecked:a.proxy(this.toggleNodeChecked,this),disableAll:a.proxy(this.disableAll,this),disableNode:a.proxy(this.disableNode,this),enableAll:a.proxy(this.enableAll,this),enableNode:a.proxy(this.enableNode,this),toggleNodeDisabled:a.proxy(this.toggleNodeDisabled,this),search:a.proxy(this.search,this),clearSearch:a.proxy(this.clearSearch,this)}};g.prototype.init=function(b){this.tree=[],this.nodes=[],b.data&&("string"==typeof b.data&&(b.data=a.parseJSON(b.data)),this.tree=a.extend(!0,[],b.data),delete b.data),this.options=a.extend({},f.settings,b),this.destroy(),this.subscribeEvents(),this.setInitialStates({nodes:this.tree},0),this.render()},g.prototype.remove=function(){this.destroy(),a.removeData(this,e),a("#"+this.styleId).remove()},g.prototype.destroy=function(){this.initialized&&(this.$wrapper.remove(),this.$wrapper=null,this.unsubscribeEvents(),this.initialized=!1)},g.prototype.unsubscribeEvents=function(){this.$element.off("click"),this.$element.off("nodeChecked"),this.$element.off("nodeCollapsed"),this.$element.off("nodeDisabled"),this.$element.off("nodeEnabled"),this.$element.off("nodeExpanded"),this.$element.off("nodeSelected"),this.$element.off("nodeUnchecked"),this.$element.off("nodeUnselected"),this.$element.off("searchComplete"),this.$element.off("searchCleared")},g.prototype.subscribeEvents=function(){this.unsubscribeEvents(),this.$element.on("click",a.proxy(this.clickHandler,this)),"function"==typeof this.options.onNodeChecked&&this.$element.on("nodeChecked",this.options.onNodeChecked),"function"==typeof this.options.onNodeCollapsed&&this.$element.on("nodeCollapsed",this.options.onNodeCollapsed),"function"==typeof this.options.onNodeDisabled&&this.$element.on("nodeDisabled",this.options.onNodeDisabled),"function"==typeof this.options.onNodeEnabled&&this.$element.on("nodeEnabled",this.options.onNodeEnabled),"function"==typeof this.options.onNodeExpanded&&this.$element.on("nodeExpanded",this.options.onNodeExpanded),"function"==typeof this.options.onNodeSelected&&this.$element.on("nodeSelected",this.options.onNodeSelected),"function"==typeof this.options.onNodeUnchecked&&this.$element.on("nodeUnchecked",this.options.onNodeUnchecked),"function"==typeof this.options.onNodeUnselected&&this.$element.on("nodeUnselected",this.options.onNodeUnselected),"function"==typeof this.options.onSearchComplete&&this.$element.on("searchComplete",this.options.onSearchComplete),"function"==typeof this.options.onSearchCleared&&this.$element.on("searchCleared",this.options.onSearchCleared)},g.prototype.setInitialStates=function(b,c){if(b.nodes){c+=1;var d=b,e=this;a.each(b.nodes,function(a,b){b.nodeId=e.nodes.length,b.parentId=d.nodeId,b.hasOwnProperty("selectable")||(b.selectable=!0),b.state=b.state||{},b.state.hasOwnProperty("checked")||(b.state.checked=!1),b.state.hasOwnProperty("disabled")||(b.state.disabled=!1),b.state.hasOwnProperty("expanded")||(!b.state.disabled&&c0?b.state.expanded=!0:b.state.expanded=!1),b.state.hasOwnProperty("selected")||(b.state.selected=!1),e.nodes.push(b),b.nodes&&e.setInitialStates(b,c)})}},g.prototype.clickHandler=function(b){this.options.enableLinks||b.preventDefault();var c=a(b.target),d=this.findNode(c);if(d&&!d.state.disabled){var e=c.attr("class")?c.attr("class").split(" "):[];-1!==e.indexOf("expand-icon")?(this.toggleExpandedState(d,f.options),this.render()):-1!==e.indexOf("check-icon")?(this.toggleCheckedState(d,f.options),this.render()):(d.selectable?this.toggleSelectedState(d,f.options):this.toggleExpandedState(d,f.options),this.render())}},g.prototype.findNode=function(a){var b=a.closest("li.list-group-item").attr("data-nodeid"),c=this.nodes[b];return c||console.log("Error: node does not exist"),c},g.prototype.toggleExpandedState=function(a,b){a&&this.setExpandedState(a,!a.state.expanded,b)},g.prototype.setExpandedState=function(b,c,d){c!==b.state.expanded&&(c&&b.nodes?(b.state.expanded=!0,d.silent||this.$element.trigger("nodeExpanded",a.extend(!0,{},b))):c||(b.state.expanded=!1,d.silent||this.$element.trigger("nodeCollapsed",a.extend(!0,{},b)),b.nodes&&!d.ignoreChildren&&a.each(b.nodes,a.proxy(function(a,b){this.setExpandedState(b,!1,d)},this))))},g.prototype.toggleSelectedState=function(a,b){a&&this.setSelectedState(a,!a.state.selected,b)},g.prototype.setSelectedState=function(b,c,d){c!==b.state.selected&&(c?(this.options.multiSelect||a.each(this.findNodes("true","g","state.selected"),a.proxy(function(a,b){this.setSelectedState(b,!1,d)},this)),b.state.selected=!0,d.silent||this.$element.trigger("nodeSelected",a.extend(!0,{},b))):(b.state.selected=!1,d.silent||this.$element.trigger("nodeUnselected",a.extend(!0,{},b))))},g.prototype.toggleCheckedState=function(a,b){a&&this.setCheckedState(a,!a.state.checked,b)},g.prototype.setCheckedState=function(b,c,d){c!==b.state.checked&&(c?(b.state.checked=!0,d.silent||this.$element.trigger("nodeChecked",a.extend(!0,{},b))):(b.state.checked=!1,d.silent||this.$element.trigger("nodeUnchecked",a.extend(!0,{},b))))},g.prototype.setDisabledState=function(b,c,d){c!==b.state.disabled&&(c?(b.state.disabled=!0,this.setExpandedState(b,!1,d),this.setSelectedState(b,!1,d),this.setCheckedState(b,!1,d),d.silent||this.$element.trigger("nodeDisabled",a.extend(!0,{},b))):(b.state.disabled=!1,d.silent||this.$element.trigger("nodeEnabled",a.extend(!0,{},b))))},g.prototype.render=function(){this.initialized||(this.$element.addClass(e),this.$wrapper=a(this.template.list),this.injectStyle(),this.initialized=!0),this.$element.empty().append(this.$wrapper.empty()),this.buildTree(this.tree,0)},g.prototype.buildTree=function(b,c){if(b){c+=1;var d=this;a.each(b,function(b,e){for(var f=a(d.template.item).addClass("node-"+d.elementId).addClass(e.state.checked?"node-checked":"").addClass(e.state.disabled?"node-disabled":"").addClass(e.state.selected?"node-selected":"").addClass(e.searchResult?"search-result":"").attr("data-nodeid",e.nodeId).attr("style",d.buildStyleOverride(e)),g=0;c-1>g;g++)f.append(d.template.indent);var h=[];if(e.nodes?(h.push("expand-icon"),h.push(e.state.expanded?d.options.collapseIcon:d.options.expandIcon)):h.push(d.options.emptyIcon),f.append(a(d.template.icon).addClass(h.join(" "))),d.options.showIcon){var h=["node-icon"];h.push(e.icon||d.options.nodeIcon),e.state.selected&&(h.pop(),h.push(e.selectedIcon||d.options.selectedIcon||e.icon||d.options.nodeIcon)),f.append(a(d.template.icon).addClass(h.join(" ")))}if(d.options.showCheckbox){var h=["check-icon"];h.push(e.state.checked?d.options.checkedIcon:d.options.uncheckedIcon),f.append(a(d.template.icon).addClass(h.join(" ")))}return f.append(d.options.enableLinks?a(d.template.link).attr("href",e.href).append(e.text):e.text),d.options.showTags&&e.tags&&a.each(e.tags,function(b,c){f.append(a(d.template.badge).append(c))}),d.$wrapper.append(f),e.nodes&&e.state.expanded&&!e.state.disabled?d.buildTree(e.nodes,c):void 0})}},g.prototype.buildStyleOverride=function(a){if(a.state.disabled)return"";var b=a.color,c=a.backColor;return this.options.highlightSelected&&a.state.selected&&(this.options.selectedColor&&(b=this.options.selectedColor),this.options.selectedBackColor&&(c=this.options.selectedBackColor)),this.options.highlightSearchResults&&a.searchResult&&!a.state.disabled&&(this.options.searchResultColor&&(b=this.options.searchResultColor),this.options.searchResultBackColor&&(c=this.options.searchResultBackColor)),"color:"+b+";background-color:"+c+";"},g.prototype.injectStyle=function(){this.options.injectStyle&&!c.getElementById(this.styleId)&&a('").appendTo("head")},g.prototype.buildStyle=function(){var a=".node-"+this.elementId+"{";return this.options.color&&(a+="color:"+this.options.color+";"),this.options.backColor&&(a+="background-color:"+this.options.backColor+";"),this.options.showBorder?this.options.borderColor&&(a+="border:1px solid "+this.options.borderColor+";"):a+="border:none;",a+="}",this.options.onhoverColor&&(a+=".node-"+this.elementId+":not(.node-disabled):hover{background-color:"+this.options.onhoverColor+";}"),this.css+a},g.prototype.template={list:'