Index: _source/core/ui.js =================================================================== --- _source/core/ui.js (revision 4139) +++ _source/core/ui.js Fri Aug 21 12:22:20 CST 2009 @@ -75,6 +75,9 @@ if ( command ) command.uiItems.push( result ); + // Replace the registered items with created instances. + this._.items[ name ] = result; + return result; }, Index: _source/plugins/richcombo/plugin.js =================================================================== --- _source/plugins/richcombo/plugin.js (revision 3712) +++ _source/plugins/richcombo/plugin.js Fri Aug 21 12:22:20 CST 2009 @@ -273,6 +273,11 @@ me.setState( CKEDITOR.TRISTATE_OFF ); }; + panel.on( 'showBlock', function() + { + this.fire( 'open', panel ); + }, this ); + if ( this.init ) this.init(); }, @@ -351,6 +356,7 @@ } }); +CKEDITOR.event.implementOn( CKEDITOR.ui.richCombo.prototype, true ); CKEDITOR.ui.prototype.addRichCombo = function( name, definition ) { this.add( name, CKEDITOR.UI_RICHCOMBO, definition ); Index: _source/plugins/menu/plugin.js =================================================================== --- _source/plugins/menu/plugin.js (revision 4036) +++ _source/plugins/menu/plugin.js Fri Aug 21 12:22:20 CST 2009 @@ -151,6 +151,12 @@ }, this ); + panel.on( 'showBlock', function() + { + this.fire( 'open', panel ); + }, this ); + + // Create an autosize block inside the panel. var block = panel.addBlock( this.id ); block.autoSize = true; @@ -241,6 +247,8 @@ } }); + CKEDITOR.event.implementOn( CKEDITOR.menu.prototype, true ); + function sortItems( items ) { items.sort( function( itemA, itemB ) Index: _source/plugins/keystrokes/plugin.js =================================================================== --- _source/plugins/keystrokes/plugin.js (revision 4036) +++ _source/plugins/keystrokes/plugin.js Fri Aug 21 21:58:34 CST 2009 @@ -83,7 +83,6 @@ { // The DOM event object is passed by the "data" property. event = event.data; - var keyCombination = event.getKeystroke(); var command = this.keystrokes[ keyCombination ]; var editor = this._.editor; Index: _source/plugins/floatpanel/plugin.js =================================================================== --- _source/plugins/floatpanel/plugin.js (revision 4027) +++ _source/plugins/floatpanel/plugin.js Fri Aug 21 12:22:20 CST 2009 @@ -217,11 +217,19 @@ if ( panel.isLoaded ) setHeight(); else - panel.onLoad = setHeight; + panel.on( 'load', setHeight ); } else - element.getFirst().removeStyle( 'height' ); + element.getFirst().removeStyle('height'); + panel.isLoaded ? + this.fire( 'showBlock', block ) + : panel.on( 'load', function( evt ) + { + evt.removeListener(); + this.fire( 'showBlock', block ); + }, this ); + // Set the IFrame focus, so the blur event gets fired. CKEDITOR.tools.setTimeout( function() { @@ -322,4 +330,7 @@ } } }); + + CKEDITOR.event.implementOn( CKEDITOR.ui.floatPanel.prototype, true ); + })(); Index: _source/plugins/dialog/plugin.js =================================================================== --- _source/plugins/dialog/plugin.js (revision 3998) +++ _source/plugins/dialog/plugin.js Fri Aug 21 12:22:20 CST 2009 @@ -2680,9 +2680,15 @@ var storedDialogs = this._.storedDialogs || ( this._.storedDialogs = {} ); - var dialog = storedDialogs[ dialogName ] || - ( storedDialogs[ dialogName ] = new CKEDITOR.dialog( this, dialogName ) ); - + var dialog = storedDialogs[ dialogName ]; + if( !dialog ) + { + dialog = ( storedDialogs[ dialogName ] = new CKEDITOR.dialog( this, dialogName ) ); + dialog.on( 'show', function() + { + this.fire( 'dialogOpen', dialog ); + }, this ); + } dialog.show(); return dialog; Index: _source/plugins/toolbar/plugin.js =================================================================== --- _source/plugins/toolbar/plugin.js (revision 4036) +++ _source/plugins/toolbar/plugin.js Fri Aug 21 12:22:20 CST 2009 @@ -193,6 +193,7 @@ } var itemObj = item.render( editor, output ); + item.toolbarItem = itemObj; index = toolbarObj.items.push( itemObj ) - 1; if ( index > 0 ) Index: _source/plugins/panelbutton/plugin.js =================================================================== --- _source/plugins/panelbutton/plugin.js (revision 3712) +++ _source/plugins/panelbutton/plugin.js Fri Aug 21 12:22:20 CST 2009 @@ -133,8 +133,14 @@ _.on = 0; me.setState( CKEDITOR.TRISTATE_OFF ); }; + panel.on( 'showBlock', function() + { + this.fire( 'open', panel ); + }, this ); } } }); + CKEDITOR.event.implementOn( CKEDITOR.ui.panelButton.prototype, true ); + })(); Index: _source/core/test.js =================================================================== --- _source/core/test.js (revision 4147) +++ _source/core/test.js Fri Aug 21 22:11:54 CST 2009 @@ -68,8 +68,235 @@ } sel.selectRanges( ranges ); + }, + + toolbar : + { + /** + * Click on a specific toolbar button and the {@param callback} will be + * fed with the consequential UI object which has been opened by this click. + * + * @param itemName The toolbar item definition name. + * @callback The callback function which is called after the affiliate + * button behavior has completed. + * @example + * + * // Click on 'Format' combo. + * CKEDITOR.test.toolbar.clickButton( 'Format' , + * function( combo ) + * { + * alert( combo instanceof CKEDITOR.ui.richCombo ); // true + * }); + * + * // Click on 'Image' dialog. + * CKEDITOR.test.toolbar.clickButton( 'Image' , + * function( dialog ) + * { + * alert( dialog instanceof CKEDITOR.dialog ); // true + * }); + */ + clickButton : function( editor, itemName, callback, context ) + { + var ui = editor.ui, + // Find the corresponding ui instances of the toolbar item. + uiItems = ui._.items, + uiItem =uiItems[ itemName ], + // Back reference the toolbar item instance. + toolbarItem = uiItem.toolbarItem, + // Find the command instance registered on this ui item. + command = editor.getCommand( uiItem.command ); + + // Special treatments for different types of button. + if( uiItem instanceof CKEDITOR.ui.button ) + { + // button of style command. + if( command && command.style ) + { + editor.on( 'selectionChange', function( evt ) + { + evt.removeListener(); + callback.call( context ); + }, null, null, 1000 ); - } + } + // button of dialog command. + if( command && command.dialogName ) + { + editor.on( 'dialogOpen', function( evt ) + { + evt.removeListener(); + callback.call( context, evt.data ); + }, null, null, 1000 ); + } + // button of panel. + else if( uiItem instanceof CKEDITOR.ui.panelButton ) + { + uiItem.on( 'open', function( evt ) + { + evt.removeListener(); + callback.call( context, uiItem ); + }, null, 1000 ); + } + // Trigger button. + toolbarItem.execute(); + } + else if( uiItem instanceof CKEDITOR.ui.richCombo ) + { + uiItem.on( 'open', function( evt ) + { + evt.removeListener(); + callback.call( context, uiItem ); + }, null, 1000 ); - + + // Trigger combo. + var comboEntry = YAHOO.util.Selector.query( 'a', toolbarItem.id, true ); + comboEntry.onclick(); + } + } + + }, + + dialog : + { + /** + * Filling the assigned dialog with a specified set of field values and finally close it. + * @param dialog {CKEDITOR.dialog} The dialog instance to populate. + * @param profile {Object} The page - field - value map to be filled into the dialog. + * @example + * CKEDITOR.test.dialog.fill( imageDialog, + * { + * info : + * { + * txtUrl : 'http://ckeditor.com/logos.gif' + * }, + * Link : + * { + * txtUrl : 'http://ckeditor.com' + * }, + * advanced : + * { + * linkId : 'link_id1', + * txtGenClass : 'cls' + * } + * } ); + * + */ + fill : function ( dialog, profile ) + { + var field, page; + for( var pageName in profile ) + { + // Activate the page. + dialog.selectPage( pageName ); + + page = profile[ pageName ]; + for( var fieldId in page ) + { + field = dialog.getContentElement( pageName, fieldId ); + // Populate the field. + field.setValue( page[ fieldId ] ); + } + } + dialog.click( 'ok' ); + } + + }, + + editor : + { + /** + * Load the editor with specified content and the denoted selection within it. + * @param editor + * @param data {String} String presentation of the HTML and selection range marker. + * @example + * CKEDITOR.test.editor.loadDataWithSelection( editor, + * "
This is some [sample text].
" ); + */ + loadDataWithSelection : function( editor, data ) + { + var docBody = editor.document.getBody(); + CKEDITOR.test.setHtmlWithSelection( docBody, data ); + }, + + /** + * Set the editor selection to what the start/end position denote. + * @param editor + * @param {Array} startPosition The expected range startContainer address plus startOffset. + * @param {Array} endPosition The expected range endContainer address plus endOffset. + * @example + * // Make the selection as:[text] selection
+ * CKEDITOR.test.editor.makeSelection( editor, [ 1, 0, 0, 0 ], [ 1, 0, 0, 4 ] ); + */ + makeSelection : function( editor, startPosition, endPosition ) + { + editor.getSelection().selectBookmarks( [ { + start : startPosition.slice( 0, startPosition.length - 1 ), + startOffset : startPosition[ startPosition.length -1 ], + end : endPosition == true ? null : endPosition.slice( 0, endPosition.length - 1 ), + endOffset : endPosition[ endPosition.length -1 ], + is2: true + } ] ); + }, + + /** + * Simulating type into the editor document char by char. + * Note: The document content will not be updated with this method, so + * it should only be used with those keystrokes whose handlers are defined + * by the editor. + * @param editor + * @param {String} sequences A sequence of ASCII characters, each of + * which represent a key stroke with the corresponding charCode, the modifier + * keys are denoted by the following syntax: + * 1. Ctrl : [] + * 2. Shfit : () + * 3. Alt : {} + * @example + * Type shift-enter key on the cursor position: + * CKEDITOR.test.editor.type( editor, "(\r)"); + */ + type : function( editor, sequences ) + { + var ctrl, alt, shift; + sequences.replace( /([()\[\]{}]*)([^()\[\]{}]+)/g, function( match, modifiers, keys ) + { + // Checking modifiers state. + for( var i = 0 ; i < modifiers.length ; i++ ) + { + var modifier = modifiers.charAt( i ); + switch( modifier ) + { + case '[' : + case ']' : + ctrl = modifier == '[' ? 1 : 0; + break; + case '(' : + case ')' : + shift = modifier == '(' ? 1 : 0; + break; + case '{' : + case '}' : + alt = modifier == '{' ? 1 : 0; + } + } + + // Simulating key strokes. + for( i = 0 ; i < keys.length ; i++ ) + { + var keyStroke = + { + charCode: keys.charCodeAt( i ), + keyCode : keys.charCodeAt( i ), + ctrlKey : !!ctrl, + altKey : !!alt, + shiftKey : !!shift + }, + target = editor.document.getBody().$; + + YAHOO.util.UserAction.keydown( target, keyStroke ); + YAHOO.util.UserAction.keyup( target, keyStroke ); + } + } ); + } + } }; // Inherit generic testing APIs from CKTESTER. Index: _source/plugins/panel/plugin.js =================================================================== --- _source/plugins/panel/plugin.js (revision 4051) +++ _source/plugins/panel/plugin.js Fri Aug 21 12:24:02 CST 2009 @@ -141,11 +141,11 @@ if ( CKEDITOR.env.isCustomDomain() ) doc.$.domain = document.domain; - var onLoad = CKEDITOR.tools.addFunction( CKEDITOR.tools.bind( function( ev ) + var onLoad = CKEDITOR.tools.addFunction( CKEDITOR.tools.bind( function() { this.isLoaded = true; - if ( this.onLoad ) - this.onLoad(); + this.fire( 'load', this ); + }, this ) ); doc.$.write( @@ -233,6 +233,7 @@ } }; +CKEDITOR.event.implementOn( CKEDITOR.ui.panel.prototype, true ); CKEDITOR.ui.panel.block = CKEDITOR.tools.createClass( { $ : function( blockHolder )