MDL-43858 atto_charmap: New plugin to insert special characters
[moodle.git] / lib / editor / atto / plugins / charmap / yui / src / button / js / button.js
CommitLineData
c7829b26
FM
1// This file is part of Moodle - http://moodle.org/
2//
3// Moodle is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// Moodle is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
15
16/**
17 * Atto text editor charmap plugin.
18 *
19 * @package atto_charmap
20 * @copyright 2014 Frédéric Massart
21 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 */
23
24/**
25 * CSS classes and IDs.
26 *
27 * @type {Object}
28 */
29var CSS = {
30 BUTTON: 'atto_charmap_character',
31 CHARMAP: 'atto_charmap_selector'
32 },
33 /**
34 * Selectors.
35 *
36 * @type {Object}
37 */
38 SELECTORS = {
39 BUTTON: '.atto_charmap_character'
40 },
41 /**
42 * Map of special characters, kindly borrowed from TinyMCE.
43 *
44 * Each entries contains in order:
45 * - {String} HTML code
46 * - {String} HTML numerical code
47 * - {Boolean} Whether or not to include it in the list
48 * - {String} The language string key
49 *
50 * @type {Array}
51 */
52 CHARMAP = [
53 ['&nbsp;', '&#160;', true, 'nobreakspace'],
54 ['&amp;', '&#38;', true, 'ampersand'],
55 ['&quot;', '&#34;', true, 'quotationmark'],
56 // Finance.
57 ['&cent;', '&#162;', true, 'centsign'],
58 ['&euro;', '&#8364;', true, 'eurosign'],
59 ['&pound;', '&#163;', true, 'poundsign'],
60 ['&yen;', '&#165;', true, 'yensign'],
61 // Signs.
62 ['&copy;', '&#169;', true, 'copyrightsign'],
63 ['&reg;', '&#174;', true, 'registeredsign'],
64 ['&trade;', '&#8482;', true, 'trademarksign'],
65 ['&permil;', '&#8240;', true, 'permillesign'],
66 ['&micro;', '&#181;', true, 'microsign'],
67 ['&middot;', '&#183;', true, 'middledot'],
68 ['&bull;', '&#8226;', true, 'bullet'],
69 ['&hellip;', '&#8230;', true, 'threedotleader'],
70 ['&prime;', '&#8242;', true, 'minutesfeet'],
71 ['&Prime;', '&#8243;', true, 'secondsinches'],
72 ['&sect;', '&#167;', true, 'sectionsign'],
73 ['&para;', '&#182;', true, 'paragraphsign'],
74 ['&szlig;', '&#223;', true, 'sharpsesszed'],
75 // Quotations.
76 ['&lsaquo;', '&#8249;', true, 'singleleftpointinganglequotationmark'],
77 ['&rsaquo;', '&#8250;', true, 'singlerightpointinganglequotationmark'],
78 ['&laquo;', '&#171;', true, 'leftpointingguillemet'],
79 ['&raquo;', '&#187;', true, 'rightpointingguillemet'],
80 ['&lsquo;', '&#8216;', true, 'leftsinglequotationmark'],
81 ['&rsquo;', '&#8217;', true, 'rightsinglequotationmark'],
82 ['&ldquo;', '&#8220;', true, 'leftdoublequotationmark'],
83 ['&rdquo;', '&#8221;', true, 'rightdoublequotationmark'],
84 ['&sbquo;', '&#8218;', true, 'singlelow9quotationmark'],
85 ['&bdquo;', '&#8222;', true, 'doublelow9quotationmark'],
86 ['&lt;', '&#60;', true, 'lessthansign'],
87 ['&gt;', '&#62;', true, 'greaterthansign'],
88 ['&le;', '&#8804;', true, 'lessthanorequalto'],
89 ['&ge;', '&#8805;', true, 'greaterthanorequalto'],
90 ['&ndash;', '&#8211;', true, 'endash'],
91 ['&mdash;', '&#8212;', true, 'emdash'],
92 ['&macr;', '&#175;', true, 'macron'],
93 ['&oline;', '&#8254;', true, 'overline'],
94 ['&curren;', '&#164;', true, 'currencysign'],
95 ['&brvbar;', '&#166;', true, 'brokenbar'],
96 ['&uml;', '&#168;', true, 'diaeresis'],
97 ['&iexcl;', '&#161;', true, 'invertedexclamationmark'],
98 ['&iquest;', '&#191;', true, 'turnedquestionmark'],
99 ['&circ;', '&#710;', true, 'circumflexaccent'],
100 ['&tilde;', '&#732;', true, 'smalltilde'],
101 ['&deg;', '&#176;', true, 'degreesign'],
102 ['&minus;', '&#8722;', true, 'minussign'],
103 ['&plusmn;', '&#177;', true, 'plusminussign'],
104 ['&divide;', '&#247;', true, 'divisionsign'],
105 ['&frasl;', '&#8260;', true, 'fractionslash'],
106 ['&times;', '&#215;', true, 'multiplicationsign'],
107 ['&sup1;', '&#185;', true, 'superscriptone'],
108 ['&sup2;', '&#178;', true, 'superscripttwo'],
109 ['&sup3;', '&#179;', true, 'superscriptthree'],
110 ['&frac14;', '&#188;', true, 'fractiononequarter'],
111 ['&frac12;', '&#189;', true, 'fractiononehalf'],
112 ['&frac34;', '&#190;', true, 'fractionthreequarters'],
113 // Math / logical.
114 ['&fnof;', '&#402;', true, 'functionflorin'],
115 ['&int;', '&#8747;', true, 'integral'],
116 ['&sum;', '&#8721;', true, 'narysumation'],
117 ['&infin;', '&#8734;', true, 'infinity'],
118 ['&radic;', '&#8730;', true, 'squareroot'],
119 ['&sim;', '&#8764;', false,'similarto'],
120 ['&cong;', '&#8773;', false,'approximatelyequalto'],
121 ['&asymp;', '&#8776;', true, 'almostequalto'],
122 ['&ne;', '&#8800;', true, 'notequalto'],
123 ['&equiv;', '&#8801;', true, 'identicalto'],
124 ['&isin;', '&#8712;', false,'elementof'],
125 ['&notin;', '&#8713;', false,'notanelementof'],
126 ['&ni;', '&#8715;', false,'containsasmember'],
127 ['&prod;', '&#8719;', true, 'naryproduct'],
128 ['&and;', '&#8743;', false,'logicaland'],
129 ['&or;', '&#8744;', false,'logicalor'],
130 ['&not;', '&#172;', true, 'notsign'],
131 ['&cap;', '&#8745;', true, 'intersection'],
132 ['&cup;', '&#8746;', false,'union'],
133 ['&part;', '&#8706;', true, 'partialdifferential'],
134 ['&forall;', '&#8704;', false,'forall'],
135 ['&exist;', '&#8707;', false,'thereexists'],
136 ['&empty;', '&#8709;', false,'diameter'],
137 ['&nabla;', '&#8711;', false,'backwarddifference'],
138 ['&lowast;', '&#8727;', false,'asteriskoperator'],
139 ['&prop;', '&#8733;', false,'proportionalto'],
140 ['&ang;', '&#8736;', false,'angle'],
141 // Undefined.
142 ['&acute;', '&#180;', true, 'acuteaccent'],
143 ['&cedil;', '&#184;', true, 'cedilla'],
144 ['&ordf;', '&#170;', true, 'feminineordinalindicator'],
145 ['&ordm;', '&#186;', true, 'masculineordinalindicator'],
146 ['&dagger;', '&#8224;', true, 'dagger'],
147 ['&Dagger;', '&#8225;', true, 'doubledagger'],
148 // Alphabetical special chars.
149 ['&Agrave;', '&#192;', true, 'agrave_caps'],
150 ['&Aacute;', '&#193;', true, 'aacute_caps'],
151 ['&Acirc;', '&#194;', true, 'acircumflex_caps'],
152 ['&Atilde;', '&#195;', true, 'atilde_caps'],
153 ['&Auml;', '&#196;', true, 'adiaeresis_caps'],
154 ['&Aring;', '&#197;', true, 'aringabove_caps'],
155 ['&AElig;', '&#198;', true, 'ligatureae_caps'],
156 ['&Ccedil;', '&#199;', true, 'ccedilla_caps'],
157 ['&Egrave;', '&#200;', true, 'egrave_caps'],
158 ['&Eacute;', '&#201;', true, 'eacute_caps'],
159 ['&Ecirc;', '&#202;', true, 'ecircumflex_caps'],
160 ['&Euml;', '&#203;', true, 'ediaeresis_caps'],
161 ['&Igrave;', '&#204;', true, 'igrave_caps'],
162 ['&Iacute;', '&#205;', true, 'iacute_caps'],
163 ['&Icirc;', '&#206;', true, 'icircumflex_caps'],
164 ['&Iuml;', '&#207;', true, 'idiaeresis_caps'],
165 ['&ETH;', '&#208;', true, 'eth_caps'],
166 ['&Ntilde;', '&#209;', true, 'ntilde_caps'],
167 ['&Ograve;', '&#210;', true, 'ograve_caps'],
168 ['&Oacute;', '&#211;', true, 'oacute_caps'],
169 ['&Ocirc;', '&#212;', true, 'ocircumflex_caps'],
170 ['&Otilde;', '&#213;', true, 'otilde_caps'],
171 ['&Ouml;', '&#214;', true, 'odiaeresis_caps'],
172 ['&Oslash;', '&#216;', true, 'oslash_caps'],
173 ['&OElig;', '&#338;', true, 'ligatureoe_caps'],
174 ['&Scaron;', '&#352;', true, 'scaron_caps'],
175 ['&Ugrave;', '&#217;', true, 'ugrave_caps'],
176 ['&Uacute;', '&#218;', true, 'uacute_caps'],
177 ['&Ucirc;', '&#219;', true, 'ucircumflex_caps'],
178 ['&Uuml;', '&#220;', true, 'udiaeresis_caps'],
179 ['&Yacute;', '&#221;', true, 'yacute_caps'],
180 ['&Yuml;', '&#376;', true, 'ydiaeresis_caps'],
181 ['&THORN;', '&#222;', true, 'thorn_caps'],
182 ['&agrave;', '&#224;', true, 'agrave'],
183 ['&aacute;', '&#225;', true, 'aacute'],
184 ['&acirc;', '&#226;', true, 'acircumflex'],
185 ['&atilde;', '&#227;', true, 'atilde'],
186 ['&auml;', '&#228;', true, 'adiaeresis'],
187 ['&aring;', '&#229;', true, 'aringabove'],
188 ['&aelig;', '&#230;', true, 'ligatureae'],
189 ['&ccedil;', '&#231;', true, 'ccedilla'],
190 ['&egrave;', '&#232;', true, 'egrave'],
191 ['&eacute;', '&#233;', true, 'eacute'],
192 ['&ecirc;', '&#234;', true, 'ecircumflex'],
193 ['&euml;', '&#235;', true, 'ediaeresis'],
194 ['&igrave;', '&#236;', true, 'igrave'],
195 ['&iacute;', '&#237;', true, 'iacute'],
196 ['&icirc;', '&#238;', true, 'icircumflex'],
197 ['&iuml;', '&#239;', true, 'idiaeresis'],
198 ['&eth;', '&#240;', true, 'eth'],
199 ['&ntilde;', '&#241;', true, 'ntilde'],
200 ['&ograve;', '&#242;', true, 'ograve'],
201 ['&oacute;', '&#243;', true, 'oacute'],
202 ['&ocirc;', '&#244;', true, 'ocircumflex'],
203 ['&otilde;', '&#245;', true, 'otilde'],
204 ['&ouml;', '&#246;', true, 'odiaeresis'],
205 ['&oslash;', '&#248;', true, 'oslash'],
206 ['&oelig;', '&#339;', true, 'ligatureoe'],
207 ['&scaron;', '&#353;', true, 'scaron'],
208 ['&ugrave;', '&#249;', true, 'ugrave'],
209 ['&uacute;', '&#250;', true, 'uacute'],
210 ['&ucirc;', '&#251;', true, 'ucircumflex'],
211 ['&uuml;', '&#252;', true, 'udiaeresis'],
212 ['&yacute;', '&#253;', true, 'yacute'],
213 ['&thorn;', '&#254;', true, 'thorn'],
214 ['&yuml;', '&#255;', true, 'ydiaeresis'],
215 ['&Alpha;', '&#913;', true, 'alpha_caps'],
216 ['&Beta;', '&#914;', true, 'beta_caps'],
217 ['&Gamma;', '&#915;', true, 'gamma_caps'],
218 ['&Delta;', '&#916;', true, 'delta_caps'],
219 ['&Epsilon;', '&#917;', true, 'epsilon_caps'],
220 ['&Zeta;', '&#918;', true, 'zeta_caps'],
221 ['&Eta;', '&#919;', true, 'eta_caps'],
222 ['&Theta;', '&#920;', true, 'theta_caps'],
223 ['&Iota;', '&#921;', true, 'iota_caps'],
224 ['&Kappa;', '&#922;', true, 'kappa_caps'],
225 ['&Lambda;', '&#923;', true, 'lambda_caps'],
226 ['&Mu;', '&#924;', true, 'mu_caps'],
227 ['&Nu;', '&#925;', true, 'nu_caps'],
228 ['&Xi;', '&#926;', true, 'xi_caps'],
229 ['&Omicron;', '&#927;', true, 'omicron_caps'],
230 ['&Pi;', '&#928;', true, 'pi_caps'],
231 ['&Rho;', '&#929;', true, 'rho_caps'],
232 ['&Sigma;', '&#931;', true, 'sigma_caps'],
233 ['&Tau;', '&#932;', true, 'tau_caps'],
234 ['&Upsilon;', '&#933;', true, 'upsilon_caps'],
235 ['&Phi;', '&#934;', true, 'phi_caps'],
236 ['&Chi;', '&#935;', true, 'chi_caps'],
237 ['&Psi;', '&#936;', true, 'psi_caps'],
238 ['&Omega;', '&#937;', true, 'omega_caps'],
239 ['&alpha;', '&#945;', true, 'alpha'],
240 ['&beta;', '&#946;', true, 'beta'],
241 ['&gamma;', '&#947;', true, 'gamma'],
242 ['&delta;', '&#948;', true, 'delta'],
243 ['&epsilon;', '&#949;', true, 'epsilon'],
244 ['&zeta;', '&#950;', true, 'zeta'],
245 ['&eta;', '&#951;', true, 'eta'],
246 ['&theta;', '&#952;', true, 'theta'],
247 ['&iota;', '&#953;', true, 'iota'],
248 ['&kappa;', '&#954;', true, 'kappa'],
249 ['&lambda;', '&#955;', true, 'lambda'],
250 ['&mu;', '&#956;', true, 'mu'],
251 ['&nu;', '&#957;', true, 'nu'],
252 ['&xi;', '&#958;', true, 'xi'],
253 ['&omicron;', '&#959;', true, 'omicron'],
254 ['&pi;', '&#960;', true, 'pi'],
255 ['&rho;', '&#961;', true, 'rho'],
256 ['&sigmaf;', '&#962;', true, 'finalsigma'],
257 ['&sigma;', '&#963;', true, 'sigma'],
258 ['&tau;', '&#964;', true, 'tau'],
259 ['&upsilon;', '&#965;', true, 'upsilon'],
260 ['&phi;', '&#966;', true, 'phi'],
261 ['&chi;', '&#967;', true, 'chi'],
262 ['&psi;', '&#968;', true, 'psi'],
263 ['&omega;', '&#969;', true, 'omega'],
264 // Symbols.
265 ['&alefsym;', '&#8501;', false,'alefsymbol'],
266 ['&piv;', '&#982;', false,'pisymbol'],
267 ['&real;', '&#8476;', false,'realpartsymbol'],
268 ['&thetasym;','&#977;', false,'thetasymbol'],
269 ['&upsih;', '&#978;', false,'upsilonhooksymbol'],
270 ['&weierp;', '&#8472;', false,'weierstrassp'],
271 ['&image;', '&#8465;', false,'imaginarypart'],
272 // Arrows.
273 ['&larr;', '&#8592;', true, 'leftwardsarrow'],
274 ['&uarr;', '&#8593;', true, 'upwardsarrow'],
275 ['&rarr;', '&#8594;', true, 'rightwardsarrow'],
276 ['&darr;', '&#8595;', true, 'downwardsarrow'],
277 ['&harr;', '&#8596;', true, 'leftrightarrow'],
278 ['&crarr;', '&#8629;', false,'carriagereturn'],
279 ['&lArr;', '&#8656;', false,'leftwardsdoublearrow'],
280 ['&uArr;', '&#8657;', false,'upwardsdoublearrow'],
281 ['&rArr;', '&#8658;', false,'rightwardsdoublearrow'],
282 ['&dArr;', '&#8659;', false,'downwardsdoublearrow'],
283 ['&hArr;', '&#8660;', false,'leftrightdoublearrow'],
284 ['&there4;', '&#8756;', false,'therefore'],
285 ['&sub;', '&#8834;', false,'subsetof'],
286 ['&sup;', '&#8835;', false,'supersetof'],
287 ['&nsub;', '&#8836;', false,'notasubsetof'],
288 ['&sube;', '&#8838;', false,'subsetoforequalto'],
289 ['&supe;', '&#8839;', false,'supersetoforequalto'],
290 ['&oplus;', '&#8853;', false,'circledplus'],
291 ['&otimes;', '&#8855;', false,'circledtimes'],
292 ['&perp;', '&#8869;', false,'perpendicular'],
293 ['&sdot;', '&#8901;', false,'dotoperator'],
294 ['&lceil;', '&#8968;', false,'leftceiling'],
295 ['&rceil;', '&#8969;', false,'rightceiling'],
296 ['&lfloor;', '&#8970;', false,'leftfloor'],
297 ['&rfloor;', '&#8971;', false,'rightfloor'],
298 ['&lang;', '&#9001;', false,'leftpointinganglebracket'],
299 ['&rang;', '&#9002;', false,'rightpointinganglebracket'],
300 ['&loz;', '&#9674;', true, 'lozenge'],
301 ['&spades;', '&#9824;', true, 'blackspadesuit'],
302 ['&clubs;', '&#9827;', true, 'blackclubsuit'],
303 ['&hearts;', '&#9829;', true, 'blackheartsuit'],
304 ['&diams;', '&#9830;', true, 'blackdiamondsuit'],
305 ['&ensp;', '&#8194;', false,'enspace'],
306 ['&emsp;', '&#8195;', false,'emspace'],
307 ['&thinsp;', '&#8201;', false,'thinspace'],
308 ['&zwnj;', '&#8204;', false,'zerowidthnonjoiner'],
309 ['&zwj;', '&#8205;', false,'zerowidthjoiner'],
310 ['&lrm;', '&#8206;', false,'lefttorightmark'],
311 ['&rlm;', '&#8207;', false,'righttoleftmark'],
312 ['&shy;', '&#173;', false,'softhyphen']
313 ];
314
315M.atto_charmap = M.atto_charmap || {
316
317 /**
318 * The ID of the current editor.
319 *
320 * @type {String}
321 */
322 currentElementId: null,
323
324 /**
325 * The dialogue to select a character.
326 *
327 * @type {M.core.dialogue}
328 */
329 dialogue: null,
330
331 /**
332 * Keeps track of the selection made by the user.
333 *
334 * @type {Mixed}
335 */
336 selection: null,
337
338 /**
339 * Init.
340 *
341 * @param {Object} params
342 *
343 * @return {Void}
344 */
345 init: function(params) {
346
347 var display_chooser = function(e, elementid) {
348 e.preventDefault();
349 if (!M.editor_atto.is_active(elementid)) {
350 M.editor_atto.focus(elementid);
351 }
352 M.atto_charmap.selection = M.editor_atto.get_selection();
353 if (M.atto_charmap.selection === false) {
354 return;
355 }
356
357 // Stores what editor we are working on.
358 M.atto_charmap.currentElementId = elementid;
359
360 // Initialising the dialogue.
361 var dialogue;
362 if (!M.atto_charmap.dialogue) {
363 dialogue = new M.core.dialogue({
364 visible: false,
365 modal: true,
366 close: true,
367 draggable: true
368 });
369
370 // Setting up the content of the dialogue.
371 dialogue.set('bodyContent', M.atto_charmap.getDialogueContent());
372 dialogue.set('headerContent', M.util.get_string('insertcharacter', 'atto_charmap'));
373 dialogue.render();
374 dialogue.centerDialogue();
375 M.atto_charmap.dialogue = dialogue;
376 } else {
377 dialogue = M.atto_charmap.dialogue;
378 }
379
380 dialogue.show();
381 };
382
383 var iconurl = M.util.image_url('e/special_character', 'core');
384 M.editor_atto.add_toolbar_button(params.elementid, 'charmap', iconurl, params.group, display_chooser);
385 },
386
387 /**
388 * Generates the content of the dialogue.
389 *
390 * @return {Node} Node containing the dialogue content
391 */
392 getDialogueContent: function() {
393 var content,
394 html = '<div class="' + CSS.CHARMAP + '">',
395 i;
396
397 for (i = 0; i < CHARMAP.length; i++) {
398 if (!CHARMAP[i][2]) {
399 continue;
400 }
401 html += '<button class="' + CSS.BUTTON + '" ' +
402 'aria-label="' + Y.Escape.html(M.util.get_string(CHARMAP[i][3], 'atto_charmap')) + '" ' +
403 'title="' + Y.Escape.html(M.util.get_string(CHARMAP[i][3], 'atto_charmap')) + '" ' +
404 'data-character="' + CHARMAP[i][0] + '" ' +
405 '>' +
406 CHARMAP[i][0] +
407 '</button>';
408 }
409 html += '</div>';
410
411 content = Y.Node.create(html);
412 Y.delegate('click', M.atto_charmap.insertChar, content, SELECTORS.BUTTON, this);
413 return content;
414 },
415
416 /**
417 * Insert the picked character in Atto.
418 *
419 * @param {Event} e The event
420 * @return {Void}
421 */
422 insertChar: function(e) {
423 var character = e.target.getData('character');
424
425 e.preventDefault();
426 e.stopPropagation();
427 M.atto_charmap.dialogue.hide();
428
429 M.editor_atto.set_selection(M.atto_charmap.selection);
430 if (document.selection && document.selection.createRange().pasteHTML) {
431 document.selection.createRange().pasteHTML(character);
432 } else {
433 document.execCommand('insertHTML', false, character);
434 }
435
436 // Clean the YUI ids from the HTML.
437 M.editor_atto.text_updated(M.atto_charmap.currentElementId);
438 }
439};