JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
522e864bb957b1a4262f2dd2404b4b87912a9276
[ckeditor.git] / _source / plugins / richcombo / plugin.js
1 /*\r
2 Copyright (c) 2003-2009, 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.plugins.add( 'richcombo',\r
7 {\r
8         requires : [ 'floatpanel', 'listblock', 'button' ],\r
9 \r
10         beforeInit : function( editor )\r
11         {\r
12                 editor.ui.addHandler( CKEDITOR.UI_RICHCOMBO, CKEDITOR.ui.richCombo.handler );\r
13         }\r
14 });\r
15 \r
16 /**\r
17  * Button UI element.\r
18  * @constant\r
19  * @example\r
20  */\r
21 CKEDITOR.UI_RICHCOMBO = 3;\r
22 \r
23 CKEDITOR.ui.richCombo = CKEDITOR.tools.createClass(\r
24 {\r
25         $ : function( definition )\r
26         {\r
27                 // Copy all definition properties to this object.\r
28                 CKEDITOR.tools.extend( this, definition,\r
29                         // Set defaults.\r
30                         {\r
31                                 title : definition.label,\r
32                                 modes : { wysiwyg : 1 }\r
33                         });\r
34 \r
35                 // We don't want the panel definition in this object.\r
36                 var panelDefinition = this.panel || {};\r
37                 delete this.panel;\r
38 \r
39                 this.id = CKEDITOR.tools.getNextNumber();\r
40 \r
41                 this.document = ( panelDefinition\r
42                                                         && panelDefinition.parent\r
43                                                         && panelDefinition.parent.getDocument() )\r
44                                                 || CKEDITOR.document;\r
45 \r
46                 panelDefinition.className = ( panelDefinition.className || '' ) + ' cke_rcombopanel';\r
47 \r
48                 this._ =\r
49                 {\r
50                         panelDefinition : panelDefinition,\r
51                         items : {},\r
52                         state : CKEDITOR.TRISTATE_OFF\r
53                 };\r
54         },\r
55 \r
56         statics :\r
57         {\r
58                 handler :\r
59                 {\r
60                         create : function( definition )\r
61                         {\r
62                                 return new CKEDITOR.ui.richCombo( definition );\r
63                         }\r
64                 }\r
65         },\r
66 \r
67         proto :\r
68         {\r
69                 renderHtml : function( editor )\r
70                 {\r
71                         var output = [];\r
72                         this.render( editor, output );\r
73                         return output.join( '' );\r
74                 },\r
75 \r
76                 /**\r
77                  * Renders the combo.\r
78                  * @param {CKEDITOR.editor} editor The editor instance which this button is\r
79                  *              to be used by.\r
80                  * @param {Array} output The output array to which append the HTML relative\r
81                  *              to this button.\r
82                  * @example\r
83                  */\r
84                 render : function( editor, output )\r
85                 {\r
86                         var id = 'cke_' + this.id;\r
87                         var clickFn = CKEDITOR.tools.addFunction( function( $element )\r
88                                 {\r
89                                         var _ = this._;\r
90 \r
91                                         if ( _.state == CKEDITOR.TRISTATE_DISABLED )\r
92                                                 return;\r
93 \r
94                                         this.createPanel( editor );\r
95 \r
96                                         if ( _.on )\r
97                                         {\r
98                                                 _.panel.hide();\r
99                                                 return;\r
100                                         }\r
101 \r
102                                         if ( !_.committed )\r
103                                         {\r
104                                                 _.list.commit();\r
105                                                 _.committed = 1;\r
106                                         }\r
107 \r
108                                         var value = this.getValue();\r
109                                         if ( value )\r
110                                                 _.list.mark( value );\r
111                                         else\r
112                                                 _.list.unmarkAll();\r
113 \r
114                                         _.panel.showBlock( this.id, new CKEDITOR.dom.element( $element ), 4 );\r
115                                 },\r
116                                 this );\r
117 \r
118                         var instance = {\r
119                                 id : id,\r
120                                 combo : this,\r
121                                 focus : function()\r
122                                 {\r
123                                         var element = CKEDITOR.document.getById( id ).getChild( 1 );\r
124                                         element.focus();\r
125                                 },\r
126                                 execute : clickFn\r
127                         };\r
128 \r
129                         editor.on( 'mode', function()\r
130                                 {\r
131                                         this.setState( this.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );\r
132                                 },\r
133                                 this );\r
134 \r
135                         var keyDownFn = CKEDITOR.tools.addFunction( function( ev, element )\r
136                                 {\r
137                                         ev = new CKEDITOR.dom.event( ev );\r
138 \r
139                                         var keystroke = ev.getKeystroke();\r
140                                         switch ( keystroke )\r
141                                         {\r
142                                                 case 13 :       // ENTER\r
143                                                 case 32 :       // SPACE\r
144                                                 case 40 :       // ARROW-DOWN\r
145                                                         // Show panel\r
146                                                         CKEDITOR.tools.callFunction( clickFn, element );\r
147                                                         break;\r
148                                                 default :\r
149                                                         // Delegate the default behavior to toolbar button key handling.\r
150                                                         instance.onkey( instance,  keystroke );\r
151                                         }\r
152 \r
153                                         // Avoid subsequent focus grab on editor document.\r
154                                         ev.preventDefault();\r
155                                 });\r
156 \r
157                         output.push(\r
158                                 '<span class="cke_rcombo">',\r
159                                 '<span id=', id );\r
160 \r
161                         if ( this.className )\r
162                                 output.push( ' class="', this.className, ' cke_off"');\r
163 \r
164                         output.push(\r
165                                 '>' +\r
166                                         '<span class=cke_label>', this.label, '</span>' +\r
167                                         '<a hidefocus=true title="', this.title, '" tabindex="-1" href="javascript:void(\'', this.label, '\')"' );\r
168 \r
169                         // Some browsers don't cancel key events in the keydown but in the\r
170                         // keypress.\r
171                         // TODO: Check if really needed for Gecko+Mac.\r
172                         if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )\r
173                         {\r
174                                 output.push(\r
175                                         ' onkeypress="return false;"' );\r
176                         }\r
177 \r
178                         // With Firefox, we need to force it to redraw, otherwise it\r
179                         // will remain in the focus state.\r
180                         if ( CKEDITOR.env.gecko )\r
181                         {\r
182                                 output.push(\r
183                                         ' onblur="this.style.cssText = this.style.cssText;"' );\r
184                         }\r
185 \r
186                         output.push(\r
187                                         ' onkeydown="CKEDITOR.tools.callFunction( ', keyDownFn, ', event, this );"' +\r
188                                         ' onclick="CKEDITOR.tools.callFunction(', clickFn, ', this); return false;">' +\r
189                                                 '<span>' +\r
190                                                         '<span class="cke_accessibility">' + ( this.voiceLabel ? this.voiceLabel + ' ' : '' ) + '</span>' +\r
191                                                         '<span id="' + id + '_text" class="cke_text cke_inline_label">' + this.label + '</span>' +\r
192                                                 '</span>' +\r
193                                                 '<span class=cke_openbutton></span>' +\r
194                                         '</a>' +\r
195                                 '</span>' +\r
196                                 '</span>' );\r
197 \r
198                         if ( this.onRender )\r
199                                 this.onRender();\r
200 \r
201                         return instance;\r
202                 },\r
203 \r
204                 createPanel : function( editor )\r
205                 {\r
206                         if ( this._.panel )\r
207                                 return;\r
208 \r
209                         var panelDefinition = this._.panelDefinition,\r
210                                 panelParentElement = panelDefinition.parent || CKEDITOR.document.getBody(),\r
211                                 panel = new CKEDITOR.ui.floatPanel( editor, panelParentElement, panelDefinition ),\r
212                                 list = panel.addListBlock( this.id, this.multiSelect ),\r
213                                 me = this;\r
214 \r
215                         panel.onShow = function()\r
216                                 {\r
217                                         if ( me.className )\r
218                                                 this.element.getFirst().addClass( me.className + '_panel' );\r
219 \r
220                                         me.setState( CKEDITOR.TRISTATE_ON );\r
221 \r
222                                         list.focus( !me.multiSelect && me.getValue() );\r
223 \r
224                                         me._.on = 1;\r
225 \r
226                                         if ( me.onOpen )\r
227                                                 me.onOpen();\r
228                                 };\r
229 \r
230                         panel.onHide = function()\r
231                                 {\r
232                                         if ( me.className )\r
233                                                 this.element.getFirst().removeClass( me.className + '_panel' );\r
234 \r
235                                         me.setState( CKEDITOR.TRISTATE_OFF );\r
236 \r
237                                         me._.on = 0;\r
238 \r
239                                         if ( me.onClose )\r
240                                                 me.onClose();\r
241                                 };\r
242 \r
243                         panel.onEscape = function()\r
244                                 {\r
245                                         panel.hide();\r
246                                         me.document.getById( 'cke_' + me.id ).getFirst().getNext().focus();\r
247                                 };\r
248 \r
249                         list.onClick = function( value, marked )\r
250                                 {\r
251                                         // Move the focus to the main windows, otherwise it will stay\r
252                                         // into the floating panel, even if invisible, and Safari and\r
253                                         // Opera will go a bit crazy.\r
254                                         me.document.getWindow().focus();\r
255 \r
256                                         if ( me.onClick )\r
257                                                 me.onClick.call( me, value, marked );\r
258 \r
259                                         if ( marked )\r
260                                                 me.setValue( value, me._.items[ value ] );\r
261                                         else\r
262                                                 me.setValue( '' );\r
263 \r
264                                         panel.hide();\r
265                                 };\r
266 \r
267                         this._.panel = panel;\r
268                         this._.list = list;\r
269 \r
270                         panel.getBlock( this.id ).onHide = function()\r
271                                 {\r
272                                         me._.on = 0;\r
273                                         me.setState( CKEDITOR.TRISTATE_OFF );\r
274                                 };\r
275 \r
276                         if ( this.init )\r
277                                 this.init();\r
278                 },\r
279 \r
280                 setValue : function( value, text )\r
281                 {\r
282                         this._.value = value;\r
283 \r
284                         var textElement = this.document.getById( 'cke_' + this.id + '_text' );\r
285 \r
286                         if ( !( value || text ) )\r
287                         {\r
288                                 text = this.label;\r
289                                 textElement.addClass( 'cke_inline_label' );\r
290                         }\r
291                         else\r
292                                 textElement.removeClass( 'cke_inline_label' );\r
293                         textElement.setHtml( typeof text != 'undefined' ? text : value );\r
294                 },\r
295 \r
296                 getValue : function()\r
297                 {\r
298                         return this._.value || '';\r
299                 },\r
300 \r
301                 unmarkAll : function()\r
302                 {\r
303                         this._.list.unmarkAll();\r
304                 },\r
305 \r
306                 mark : function( value )\r
307                 {\r
308                         this._.list.mark( value );\r
309                 },\r
310 \r
311                 hideItem : function( value )\r
312                 {\r
313                         this._.list.hideItem( value );\r
314                 },\r
315 \r
316                 hideGroup : function( groupTitle )\r
317                 {\r
318                         this._.list.hideGroup( groupTitle );\r
319                 },\r
320 \r
321                 showAll : function()\r
322                 {\r
323                         this._.list.showAll();\r
324                 },\r
325 \r
326                 add : function( value, html, text )\r
327                 {\r
328                         this._.items[ value ] = text || value;\r
329                         this._.list.add( value, html, text );\r
330                 },\r
331 \r
332                 startGroup : function( title )\r
333                 {\r
334                         this._.list.startGroup( title );\r
335                 },\r
336 \r
337                 commit : function()\r
338                 {\r
339                         this._.list.commit();\r
340                 },\r
341 \r
342                 setState : function( state )\r
343                 {\r
344                         if ( this._.state == state )\r
345                                 return;\r
346 \r
347                         this.document.getById( 'cke_' + this.id ).setState( state );\r
348 \r
349                         this._.state = state;\r
350                 }\r
351         }\r
352 });\r
353 \r
354 CKEDITOR.ui.prototype.addRichCombo = function( name, definition )\r
355 {\r
356         this.add( name, CKEDITOR.UI_RICHCOMBO, definition );\r
357 };\r