4 * Released under LGPL License.
5 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
7 * License: http://www.tinymce.com/license
8 * Contributing: http://www.tinymce.com/contributing
11 /*global tinymce:true */
13 tinymce.PluginManager.add('charmap', function(editor) {
14 var isArray = tinymce.util.Tools.isArray;
16 function getDefaultCharMap() {
18 ['160', 'no-break space'],
19 ['173', 'soft hyphen'],
20 ['34', 'quotation mark'],
23 ['8364', 'euro sign'],
24 ['163', 'pound sign'],
27 ['169', 'copyright sign'],
28 ['174', 'registered sign'],
29 ['8482', 'trade mark sign'],
30 ['8240', 'per mille sign'],
31 ['181', 'micro sign'],
32 ['183', 'middle dot'],
34 ['8230', 'three dot leader'],
35 ['8242', 'minutes / feet'],
36 ['8243', 'seconds / inches'],
37 ['167', 'section sign'],
38 ['182', 'paragraph sign'],
39 ['223', 'sharp s / ess-zed'],
41 ['8249', 'single left-pointing angle quotation mark'],
42 ['8250', 'single right-pointing angle quotation mark'],
43 ['171', 'left pointing guillemet'],
44 ['187', 'right pointing guillemet'],
45 ['8216', 'left single quotation mark'],
46 ['8217', 'right single quotation mark'],
47 ['8220', 'left double quotation mark'],
48 ['8221', 'right double quotation mark'],
49 ['8218', 'single low-9 quotation mark'],
50 ['8222', 'double low-9 quotation mark'],
51 ['60', 'less-than sign'],
52 ['62', 'greater-than sign'],
53 ['8804', 'less-than or equal to'],
54 ['8805', 'greater-than or equal to'],
59 ['164', 'currency sign'],
60 ['166', 'broken bar'],
62 ['161', 'inverted exclamation mark'],
63 ['191', 'turned question mark'],
64 ['710', 'circumflex accent'],
65 ['732', 'small tilde'],
66 ['176', 'degree sign'],
67 ['8722', 'minus sign'],
68 ['177', 'plus-minus sign'],
69 ['247', 'division sign'],
70 ['8260', 'fraction slash'],
71 ['215', 'multiplication sign'],
72 ['185', 'superscript one'],
73 ['178', 'superscript two'],
74 ['179', 'superscript three'],
75 ['188', 'fraction one quarter'],
76 ['189', 'fraction one half'],
77 ['190', 'fraction three quarters'],
79 ['402', 'function / florin'],
81 ['8721', 'n-ary sumation'],
83 ['8730', 'square root'],
84 ['8764', 'similar to'],
85 ['8773', 'approximately equal to'],
86 ['8776', 'almost equal to'],
87 ['8800', 'not equal to'],
88 ['8801', 'identical to'],
89 ['8712', 'element of'],
90 ['8713', 'not an element of'],
91 ['8715', 'contains as member'],
92 ['8719', 'n-ary product'],
93 ['8743', 'logical and'],
94 ['8744', 'logical or'],
96 ['8745', 'intersection'],
98 ['8706', 'partial differential'],
100 ['8707', 'there exists'],
101 ['8709', 'diameter'],
102 ['8711', 'backward difference'],
103 ['8727', 'asterisk operator'],
104 ['8733', 'proportional to'],
107 ['180', 'acute accent'],
109 ['170', 'feminine ordinal indicator'],
110 ['186', 'masculine ordinal indicator'],
112 ['8225', 'double dagger'],
113 // alphabetical special chars
114 ['192', 'A - grave'],
115 ['193', 'A - acute'],
116 ['194', 'A - circumflex'],
117 ['195', 'A - tilde'],
118 ['196', 'A - diaeresis'],
119 ['197', 'A - ring above'],
120 ['256', 'A - macron'],
121 ['198', 'ligature AE'],
122 ['199', 'C - cedilla'],
123 ['200', 'E - grave'],
124 ['201', 'E - acute'],
125 ['202', 'E - circumflex'],
126 ['203', 'E - diaeresis'],
127 ['274', 'E - macron'],
128 ['204', 'I - grave'],
129 ['205', 'I - acute'],
130 ['206', 'I - circumflex'],
131 ['207', 'I - diaeresis'],
132 ['298', 'I - macron'],
134 ['209', 'N - tilde'],
135 ['210', 'O - grave'],
136 ['211', 'O - acute'],
137 ['212', 'O - circumflex'],
138 ['213', 'O - tilde'],
139 ['214', 'O - diaeresis'],
140 ['216', 'O - slash'],
141 ['332', 'O - macron'],
142 ['338', 'ligature OE'],
143 ['352', 'S - caron'],
144 ['217', 'U - grave'],
145 ['218', 'U - acute'],
146 ['219', 'U - circumflex'],
147 ['220', 'U - diaeresis'],
148 ['362', 'U - macron'],
149 ['221', 'Y - acute'],
150 ['376', 'Y - diaeresis'],
151 ['562', 'Y - macron'],
153 ['224', 'a - grave'],
154 ['225', 'a - acute'],
155 ['226', 'a - circumflex'],
156 ['227', 'a - tilde'],
157 ['228', 'a - diaeresis'],
158 ['229', 'a - ring above'],
159 ['257', 'a - macron'],
160 ['230', 'ligature ae'],
161 ['231', 'c - cedilla'],
162 ['232', 'e - grave'],
163 ['233', 'e - acute'],
164 ['234', 'e - circumflex'],
165 ['235', 'e - diaeresis'],
166 ['275', 'e - macron'],
167 ['236', 'i - grave'],
168 ['237', 'i - acute'],
169 ['238', 'i - circumflex'],
170 ['239', 'i - diaeresis'],
171 ['299', 'i - macron'],
173 ['241', 'n - tilde'],
174 ['242', 'o - grave'],
175 ['243', 'o - acute'],
176 ['244', 'o - circumflex'],
177 ['245', 'o - tilde'],
178 ['246', 'o - diaeresis'],
181 ['339', 'ligature oe'],
182 ['353', 's - caron'],
183 ['249', 'u - grave'],
184 ['250', 'u - acute'],
185 ['251', 'u - circumflex'],
186 ['252', 'u - diaeresis'],
187 ['363', 'u - macron'],
188 ['253', 'y - acute'],
190 ['255', 'y - diaeresis'],
191 ['563', 'y - macron'],
233 ['962', 'final sigma'],
242 ['8501', 'alef symbol'],
243 ['982', 'pi symbol'],
244 ['8476', 'real part symbol'],
245 ['978', 'upsilon - hook symbol'],
246 ['8472', 'Weierstrass p'],
247 ['8465', 'imaginary part'],
249 ['8592', 'leftwards arrow'],
250 ['8593', 'upwards arrow'],
251 ['8594', 'rightwards arrow'],
252 ['8595', 'downwards arrow'],
253 ['8596', 'left right arrow'],
254 ['8629', 'carriage return'],
255 ['8656', 'leftwards double arrow'],
256 ['8657', 'upwards double arrow'],
257 ['8658', 'rightwards double arrow'],
258 ['8659', 'downwards double arrow'],
259 ['8660', 'left right double arrow'],
260 ['8756', 'therefore'],
261 ['8834', 'subset of'],
262 ['8835', 'superset of'],
263 ['8836', 'not a subset of'],
264 ['8838', 'subset of or equal to'],
265 ['8839', 'superset of or equal to'],
266 ['8853', 'circled plus'],
267 ['8855', 'circled times'],
268 ['8869', 'perpendicular'],
269 ['8901', 'dot operator'],
270 ['8968', 'left ceiling'],
271 ['8969', 'right ceiling'],
272 ['8970', 'left floor'],
273 ['8971', 'right floor'],
274 ['9001', 'left-pointing angle bracket'],
275 ['9002', 'right-pointing angle bracket'],
277 ['9824', 'black spade suit'],
278 ['9827', 'black club suit'],
279 ['9829', 'black heart suit'],
280 ['9830', 'black diamond suit'],
281 ['8194', 'en space'],
282 ['8195', 'em space'],
283 ['8201', 'thin space'],
284 ['8204', 'zero width non-joiner'],
285 ['8205', 'zero width joiner'],
286 ['8206', 'left-to-right mark'],
287 ['8207', 'right-to-left mark']
291 function charmapFilter(charmap) {
292 return tinymce.util.Tools.grep(charmap, function(item) {
293 return isArray(item) && item.length == 2;
297 function getCharsFromSetting(settingValue) {
298 if (isArray(settingValue)) {
299 return [].concat(charmapFilter(settingValue));
302 if (typeof settingValue == "function") {
303 return settingValue();
309 function extendCharMap(charmap) {
310 var settings = editor.settings;
312 if (settings.charmap) {
313 charmap = getCharsFromSetting(settings.charmap);
316 if (settings.charmap_append) {
317 return [].concat(charmap).concat(getCharsFromSetting(settings.charmap_append));
323 function getCharMap() {
324 return extendCharMap(getDefaultCharMap());
327 function insertChar(chr) {
328 editor.fire('insertCustomChar', {chr: chr}).chr;
329 editor.execCommand('mceInsertContent', false, chr);
332 function showDialog() {
333 var gridHtml, x, y, win;
335 function getParentTd(elm) {
337 if (elm.nodeName == 'TD') {
341 elm = elm.parentNode;
345 gridHtml = '<table role="presentation" cellspacing="0" class="mce-charmap"><tbody>';
347 var charmap = getCharMap();
348 var width = Math.min(charmap.length, 25);
349 var height = Math.ceil(charmap.length / width);
350 for (y = 0; y < height; y++) {
353 for (x = 0; x < width; x++) {
354 var index = y * width + x;
355 if (index < charmap.length) {
356 var chr = charmap[index];
357 var chrText = chr ? String.fromCharCode(parseInt(chr[0], 10)) : ' ';
360 '<td title="' + chr[1] + '"><div tabindex="-1" title="' + chr[1] + '" role="button" data-chr="' + chrText + '">' +
365 gridHtml += '<td />';
372 gridHtml += '</tbody></table>';
377 onclick: function(e) {
378 var target = e.target;
380 if (/^(TD|DIV)$/.test(target.nodeName)) {
381 if (getParentTd(target).firstChild) {
382 insertChar(target.getAttribute('data-chr'));
390 onmouseover: function(e) {
391 var td = getParentTd(e.target);
393 if (td && td.firstChild) {
394 win.find('#preview').text(td.firstChild.firstChild.data);
395 win.find('#previewTitle').text(td.title);
397 win.find('#preview').text(' ');
398 win.find('#previewTitle').text(' ');
403 win = editor.windowManager.open({
404 title: "Special character",
422 style: 'font-size: 40px; text-align: center',
429 name: 'previewTitle',
431 style: 'text-align: center',
440 {text: "Close", onclick: function() {
447 editor.addCommand('mceShowCharmap', showDialog);
449 editor.addButton('charmap', {
451 tooltip: 'Special character',
452 cmd: 'mceShowCharmap'
455 editor.addMenuItem('charmap', {
457 text: 'Special character',
458 cmd: 'mceShowCharmap',
463 getCharMap: getCharMap,
464 insertChar: insertChar