6d6473bbe425e8eedb641f3824a67d6602d4062e
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / htmlarea / plugins / CharacterMap / character-map.js
1 /***************************************************************
2 * Copyright notice
3 *
4 * (c) 2004 Bernhard Pfeifer novocaine@gmx.net
5 * (c) 2004 systemconcept.de. Authored by Holger Hees based on HTMLArea XTD 1.5 (http://mosforge.net/projects/htmlarea3xtd/).
6 * (c) 2005-2012 Stanislas Rolland <typo3(arobas)sjbr.ca>
7 * All rights reserved
8 *
9 * This script is part of the TYPO3 project. The TYPO3 project is
10 * free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
17 * A copy is found in the textfile GPL.txt and important notices to the license
18 * from the author is found in LICENSE.txt distributed with these scripts.
19 *
20 *
21 * This script is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * This script is a modified version of a script published under the htmlArea License.
27 * A copy of the htmlArea License may be found in the textfile HTMLAREA_LICENSE.txt.
28 *
29 * This copyright notice MUST APPEAR in all copies of the script!
30 ***************************************************************/
31 /*
32 * Character Map Plugin for TYPO3 htmlArea RTE
33 */
34 HTMLArea.CharacterMap = Ext.extend(HTMLArea.Plugin, {
35 /*
36 * This function gets called by the class constructor
37 */
38 configurePlugin : function(editor) {
39 /*
40 * Registering plugin "About" information
41 */
42 var pluginInformation = {
43 version : '4.0',
44 developer : 'Holger Hees, Bernhard Pfeifer, Stanislas Rolland',
45 developerUrl : 'http://www.sjbr.ca/',
46 copyrightOwner : 'Holger Hees, Bernhard Pfeifer, Stanislas Rolland',
47 sponsor : 'System Concept GmbH, Bernhard Pfeifer, SJBR, BLE',
48 sponsorUrl : 'http://www.sjbr.ca/',
49 license : 'GPL'
50 };
51 this.registerPluginInformation(pluginInformation);
52 /*
53 * Registering the buttons
54 */
55 for (var i = 0, n = this.buttons.length; i < n; ++i) {
56 var button = this.buttons[i];
57 buttonId = button[0];
58 var buttonConfiguration = {
59 id: buttonId,
60 tooltip: this.localize(buttonId + '-Tooltip'),
61 action: 'onButtonPress',
62 context: button[1],
63 dialog: false,
64 iconCls: 'htmlarea-action-' + button[2]
65 };
66 this.registerButton(buttonConfiguration);
67 }
68 /*
69 * Localizing the maps
70 */
71 Ext.iterate(this.maps, function (key, map, maps) {
72 for (var i = map.length; --i >= 0;) {
73 maps[key][i].push(this.localize(map[i][1]));
74 }
75 }, this);
76 return true;
77 },
78 /*
79 * The list of buttons added by this plugin
80 */
81 buttons: [
82 ['InsertCharacter', null, 'character-insert-from-map'],
83 ['InsertSoftHyphen', null, 'soft-hyphen-insert']
84 ],
85 /*
86 * Character maps
87 */
88 maps: {
89 general: [
90 ['&nbsp;', 'nbsp'],
91 ['&Agrave;', 'Agrave'],
92 ['&agrave;', 'agrave'],
93 ['&Aacute;', 'Aacute'],
94 ['&aacute;', 'aacute'],
95 ['&Acirc;', 'Acirc'],
96 ['&acirc;', 'acirc'],
97 ['&Atilde;', 'Atilde'],
98 ['&atilde;', 'atilde'],
99 ['&Auml;', 'Auml'],
100 ['&auml;', 'auml'],
101 ['&Aring;', 'Aring'],
102 ['&aring;', 'aring'],
103 ['&AElig;', 'AElig'],
104 ['&aelig;', 'aelig'],
105 ['&ordf;', 'ordf'],
106 ['&Ccedil;', 'Ccedil'],
107 ['&ccedil;', 'ccedil'],
108 ['&ETH;', 'ETH'],
109 ['&eth;', 'eth'],
110 ['&Egrave;', 'Egrave'],
111 ['&egrave;', 'egrave'],
112 ['&Eacute;', 'Eacute'],
113 ['&eacute;', 'eacute'],
114 ['&Ecirc;', 'Ecirc'],
115 ['&ecirc;', 'ecirc'],
116 ['&Euml;', 'Euml'],
117 ['&euml;', 'euml'],
118 ['&Igrave;', 'Igrave'],
119 ['&igrave;', 'igrave'],
120 ['&Iacute;', 'Iacute'],
121 ['&iacute;', 'iacute'],
122 ['&Icirc;', 'Icirc'],
123 ['&icirc;', 'icirc'],
124 ['&Iuml;', 'Iuml'],
125 ['&iuml;', 'iuml'],
126 ['&Ntilde;', 'Ntilde'],
127 ['&ntilde;', 'ntilde'],
128 ['&Ograve;', 'Ograve'],
129 ['&ograve;', 'ograve'],
130 ['&Oacute;', 'Oacute'],
131 ['&oacute;', 'oacute'],
132 ['&Ocirc;', 'Ocirc'],
133 ['&ocirc;', 'ocirc'],
134 ['&Otilde;', 'Otilde'],
135 ['&otilde;', 'otilde'],
136 ['&Ouml;', 'Ouml'],
137 ['&ouml;', 'ouml'],
138 ['&Oslash;', 'Oslash'],
139 ['&oslash;', 'oslash'],
140 ['&OElig;', 'OElig'],
141 ['&oelig;', 'oelig'],
142 ['&ordm;', 'ordm'],
143 ['&Scaron;', 'Scaron'],
144 ['&scaron;', 'scaron'],
145 ['&szlig;', 'szlig'],
146 ['&THORN;', 'THORN'],
147 ['&thorn;', 'thorn'],
148 ['&Ugrave;', 'Ugrave'],
149 ['&ugrave;', 'ugrave'],
150 ['&Uacute;', 'Uacute'],
151 ['&uacute;', 'uacute'],
152 ['&Ucirc;', 'Ucirc'],
153 ['&ucirc;', 'ucirc'],
154 ['&Uuml;', 'Uuml'],
155 ['&uuml;', 'uuml'],
156 ['&Yacute;', 'Yacute'],
157 ['&yacute;', 'yacute'],
158 ['&Yuml;', 'Yuml'],
159 ['&yuml;', 'yuml'],
160 ['&acute;', 'acute'],
161 ['&circ;', 'circ'],
162 ['&tilde;', 'tilde'],
163 ['&uml;', 'uml'],
164 ['&cedil;', 'cedil'],
165 ['&shy;', 'shy'],
166 ['&ndash;', 'ndash'],
167 ['&mdash;', 'mdash'],
168 ['&lsquo;', 'lsquo'],
169 ['&rsquo;', 'rsquo'],
170 ['&sbquo;', 'sbquo'],
171 ['&ldquo;', 'ldquo'],
172 ['&rdquo;', 'rdquo'],
173 ['&bdquo;', 'bdquo'],
174 ['&lsaquo;', 'lsaquo'],
175 ['&rsaquo;', 'rsaquo'],
176 ['&laquo;', 'laquo'],
177 ['&raquo;', 'raquo'],
178 ['&quot;', 'quot'],
179 ['&hellip;', 'hellip'],
180 ['&iquest;', 'iquest'],
181 ['&iexcl;', 'iexcl'],
182 ['&bull;', 'bull'],
183 ['&dagger;', 'dagger'],
184 ['&Dagger;', 'Dagger'],
185 ['&brvbar;', 'brvbar'],
186 ['&para;', 'para'],
187 ['&sect;', 'sect'],
188 ['&loz;', 'loz'],
189 ['&#064;', '#064'],
190 ['&copy;', 'copy'],
191 ['&reg;', 'reg'],
192 ['&trade;', 'trade'],
193 ['&curren;', 'curren'],
194 ['&cent;', 'cent'],
195 ['&euro;', 'euro'],
196 ['&pound;', 'pound'],
197 ['&yen;', 'yen'],
198 ['&emsp;', 'emsp'],
199 ['&ensp;', 'ensp'],
200 ['&thinsp;', 'thinsp'],
201 ['&zwj;', 'zwj'],
202 ['&zwnj;', 'zwnj']
203 ],
204 mathematical: [
205 ['&minus;', 'minus'],
206 ['&plusmn;', 'plusmn'],
207 ['&times;', 'times'],
208 ['&divide;', 'divide'],
209 ['&radic;', 'radic'],
210 ['&sdot;', 'sdot'],
211 ['&otimes;', 'otimes'],
212 ['&lowast;', 'lowast'],
213 ['&ge;', 'ge'],
214 ['&le;', 'le'],
215 ['&ne;', 'ne'],
216 ['&asymp;', 'asymp'],
217 ['&sim;', 'sim'],
218 ['&prop;', 'prop'],
219 ['&deg;', 'deg'],
220 ['&prime;', 'prime'],
221 ['&Prime;', 'Prime'],
222 ['&micro;', 'micro'],
223 ['&ang;', 'ang'],
224 ['&perp;', 'perp'],
225 ['&permil;', 'permil'],
226 ['&frasl;', 'frasl'],
227 ['&frac14;', 'frac14'],
228 ['&frac12;', 'frac12'],
229 ['&frac34;', 'frac34'],
230 ['&sup1;', 'sup1'],
231 ['&sup2;', 'sup2'],
232 ['&sup3;', 'sup3'],
233 ['&not;', 'not'],
234 ['&and;', 'and'],
235 ['&or;', 'or'],
236 ['&there4;', 'there4'],
237 ['&cong;', 'cong'],
238 ['&isin;', 'isin'],
239 ['&ni;', 'ni'],
240 ['&notin;', 'notin'],
241 ['&sub;', 'sub'],
242 ['&sube;', 'sube'],
243 ['&nsub;', 'nsub'],
244 ['&sup;', 'sup'],
245 ['&supe;', 'supe'],
246 ['&cap;', 'cap'],
247 ['&cup;', 'cup'],
248 ['&oplus;', 'oplus'],
249 ['&nabla;', 'nabla'],
250 ['&empty;', 'empty'],
251 ['&equiv;', 'equiv'],
252 ['&sum;', 'sum'],
253 ['&prod;', 'prod'],
254 ['&weierp;', 'weierp'],
255 ['&exist;', 'exist'],
256 ['&forall;', 'forall'],
257 ['&infin;', 'infin'],
258 ['&alefsym;', 'alefsym'],
259 ['&real;', 'real'],
260 ['&image;', 'image'],
261 ['&fnof;', 'fnof'],
262 ['&int;', 'int'],
263 ['&part;', 'part'],
264 ['&Alpha;', 'Alpha'],
265 ['&alpha;', 'alpha'],
266 ['&Beta;', 'Beta'],
267 ['&beta;', 'beta'],
268 ['&Gamma;', 'Gamma'],
269 ['&gamma;', 'gamma'],
270 ['&Delta;', 'Delta'],
271 ['&delta;', 'delta'],
272 ['&Epsilon;', 'Epsilon'],
273 ['&epsilon;', 'epsilon'],
274 ['&Zeta;', 'Zeta'],
275 ['&zeta;', 'zeta'],
276 ['&Eta;', 'Eta'],
277 ['&eta;', 'eta'],
278 ['&Theta;', 'Theta'],
279 ['&theta;', 'theta'],
280 ['&thetasym;', 'thetasym'],
281 ['&Iota;', 'Iota'],
282 ['&iota;', 'iota'],
283 ['&Kappa;', 'Kappa'],
284 ['&kappa;', 'kappa'],
285 ['&Lambda;', 'Lambda'],
286 ['&lambda;', 'lambda'],
287 ['&Mu;', 'Mu'],
288 ['&mu;', 'mu'],
289 ['&Nu;', 'Nu'],
290 ['&nu;', 'nu'],
291 ['&Xi;', 'Xi'],
292 ['&xi;', 'xi'],
293 ['&Omicron;', 'Omicron'],
294 ['&omicron;', 'omicron'],
295 ['&Pi;', 'Pi'],
296 ['&pi;', 'pi'],
297 ['&piv;', 'piv'],
298 ['&Rho;', 'Rho'],
299 ['&rho;', 'rho'],
300 ['&Sigma;', 'Sigma'],
301 ['&sigma;', 'sigma'],
302 ['&sigmaf;', 'sigmaf'],
303 ['&Tau;', 'Tau'],
304 ['&tau;', 'tau'],
305 ['&Upsilon;', 'Upsilon'],
306 ['&upsih;', 'upsih'],
307 ['&upsilon;', 'upsilon'],
308 ['&Phi;', 'Phi'],
309 ['&phi;', 'phi'],
310 ['&Chi;', 'Chi'],
311 ['&chi;', 'chi'],
312 ['&Psi;', 'Psi'],
313 ['&psi;', 'psi'],
314 ['&Omega;', 'Omega'],
315 ['&omega;', 'omega']
316 ],
317 graphical: [
318 ['&crarr;', 'crarr'],
319 ['&uarr;', 'uarr'],
320 ['&darr;', 'darr'],
321 ['&larr;', 'larr'],
322 ['&rarr;', 'rarr'],
323 ['&harr;', 'harr'],
324 ['&uArr;', 'uArr'],
325 ['&dArr;', 'dArr'],
326 ['&lArr;', 'lArr'],
327 ['&rArr;', 'rArr'],
328 ['&hArr;', 'hArr'],
329 ['&nbsp;', 'nbsp'],
330 ['&nbsp;', 'nbsp'],
331 ['&nbsp;', 'nbsp'],
332 ['&nbsp;', 'nbsp'],
333 ['&clubs;', 'clubs'],
334 ['&diams;', 'diams'],
335 ['&hearts;', 'hearts'],
336 ['&spades;', 'spades']
337 ]
338 },
339 /*
340 * This function gets called when the button was pressed.
341 *
342 * @param object editor: the editor instance
343 * @param string id: the button id or the key
344 *
345 * @return boolean false if action is completed
346 */
347 onButtonPress: function (editor, id) {
348 // Could be a button or its hotkey
349 var buttonId = this.translateHotKey(id);
350 buttonId = buttonId ? buttonId : id;
351 switch (buttonId) {
352 case 'InsertCharacter':
353 this.openDialogue(
354 buttonId,
355 'Insert special character',
356 this.getWindowDimensions(
357 {
358 width: 434,
359 height: 360
360 },
361 buttonId
362 ),
363 this.buildTabItems()
364 );
365 break;
366 case 'InsertSoftHyphen':
367 this.insertEntity('\xAD');
368 break;
369 }
370 return false;
371 },
372 /*
373 * Open the dialogue window
374 *
375 * @param string buttonId: the button id
376 * @param string title: the window title
377 * @param integer dimensions: the opening width of the window
378 * @param object tabItems: the configuration of the tabbed panel
379 * @param function handler: handler when the OK button if clicked
380 *
381 * @return void
382 */
383 openDialogue: function (buttonId, title, dimensions, tabItems, handler) {
384 this.dialog = new Ext.Window({
385 title: this.localize(title),
386 cls: 'htmlarea-window',
387 border: false,
388 width: dimensions.width,
389 height: 'auto',
390 iconCls: this.getButton(buttonId).iconCls,
391 listeners: {
392 close: {
393 fn: this.onClose,
394 scope: this
395 }
396 },
397 items: {
398 xtype: 'tabpanel',
399 activeTab: 0,
400 listeners: {
401 activate: {
402 fn: this.resetFocus,
403 scope: this
404 },
405 tabchange: {
406 fn: this.syncHeight,
407 scope: this
408 }
409 },
410 items: tabItems
411 },
412 buttons: [
413 this.buildButtonConfig('Cancel', this.onCancel)
414 ]
415 });
416 this.show();
417 },
418 /*
419 * Build the configuration of the the tab items
420 *
421 * @return array the configuration array of tab items
422 */
423 buildTabItems: function () {
424 var tabItems = [];
425 Ext.iterate(this.maps, function (id, map) {
426 tabItems.push({
427 xtype: 'box',
428 cls: 'character-map',
429 title: this.localize(id),
430 itemId: id,
431 tpl: new Ext.XTemplate(
432 '<tpl for="."><a href="#" class="character" hidefocus="on" ext:qtitle="<span>&</span>{1};" ext:qtip="{2}">{0}</a></tpl>'
433 ),
434 listeners: {
435 render: {
436 fn: this.renderMap,
437 scope: this
438 }
439 }
440 });
441 }, this);
442 return tabItems;
443 },
444 /*
445 * Render an array of characters
446 *
447 * @param object component: the box containing the characters
448 *
449 * @return void
450 */
451 renderMap: function (component) {
452 component.tpl.overwrite(component.el, this.maps[component.itemId]);
453 component.mon(component.el, 'click', this.insertCharacter, this, {delegate: 'a'});
454 },
455 /*
456 * Handle the click on an item of the map
457 *
458 * @param object event: the Ext event
459 * @param HTMLelement target: the html element target
460 *
461 * @return boolean
462 */
463 insertCharacter: function (event, target) {
464 event.stopEvent();
465 this.restoreSelection();
466 var entity = Ext.get(target).dom.innerHTML;
467 this.insertEntity(entity);
468 if (Ext.isIE) {
469 this.saveSelection();
470 }
471 return false;
472 },
473 /*
474 * Insert the selected entity
475 *
476 * @param string entity: the entity to insert at the current selection
477 *
478 * @return void
479 */
480 insertEntity: function (entity) {
481 if (Ext.isIE) {
482 this.editor.getSelection().insertHtml(entity);
483 } else {
484 // Firefox and WebKit convert '&nbsp;' to '&amp;nbsp;'
485 var node = this.editor.document.createTextNode(((Ext.isGecko || Ext.isWebKit) && entity == '&nbsp;') ? '\xA0' : entity);
486 this.editor.getSelection().insertNode(node);
487 this.editor.getSelection().selectNode(node, false);
488 }
489 },
490 /*
491 * Reset focus on the the current selection, if at all possible
492 *
493 */
494 resetFocus: function () {
495 this.restoreSelection();
496 }
497 });