[FEATURE] Select first element of PageTree toolbar on initialization
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Resources / Public / JavaScript / PageTree / PageTreeToolbar.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 /**
15 * Module: TYPO3/CMS/Backend/FormEngine/Element/TreeToolbar
16 */
17 define(['jquery',
18 'TYPO3/CMS/Backend/Icons',
19 'd3',
20 'TYPO3/CMS/Backend/PageTree/PageTreeDragDrop',
21 'TYPO3/CMS/Backend/Tooltip',
22 'TYPO3/CMS/Backend/SvgTree'
23 ],
24 function($, Icons, d3, PageTreeDragDrop) {
25 'use strict';
26
27 /**
28 * TreeToolbar class
29 *
30 * @constructor
31 * @exports TYPO3/CMS/Backend/FormEngine/Element/TreeToolbar
32 */
33 var TreeToolbar = function() {
34 this.settings = {
35 toolbarSelector: 'tree-toolbar',
36 searchInput: '.search-input',
37 target: '.svg-toolbar'
38 };
39
40 /**
41 * jQuery object wrapping the SvgTree
42 *
43 * @type {jQuery}
44 */
45 this.$treeWrapper = null;
46
47 /**
48 * SvgTree instance
49 *
50 * @type {SvgTree}
51 */
52 this.tree = null;
53
54 /**
55 * State of the hide unchecked toggle button
56 *
57 * @type {boolean}
58 * @private
59 */
60 this._hideUncheckedState = false;
61
62 /**
63 * Toolbar template
64 *
65 * @type {jQuery}
66 */
67 this.template = null;
68 };
69
70 /**
71 * Toolbar initialization
72 *
73 * @param {String} treeSelector
74 * @param {Object} settings
75 */
76 TreeToolbar.prototype.initialize = function(treeSelector, settings) {
77 var _this = this;
78 _this.$treeWrapper = $(treeSelector);
79
80 this.dragDrop = PageTreeDragDrop;
81 this.dragDrop.init(this);
82 if (!_this.$treeWrapper.data('svgtree-initialized') || typeof _this.$treeWrapper.data('svgtree') !== 'object') {
83 //both toolbar and tree are loaded independently through require js,
84 //so we don't know which is loaded first
85 //in case of toolbar being loaded first, we wait for an event from svgTree
86 _this.$treeWrapper.on('svgTree.initialized', _this.render.bind(_this));
87 return;
88 }
89
90 $.extend(this.settings, settings);
91 this.render();
92 };
93
94 /**
95 * Create toolbar template
96 */
97 TreeToolbar.prototype.createTemplate = function() {
98 var _this = this;
99
100 var $template = $(
101 '<div class="' + _this.settings.toolbarSelector + '">' +
102 '<div class="svg-toolbar__menu">' +
103 '<div class="x-btn btn btn-default btn-sm x-btn-noicon" data-tree-show-submenu="filter">' +
104 '<button class="svg-toolbar__btn" data-tree-icon="actions-filter" title="' + TYPO3.lang['tree.buttonFilter'] + '"></button>' +
105 '</div>' +
106 '<div class="x-btn btn btn-default btn-sm x-btn-noicon js-svg-refresh">' +
107 '<button class="svg-toolbar__btn" data-tree-icon="actions-refresh" title="' + TYPO3.lang['labels.refresh'] + '"></button>' +
108 '</div>' +
109 '</div>' +
110 '<div class="svg-toolbar__submenu">' +
111 '<div class="svg-toolbar__submenu-item" data-tree-submenu="filter">' +
112 '<input type="text" class="form-control search-input" placeholder="' + TYPO3.lang['tree.searchTermInfo'] + '">' +
113 '</div>' +
114 '<div class="svg-toolbar__submenu-item" data-tree-submenu="page-new">' +
115 '</div>' +
116 '</div>' +
117 '</div>'
118 );
119
120 if (this.tree.settings.doktypes && this.tree.settings.doktypes.length) {
121 var $buttons = $template.find('[data-tree-submenu=page-new]');
122 $template.find('.svg-toolbar__menu').prepend('<div class="x-btn btn btn-default btn-sm x-btn-noicon" data-tree-show-submenu="page-new">' +
123 '<button class="svg-toolbar__btn" data-tree-icon="actions-page-new" title="' + TYPO3.lang['tree.buttonNewNode'] + '"></button>' +
124 '</div>'
125 );
126
127 $.each(this.tree.settings.doktypes, function(id, e) {
128 _this.tree.fetchIcon(e.icon, false);
129 $buttons.append('<div class="svg-toolbar__drag-node" data-tree-icon="' + e.icon + '" data-node-type="' + e.nodeType + '" title="' + e.title + '" tooltip="' + e.tooltip + '"></div>');
130 });
131 }
132
133 _this.template = $template;
134 };
135
136 /**
137 * Renders toolbar
138 */
139 TreeToolbar.prototype.render = function() {
140 var _this = this;
141 this.tree = this.$treeWrapper.data('svgtree');
142
143 $.extend(this.settings, this.tree.settings);
144 this.createTemplate();
145
146 var $toolbar = $(this.settings.target).append(this.template);
147
148 //get icons
149 $toolbar.find('[data-tree-icon]').each(function() {
150 var $this = $(this);
151
152 Icons.getIcon($this.attr('data-tree-icon'), Icons.sizes.small).done(function(icon) {
153 $this.append(icon);
154 });
155 });
156
157 //toggle toolbar submenu
158 $toolbar.find('[data-tree-show-submenu]').each(function() {
159 $(this).click(function() {
160 var $this = $(this);
161 var name = $this.attr('data-tree-show-submenu');
162 var $submenu = $toolbar.find('[data-tree-submenu=' + name + ']');
163
164 $toolbar.find('[data-tree-show-submenu]').not(this).removeClass('active');
165 $this.addClass('active');
166
167 $toolbar.find('[data-tree-submenu]').not($submenu).removeClass('active');
168 $submenu.addClass('active');
169 $submenu.find('input').focus();
170 });
171 });
172
173 $toolbar.find('.js-svg-refresh').on('click', this.refreshTree.bind(this));
174
175 var d3Toolbar = d3.select('.svg-toolbar');
176
177 $.each(this.tree.settings.doktypes, function(id, e) {
178 if (e.icon) {
179 d3Toolbar
180 .selectAll('[data-tree-icon=' + e.icon + ']')
181 .call(_this.dragDrop.dragToolbar());
182 } else {
183 console.warn('Missing icon definition for doktype: ' + e.nodeType);
184 }
185 });
186
187 $toolbar.find(this.settings.searchInput).on('input', function() {
188 _this.search.call(_this, this);
189 });
190
191 $toolbar.find('[data-toggle="tooltip"]').tooltip();
192
193 if ($('[data-tree-show-submenu="page-new"]').length) {
194 $('[data-tree-show-submenu="page-new"]').trigger('click');
195 } else {
196 $('.svg-toolbar__menu :first-child:not(.js-svg-refresh)').trigger('click');
197 }
198 };
199
200 /**
201 * Refresh tree
202 */
203 TreeToolbar.prototype.refreshTree = function() {
204 this.tree.refreshTree();
205 };
206
207 /**
208 * Find node by name
209 *
210 * @param {HTMLElement} input
211 */
212 TreeToolbar.prototype.search = function(input) {
213 var _this = this;
214 var name = $(input).val().trim();
215
216 this.tree.nodes[0].expanded = false;
217 this.tree.nodes.forEach(function(node) {
218 var regex = new RegExp(name, 'i');
219 if (node.identifier.toString() === name || regex.test(node.name) || regex.test(node.alias)) {
220 _this.showParents(node);
221 node.expanded = true;
222 node.hidden = false;
223 } else if (node.depth !== 0) {
224 node.hidden = true;
225 node.expanded = false;
226 }
227 });
228
229 this.tree.prepareDataForVisibleNodes();
230 this.tree.update();
231 };
232
233 /**
234 * Show only checked items
235 *
236 * @param {HTMLElement} input
237 */
238 TreeToolbar.prototype.toggleHideUnchecked = function(input) {
239 var _this = this;
240
241 this._hideUncheckedState = !this._hideUncheckedState;
242
243 if (this._hideUncheckedState) {
244 this.tree.nodes.forEach(function(node) {
245 if (node.checked) {
246 _this.showParents(node);
247 node.expanded = true;
248 node.hidden = false;
249 } else {
250 node.hidden = true;
251 node.expanded = false;
252 }
253 });
254 } else {
255 this.tree.nodes.forEach(function(node) {
256 node.hidden = false;
257 });
258 }
259
260 this.tree.prepareDataForVisibleNodes();
261 this.tree.update();
262 };
263
264 /**
265 * Finds and show all parents of node
266 *
267 * @param {Node} node
268 * @returns {Boolean}
269 */
270 TreeToolbar.prototype.showParents = function(node) {
271 if (node.parents.length === 0) {
272 return true;
273 }
274
275 var parent = this.tree.nodes[node.parents[0]];
276 parent.hidden = false;
277
278 //expand parent node
279 parent.expanded = true;
280 this.showParents(parent);
281 };
282
283 return TreeToolbar;
284 });