JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
0fba305db68fb1f0e4e71297cc3698aadf6e08d3
[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( true ),\r
19                         range, textNode;\r
20 \r
21                 editor.fire( 'saveSnapshot' );\r
22 \r
23                 for ( var i = ranges.length - 1; i >= 0 ; 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                 if ( range )\r
33                 {\r
34                         range.moveToPosition( textNode, CKEDITOR.POSITION_AFTER_END );\r
35                         range.select();\r
36                 }\r
37 \r
38                 editor.fire( 'saveSnapshot' );\r
39         };\r
40 \r
41         var onChoice = function( evt )\r
42         {\r
43                 var target, value;\r
44                 if ( evt.data )\r
45                         target = evt.data.getTarget();\r
46                 else\r
47                         target = new CKEDITOR.dom.element( evt );\r
48 \r
49                 if ( target.getName() == 'a' && ( value = target.getChild( 0 ).getHtml() ) )\r
50                 {\r
51                         target.removeClass( "cke_light_background" );\r
52                         dialog.hide();\r
53 \r
54                         // Firefox has bug on insert chars into a element use its own API. (#5170)\r
55                         if ( CKEDITOR.env.gecko )\r
56                                 insertSpecialChar( value );\r
57                         else\r
58                                 editor.insertHtml( value );\r
59                 }\r
60         };\r
61 \r
62         var onClick = CKEDITOR.tools.addFunction( onChoice );\r
63 \r
64         var focusedNode;\r
65 \r
66         var onFocus = function( evt, target )\r
67         {\r
68                 var value;\r
69                 target = target || evt.data.getTarget();\r
70 \r
71                 if ( target.getName() == 'span' )\r
72                         target = target.getParent();\r
73 \r
74                 if ( target.getName() == 'a' && ( value = target.getChild( 0 ).getHtml() ) )\r
75                 {\r
76                         // Trigger blur manually if there is focused node.\r
77                         if ( focusedNode )\r
78                                 onBlur( null, focusedNode );\r
79 \r
80                         var htmlPreview = dialog.getContentElement( 'info', 'htmlPreview' ).getElement();\r
81 \r
82                         dialog.getContentElement( 'info', 'charPreview' ).getElement().setHtml( value );\r
83                         htmlPreview.setHtml( CKEDITOR.tools.htmlEncode( value ) );\r
84                         target.getParent().addClass( "cke_light_background" );\r
85 \r
86                         // Memorize focused node.\r
87                         focusedNode = target;\r
88                 }\r
89         };\r
90 \r
91         var onBlur = function( evt, target )\r
92         {\r
93                 target = target || evt.data.getTarget();\r
94 \r
95                 if ( target.getName() == 'span' )\r
96                         target = target.getParent();\r
97 \r
98                 if ( target.getName() == 'a' )\r
99                 {\r
100                         dialog.getContentElement( 'info', 'charPreview' ).getElement().setHtml( ' ' );\r
101                         dialog.getContentElement( 'info', 'htmlPreview' ).getElement().setHtml( ' ' );\r
102                         target.getParent().removeClass( "cke_light_background" );\r
103 \r
104                         focusedNode = undefined;\r
105                 }\r
106         };\r
107 \r
108         var onKeydown = CKEDITOR.tools.addFunction( function( ev )\r
109         {\r
110                 ev = new CKEDITOR.dom.event( ev );\r
111 \r
112                 // Get an Anchor element.\r
113                 var element = ev.getTarget();\r
114                 var relative, nodeToMove;\r
115                 var keystroke = ev.getKeystroke(),\r
116                         rtl = editor.lang.dir == 'rtl';\r
117 \r
118                 switch ( keystroke )\r
119                 {\r
120                         // UP-ARROW\r
121                         case 38 :\r
122                                 // relative is TR\r
123                                 if ( ( relative = element.getParent().getParent().getPrevious() ) )\r
124                                 {\r
125                                         nodeToMove = relative.getChild( [element.getParent().getIndex(), 0] );\r
126                                         nodeToMove.focus();\r
127                                         onBlur( null, element );\r
128                                         onFocus( null, nodeToMove );\r
129                                 }\r
130                                 ev.preventDefault();\r
131                                 break;\r
132                         // DOWN-ARROW\r
133                         case 40 :\r
134                                 // relative is TR\r
135                                 if ( ( relative = element.getParent().getParent().getNext() ) )\r
136                                 {\r
137                                         nodeToMove = relative.getChild( [ element.getParent().getIndex(), 0 ] );\r
138                                         if ( nodeToMove && nodeToMove.type == 1 )\r
139                                         {\r
140                                                 nodeToMove.focus();\r
141                                                 onBlur( null, element );\r
142                                                 onFocus( null, nodeToMove );\r
143                                         }\r
144                                 }\r
145                                 ev.preventDefault();\r
146                                 break;\r
147                         // SPACE\r
148                         // ENTER is already handled as onClick\r
149                         case 32 :\r
150                                 onChoice( { data: ev } );\r
151                                 ev.preventDefault();\r
152                                 break;\r
153 \r
154                         // RIGHT-ARROW\r
155                         case rtl ? 37 : 39 :\r
156                         // TAB\r
157                         case 9 :\r
158                                 // relative is TD\r
159                                 if ( ( relative = element.getParent().getNext() ) )\r
160                                 {\r
161                                         nodeToMove = relative.getChild( 0 );\r
162                                         if ( nodeToMove.type == 1 )\r
163                                         {\r
164                                                 nodeToMove.focus();\r
165                                                 onBlur( null, element );\r
166                                                 onFocus( null, nodeToMove );\r
167                                                 ev.preventDefault( true );\r
168                                         }\r
169                                         else\r
170                                                 onBlur( null, element );\r
171                                 }\r
172                                 // relative is TR\r
173                                 else if ( ( relative = element.getParent().getParent().getNext() ) )\r
174                                 {\r
175                                         nodeToMove = relative.getChild( [ 0, 0 ] );\r
176                                         if ( nodeToMove && nodeToMove.type == 1 )\r
177                                         {\r
178                                                 nodeToMove.focus();\r
179                                                 onBlur( null, element );\r
180                                                 onFocus( null, nodeToMove );\r
181                                                 ev.preventDefault( true );\r
182                                         }\r
183                                         else\r
184                                                 onBlur( null, element );\r
185                                 }\r
186                                 break;\r
187 \r
188                         // LEFT-ARROW\r
189                         case rtl ? 39 : 37 :\r
190                         // SHIFT + TAB\r
191                         case CKEDITOR.SHIFT + 9 :\r
192                                 // relative is TD\r
193                                 if ( ( relative = element.getParent().getPrevious() ) )\r
194                                 {\r
195                                         nodeToMove = relative.getChild( 0 );\r
196                                         nodeToMove.focus();\r
197                                         onBlur( null, element );\r
198                                         onFocus( null, nodeToMove );\r
199                                         ev.preventDefault( true );\r
200                                 }\r
201                                 // relative is TR\r
202                                 else if ( ( relative = element.getParent().getParent().getPrevious() ) )\r
203                                 {\r
204                                         nodeToMove = relative.getLast().getChild( 0 );\r
205                                         nodeToMove.focus();\r
206                                         onBlur( null, element );\r
207                                         onFocus( null, nodeToMove );\r
208                                         ev.preventDefault( true );\r
209                                 }\r
210                                 else\r
211                                         onBlur( null, element );\r
212                                 break;\r
213                         default :\r
214                                 // Do not stop not handled events.\r
215                                 return;\r
216                 }\r
217         });\r
218 \r
219         return {\r
220                 title : lang.title,\r
221                 minWidth : 430,\r
222                 minHeight : 280,\r
223                 buttons : [ CKEDITOR.dialog.cancelButton ],\r
224                 charColumns : 17,\r
225                 chars :\r
226                         [\r
227                                 '!','"','#','$','%','&',"'",'(',')','*','+','-','.','/',\r
228                                 '0','1','2','3','4','5','6','7','8','9',':',';',\r
229                                 '<','=','>','?','@',\r
230                                 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',\r
231                                 'P','Q','R','S','T','U','V','W','X','Y','Z',\r
232                                 '[',']','^','_','`',\r
233                                 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',\r
234                                 'q','r','s','t','u','v','w','x','y','z',\r
235                                 '{','|','}','~','€(EURO SIGN)','‘(LEFT SINGLE QUOTATION MARK)','’(RIGHT SINGLE QUOTATION MARK)','“(LEFT DOUBLE QUOTATION MARK)',\r
236                                 '”(RIGHT DOUBLE QUOTATION MARK)','–(EN DASH)','—(EM DASH)','¡(INVERTED EXCLAMATION MARK)','¢(CENT SIGN)','£(POUND SIGN)',\r
237                                 '¤(CURRENCY SIGN)','¥(YEN SIGN)','¦(BROKEN BAR)','§(SECTION SIGN)','¨(DIAERESIS)','©(COPYRIGHT SIGN)','ª(FEMININE ORDINAL INDICATOR)',\r
238                                 '«(LEFT-POINTING DOUBLE ANGLE QUOTATION MARK)','¬(NOT SIGN)','®(REGISTERED SIGN)','¯(MACRON)','°(DEGREE SIGN)','±(PLUS-MINUS SIGN)','²(SUPERSCRIPT TWO)',\r
239                                 '³(SUPERSCRIPT THREE)','´(ACUTE ACCENT)','µ(MICRO SIGN)','¶(PILCROW SIGN)','·(MIDDLE DOT)','¸(CEDILLA)',\r
240                                 '¹(SUPERSCRIPT ONE)','º(MASCULINE ORDINAL INDICATOR)','»(RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK)','¼(VULGAR FRACTION ONE QUARTER)','½(VULGAR FRACTION ONE HALF)','¾(VULGAR FRACTION THREE QUARTERS)',\r
241                                 '¿(INVERTED QUESTION MARK)','À(LATIN CAPITAL LETTER A WITH GRAVE)','Á(LATIN CAPITAL LETTER A WITH ACUTE)','Â(LATIN CAPITAL LETTER A WITH CIRCUMFLEX)','Ã(LATIN CAPITAL LETTER A WITH TILDE)','Ä(LATIN CAPITAL LETTER A WITH DIAERESIS)',\r
242                                 'Å(LATIN CAPITAL LETTER A WITH RING ABOVE)','Æ(LATIN CAPITAL LETTER AE)','Ç(LATIN CAPITAL LETTER C WITH CEDILLA)','È(LATIN CAPITAL LETTER E WITH GRAVE)','É(LATIN CAPITAL LETTER E WITH ACUTE)','Ê(LATIN CAPITAL LETTER E WITH CIRCUMFLEX)',\r
243                                 'Ë(LATIN CAPITAL LETTER E WITH DIAERESIS)','Ì(LATIN CAPITAL LETTER I WITH GRAVE)','Í(LATIN CAPITAL LETTER I WITH ACUTE)','Î(LATIN CAPITAL LETTER I WITH CIRCUMFLEX)','Ï(LATIN CAPITAL LETTER I WITH DIAERESIS)','Ð(LATIN CAPITAL LETTER ETH)',\r
244                                 'Ñ(LATIN CAPITAL LETTER N WITH TILDE)','Ò(LATIN CAPITAL LETTER O WITH GRAVE)','Ó(LATIN CAPITAL LETTER O WITH ACUTE)','Ô(LATIN CAPITAL LETTER O WITH CIRCUMFLEX)','Õ(LATIN CAPITAL LETTER O WITH TILDE)','Ö(LATIN CAPITAL LETTER O WITH DIAERESIS)',\r
245                                 '×(MULTIPLICATION SIGN)','Ø(LATIN CAPITAL LETTER O WITH STROKE)','Ù(LATIN CAPITAL LETTER U WITH GRAVE)','Ú(LATIN CAPITAL LETTER U WITH ACUTE)','Û(LATIN CAPITAL LETTER U WITH CIRCUMFLEX)','Ü(LATIN CAPITAL LETTER U WITH DIAERESIS)',\r
246                                 'Ý(LATIN CAPITAL LETTER Y WITH ACUTE)','Þ(LATIN CAPITAL LETTER THORN)','ß(LATIN SMALL LETTER SHARP S)','à(LATIN SMALL LETTER A WITH GRAVE)','á(LATIN SMALL LETTER A WITH ACUTE)','â(LATIN SMALL LETTER A WITH CIRCUMFLEX)',\r
247                                 'ã(LATIN SMALL LETTER A WITH TILDE)','ä(LATIN SMALL LETTER A WITH DIAERESIS)','å(LATIN SMALL LETTER A WITH RING ABOVE)','æ(LATIN SMALL LETTER AE)','ç(LATIN SMALL LETTER C WITH CEDILLA)','è(LATIN SMALL LETTER E WITH GRAVE)',\r
248                                 'é(LATIN SMALL LETTER E WITH ACUTE)','ê(LATIN SMALL LETTER E WITH CIRCUMFLEX)','ë(LATIN SMALL LETTER E WITH DIAERESIS)','ì(LATIN SMALL LETTER I WITH GRAVE)','í(LATIN SMALL LETTER I WITH ACUTE)','î(LATIN SMALL LETTER I WITH CIRCUMFLEX)',\r
249                                 'ï(LATIN SMALL LETTER I WITH DIAERESIS)','ð(LATIN SMALL LETTER ETH)','ñ(LATIN SMALL LETTER N WITH TILDE)','ò(LATIN SMALL LETTER O WITH GRAVE)','ó(LATIN SMALL LETTER O WITH ACUTE)','ô(LATIN SMALL LETTER O WITH CIRCUMFLEX)',\r
250                                 'õ(LATIN SMALL LETTER O WITH TILDE)','ö(LATIN SMALL LETTER O WITH DIAERESIS)',\r
251                                 '÷(DIVISION SIGN)','ø(LATIN SMALL LETTER O WITH STROKE)',\r
252                                 'ù(LATIN SMALL LETTER U WITH GRAVE)','ú(LATIN SMALL LETTER U WITH ACUTE)',\r
253                                 'û(LATIN SMALL LETTER U WITH CIRCUMFLEX)','ü(LATIN SMALL LETTER U WITH DIAERESIS)',\r
254                                 'ü(LATIN SMALL LETTER U WITH DIAERESIS)','ý(LATIN SMALL LETTER Y WITH ACUTE)','þ(LATIN SMALL LETTER THORN)','ÿ(LATIN SMALL LETTER Y WITH DIAERESIS)',\r
255                                 'Œ(LATIN CAPITAL LIGATURE OE)',\r
256                                 'œ(LATIN SMALL LIGATURE OE)','Ŵ(LATIN CAPITAL LETTER W WITH CIRCUMFLEX)',\r
257                                 '&#374(LATIN CAPITAL LETTER Y WITH CIRCUMFLEX)','&#373(LATIN SMALL LETTER W WITH CIRCUMFLEX)',\r
258                                 'ŷ(LATIN SMALL LETTER Y WITH CIRCUMFLEX)','‚(SINGLE LOW-9 QUOTATION MARK)',\r
259                                 '‛(SINGLE HIGH-REVERSED-9 QUOTATION MARK)','„(DOUBLE LOW-9 QUOTATION MARK)','…(HORIZONTAL ELLIPSIS)',\r
260                                 '™(TRADE MARK SIGN)','►(BLACK RIGHT-POINTING POINTER)','•(BULLET)',\r
261                                 '→(RIGHTWARDS ARROW)','⇒(RIGHTWARDS DOUBLE ARROW)','⇔(LEFT RIGHT DOUBLE ARROW)','♦(BLACK DIAMOND SUIT)','≈(ALMOST EQUAL TO)'\r
262                         ],\r
263                 onLoad :  function()\r
264                 {\r
265                         var columns = this.definition.charColumns,\r
266                                 chars = this.definition.chars;\r
267 \r
268                         var charsTableLabel =  CKEDITOR.tools.getNextId() + '_specialchar_table_label';\r
269                         var html = [ '<table role="listbox" aria-labelledby="' + charsTableLabel + '"' +\r
270                                                                         ' style="width: 320px; height: 100%; border-collapse: separate;"' +\r
271                                                                         ' align="center" cellspacing="2" cellpadding="2" border="0">' ];\r
272 \r
273                         var i = 0,\r
274                                 size = chars.length,\r
275                                 character,\r
276                                 charDesc;\r
277 \r
278                         while ( i < size )\r
279                         {\r
280                                 html.push( '<tr>' ) ;\r
281 \r
282                                 for ( var j = 0 ; j < columns ; j++, i++ )\r
283                                 {\r
284                                         if ( ( character = chars[ i ] ) )\r
285                                         {\r
286                                                 charDesc = '';\r
287                                                 character = character.replace( /\((.*?)\)/, function( match, desc )\r
288                                                         {\r
289                                                                 charDesc = desc;\r
290                                                                 return '';\r
291                                                         } );\r
292 \r
293                                                 // Use character in case description unavailable.\r
294                                                 charDesc = charDesc || character;\r
295 \r
296                                                 var charLabelId =  'cke_specialchar_label_' + i + '_' + CKEDITOR.tools.getNextNumber();\r
297 \r
298                                                 html.push(\r
299                                                         '<td class="cke_dark_background" style="cursor: default" role="presentation">' +\r
300                                                         '<a href="javascript: void(0);" role="option"' +\r
301                                                         ' aria-posinset="' + ( i +1 ) + '"',\r
302                                                         ' aria-setsize="' + size + '"',\r
303                                                         ' aria-labelledby="' + charLabelId + '"',\r
304                                                         ' style="cursor: inherit; display: block; height: 1.25em; margin-top: 0.25em; text-align: center;" title="', CKEDITOR.tools.htmlEncode( charDesc ), '"' +\r
305                                                         ' onkeydown="CKEDITOR.tools.callFunction( ' + onKeydown + ', event, this )"' +\r
306                                                         ' onclick="CKEDITOR.tools.callFunction(' + onClick + ', this); return false;"' +\r
307                                                         ' tabindex="-1">' +\r
308                                                         '<span style="margin: 0 auto;cursor: inherit">' +\r
309                                                         character +\r
310                                                         '</span>' +\r
311                                                         '<span class="cke_voice_label" id="' + charLabelId + '">' +\r
312                                                         charDesc +\r
313                                                         '</span></a>');\r
314                                         }\r
315                                         else\r
316                                                 html.push( '<td class="cke_dark_background">&nbsp;' );\r
317 \r
318                                         html.push( '</td>' );\r
319                                 }\r
320                                 html.push( '</tr>' );\r
321                         }\r
322 \r
323                         html.push( '</tbody></table>', '<span id="' + charsTableLabel + '" class="cke_voice_label">' + lang.options +'</span>' );\r
324 \r
325                         this.getContentElement( 'info', 'charContainer' ).getElement().setHtml( html.join( '' ) );\r
326                 },\r
327                 contents : [\r
328                         {\r
329                                 id : 'info',\r
330                                 label : editor.lang.common.generalTab,\r
331                                 title : editor.lang.common.generalTab,\r
332                                 padding : 0,\r
333                                 align : 'top',\r
334                                 elements : [\r
335                                         {\r
336                                                 type : 'hbox',\r
337                                                 align : 'top',\r
338                                                 widths : [ '320px', '90px' ],\r
339                                                 children :\r
340                                                 [\r
341                                                         {\r
342                                                                 type : 'html',\r
343                                                                 id : 'charContainer',\r
344                                                                 html : '',\r
345                                                                 onMouseover : onFocus,\r
346                                                                 onMouseout : onBlur,\r
347                                                                 focus : function()\r
348                                                                 {\r
349                                                                         var firstChar = this.getElement().getElementsByTag( 'a' ).getItem( 0 );\r
350                                                                         setTimeout( function()\r
351                                                                         {\r
352                                                                                 firstChar.focus();\r
353                                                                                 onFocus( null, firstChar );\r
354                                                                         }, 0 );\r
355                                                                 },\r
356                                                                 onShow : function()\r
357                                                                 {\r
358                                                                         var firstChar = this.getElement().getChild( [ 0, 0, 0, 0, 0 ] );\r
359                                                                         setTimeout( function()\r
360                                                                                 {\r
361                                                                                         firstChar.focus();\r
362                                                                                         onFocus( null, firstChar );\r
363                                                                                 }, 0 );\r
364                                                                 },\r
365                                                                 onLoad : function( event )\r
366                                                                 {\r
367                                                                         dialog = event.sender;\r
368                                                                 }\r
369                                                         },\r
370                                                         {\r
371                                                                 type : 'hbox',\r
372                                                                 align : 'top',\r
373                                                                 widths : [ '100%' ],\r
374                                                                 children :\r
375                                                                 [\r
376                                                                         {\r
377                                                                                 type : 'vbox',\r
378                                                                                 align : 'top',\r
379                                                                                 children :\r
380                                                                                 [\r
381                                                                                         {\r
382                                                                                                 type : 'html',\r
383                                                                                                 html : '<div></div>'\r
384                                                                                         },\r
385                                                                                         {\r
386                                                                                                 type : 'html',\r
387                                                                                                 id : 'charPreview',\r
388                                                                                                 className : 'cke_dark_background',\r
389                                                                                                 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
390                                                                                                 html : '<div>&nbsp;</div>'\r
391                                                                                         },\r
392                                                                                         {\r
393                                                                                                 type : 'html',\r
394                                                                                                 id : 'htmlPreview',\r
395                                                                                                 className : 'cke_dark_background',\r
396                                                                                                 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
397                                                                                                 html : '<div>&nbsp;</div>'\r
398                                                                                         }\r
399                                                                                 ]\r
400                                                                         }\r
401                                                                 ]\r
402                                                         }\r
403                                                 ]\r
404                                         }\r
405                                 ]\r
406                         }\r
407                 ]\r
408         };\r
409 } );\r