41d4dc660c762ec6a1946ac3a69b5f0490f37b75
[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 var text = document.createElement('label');
157 text.innerHTML = item.fieldLabel;
158 Dom.addClass(text, 'x-form-item-label');
159 text.setAttribute('for', item.getEl().dom.id);
160 textDiv.appendChild(text);
161 this.el.insertBefore(textDiv, wrapDiv);
162 }
163 } else {
164 item.render(this.el);
165 var itemDiv = this.el.appendChild(item.getEl().dom);
166 Dom.addClass(item.getEl().dom, 'x-form-item');
167 }
168 if (item.xtype === 'htmlareatoolbartext') {
169 Dom.addClass(item.getEl().dom, 'x-form-item-label');
170 }
171 if (item.itemId) {
172 this.items[item.itemId] = item;
173 }
174 },
175
176 /**
177 * Add a spacer to the toolbar
178 *
179 * @param string cls: a class to be added on the spacer
180 * @return void
181 */
182 addSpacer: function (cls) {
183 var spacer = document.createElement('div');
184 Dom.addClass(spacer, 'space');
185 if (typeof cls === 'string') {
186 Dom.addClass(spacer, cls);
187 }
188 this.el.appendChild(spacer);
189 },
190
191 /**
192 * Add a separator to the toolbar
193 *
194 * @param string cls: a class to be added on the separator
195 * @return void
196 */
197 addSeparator: function (cls) {
198 var spacer = document.createElement('div');
199 Dom.addClass(spacer, 'separator');
200 if (typeof cls === 'string') {
201 Dom.addClass(spacer, cls);
202 }
203 this.el.appendChild(spacer);
204 },
205
206 /**
207 * Remove a button from the toolbar
208 *
209 * @param string buttonId: the itemId of the item to remove
210 * @return void
211 */
212 remove: function (buttonId) {
213 var item = this.items[buttonId];
214 if (item) {
215 if (item.getEl()) {
216 Dom.removeFromParent(item.getEl().dom);
217 }
218 this.items[item.itemId] = null;
219 }
220 },
221
222 /**
223 * Retrieve a toolbar item by itemId
224 */
225 getButton: function (buttonId) {
226 return this.items[buttonId];
227 },
228
229 /**
230 * Get the current height of the toolbar
231 */
232 getHeight: function () {
233 return Dom.getSize(this.el).height;
234 },
235
236 /**
237 * Update the toolbar after some delay
238 */
239 updateLater: function (delay) {
240 if (this.updateToolbarLater) {
241 window.clearTimeout(this.updateToolbarLater);
242 }
243 if (delay) {
244 var self = this;
245 this.updateToolbarLater = window.setTimeout(function () {
246 self.update();
247 }, delay);
248 } else {
249 this.update();
250 }
251 },
252
253 /**
254 * Update the state of the toolbar
255 */
256 update: function() {
257 var editor = this.getEditor(),
258 mode = editor.getMode(),
259 selection = editor.getSelection(),
260 selectionEmpty = true,
261 ancestors = null,
262 endPointsInSameBlock = true;
263 if (editor.getMode() === 'wysiwyg') {
264 selectionEmpty = selection.isEmpty();
265 ancestors = selection.getAllAncestors();
266 endPointsInSameBlock = selection.endPointsInSameBlock();
267 }
268 /**
269 * @event HTMLAreaEventToolbarUpdate
270 * Fires when the toolbar is updated
271 */
272 Event.trigger(this, 'HTMLAreaEventToolbarUpdate', [mode, selectionEmpty, ancestors, endPointsInSameBlock]);
273 },
274
275 /**
276 * Cleanup (called by framework onBeforeDestroy)
277 */
278 onBeforeDestroy: function () {
279 Event.off(this);
280 while (node = this.el.firstChild) {
281 this.el.removeChild(node);
282 }
283 for (var itemId in this.items) {
284 if (typeof this.items[itemId].destroy === 'function') {
285 try {
286 this.items[itemId].destroy();
287 } catch (e) {}
288 }
289 }
290 }
291 };
292
293 return Toolbar;
294
295 });