442 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			442 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
/**
 | 
						|
 * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
 | 
						|
 * For licensing, see LICENSE.md or http://ckeditor.com/license
 | 
						|
 */
 | 
						|
 | 
						|
CKEDITOR.plugins.add( 'richcombo', {
 | 
						|
	requires: 'floatpanel,listblock,button',
 | 
						|
 | 
						|
	beforeInit: function( editor ) {
 | 
						|
		editor.ui.addHandler( CKEDITOR.UI_RICHCOMBO, CKEDITOR.ui.richCombo.handler );
 | 
						|
	}
 | 
						|
} );
 | 
						|
 | 
						|
( function() {
 | 
						|
	var template = '<span id="{id}"' +
 | 
						|
		' class="cke_combo cke_combo__{name} {cls}"' +
 | 
						|
		' role="presentation">' +
 | 
						|
			'<span id="{id}_label" class="cke_combo_label">{label}</span>' +
 | 
						|
			'<a class="cke_combo_button" hidefocus=true title="{title}" tabindex="-1"' +
 | 
						|
			( CKEDITOR.env.gecko && CKEDITOR.env.version >= 10900 && !CKEDITOR.env.hc ? '' : '" href="javascript:void(\'{titleJs}\')"' ) +
 | 
						|
			' hidefocus="true"' +
 | 
						|
			' role="button"' +
 | 
						|
			' aria-labelledby="{id}_label"' +
 | 
						|
			' aria-haspopup="true"';
 | 
						|
 | 
						|
	// Some browsers don't cancel key events in the keydown but in the
 | 
						|
	// keypress.
 | 
						|
	// TODO: Check if really needed for Gecko+Mac.
 | 
						|
	if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )
 | 
						|
		template += ' onkeypress="return false;"';
 | 
						|
 | 
						|
	// With Firefox, we need to force the button to redraw, otherwise it
 | 
						|
	// will remain in the focus state.
 | 
						|
	if ( CKEDITOR.env.gecko )
 | 
						|
		template += ' onblur="this.style.cssText = this.style.cssText;"';
 | 
						|
 | 
						|
	template +=
 | 
						|
		' onkeydown="return CKEDITOR.tools.callFunction({keydownFn},event,this);"' +
 | 
						|
		' onmousedown="return CKEDITOR.tools.callFunction({mousedownFn},event);" ' +
 | 
						|
		' onfocus="return CKEDITOR.tools.callFunction({focusFn},event);" ' +
 | 
						|
			( CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick' ) + // #188
 | 
						|
				'="CKEDITOR.tools.callFunction({clickFn},this);return false;">' +
 | 
						|
			'<span id="{id}_text" class="cke_combo_text cke_combo_inlinelabel">{label}</span>' +
 | 
						|
			'<span class="cke_combo_open">' +
 | 
						|
				'<span class="cke_combo_arrow">' +
 | 
						|
				// BLACK DOWN-POINTING TRIANGLE
 | 
						|
	( CKEDITOR.env.hc ? '▼' : CKEDITOR.env.air ? ' ' : '' ) +
 | 
						|
				'</span>' +
 | 
						|
			'</span>' +
 | 
						|
		'</a>' +
 | 
						|
		'</span>';
 | 
						|
 | 
						|
	var rcomboTpl = CKEDITOR.addTemplate( 'combo', template );
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Button UI element.
 | 
						|
	 *
 | 
						|
	 * @readonly
 | 
						|
	 * @property {String} [='richcombo']
 | 
						|
	 * @member CKEDITOR
 | 
						|
	 */
 | 
						|
	CKEDITOR.UI_RICHCOMBO = 'richcombo';
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @class
 | 
						|
	 * @todo
 | 
						|
	 */
 | 
						|
	CKEDITOR.ui.richCombo = CKEDITOR.tools.createClass( {
 | 
						|
		$: function( definition ) {
 | 
						|
			// Copy all definition properties to this object.
 | 
						|
			CKEDITOR.tools.extend( this, definition,
 | 
						|
			// Set defaults.
 | 
						|
			{
 | 
						|
				// The combo won't participate in toolbar grouping.
 | 
						|
				canGroup: false,
 | 
						|
				title: definition.label,
 | 
						|
				modes: { wysiwyg: 1 },
 | 
						|
				editorFocus: 1
 | 
						|
			} );
 | 
						|
 | 
						|
			// We don't want the panel definition in this object.
 | 
						|
			var panelDefinition = this.panel || {};
 | 
						|
			delete this.panel;
 | 
						|
 | 
						|
			this.id = CKEDITOR.tools.getNextNumber();
 | 
						|
 | 
						|
			this.document = ( panelDefinition.parent && panelDefinition.parent.getDocument() ) || CKEDITOR.document;
 | 
						|
 | 
						|
			panelDefinition.className = 'cke_combopanel';
 | 
						|
			panelDefinition.block = {
 | 
						|
				multiSelect: panelDefinition.multiSelect,
 | 
						|
				attributes: panelDefinition.attributes
 | 
						|
			};
 | 
						|
			panelDefinition.toolbarRelated = true;
 | 
						|
 | 
						|
			this._ = {
 | 
						|
				panelDefinition: panelDefinition,
 | 
						|
				items: {}
 | 
						|
			};
 | 
						|
		},
 | 
						|
 | 
						|
		proto: {
 | 
						|
			renderHtml: function( editor ) {
 | 
						|
				var output = [];
 | 
						|
				this.render( editor, output );
 | 
						|
				return output.join( '' );
 | 
						|
			},
 | 
						|
 | 
						|
			/**
 | 
						|
			 * Renders the combo.
 | 
						|
			 *
 | 
						|
			 * @param {CKEDITOR.editor} editor The editor instance which this button is
 | 
						|
			 * to be used by.
 | 
						|
			 * @param {Array} output The output array to which append the HTML relative
 | 
						|
			 * to this button.
 | 
						|
			 */
 | 
						|
			render: function( editor, output ) {
 | 
						|
				var env = CKEDITOR.env;
 | 
						|
 | 
						|
				var id = 'cke_' + this.id;
 | 
						|
				var clickFn = CKEDITOR.tools.addFunction( function( el ) {
 | 
						|
					// Restore locked selection in Opera.
 | 
						|
					if ( selLocked ) {
 | 
						|
						editor.unlockSelection( 1 );
 | 
						|
						selLocked = 0;
 | 
						|
					}
 | 
						|
					instance.execute( el );
 | 
						|
				}, this );
 | 
						|
 | 
						|
				var combo = this;
 | 
						|
				var instance = {
 | 
						|
					id: id,
 | 
						|
					combo: this,
 | 
						|
					focus: function() {
 | 
						|
						var element = CKEDITOR.document.getById( id ).getChild( 1 );
 | 
						|
						element.focus();
 | 
						|
					},
 | 
						|
					execute: function( el ) {
 | 
						|
						var _ = combo._;
 | 
						|
 | 
						|
						if ( _.state == CKEDITOR.TRISTATE_DISABLED )
 | 
						|
							return;
 | 
						|
 | 
						|
						combo.createPanel( editor );
 | 
						|
 | 
						|
						if ( _.on ) {
 | 
						|
							_.panel.hide();
 | 
						|
							return;
 | 
						|
						}
 | 
						|
 | 
						|
						combo.commit();
 | 
						|
						var value = combo.getValue();
 | 
						|
						if ( value )
 | 
						|
							_.list.mark( value );
 | 
						|
						else
 | 
						|
							_.list.unmarkAll();
 | 
						|
 | 
						|
						_.panel.showBlock( combo.id, new CKEDITOR.dom.element( el ), 4 );
 | 
						|
					},
 | 
						|
					clickFn: clickFn
 | 
						|
				};
 | 
						|
 | 
						|
				function updateState() {
 | 
						|
					var state = this.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;
 | 
						|
 | 
						|
					if ( editor.readOnly && !this.readOnly )
 | 
						|
						state = CKEDITOR.TRISTATE_DISABLED;
 | 
						|
 | 
						|
					this.setState( state );
 | 
						|
					this.setValue( '' );
 | 
						|
 | 
						|
					// Let plugin to disable button.
 | 
						|
					if ( state != CKEDITOR.TRISTATE_DISABLED && this.refresh )
 | 
						|
						this.refresh();
 | 
						|
				}
 | 
						|
 | 
						|
				// Update status when activeFilter, mode, selection or readOnly changes.
 | 
						|
				editor.on( 'activeFilterChange', updateState, this );
 | 
						|
				editor.on( 'mode', updateState, this );
 | 
						|
				editor.on( 'selectionChange', updateState, this );
 | 
						|
				// If this combo is sensitive to readOnly state, update it accordingly.
 | 
						|
				!this.readOnly && editor.on( 'readOnly', updateState, this );
 | 
						|
 | 
						|
				var keyDownFn = CKEDITOR.tools.addFunction( function( ev, element ) {
 | 
						|
					ev = new CKEDITOR.dom.event( ev );
 | 
						|
 | 
						|
					var keystroke = ev.getKeystroke();
 | 
						|
 | 
						|
					// ARROW-DOWN
 | 
						|
					// This call is duplicated in plugins/toolbar/plugin.js in itemKeystroke().
 | 
						|
					// Move focus to the first element after drop down was opened by the arrow down key.
 | 
						|
					if ( keystroke == 40 ) {
 | 
						|
						editor.once( 'panelShow', function( evt ) {
 | 
						|
							evt.data._.panel._.currentBlock.onKeyDown( 40 );
 | 
						|
						} );
 | 
						|
					}
 | 
						|
 | 
						|
					switch ( keystroke ) {
 | 
						|
						case 13: // ENTER
 | 
						|
						case 32: // SPACE
 | 
						|
						case 40: // ARROW-DOWN
 | 
						|
							// Show panel
 | 
						|
							CKEDITOR.tools.callFunction( clickFn, element );
 | 
						|
							break;
 | 
						|
						default:
 | 
						|
							// Delegate the default behavior to toolbar button key handling.
 | 
						|
							instance.onkey( instance, keystroke );
 | 
						|
					}
 | 
						|
 | 
						|
					// Avoid subsequent focus grab on editor document.
 | 
						|
					ev.preventDefault();
 | 
						|
				} );
 | 
						|
 | 
						|
				var focusFn = CKEDITOR.tools.addFunction( function() {
 | 
						|
					instance.onfocus && instance.onfocus();
 | 
						|
				} );
 | 
						|
 | 
						|
				var selLocked = 0;
 | 
						|
				var mouseDownFn = CKEDITOR.tools.addFunction( function() {
 | 
						|
					// Opera: lock to prevent loosing editable text selection when clicking on button.
 | 
						|
					if ( CKEDITOR.env.opera ) {
 | 
						|
						var edt = editor.editable();
 | 
						|
						if ( edt.isInline() && edt.hasFocus ) {
 | 
						|
							editor.lockSelection();
 | 
						|
							selLocked = 1;
 | 
						|
						}
 | 
						|
					}
 | 
						|
				} );
 | 
						|
 | 
						|
				// For clean up
 | 
						|
				instance.keyDownFn = keyDownFn;
 | 
						|
 | 
						|
				var params = {
 | 
						|
					id: id,
 | 
						|
					name: this.name || this.command,
 | 
						|
					label: this.label,
 | 
						|
					title: this.title,
 | 
						|
					cls: this.className || '',
 | 
						|
					titleJs: env.gecko && env.version >= 10900 && !env.hc ? '' : ( this.title || '' ).replace( "'", '' ),
 | 
						|
					keydownFn: keyDownFn,
 | 
						|
					mousedownFn: mouseDownFn,
 | 
						|
					focusFn: focusFn,
 | 
						|
					clickFn: clickFn
 | 
						|
				};
 | 
						|
 | 
						|
				rcomboTpl.output( params, output );
 | 
						|
 | 
						|
				if ( this.onRender )
 | 
						|
					this.onRender();
 | 
						|
 | 
						|
				return instance;
 | 
						|
			},
 | 
						|
 | 
						|
			createPanel: function( editor ) {
 | 
						|
				if ( this._.panel )
 | 
						|
					return;
 | 
						|
 | 
						|
				var panelDefinition = this._.panelDefinition,
 | 
						|
					panelBlockDefinition = this._.panelDefinition.block,
 | 
						|
					panelParentElement = panelDefinition.parent || CKEDITOR.document.getBody(),
 | 
						|
					namedPanelCls = 'cke_combopanel__' + this.name,
 | 
						|
					panel = new CKEDITOR.ui.floatPanel( editor, panelParentElement, panelDefinition ),
 | 
						|
					list = panel.addListBlock( this.id, panelBlockDefinition ),
 | 
						|
					me = this;
 | 
						|
 | 
						|
				panel.onShow = function() {
 | 
						|
					this.element.addClass( namedPanelCls );
 | 
						|
 | 
						|
					me.setState( CKEDITOR.TRISTATE_ON );
 | 
						|
 | 
						|
					me._.on = 1;
 | 
						|
 | 
						|
					me.editorFocus && !editor.focusManager.hasFocus && editor.focus();
 | 
						|
 | 
						|
					if ( me.onOpen )
 | 
						|
						me.onOpen();
 | 
						|
 | 
						|
					// The "panelShow" event is fired assinchronously, after the
 | 
						|
					// onShow method call.
 | 
						|
					editor.once( 'panelShow', function() {
 | 
						|
						list.focus( !list.multiSelect && me.getValue() );
 | 
						|
					} );
 | 
						|
				};
 | 
						|
 | 
						|
				panel.onHide = function( preventOnClose ) {
 | 
						|
					this.element.removeClass( namedPanelCls );
 | 
						|
 | 
						|
					me.setState( me.modes && me.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );
 | 
						|
 | 
						|
					me._.on = 0;
 | 
						|
 | 
						|
					if ( !preventOnClose && me.onClose )
 | 
						|
						me.onClose();
 | 
						|
				};
 | 
						|
 | 
						|
				panel.onEscape = function() {
 | 
						|
					// Hide drop-down with focus returned.
 | 
						|
					panel.hide( 1 );
 | 
						|
				};
 | 
						|
 | 
						|
				list.onClick = function( value, marked ) {
 | 
						|
 | 
						|
					if ( me.onClick )
 | 
						|
						me.onClick.call( me, value, marked );
 | 
						|
 | 
						|
					panel.hide();
 | 
						|
				};
 | 
						|
 | 
						|
				this._.panel = panel;
 | 
						|
				this._.list = list;
 | 
						|
 | 
						|
				panel.getBlock( this.id ).onHide = function() {
 | 
						|
					me._.on = 0;
 | 
						|
					me.setState( CKEDITOR.TRISTATE_OFF );
 | 
						|
				};
 | 
						|
 | 
						|
				if ( this.init )
 | 
						|
					this.init();
 | 
						|
			},
 | 
						|
 | 
						|
			setValue: function( value, text ) {
 | 
						|
				this._.value = value;
 | 
						|
 | 
						|
				var textElement = this.document.getById( 'cke_' + this.id + '_text' );
 | 
						|
				if ( textElement ) {
 | 
						|
					if ( !( value || text ) ) {
 | 
						|
						text = this.label;
 | 
						|
						textElement.addClass( 'cke_combo_inlinelabel' );
 | 
						|
					} else
 | 
						|
						textElement.removeClass( 'cke_combo_inlinelabel' );
 | 
						|
 | 
						|
					textElement.setText( typeof text != 'undefined' ? text : value );
 | 
						|
				}
 | 
						|
			},
 | 
						|
 | 
						|
			getValue: function() {
 | 
						|
				return this._.value || '';
 | 
						|
			},
 | 
						|
 | 
						|
			unmarkAll: function() {
 | 
						|
				this._.list.unmarkAll();
 | 
						|
			},
 | 
						|
 | 
						|
			mark: function( value ) {
 | 
						|
				this._.list.mark( value );
 | 
						|
			},
 | 
						|
 | 
						|
			hideItem: function( value ) {
 | 
						|
				this._.list.hideItem( value );
 | 
						|
			},
 | 
						|
 | 
						|
			hideGroup: function( groupTitle ) {
 | 
						|
				this._.list.hideGroup( groupTitle );
 | 
						|
			},
 | 
						|
 | 
						|
			showAll: function() {
 | 
						|
				this._.list.showAll();
 | 
						|
			},
 | 
						|
 | 
						|
			add: function( value, html, text ) {
 | 
						|
				this._.items[ value ] = text || value;
 | 
						|
				this._.list.add( value, html, text );
 | 
						|
			},
 | 
						|
 | 
						|
			startGroup: function( title ) {
 | 
						|
				this._.list.startGroup( title );
 | 
						|
			},
 | 
						|
 | 
						|
			commit: function() {
 | 
						|
				if ( !this._.committed ) {
 | 
						|
					this._.list.commit();
 | 
						|
					this._.committed = 1;
 | 
						|
					CKEDITOR.ui.fire( 'ready', this );
 | 
						|
				}
 | 
						|
				this._.committed = 1;
 | 
						|
			},
 | 
						|
 | 
						|
			setState: function( state ) {
 | 
						|
				if ( this._.state == state )
 | 
						|
					return;
 | 
						|
 | 
						|
				var el = this.document.getById( 'cke_' + this.id );
 | 
						|
				el.setState( state, 'cke_combo' );
 | 
						|
 | 
						|
				state == CKEDITOR.TRISTATE_DISABLED ?
 | 
						|
					el.setAttribute( 'aria-disabled', true ) :
 | 
						|
					el.removeAttribute( 'aria-disabled' );
 | 
						|
 | 
						|
				this._.state = state;
 | 
						|
			},
 | 
						|
 | 
						|
			getState: function() {
 | 
						|
				return this._.state;
 | 
						|
			},
 | 
						|
 | 
						|
			enable: function() {
 | 
						|
				if ( this._.state == CKEDITOR.TRISTATE_DISABLED )
 | 
						|
					this.setState( this._.lastState );
 | 
						|
			},
 | 
						|
 | 
						|
			disable: function() {
 | 
						|
				if ( this._.state != CKEDITOR.TRISTATE_DISABLED ) {
 | 
						|
					this._.lastState = this._.state;
 | 
						|
					this.setState( CKEDITOR.TRISTATE_DISABLED );
 | 
						|
				}
 | 
						|
			}
 | 
						|
		},
 | 
						|
 | 
						|
		/**
 | 
						|
		 * Represents richCombo handler object.
 | 
						|
		 *
 | 
						|
		 * @class CKEDITOR.ui.richCombo.handler
 | 
						|
		 * @singleton
 | 
						|
		 * @extends CKEDITOR.ui.handlerDefinition
 | 
						|
		 */
 | 
						|
		statics: {
 | 
						|
			handler: {
 | 
						|
				/**
 | 
						|
				 * Transforms a richCombo definition in a {@link CKEDITOR.ui.richCombo} instance.
 | 
						|
				 *
 | 
						|
				 * @param {Object} definition
 | 
						|
				 * @returns {CKEDITOR.ui.richCombo}
 | 
						|
				 */
 | 
						|
				create: function( definition ) {
 | 
						|
					return new CKEDITOR.ui.richCombo( definition );
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} );
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @param {String} name
 | 
						|
	 * @param {Object} definition
 | 
						|
	 * @member CKEDITOR.ui
 | 
						|
	 * @todo
 | 
						|
	 */
 | 
						|
	CKEDITOR.ui.prototype.addRichCombo = function( name, definition ) {
 | 
						|
		this.add( name, CKEDITOR.UI_RICHCOMBO, definition );
 | 
						|
	};
 | 
						|
 | 
						|
} )();
 |