2b41b3a831b628b3cc46e5b550e84aedeb5cdd7b
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Resources / Public / JavaScript / tree.js
1 /*
2 * This file is part of the TYPO3 CMS project.
3 *
4 * It is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License, either version 2
6 * of the License, or any later version.
7 *
8 * For the full copyright and license information, please read the
9 * LICENSE.txt file that was distributed with this source code.
10 *
11 * The TYPO3 project - inspiring people to share!
12 */
13
14 Ext.ns('TYPO3.Components', 'TYPO3.Components.Tree');
15
16 /**
17 * TYPO3window - General TYPO3 tree component
18 */
19
20 TYPO3.Components.Tree = {};
21 TYPO3.Components.Tree.StandardTreeItemData = [];
22
23 TYPO3.Components.Tree.StandardTree = function(config) {
24 var conf = Ext.apply({
25 header: false,
26 width: 280,
27 rootVisible: false,
28 useArrows: false,
29 lines: true,
30 autoScroll: true,
31 containerScroll: true,
32 exclusiveSelectedKey: null,
33 stateful: true,
34 filterOptionStartsWith: true,
35 countSelectedNodes: 0,
36 loader: new Ext.tree.TreeLoader({
37 preloadChildren: true,
38 clearOnLoad: false
39 }),
40 root: new Ext.tree.AsyncTreeNode({
41 text: TYPO3.l10n.localize('tcatree'),
42 id: 'root',
43 expanded: true,
44 children: TYPO3.Components.Tree.StandardTreeItemData[config.id]
45 }),
46 collapseFirst: false,
47 listeners: {
48 'checkchange': function(checkedNode, checked) {
49 if (Ext.isFunction(this.checkChangeHandler)) {
50 this.checkChangeHandler.call(this, checkedNode, checked);
51 }
52 },
53 scope: this
54 }
55 }, config);
56 TYPO3.Components.Tree.StandardTree.superclass.constructor.call(this, conf);
57 };
58
59
60 Ext.extend(TYPO3.Components.Tree.StandardTree, Ext.tree.TreePanel, {
61
62 initComponent: function() {
63 Ext.apply(this, {
64 tbar: this.initialConfig.showHeader ? TYPO3.Components.Tree.Toolbar([], this) : null
65 });
66 TYPO3.Components.Tree.StandardTree.superclass.initComponent.call(this);
67 },
68 filterTree: function(filterText) {
69 var text = filterText.getValue();
70 Ext.each(this.hiddenNodes, function(node) {
71 node.ui.show();
72 node.ui.removeClass('bgColor6');
73 });
74 if (!text) {
75 this.filter.clear();
76 return;
77 }
78 this.expandAll();
79 var regText = (this.filterOptionStartsWith ? '^' : '') + Ext.escapeRe(text);
80 var re = new RegExp(regText, 'i');
81
82 // hide empty nodes that weren't filtered
83 this.hiddenNodes = [];
84 var me = this;
85 this.root.cascade(function(node) {
86 if (node.ui.ctNode.offsetHeight < 3) {
87 if (!re.test(node.text)) {
88 node.ui.hide();
89 me.hiddenNodes.push(node);
90 } else {
91 node.ui.addClass('bgColor6');
92 }
93 }
94 }, this);
95 }
96 });
97
98 TYPO3.Components.Tree.Toolbar = function(items, scope) {
99 items = items || [];
100 items.push([
101 ' ',
102 {
103 iconCls: 'icon-tree-search-open',
104 menu: {
105 items: [
106 {
107 text: TYPO3.l10n.localize('tcatree.filter.startsWith'),
108 checked: true,
109 group: 'searchStartsWith',
110 handler: function(item) {
111 scope.filterOptionStartsWith = true;
112 scope.filterTree(scope.getTopToolbar().getComponent('filterText'));
113 },
114 scope: scope
115 },
116 {
117 text: TYPO3.l10n.localize('tcatree.filter.contains'),
118 checked: false,
119 group: 'searchStartsWith',
120 handler: function(item) {
121 scope.filterOptionStartsWith = false;
122 scope.filterTree(scope.getTopToolbar().getComponent('filterText'));
123 },
124 scope: scope
125 }
126 ]
127 }
128 },
129 new Ext.form.TextField({
130 width: 150,
131 emptyText: TYPO3.l10n.localize('tcatree.findItem'),
132 enableKeyEvents: true,
133 itemId: 'filterText',
134 listeners:{
135 render: function(f) {
136 this.filter = new Ext.tree.TreeFilter(this, {
137 clearBlank: true,
138 autoClear: true
139 });
140 },
141 keydown: {
142 fn: scope.filterTree,
143 buffer: 350,
144 scope: scope
145 },
146 scope: scope
147 }
148 }),
149 '->',
150 {
151 iconCls: 'icon-select-recursive',
152 tooltip: TYPO3.lang['tcatree.enableRecursiveSelection'],
153 enableToggle: true,
154 disable: scope.tcaSelectRecursive,
155 toggleHandler: function(btn, state) {
156 this.tcaSelectRecursive = state;
157 },
158 scope: scope
159 },
160 {
161 iconCls: 'icon-expand-all',
162 tooltip: TYPO3.l10n.localize('tcatree.expandAll'),
163 handler: function() {
164 this.root.expand(true);
165 },
166 scope: scope
167 }, {
168 iconCls: 'icon-collapse-all',
169 tooltip: TYPO3.l10n.localize('tcatree.collapseAll'),
170 handler: function() {
171 this.root.collapse(true);
172 },
173 scope: scope
174 }
175 ]);
176 return items;
177 };
178
179 TYPO3.Components.Tree.EmptySelectionModel = new Ext.tree.DefaultSelectionModel({
180 select: Ext.emptyFn
181 })
182
183 TYPO3.Components.Tree.TcaCheckChangeHandler = function(checkedNode, checked) {
184 var exclusiveKeys = this.tcaExclusiveKeys.split(','),
185 uid = '' + checkedNode.attributes.uid;
186
187 this.suspendEvents();
188
189 if (this.tcaExclusiveKeys.length) {
190 if (checked === true && exclusiveKeys.indexOf(uid) > -1) {
191 // this key is exclusive, so uncheck all others
192 this.root.cascade(function(node) {
193 if (node !== checkedNode && node.attributes.checked) {
194 node.attributes.checked = false;
195 node.ui.toggleCheck(false);
196 }
197 });
198 this.exclusiveSelectedKey = uid;
199 } else if (checked === true && exclusiveKeys.indexOf(uid) === -1 && !Ext.isEmpty(this.exclusiveSelectedKey)) {
200 // this key is exclusive, so uncheck all others
201 this.root.cascade(function(node) {
202 if (exclusiveKeys.indexOf('' + node.attributes.uid) > -1) {
203 node.attributes.checked = false;
204 node.ui.toggleCheck(false);
205 }
206 });
207 this.exclusiveSelectedKey = null;
208 }
209 }
210
211 if (checked === true && this.countSelectedNodes >= this.tcaMaxItems) {
212 checkedNode.attributes.checked = false;
213 checkedNode.getUI().toggleCheck(false);
214 this.resumeEvents();
215 return false;
216 }
217 if (checked) {
218 checkedNode.getUI().addClass('complete');
219 } else {
220 checkedNode.getUI().removeClass('complete');
221 }
222 // if recursive selection is asked, hand over selection
223 if(this.tcaSelectRecursive) {
224 checkedNode.cascade(function(node) {
225 node.attributes.checked = checkedNode.attributes.checked;
226 node.ui.toggleCheck(checkedNode.attributes.checked);
227 })
228 }
229 var selected = [];
230 this.root.cascade(function(node) {
231 if (node.ui.isChecked()) {
232 selected.push(node.attributes.uid);
233 }
234 });
235 this.countSelectedNodes = selected.length;
236 Ext.fly('treeinput' + this.id).dom.value = selected.join(',');
237 eval(this.onChange);
238
239 this.resumeEvents();
240 };