JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.2.2
[ckeditor.git] / _source / plugins / specialchar / dialogs / specialchar.js
1 /*\r
2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license\r
4 */\r
5 \r
6 CKEDITOR.dialog.add( 'specialchar', function( editor )\r
7 {\r
8         /**\r
9          * Simulate "this" of a dialog for non-dialog events.\r
10          * @type {CKEDITOR.dialog}\r
11          */\r
12         var dialog,\r
13                 lang = editor.lang.specialChar;\r
14 \r
15         var insertSpecialChar = function ( specialChar )\r
16         {\r
17                 var selection = editor.getSelection(),\r
18                         ranges    = selection.getRanges(),\r
19                         range, textNode;\r
20 \r
21                 editor.fire( 'saveSnapshot' );\r
22 \r
23                 for ( var i = 0, len = ranges.length ; i < len ; i++ )\r
24                 {\r
25                         range = ranges[ i ];\r
26                         range.deleteContents();\r
27 \r
28                         textNode =  CKEDITOR.dom.element.createFromHtml( specialChar );\r
29                         range.insertNode( textNode );\r
30                 }\r
31 \r
32                 range.moveToPosition( textNode, CKEDITOR.POSITION_AFTER_END );\r
33                 range.select();\r
34 \r
35                 editor.fire( 'saveSnapshot' );\r
36         };\r
37 \r
38         var onChoice = function( evt )\r
39         {\r
40                 var target, value;\r
41                 if ( evt.data )\r
42                         target = evt.data.getTarget();\r
43                 else\r
44                         target = new CKEDITOR.dom.element( evt );\r
45 \r
46                 if ( target.getName() == 'a' && ( value = target.getChild( 0 ).getHtml() ) )\r
47                 {\r
48                         target.removeClass( "cke_light_background" );\r
49                         dialog.hide();\r
50 \r
51                         // Firefox has bug on insert chars into a element use its own API. (#5170)\r
52                         if ( CKEDITOR.env.gecko )\r
53                                 insertSpecialChar( value );\r
54                         else\r
55                                 editor.insertHtml( value );\r
56                 }\r
57         };\r
58 \r
59         var onClick = CKEDITOR.tools.addFunction( onChoice );\r
60 \r
61         var focusedNode;\r
62 \r
63         var onFocus = function( evt, target )\r
64         {\r
65                 var value;\r
66                 target = target || evt.data.getTarget();\r
67 \r
68                 if ( target.getName() == 'span' )\r
69                         target = target.getParent();\r
70 \r
71                 if ( target.getName() == 'a' && ( value = target.getChild( 0 ).getHtml() ) )\r
72                 {\r
73                         // Trigger blur manually if there is focused node.\r
74                         if ( focusedNode )\r
75                                 onBlur( null, focusedNode );\r
76 \r
77                         var htmlPreview = dialog.getContentElement( 'info', 'htmlPreview' ).getElement();\r
78 \r
79                         dialog.getContentElement( 'info', 'charPreview' ).getElement().setHtml( value );\r
80                         htmlPreview.setHtml( CKEDITOR.tools.htmlEncode( value ) );\r
81                         target.getParent().addClass( "cke_light_background" );\r
82 \r
83                         // Memorize focused node.\r
84                         focusedNode = target;\r
85                 }\r
86         };\r
87 \r
88         var onBlur = function( evt, target )\r
89         {\r
90                 target = target || evt.data.getTarget();\r
91 \r
92                 if ( target.getName() == 'span' )\r
93                         target = target.getParent();\r
94 \r
95                 if ( target.getName() == 'a' )\r
96                 {\r
97                         dialog.getContentElement( 'info', 'charPreview' ).getElement().setHtml( '&nbsp;' );\r
98                         dialog.getContentElement( 'info', 'htmlPreview' ).getElement().setHtml( '&nbsp;' );\r
99                         target.getParent().removeClass( "cke_light_background" );\r
100 \r
101                         focusedNode = undefined;\r
102                 }\r
103         };\r
104 \r
105         var onKeydown = CKEDITOR.tools.addFunction( function( ev )\r
106         {\r
107                 ev = new CKEDITOR.dom.event( ev );\r
108 \r
109                 // Get an Anchor element.\r
110                 var element = ev.getTarget();\r
111                 var relative, nodeToMove;\r
112                 var keystroke = ev.getKeystroke();\r
113                 var rtl = editor.lang.dir == 'rtl';\r
114 \r
115                 switch ( keystroke )\r
116                 {\r
117                         // UP-ARROW\r
118                         case 38 :\r
119                                 // relative is TR\r
120                                 if ( ( relative = element.getParent().getParent().getPrevious() ) )\r
121                                 {\r
122                                         nodeToMove = relative.getChild( [element.getParent().getIndex(), 0] );\r
123                                         nodeToMove.focus();\r
124                                         onBlur( null, element );\r
125                                         onFocus( null, nodeToMove );\r
126                                 }\r
127                                 ev.preventDefault();\r
128                                 break;\r
129                         // DOWN-ARROW\r
130                         case 40 :\r
131                                 // relative is TR\r
132                                 if ( ( relative = element.getParent().getParent().getNext() ) )\r
133                                 {\r
134                                         nodeToMove = relative.getChild( [ element.getParent().getIndex(), 0 ] );\r
135                                         if ( nodeToMove && nodeToMove.type == 1 )\r
136                                         {\r
137                                                 nodeToMove.focus();\r
138                                                 onBlur( null, element );\r
139                                                 onFocus( null, nodeToMove );\r
140                                         }\r
141                                 }\r
142                                 ev.preventDefault();\r
143                                 break;\r
144                         // SPACE\r
145                         // ENTER is already handled as onClick\r
146                         case 32 :\r
147                                 onChoice( { data: ev } );\r
148                                 ev.preventDefault();\r
149                                 break;\r
150 \r
151                         // RIGHT-ARROW\r
152                         case rtl ? 37 : 39 :\r
153                         // TAB\r
154                         case 9 :\r
155                                 // relative is TD\r
156                                 if ( ( relative = element.getParent().getNext() ) )\r
157                                 {\r
158                                         nodeToMove = relative.getChild( 0 );\r
159                                         if ( nodeToMove.type == 1 )\r
160                                         {\r
161                                                 nodeToMove.focus();\r
162                                                 onBlur( null, element );\r
163                                                 onFocus( null, nodeToMove );\r
164                                                 ev.preventDefault( true );\r
165                                         }\r
166                                         else\r
167                                                 onBlur( null, element );\r
168                                 }\r
169                                 // relative is TR\r
170                                 else if ( ( relative = element.getParent().getParent().getNext() ) )\r
171                                 {\r
172                                         nodeToMove = relative.getChild( [ 0, 0 ] );\r
173                                         if ( nodeToMove && nodeToMove.type == 1 )\r
174                                         {\r
175                                                 nodeToMove.focus();\r
176                                                 onBlur( null, element );\r
177                                                 onFocus( null, nodeToMove );\r
178                                                 ev.preventDefault( true );\r
179                                         }\r
180                                         else\r
181                                                 onBlur( null, element );\r
182                                 }\r
183                                 break;\r
184 \r
185                         // LEFT-ARROW\r
186                         case rtl ? 39 : 37 :\r
187                         // SHIFT + TAB\r
188                         case CKEDITOR.SHIFT + 9 :\r
189                                 // relative is TD\r
190                                 if ( ( relative = element.getParent().getPrevious() ) )\r
191                                 {\r
192                                         nodeToMove = relative.getChild( 0 );\r
193                                         nodeToMove.focus();\r
194                                         onBlur( null, element );\r
195                                         onFocus( null, nodeToMove );\r
196                                         ev.preventDefault( true );\r
197                                 }\r
198                                 // relative is TR\r
199                                 else if ( ( relative = element.getParent().getParent().getPrevious() ) )\r
200                                 {\r
201                                         nodeToMove = relative.getLast().getChild( 0 );\r
202                                         nodeToMove.focus();\r
203                                         onBlur( null, element );\r
204                                         onFocus( null, nodeToMove );\r
205                                         ev.preventDefault( true );\r
206                                 }\r
207                                 else\r
208                                         onBlur( null, element );\r
209                                 break;\r
210                         default :\r
211                                 // Do not stop not handled events.\r
212                                 return;\r
213                 }\r
214         });\r
215 \r
216         return {\r
217                 title : lang.title,\r
218                 minWidth : 430,\r
219                 minHeight : 280,\r
220                 buttons : [ CKEDITOR.dialog.cancelButton ],\r
221                 charColumns : 17,\r
222                 chars :\r
223                         [\r
224                                 '!','&quot;','#','$','%','&amp;',"'",'(',')','*','+','-','.','/',\r
225                                 '0','1','2','3','4','5','6','7','8','9',':',';',\r
226                                 '&lt;','=','&gt;','?','@',\r
227                                 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',\r
228                                 'P','Q','R','S','T','U','V','W','X','Y','Z',\r
229                                 '[',']','^','_','`',\r
230                                 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',\r
231                                 'q','r','s','t','u','v','w','x','y','z',\r
232                                 '{','|','}','~','&euro;(EURO SIGN)','&lsquo;(LEFT SINGLE QUOTATION MARK)','&rsquo;(RIGHT SINGLE QUOTATION MARK)','&ldquo;(LEFT DOUBLE QUOTATION MARK)',\r
233                                 '&rdquo;(RIGHT DOUBLE QUOTATION MARK)','&ndash;(EN DASH)','&mdash;(EM DASH)','&iexcl;(INVERTED EXCLAMATION MARK)','&cent;(CENT SIGN)','&pound;(POUND SIGN)',\r
234                                 '&curren;(CURRENCY SIGN)','&yen;(YEN SIGN)','&brvbar;(BROKEN BAR)','&sect;(SECTION SIGN)','&uml;(DIAERESIS)','&copy;(COPYRIGHT SIGN)','&ordf;(FEMININE ORDINAL INDICATOR)',\r
235                                 '&laquo;(LEFT-POINTING DOUBLE ANGLE QUOTATION MARK)','&not;(NOT SIGN)','&reg;(REGISTERED SIGN)','&macr;(MACRON)','&deg;(DEGREE SIGN)','&plusmn;(PLUS-MINUS SIGN)','&sup2;(SUPERSCRIPT TWO)',\r
236                                 '&sup3;(SUPERSCRIPT THREE)','&acute;(ACUTE ACCENT)','&micro;(MICRO SIGN)','&para;(PILCROW SIGN)','&middot;(MIDDLE DOT)','&cedil;(CEDILLA)',\r
237                                 '&sup1;(SUPERSCRIPT ONE)','&ordm;(MASCULINE ORDINAL INDICATOR)','&raquo;(RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK)','&frac14;(VULGAR FRACTION ONE QUARTER)','&frac12;(VULGAR FRACTION ONE HALF)','&frac34;(VULGAR FRACTION THREE QUARTERS)',\r
238                                 '&iquest;(INVERTED QUESTION MARK)','&Agrave;(LATIN CAPITAL LETTER A WITH GRAVE)','&Aacute;(LATIN CAPITAL LETTER A WITH ACUTE)','&Acirc;(LATIN CAPITAL LETTER A WITH CIRCUMFLEX)','&Atilde;(LATIN CAPITAL LETTER A WITH TILDE)','&Auml;(LATIN CAPITAL LETTER A WITH DIAERESIS)',\r
239                                 '&Aring;(LATIN CAPITAL LETTER A WITH RING ABOVE)','&AElig;(LATIN CAPITAL LETTER AE)','&Ccedil;(LATIN CAPITAL LETTER C WITH CEDILLA)','&Egrave;(LATIN CAPITAL LETTER E WITH GRAVE)','&Eacute;(LATIN CAPITAL LETTER E WITH ACUTE)','&Ecirc;(LATIN CAPITAL LETTER E WITH CIRCUMFLEX)',\r
240                                 '&Euml;(LATIN CAPITAL LETTER E WITH DIAERESIS)','&Igrave;(LATIN CAPITAL LETTER I WITH GRAVE)','&Iacute;(LATIN CAPITAL LETTER I WITH ACUTE)','&Icirc;(LATIN CAPITAL LETTER I WITH CIRCUMFLEX)','&Iuml;(LATIN CAPITAL LETTER I WITH DIAERESIS)','&ETH;(LATIN CAPITAL LETTER ETH)',\r
241                                 '&Ntilde;(LATIN CAPITAL LETTER N WITH TILDE)','&Ograve;(LATIN CAPITAL LETTER O WITH GRAVE)','&Oacute;(LATIN CAPITAL LETTER O WITH ACUTE)','&Ocirc;(LATIN CAPITAL LETTER O WITH CIRCUMFLEX)','&Otilde;(LATIN CAPITAL LETTER O WITH TILDE)','&Ouml;(LATIN CAPITAL LETTER O WITH DIAERESIS)',\r
242                                 '&times;(MULTIPLICATION SIGN)','&Oslash;(LATIN CAPITAL LETTER O WITH STROKE)','&Ugrave;(LATIN CAPITAL LETTER U WITH GRAVE)','&Uacute;(LATIN CAPITAL LETTER U WITH ACUTE)','&Ucirc;(LATIN CAPITAL LETTER U WITH CIRCUMFLEX)','&Uuml;(LATIN CAPITAL LETTER U WITH DIAERESIS)',\r
243                                 '&Yacute;(LATIN CAPITAL LETTER Y WITH ACUTE)','&THORN;(LATIN CAPITAL LETTER THORN)','&szlig;(LATIN SMALL LETTER SHARP S)','&agrave;(LATIN SMALL LETTER A WITH GRAVE)','&aacute;(LATIN SMALL LETTER A WITH ACUTE)','&acirc;(LATIN SMALL LETTER A WITH CIRCUMFLEX)',\r
244                                 '&atilde;(LATIN SMALL LETTER A WITH TILDE)','&auml;(LATIN SMALL LETTER A WITH DIAERESIS)','&aring;(LATIN SMALL LETTER A WITH RING ABOVE)','&aelig;(LATIN SMALL LETTER AE)','&ccedil;(LATIN SMALL LETTER C WITH CEDILLA)','&egrave;(LATIN SMALL LETTER E WITH GRAVE)',\r
245                                 '&eacute;(LATIN SMALL LETTER E WITH ACUTE)','&ecirc;(LATIN SMALL LETTER E WITH CIRCUMFLEX)','&euml;(LATIN SMALL LETTER E WITH DIAERESIS)','&igrave;(LATIN SMALL LETTER I WITH GRAVE)','&iacute;(LATIN SMALL LETTER I WITH ACUTE)','&icirc;(LATIN SMALL LETTER I WITH CIRCUMFLEX)',\r
246                                 '&iuml;(LATIN SMALL LETTER I WITH DIAERESIS)','&eth;(LATIN SMALL LETTER ETH)','&ntilde;(LATIN SMALL LETTER N WITH TILDE)','&ograve;(LATIN SMALL LETTER O WITH GRAVE)','&oacute;(LATIN SMALL LETTER O WITH ACUTE)','&ocirc;(LATIN SMALL LETTER O WITH CIRCUMFLEX)',\r
247                                 '&otilde;(LATIN SMALL LETTER O WITH TILDE)','&ouml;(LATIN SMALL LETTER O WITH DIAERESIS)',\r
248                                 '&divide;(DIVISION SIGN)','&oslash;(LATIN SMALL LETTER O WITH STROKE)',\r
249                                 '&ugrave;(LATIN SMALL LETTER U WITH GRAVE)','&uacute;(LATIN SMALL LETTER U WITH ACUTE)',\r
250                                 '&ucirc;(LATIN SMALL LETTER U WITH CIRCUMFLEX)','&uuml;(LATIN SMALL LETTER U WITH DIAERESIS)',\r
251                                 '&uuml;(LATIN SMALL LETTER U WITH DIAERESIS)','&yacute;(LATIN SMALL LETTER Y WITH ACUTE)','&thorn;(LATIN SMALL LETTER THORN)','&yuml;(LATIN SMALL LETTER Y WITH DIAERESIS)',\r
252                                 '&OElig;(LATIN CAPITAL LIGATURE OE)',\r
253                                 '&oelig;(LATIN SMALL LIGATURE OE)','&#372;(LATIN CAPITAL LETTER W WITH CIRCUMFLEX)',\r
254                                 '&#374(LATIN CAPITAL LETTER Y WITH CIRCUMFLEX)','&#373(LATIN SMALL LETTER W WITH CIRCUMFLEX)',\r
255                                 '&#375;(LATIN SMALL LETTER Y WITH CIRCUMFLEX)','&sbquo;(SINGLE LOW-9 QUOTATION MARK)',\r
256                                 '&#8219;(SINGLE HIGH-REVERSED-9 QUOTATION MARK)','&bdquo;(DOUBLE LOW-9 QUOTATION MARK)','&hellip;(HORIZONTAL ELLIPSIS)',\r
257                                 '&trade;(TRADE MARK SIGN)','&#9658;(BLACK RIGHT-POINTING POINTER)','&bull;(BULLET)',\r
258                                 '&rarr;(RIGHTWARDS ARROW)','&rArr;(RIGHTWARDS DOUBLE ARROW)','&hArr;(LEFT RIGHT DOUBLE ARROW)','&diams;(BLACK DIAMOND SUIT)','&asymp;(ALMOST EQUAL TO)'\r
259                         ],\r
260                 onLoad :  function()\r
261                 {\r
262                         var columns = this.definition.charColumns,\r
263                                 chars = this.definition.chars;\r
264 \r
265                         var charsTableLabel =  'specialchar_table_label' + CKEDITOR.tools.getNextNumber();\r
266                         var html = [ '<table role="listbox" aria-labelledby="' + charsTableLabel + '"' +\r
267                                                                         ' style="width: 320px; height: 100%; border-collapse: separate;"' +\r
268                                                                         ' align="center" cellspacing="2" cellpadding="2" border="0">' ];\r
269 \r
270                         var i = 0,\r
271                                 size = chars.length,\r
272                                 character,\r
273                                 charDesc;\r
274 \r
275                         while ( i < size )\r
276                         {\r
277                                 html.push( '<tr>' ) ;\r
278 \r
279                                 for ( var j = 0 ; j < columns ; j++, i++ )\r
280                                 {\r
281                                         if ( ( character = chars[ i ] ) )\r
282                                         {\r
283                                                 charDesc = '';\r
284                                                 character = character.replace( /\((.*?)\)/, function( match, desc )\r
285                                                         {\r
286                                                                 charDesc = desc;\r
287                                                                 return '';\r
288                                                         } );\r
289 \r
290                                                 // Use character in case description unavailable.\r
291                                                 charDesc = charDesc || character;\r
292 \r
293                                                 var charLabelId =  'cke_specialchar_label_' + i + '_' + CKEDITOR.tools.getNextNumber();\r
294 \r
295                                                 html.push(\r
296                                                         '<td class="cke_dark_background" style="cursor: default" role="presentation">' +\r
297                                                         '<a href="javascript: void(0);" role="option"' +\r
298                                                         ' aria-posinset="' + ( i +1 ) + '"',\r
299                                                         ' aria-setsize="' + size + '"',\r
300                                                         ' aria-labelledby="' + charLabelId + '"',\r
301                                                         ' style="cursor: inherit; display: block; height: 1.25em; margin-top: 0.25em; text-align: center;" title="', CKEDITOR.tools.htmlEncode( charDesc ), '"' +\r
302                                                         ' onkeydown="CKEDITOR.tools.callFunction( ' + onKeydown + ', event, this )"' +\r
303                                                         ' onclick="CKEDITOR.tools.callFunction(' + onClick + ', this); return false;"' +\r
304                                                         ' tabindex="-1">' +\r
305                                                         '<span style="margin: 0 auto;cursor: inherit">' +\r
306                                                         character +\r
307                                                         '</span>' +\r
308                                                         '<span class="cke_voice_label" id="' + charLabelId + '">' +\r
309                                                         charDesc +\r
310                                                         '</span></a>');\r
311                                         }\r
312                                         else\r
313                                                 html.push( '<td class="cke_dark_background">&nbsp;' );\r
314 \r
315                                         html.push( '</td>' );\r
316                                 }\r
317                                 html.push( '</tr>' );\r
318                         }\r
319 \r
320                         html.push( '</tbody></table>', '<span id="' + charsTableLabel + '" class="cke_voice_label">' + lang.options +'</span>' );\r
321 \r
322                         this.getContentElement( 'info', 'charContainer' ).getElement().setHtml( html.join( '' ) );\r
323                 },\r
324                 contents : [\r
325                         {\r
326                                 id : 'info',\r
327                                 label : editor.lang.common.generalTab,\r
328                                 title : editor.lang.common.generalTab,\r
329                                 padding : 0,\r
330                                 align : 'top',\r
331                                 elements : [\r
332                                         {\r
333                                                 type : 'hbox',\r
334                                                 align : 'top',\r
335                                                 widths : [ '320px', '90px' ],\r
336                                                 children :\r
337                                                 [\r
338                                                         {\r
339                                                                 type : 'html',\r
340                                                                 id : 'charContainer',\r
341                                                                 html : '',\r
342                                                                 onMouseover : onFocus,\r
343                                                                 onMouseout : onBlur,\r
344                                                                 focus : function()\r
345                                                                 {\r
346                                                                         var firstChar = this.getElement().getElementsByTag( 'a' ).getItem( 0 );\r
347                                                                         setTimeout(function()\r
348                                                                         {\r
349                                                                                 firstChar.focus();\r
350                                                                                 onFocus( null, firstChar );\r
351                                                                         });\r
352                                                                 },\r
353                                                                 onShow : function()\r
354                                                                 {\r
355                                                                         var firstChar = this.getElement().getChild( [ 0, 0, 0, 0, 0 ] );\r
356                                                                         setTimeout( function()\r
357                                                                                 {\r
358                                                                                         firstChar.focus();\r
359                                                                                         onFocus( null, firstChar );\r
360                                                                                 });\r
361                                                                 },\r
362                                                                 onLoad : function( event )\r
363                                                                 {\r
364                                                                         dialog = event.sender;\r
365                                                                 }\r
366                                                         },\r
367                                                         {\r
368                                                                 type : 'hbox',\r
369                                                                 align : 'top',\r
370                                                                 widths : [ '100%' ],\r
371                                                                 children :\r
372                                                                 [\r
373                                                                         {\r
374                                                                                 type : 'vbox',\r
375                                                                                 align : 'top',\r
376                                                                                 children :\r
377                                                                                 [\r
378                                                                                         {\r
379                                                                                                 type : 'html',\r
380                                                                                                 html : '<div></div>'\r
381                                                                                         },\r
382                                                                                         {\r
383                                                                                                 type : 'html',\r
384                                                                                                 id : 'charPreview',\r
385                                                                                                 className : 'cke_dark_background',\r
386                                                                                                 style : 'border:1px solid #eeeeee;font-size:28px;height:40px;width:70px;padding-top:9px;font-family:\'Microsoft Sans Serif\',Arial,Helvetica,Verdana;text-align:center;',\r
387                                                                                                 html : '<div>&nbsp;</div>'\r
388                                                                                         },\r
389                                                                                         {\r
390                                                                                                 type : 'html',\r
391                                                                                                 id : 'htmlPreview',\r
392                                                                                                 className : 'cke_dark_background',\r
393                                                                                                 style : 'border:1px solid #eeeeee;font-size:14px;height:20px;width:70px;padding-top:2px;font-family:\'Microsoft Sans Serif\',Arial,Helvetica,Verdana;text-align:center;',\r
394                                                                                                 html : '<div>&nbsp;</div>'\r
395                                                                                         }\r
396                                                                                 ]\r
397                                                                         }\r
398                                                                 ]\r
399                                                         }\r
400                                                 ]\r
401                                         }\r
402                                 ]\r
403                         }\r
404                 ]\r
405         };\r
406 } );\r