c7d51d4a363114c5c6901db1ffd99c777d83941c
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / Resources / Public / JavaScript / HTMLArea / Editor / Toolbar.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 * The editor toolbar
16 */
17 define('TYPO3/CMS/Rtehtmlarea/HTMLArea/Editor/Toolbar',
18 ['TYPO3/CMS/Rtehtmlarea/HTMLArea/Util/Util',
19 'TYPO3/CMS/Rtehtmlarea/HTMLArea/DOM/DOM',
20 'TYPO3/CMS/Rtehtmlarea/HTMLArea/Event/Event',
21 'TYPO3/CMS/Rtehtmlarea/HTMLArea/Extjs/ux/Combo',
22 'TYPO3/CMS/Rtehtmlarea/HTMLArea/Extjs/ux/Button',
23 'TYPO3/CMS/Rtehtmlarea/HTMLArea/Extjs/ux/ToolbarText'],
24 function (Util, Dom, Event, Combo, Button, ToolbarText) {
25
26 /**
27 * Editor toolbar constructor
28 */
29 var Toolbar = function (config) {
30 Util.apply(this, config);
31 };
32
33 Toolbar.prototype = {
34
35 /**
36 * Render the toolbar (called by framework rendering)
37 *
38 * @param object container: the container into which to insert the toolbar (that is the framework)
39 * @return void
40 */
41 render: function (container) {
42 this.el = document.createElement('div');
43 if (this.id) {
44 this.el.setAttribute('id', this.id);
45 }
46 if (this.cls) {
47 this.el.setAttribute('class', this.cls);
48 }
49 this.el = container.appendChild(this.el);
50 this.addItems();
51 this.rendered = true;
52 },
53
54 /**
55 * Get the element to which the toolbar is rendered
56 */
57 getEl: function () {
58 return this.el;
59 },
60
61 /**
62 * editorId should be set in config
63 */
64 editorId: null,
65
66 /**
67 * Get a reference to the editor
68 */
69 getEditor: function() {
70 return RTEarea[this.editorId].editor;
71 },
72
73 /**
74 * The toolbar items
75 */
76 items: {},
77
78 /**
79 * Create the toolbar items based on editor toolbar configuration
80 */
81 addItems: function () {
82 var editor = this.getEditor();
83 // Walk through the editor toolbar configuration nested arrays: [ toolbar [ row [ group ] ] ]
84 var firstOnRow = true;
85 var firstInGroup = true;
86 var i, j, k, n, m, p, row, group, item;
87 for (i = 0, n = editor.config.toolbar.length; i < n; i++) {
88 row = editor.config.toolbar[i];
89 if (!firstOnRow) {
90 // If a visible item was added to the previous line
91 this.addSpacer('space-clear-left');
92 }
93 firstOnRow = true;
94 // Add the groups
95 for (j = 0, m = row.length; j < m; j++) {
96 group = row[j];
97 // To do: this.config.keepButtonGroupTogether ...
98 if (!firstOnRow && !firstInGroup) {
99 // If a visible item was added to the line
100 this.addSeparator();
101 }
102 firstInGroup = true;
103 // Add each item
104 for (k = 0, p = group.length; k < p; k++) {
105 item = group[k];
106 if (item == 'space') {
107 this.addSpacer();
108 } else {
109 // Get the item's config as registered by some plugin
110 var itemConfig = editor.config.buttonsConfig[item];
111 if (typeof itemConfig === 'object' && itemConfig !== null) {
112 itemConfig.id = this.editorId + '-' + itemConfig.id;
113 itemConfig.toolbar = this;
114 switch (itemConfig.xtype) {
115 case 'htmlareabutton':
116 this.add(new Button(itemConfig));
117 break;
118 case 'htmlareacombo':
119 this.add(new Combo(itemConfig));
120 break;
121 case 'htmlareatoolbartext':
122 this.add(new ToolbarText(itemConfig));
123 break;
124 default:
125 this.add(itemConfig);
126 }
127 firstInGroup = firstInGroup && itemConfig.hidden;
128 firstOnRow = firstOnRow && firstInGroup;
129 }
130 }
131 }
132 }
133 }
134 this.addSpacer('space-clear-left');
135 },
136
137 /**
138 * Add an item to the toolbar
139 *
140 * @param object item: the item to be added (not yet rendered)
141 * @return void
142 */
143 add: function (item) {
144 if (item.xtype === 'htmlareacombo') {
145 var wrapDiv = document.createElement('div');
146 Dom.addClass(wrapDiv, 'x-form-item');
147 wrapDiv = this.el.appendChild(wrapDiv);
148 item.render(wrapDiv);
149 if (item.helpTitle) {
150 item.getEl().dom.setAttribute('title', item.helpTitle);
151 }
152 wrapDiv.appendChild(item.getEl().dom);
153 if (item.fieldLabel) {
154 var textDiv = document.createElement('div');
155 Dom.addClass(textDiv, 'x-form-item');
156 Dom.addClass(textDiv, 'toolbar-text');
157 var text = document.createElement('label');
158 text.innerHTML = item.fieldLabel;
159 Dom.addClass(text, 'x-form-item-label');
160 text.setAttribute('for', item.getEl().dom.id);
161 textDiv.appendChild(text);
162 this.el.insertBefore(textDiv, wrapDiv);
163 }
164 } else {
165 item.render(this.el);
166 var itemDiv = this.el.appendChild(item.getEl().dom);
167 Dom.addClass(item.getEl().dom, 'x-form-item');
168 }
169 if (item.xtype === 'htmlareatoolbartext') {
170 Dom.addClass(item.getEl().dom, 'x-form-item-label');
171 }
172 if (item.itemId) {
173 this.items[item.itemId] = item;
174 }
175 },
176
177 /**
178 * Add a spacer to the toolbar
179 *
180 * @param string cls: a class to be added on the spacer
181 * @return void
182 */
183 addSpacer: function (cls) {
184 var spacer = document.createElement('div');
185 Dom.addClass(spacer, 'space');
186 if (typeof cls === 'string') {
187 Dom.addClass(spacer, cls);
188 }
189 this.el.appendChild(spacer);
190 },
191
192 /**
193 * Add a separator to the toolbar
194 *
195 * @param string cls: a class to be added on the separator
196 * @return void
197 */
198 addSeparator: function (cls) {
199 var spacer = document.createElement('div');
200 Dom.addClass(spacer, 'separator');
201 if (typeof cls === 'string') {
202 Dom.addClass(spacer, cls);
203 }
204 this.el.appendChild(spacer);
205 },
206
207 /**
208 * Remove a button from the toolbar
209 *
210 * @param string buttonId: the itemId of the item to remove
211 * @return void
212 */
213 remove: function (buttonId) {
214 var item = this.items[buttonId];
215 if (item) {
216 if (item.getEl()) {
217 Dom.removeFromParent(item.getEl().dom);
218 }
219 this.items[item.itemId] = null;
220 }
221 },
222
223 /**
224 * Retrieve a toolbar item by itemId
225 */
226 getButton: function (buttonId) {
227 return this.items[buttonId];
228 },
229
230 /**
231 * Get the current height of the toolbar
232 */
233 getHeight: function () {
234 return Dom.getSize(this.el).height;
235 },
236
237 /**
238 * Update the toolbar after some delay
239 */
240 updateLater: function (delay) {
241 if (this.updateToolbarLater) {
242 window.clearTimeout(this.updateToolbarLater);
243 }
244 if (delay) {
245 var self = this;
246 this.updateToolbarLater = window.setTimeout(function () {
247 self.update();
248 }, delay);
249 } else {
250 this.update();
251 }
252 },
253
254 /**
255 * Update the state of the toolbar
256 */
257 update: function() {
258 var editor = this.getEditor(),
259 mode = editor.getMode(),
260 selection = editor.getSelection(),
261 selectionEmpty = true,
262 ancestors = null,
263 endPointsInSameBlock = true;
264 if (editor.getMode() === 'wysiwyg') {
265 selectionEmpty = selection.isEmpty();
266 ancestors = selection.getAllAncestors();
267 endPointsInSameBlock = selection.endPointsInSameBlock();
268 }
269 /**
270 * @event HTMLAreaEventToolbarUpdate
271 * Fires when the toolbar is updated
272 */
273 Event.trigger(this, 'HTMLAreaEventToolbarUpdate', [mode, selectionEmpty, ancestors, endPointsInSameBlock]);
274 },
275
276 /**
277 * Cleanup (called by framework onBeforeDestroy)
278 */
279 onBeforeDestroy: function () {
280 Event.off(this);
281 while (node = this.el.firstChild) {
282 this.el.removeChild(node);
283 }
284 for (var itemId in this.items) {
285 if (typeof this.items[itemId].destroy === 'function') {
286 try {
287 this.items[itemId].destroy();
288 } catch (e) {}
289 }
290 }
291 }
292 };
293
294 return Toolbar;
295
296 });