--- /dev/null
+/*\r
+Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
+For licensing, see LICENSE.html or http://ckeditor.com/license\r
+*/\r
+\r
+CKEDITOR.plugins.add( 'richcombo',\r
+{\r
+ requires : [ 'floatpanel', 'listblock', 'button' ],\r
+\r
+ beforeInit : function( editor )\r
+ {\r
+ editor.ui.addHandler( CKEDITOR.UI_RICHCOMBO, CKEDITOR.ui.richCombo.handler );\r
+ }\r
+});\r
+\r
+/**\r
+ * Button UI element.\r
+ * @constant\r
+ * @example\r
+ */\r
+CKEDITOR.UI_RICHCOMBO = 'richcombo';\r
+\r
+CKEDITOR.ui.richCombo = CKEDITOR.tools.createClass(\r
+{\r
+ $ : function( definition )\r
+ {\r
+ // Copy all definition properties to this object.\r
+ CKEDITOR.tools.extend( this, definition,\r
+ // Set defaults.\r
+ {\r
+ title : definition.label,\r
+ modes : { wysiwyg : 1 }\r
+ });\r
+\r
+ // We don't want the panel definition in this object.\r
+ var panelDefinition = this.panel || {};\r
+ delete this.panel;\r
+\r
+ this.id = CKEDITOR.tools.getNextNumber();\r
+\r
+ this.document = ( panelDefinition\r
+ && panelDefinition.parent\r
+ && panelDefinition.parent.getDocument() )\r
+ || CKEDITOR.document;\r
+\r
+ panelDefinition.className = ( panelDefinition.className || '' ) + ' cke_rcombopanel';\r
+ panelDefinition.block =\r
+ {\r
+ multiSelect : panelDefinition.multiSelect,\r
+ attributes : panelDefinition.attributes\r
+ };\r
+\r
+ this._ =\r
+ {\r
+ panelDefinition : panelDefinition,\r
+ items : {},\r
+ state : CKEDITOR.TRISTATE_OFF\r
+ };\r
+ },\r
+\r
+ statics :\r
+ {\r
+ handler :\r
+ {\r
+ create : function( definition )\r
+ {\r
+ return new CKEDITOR.ui.richCombo( definition );\r
+ }\r
+ }\r
+ },\r
+\r
+ proto :\r
+ {\r
+ renderHtml : function( editor )\r
+ {\r
+ var output = [];\r
+ this.render( editor, output );\r
+ return output.join( '' );\r
+ },\r
+\r
+ /**\r
+ * Renders the combo.\r
+ * @param {CKEDITOR.editor} editor The editor instance which this button is\r
+ * to be used by.\r
+ * @param {Array} output The output array to which append the HTML relative\r
+ * to this button.\r
+ * @example\r
+ */\r
+ render : function( editor, output )\r
+ {\r
+ var env = CKEDITOR.env;\r
+\r
+ var id = 'cke_' + this.id;\r
+ var clickFn = CKEDITOR.tools.addFunction( function( $element )\r
+ {\r
+ var _ = this._;\r
+\r
+ if ( _.state == CKEDITOR.TRISTATE_DISABLED )\r
+ return;\r
+\r
+ this.createPanel( editor );\r
+\r
+ if ( _.on )\r
+ {\r
+ _.panel.hide();\r
+ return;\r
+ }\r
+\r
+ this.commit();\r
+ var value = this.getValue();\r
+ if ( value )\r
+ _.list.mark( value );\r
+ else\r
+ _.list.unmarkAll();\r
+\r
+ _.panel.showBlock( this.id, new CKEDITOR.dom.element( $element ), 4 );\r
+ },\r
+ this );\r
+\r
+ var instance = {\r
+ id : id,\r
+ combo : this,\r
+ focus : function()\r
+ {\r
+ var element = CKEDITOR.document.getById( id ).getChild( 1 );\r
+ element.focus();\r
+ },\r
+ clickFn : clickFn\r
+ };\r
+\r
+ function updateState()\r
+ {\r
+ var state = this.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;\r
+ this.setState( editor.readOnly && !this.readOnly ? CKEDITOR.TRISTATE_DISABLED : state );\r
+ this.setValue( '' );\r
+ }\r
+\r
+ editor.on( 'mode', updateState, this );\r
+ // If this combo is sensitive to readOnly state, update it accordingly.\r
+ !this.readOnly && editor.on( 'readOnly', updateState, this);\r
+\r
+ var keyDownFn = CKEDITOR.tools.addFunction( function( ev, element )\r
+ {\r
+ ev = new CKEDITOR.dom.event( ev );\r
+\r
+ var keystroke = ev.getKeystroke();\r
+ switch ( keystroke )\r
+ {\r
+ case 13 : // ENTER\r
+ case 32 : // SPACE\r
+ case 40 : // ARROW-DOWN\r
+ // Show panel\r
+ CKEDITOR.tools.callFunction( clickFn, element );\r
+ break;\r
+ default :\r
+ // Delegate the default behavior to toolbar button key handling.\r
+ instance.onkey( instance, keystroke );\r
+ }\r
+\r
+ // Avoid subsequent focus grab on editor document.\r
+ ev.preventDefault();\r
+ });\r
+\r
+ var focusFn = CKEDITOR.tools.addFunction( function() { instance.onfocus && instance.onfocus(); } );\r
+\r
+ // For clean up\r
+ instance.keyDownFn = keyDownFn;\r
+\r
+ output.push(\r
+ '<span class="cke_rcombo" role="presentation">',\r
+ '<span id=', id );\r
+\r
+ if ( this.className )\r
+ output.push( ' class="', this.className, ' cke_off"');\r
+\r
+ output.push(\r
+ ' role="presentation">',\r
+ '<span id="' + id+ '_label" class=cke_label>', this.label, '</span>',\r
+ '<a hidefocus=true title="', this.title, '" tabindex="-1"',\r
+ env.gecko && env.version >= 10900 && !env.hc ? '' : ' href="javascript:void(\'' + this.label + '\')"',\r
+ ' role="button" aria-labelledby="', id , '_label" aria-describedby="', id, '_text" aria-haspopup="true"' );\r
+\r
+ // Some browsers don't cancel key events in the keydown but in the\r
+ // keypress.\r
+ // TODO: Check if really needed for Gecko+Mac.\r
+ if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )\r
+ {\r
+ output.push(\r
+ ' onkeypress="return false;"' );\r
+ }\r
+\r
+ // With Firefox, we need to force it to redraw, otherwise it\r
+ // will remain in the focus state.\r
+ if ( CKEDITOR.env.gecko )\r
+ {\r
+ output.push(\r
+ ' onblur="this.style.cssText = this.style.cssText;"' );\r
+ }\r
+\r
+ output.push(\r
+ ' onkeydown="CKEDITOR.tools.callFunction( ', keyDownFn, ', event, this );"' +\r
+ ' onfocus="return CKEDITOR.tools.callFunction(', focusFn, ', event);" ' +\r
+ ( CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick' ) + // #188\r
+ '="CKEDITOR.tools.callFunction(', clickFn, ', this); return false;">' +\r
+ '<span>' +\r
+ '<span id="' + id + '_text" class="cke_text cke_inline_label">' + this.label + '</span>' +\r
+ '</span>' +\r
+ '<span class=cke_openbutton><span class=cke_icon>' + ( CKEDITOR.env.hc ? '▼' : CKEDITOR.env.air ? ' ' : '' ) + '</span></span>' + // BLACK DOWN-POINTING TRIANGLE\r
+ '</a>' +\r
+ '</span>' +\r
+ '</span>' );\r
+\r
+ if ( this.onRender )\r
+ this.onRender();\r
+\r
+ return instance;\r
+ },\r
+\r
+ createPanel : function( editor )\r
+ {\r
+ if ( this._.panel )\r
+ return;\r
+\r
+ var panelDefinition = this._.panelDefinition,\r
+ panelBlockDefinition = this._.panelDefinition.block,\r
+ panelParentElement = panelDefinition.parent || CKEDITOR.document.getBody(),\r
+ panel = new CKEDITOR.ui.floatPanel( editor, panelParentElement, panelDefinition ),\r
+ list = panel.addListBlock( this.id, panelBlockDefinition ),\r
+ me = this;\r
+\r
+ panel.onShow = function()\r
+ {\r
+ if ( me.className )\r
+ this.element.getFirst().addClass( me.className + '_panel' );\r
+\r
+ me.setState( CKEDITOR.TRISTATE_ON );\r
+\r
+ list.focus( !me.multiSelect && me.getValue() );\r
+\r
+ me._.on = 1;\r
+\r
+ if ( me.onOpen )\r
+ me.onOpen();\r
+ };\r
+\r
+ panel.onHide = function( preventOnClose )\r
+ {\r
+ if ( me.className )\r
+ this.element.getFirst().removeClass( me.className + '_panel' );\r
+\r
+ me.setState( me.modes && me.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );\r
+\r
+ me._.on = 0;\r
+\r
+ if ( !preventOnClose && me.onClose )\r
+ me.onClose();\r
+ };\r
+\r
+ panel.onEscape = function()\r
+ {\r
+ panel.hide();\r
+ };\r
+\r
+ list.onClick = function( value, marked )\r
+ {\r
+ // Move the focus to the main windows, otherwise it will stay\r
+ // into the floating panel, even if invisible, and Safari and\r
+ // Opera will go a bit crazy.\r
+ me.document.getWindow().focus();\r
+\r
+ if ( me.onClick )\r
+ me.onClick.call( me, value, marked );\r
+\r
+ if ( marked )\r
+ me.setValue( value, me._.items[ value ] );\r
+ else\r
+ me.setValue( '' );\r
+\r
+ panel.hide( false );\r
+ };\r
+\r
+ this._.panel = panel;\r
+ this._.list = list;\r
+\r
+ panel.getBlock( this.id ).onHide = function()\r
+ {\r
+ me._.on = 0;\r
+ me.setState( CKEDITOR.TRISTATE_OFF );\r
+ };\r
+\r
+ if ( this.init )\r
+ this.init();\r
+ },\r
+\r
+ setValue : function( value, text )\r
+ {\r
+ this._.value = value;\r
+\r
+ var textElement = this.document.getById( 'cke_' + this.id + '_text' );\r
+ if ( textElement )\r
+ {\r
+ if ( !( value || text ) )\r
+ {\r
+ text = this.label;\r
+ textElement.addClass( 'cke_inline_label' );\r
+ }\r
+ else\r
+ textElement.removeClass( 'cke_inline_label' );\r
+\r
+ textElement.setHtml( typeof text != 'undefined' ? text : value );\r
+ }\r
+ },\r
+\r
+ getValue : function()\r
+ {\r
+ return this._.value || '';\r
+ },\r
+\r
+ unmarkAll : function()\r
+ {\r
+ this._.list.unmarkAll();\r
+ },\r
+\r
+ mark : function( value )\r
+ {\r
+ this._.list.mark( value );\r
+ },\r
+\r
+ hideItem : function( value )\r
+ {\r
+ this._.list.hideItem( value );\r
+ },\r
+\r
+ hideGroup : function( groupTitle )\r
+ {\r
+ this._.list.hideGroup( groupTitle );\r
+ },\r
+\r
+ showAll : function()\r
+ {\r
+ this._.list.showAll();\r
+ },\r
+\r
+ add : function( value, html, text )\r
+ {\r
+ this._.items[ value ] = text || value;\r
+ this._.list.add( value, html, text );\r
+ },\r
+\r
+ startGroup : function( title )\r
+ {\r
+ this._.list.startGroup( title );\r
+ },\r
+\r
+ commit : function()\r
+ {\r
+ if ( !this._.committed )\r
+ {\r
+ this._.list.commit();\r
+ this._.committed = 1;\r
+ CKEDITOR.ui.fire( 'ready', this );\r
+ }\r
+ this._.committed = 1;\r
+ },\r
+\r
+ setState : function( state )\r
+ {\r
+ if ( this._.state == state )\r
+ return;\r
+\r
+ this.document.getById( 'cke_' + this.id ).setState( state );\r
+\r
+ this._.state = state;\r
+ }\r
+ }\r
+});\r
+\r
+CKEDITOR.ui.prototype.addRichCombo = function( name, definition )\r
+{\r
+ this.add( name, CKEDITOR.UI_RICHCOMBO, definition );\r
+};\r