X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Fdialog%2Fplugin.js;h=b5aab8182c2060c5e27b7863ba76f6b848dce35b;hb=9afde8772159bd3436f1f5b7862960307710ae5a;hp=706c92b61f017e806f7888dfdaaab8fe362ef14e;hpb=941b0a9ba4e673e292510d80a5a86806994b8ea6;p=ckeditor.git diff --git a/_source/plugins/dialog/plugin.js b/_source/plugins/dialog/plugin.js index 706c92b..b5aab81 100644 --- a/_source/plugins/dialog/plugin.js +++ b/_source/plugins/dialog/plugin.js @@ -33,6 +33,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; (function() { + var cssLength = CKEDITOR.tools.cssLength; function isTabVisible( tabId ) { return !!this._.tabs[ tabId ][ 0 ].$.offsetHeight; @@ -68,6 +69,30 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; return null; } + + function clearOrRecoverTextInputValue( container, isRecover ) + { + var inputs = container.$.getElementsByTagName( 'input' ); + for ( var i = 0, length = inputs.length; i < length ; i++ ) + { + var item = new CKEDITOR.dom.element( inputs[ i ] ); + + if ( item.getAttribute( 'type' ).toLowerCase() == 'text' ) + { + if ( isRecover ) + { + item.setAttribute( 'value', item.getCustomData( 'fake_value' ) || '' ); + item.removeCustomData( 'fake_value' ); + } + else + { + item.setCustomData( 'fake_value', item.getAttribute( 'value' ) ); + item.setAttribute( 'value', '' ); + } + } + } + } + /** * This is the base class for runtime dialog objects. An instance of this * class represents a single named dialog for a single editor instance. @@ -80,10 +105,19 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; CKEDITOR.dialog = function( editor, dialogName ) { // Load the dialog definition. - var definition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ]; + var definition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ], + defaultDefinition = CKEDITOR.tools.clone( defaultDialogDefinition ), + buttonsOrder = editor.config.dialog_buttonsOrder || 'OS', + dir = editor.lang.dir; + + if ( ( buttonsOrder == 'OS' && CKEDITOR.env.mac ) || // The buttons in MacOS Apps are in reverse order (#4750) + ( buttonsOrder == 'rtl' && dir == 'ltr' ) || + ( buttonsOrder == 'ltr' && dir == 'rtl' ) ) + defaultDefinition.buttons.reverse(); + // Completes the definition with the default values. - definition = CKEDITOR.tools.extend( definition( editor ), defaultDialogDefinition ); + definition = CKEDITOR.tools.extend( definition( editor ), defaultDefinition ); // Clone a functionally independent copy for this dialog. definition = CKEDITOR.tools.clone( definition ); @@ -92,15 +126,6 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // functions. definition = new definitionObject( this, definition ); - // Fire the "dialogDefinition" event, making it possible to customize - // the dialog definition. - this.definition = definition = CKEDITOR.fire( 'dialogDefinition', - { - name : dialogName, - definition : definition - } - , editor ).definition; - var doc = CKEDITOR.document; var themeBuilt = editor.theme.buildDialog( editor ); @@ -113,7 +138,6 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; name : dialogName, contentSize : { width : 0, height : 0 }, size : { width : 0, height : 0 }, - updateSize : false, contents : {}, buttons : {}, accessKeyMap : {}, @@ -135,6 +159,12 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; this.parts = themeBuilt.parts; + CKEDITOR.tools.setTimeout( function() + { + editor.fire( 'ariaWidget', this.parts.contents ); + }, + 0, this ); + // Set the startup styles for the dialog, avoiding it enlarging the // page size on the dialog creation. this.parts.dialog.setStyles( @@ -148,6 +178,42 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // Call the CKEDITOR.event constructor to initialize this instance. CKEDITOR.event.call( this ); + // Fire the "dialogDefinition" event, making it possible to customize + // the dialog definition. + this.definition = definition = CKEDITOR.fire( 'dialogDefinition', + { + name : dialogName, + definition : definition + } + , editor ).definition; + + var tabsToRemove = {}; + // Cache tabs that should be removed. + if ( !( 'removeDialogTabs' in editor._ ) && editor.config.removeDialogTabs ) + { + var removeContents = editor.config.removeDialogTabs.split( ';' ); + + for ( i = 0; i < removeContents.length; i++ ) + { + var parts = removeContents[ i ].split( ':' ); + if ( parts.length == 2 ) + { + var removeDialogName = parts[ 0 ]; + if ( !tabsToRemove[ removeDialogName ] ) + tabsToRemove[ removeDialogName ] = []; + tabsToRemove[ removeDialogName ].push( parts[ 1 ] ); + } + } + editor._.removeDialogTabs = tabsToRemove; + } + + // Remove tabs of this dialog. + if ( editor._.removeDialogTabs && ( tabsToRemove = editor._.removeDialogTabs[ dialogName ] ) ) + { + for ( i = 0; i < tabsToRemove.length; i++ ) + definition.removeContents( tabsToRemove[ i ] ); + } + // Initialize load, show, hide, ok and cancel events. if ( definition.onLoad ) this.on( 'load', definition.onLoad ); @@ -162,6 +228,9 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { this.on( 'ok', function( evt ) { + // Dialog confirm might probably introduce content changes (#5415). + editor.fire( 'saveSnapshot' ); + setTimeout( function () { editor.fire( 'saveSnapshot' ); }, 0 ); if ( definition.onOk.call( this, evt ) === false ) evt.data.hide = false; }); @@ -242,8 +311,29 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { if ( this.fire( 'cancel', { hide : true } ).hide !== false ) this.hide(); + evt.data.preventDefault(); }, this ); + // Sort focus list according to tab order definitions. + function setupFocus() + { + var focusList = me._.focusList; + focusList.sort( function( a, b ) + { + // Mimics browser tab order logics; + if ( a.tabIndex != b.tabIndex ) + return b.tabIndex - a.tabIndex; + // Sort is not stable in some browsers, + // fall-back the comparator to 'focusIndex'; + else + return a.focusIndex - b.focusIndex; + }); + + var size = focusList.length; + for ( var i = 0; i < size; i++ ) + focusList[ i ].focusIndex = i; + } + function changeFocus( forward ) { var focusList = me._.focusList, @@ -251,7 +341,17 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( focusList.length < 1 ) return; - var startIndex = ( me._.currentFocusIndex + offset + focusList.length ) % focusList.length, + var current = me._.currentFocusIndex; + + // Trigger the 'blur' event of any input element before anything, + // since certain UI updates may depend on it. + try + { + focusList[ current ].getInputElement().$.blur(); + } + catch( e ){} + + var startIndex = ( current + offset + focusList.length ) % focusList.length, currentIndex = startIndex; while ( !focusList[ currentIndex ].isFocusable() ) { @@ -266,6 +366,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; focusList[ currentIndex ].select(); } + this.changeFocus = changeFocus; + var processed; function focusKeydownHandler( evt ) @@ -274,7 +376,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( me != CKEDITOR.dialog._.currentTop ) return; - var keystroke = evt.data.getKeystroke(); + var keystroke = evt.data.getKeystroke(), + rtl = editor.lang.dir == 'rtl'; processed = 0; if ( keystroke == 9 || keystroke == CKEDITOR.SHIFT + 9 ) @@ -297,7 +400,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; processed = 1; } - else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode ) + else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode && me.getPageCount() > 1 ) { // Alt-F10 puts focus into the current tab item in the tab bar. me._.tabBarMode = true; @@ -307,11 +410,19 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; else if ( ( keystroke == 37 || keystroke == 39 ) && me._.tabBarMode ) { // Arrow keys - used for changing tabs. - nextId = ( keystroke == 37 ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) ); + nextId = ( keystroke == ( rtl ? 39 : 37 ) ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) ); me.selectPage( nextId ); me._.tabs[ nextId ][ 0 ].focus(); processed = 1; } + else if ( ( keystroke == 13 || keystroke == 32 ) && me._.tabBarMode ) + { + this.selectPage( this._.currentTabId ); + this._.tabBarMode = false; + this._.currentFocusIndex = -1; + changeFocus( true ); + processed = 1; + } if ( processed ) { @@ -325,26 +436,22 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; processed && evt.data.preventDefault(); } + var dialogElement = this._.element; // Add the dialog keyboard handlers. this.on( 'show', function() { - CKEDITOR.document.on( 'keydown', focusKeydownHandler, this, null, 0 ); + dialogElement.on( 'keydown', focusKeydownHandler, this, null, 0 ); // Some browsers instead, don't cancel key events in the keydown, but in the // keypress. So we must do a longer trip in those cases. (#4531) if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) ) - CKEDITOR.document.on( 'keypress', focusKeyPressHandler, this ); + dialogElement.on( 'keypress', focusKeyPressHandler, this ); - if ( CKEDITOR.env.ie6Compat ) - { - var coverDoc = coverElement.getChild( 0 ).getFrameDocument(); - coverDoc.on( 'keydown', focusKeydownHandler, this, null, 0 ); - } } ); this.on( 'hide', function() { - CKEDITOR.document.removeListener( 'keydown', focusKeydownHandler ); + dialogElement.removeListener( 'keydown', focusKeydownHandler ); if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) ) - CKEDITOR.document.removeListener( 'keypress', focusKeyPressHandler ); + dialogElement.removeListener( 'keypress', focusKeyPressHandler ); } ); this.on( 'iframeAdded', function( evt ) { @@ -355,10 +462,30 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // Auto-focus logic in dialog. this.on( 'show', function() { - if ( !this._.hasFocus ) + // Setup tabIndex on showing the dialog instead of on loading + // to allow dynamic tab order happen in dialog definition. + setupFocus(); + + if ( editor.config.dialog_startupFocusTab + && me._.pageCount > 1 ) + { + me._.tabBarMode = true; + me._.tabs[ me._.currentTabId ][ 0 ].focus(); + } + else if ( !this._.hasFocus ) { this._.currentFocusIndex = -1; - changeFocus( true ); + + // Decide where to put the initial focus. + if ( definition.onFocus ) + { + var initialFocus = definition.onFocus.call( this ); + // Focus the field that the user specified. + initialFocus && initialFocus.focus(); + } + // Focus the first field in layout order. + else + changeFocus( true ); /* * IE BUG: If the initial focus went into a non-text element (e.g. button), @@ -405,30 +532,29 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // Insert the tabs and contents. for ( var i = 0 ; i < definition.contents.length ; i++ ) - this.addPage( definition.contents[i] ); + { + var page = definition.contents[i]; + page && this.addPage( page ); + } - var tabRegex = /cke_dialog_tab(\s|$|_)/, - tabOuterRegex = /cke_dialog_tab(\s|$)/; - this.parts['tabs'].on( 'click', function( evt ) + this.parts[ 'tabs' ].on( 'click', function( evt ) { - var target = evt.data.getTarget(), firstNode = target, id, page; - + var target = evt.data.getTarget(); // If we aren't inside a tab, bail out. - if ( !( tabRegex.test( target.$.className ) || target.getName() == 'a' ) ) - return; - - // Find the outer container of the tab. - id = target.$.id.substr( 0, target.$.id.lastIndexOf( '_' ) ); - this.selectPage( id ); - - if ( this._.tabBarMode ) + if ( target.hasClass( 'cke_dialog_tab' ) ) { - this._.tabBarMode = false; - this._.currentFocusIndex = -1; - changeFocus( true ); - } + // Get the ID of the tab, without the 'cke_' prefix and the unique number suffix. + var id = target.$.id; + this.selectPage( id.substring( 4, id.lastIndexOf( '_' ) ) ); - evt.data.preventDefault(); + if ( this._.tabBarMode ) + { + this._.tabBarMode = false; + this._.currentFocusIndex = -1; + changeFocus( true ); + } + evt.data.preventDefault(); + } }, this ); // Insert buttons. @@ -444,8 +570,6 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; for ( i = 0 ; i < buttons.length ; i++ ) this._.buttons[ buttons[i].id ] = buttons[i]; - - CKEDITOR.skins.load( editor, 'dialog' ); }; // Focusable interface. Use it via dialog.addFocusable. @@ -453,6 +577,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { this.element = element; this.focusIndex = index; + // TODO: support tabIndex for focusables. + this.tabIndex = 0; this.isFocusable = function() { return !element.getAttribute( 'disabled' ) && element.isVisible(); @@ -480,6 +606,12 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; CKEDITOR.dialog.prototype = { + destroy : function() + { + this.hide(); + this._.element.remove(); + }, + /** * Resizes the dialog. * @param {Number} width The width of the dialog in pixels. @@ -504,7 +636,6 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; }, this._.editor ); this._.contentSize = { width : width, height : height }; - this._.updateSize = true; }; })(), @@ -516,15 +647,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; */ getSize : function() { - if ( !this._.updateSize ) - return this._.size; var element = this._.element.getFirst(); - var size = this._.size = { width : element.$.offsetWidth || 0, height : element.$.offsetHeight || 0}; - - // If either the offsetWidth or offsetHeight is 0, the element isn't visible. - this._.updateSize = !size.width || !size.height; - - return size; + return { width : element.$.offsetWidth || 0, height : element.$.offsetHeight || 0}; }, /** @@ -532,13 +656,14 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; * @function * @param {Number} x The target x-coordinate. * @param {Number} y The target y-coordinate. + * @param {Boolean} save Flag indicate whether the dialog position should be remembered on next open up. * @example * dialogObj.move( 10, 40 ); */ move : (function() { var isFixed; - return function( x, y ) + return function( x, y, save ) { // The dialog may be fixed positioned or absolute positioned. Ask the // browser what is the current situation first. @@ -565,6 +690,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; 'left' : ( x > 0 ? x : 0 ) + 'px', 'top' : ( y > 0 ? y : 0 ) + 'px' }); + + save && ( this._.moved = 1 ); }; })(), @@ -596,7 +723,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( !( element.getParent() && element.getParent().equals( CKEDITOR.document.getBody() ) ) ) element.appendTo( CKEDITOR.document.getBody() ); else - return; + element.setStyle( 'display', 'block' ); // FIREFOX BUG: Fix vanishing caret for Firefox 2 or Gecko 1.8. if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 ) @@ -611,14 +738,15 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // First, set the dialog to an appropriate size. - this.resize( definition.minWidth, definition.minHeight ); - - // Select the first tab by default. - this.selectPage( this.definition.contents[0].id ); + this.resize( this._.contentSize && this._.contentSize.width || definition.minWidth, + this._.contentSize && this._.contentSize.height || definition.minHeight ); // Reset all inputs back to their default value. this.reset(); + // Select the first tab by default. + this.selectPage( this.definition.contents[0].id ); + // Set z-index. if ( CKEDITOR.dialog._.currentZIndex === null ) CKEDITOR.dialog._.currentZIndex = this._.editor.config.baseFloatZIndex; @@ -630,7 +758,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { CKEDITOR.dialog._.currentTop = this; this._.parentDialog = null; - addCover( this._.editor ); + showCover( this._.editor ); element.on( 'keydown', accessKeyDownHandler ); element.on( CKEDITOR.env.opera ? 'keypress' : 'keyup', accessKeyUpHandler ); @@ -656,20 +784,15 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // Reset the hasFocus state. this._.hasFocus = false; - // Rearrange the dialog to the middle of the window. CKEDITOR.tools.setTimeout( function() { - var viewSize = CKEDITOR.document.getWindow().getViewPaneSize(); - var dialogSize = this.getSize(); - - // We're using definition size for initial position because of - // offten corrupted data in offsetWidth at this point. (#4084) - this.move( ( viewSize.width - definition.minWidth ) / 2, ( viewSize.height - dialogSize.height ) / 2 ); - + this.layout(); this.parts.dialog.setStyle( 'visibility', '' ); // Execute onLoad for the first show. this.fireOnce( 'load', {} ); + CKEDITOR.ui.fire( 'ready', this ); + this.fire( 'show', {} ); this._.editor.fire( 'dialogShow', this ); @@ -681,6 +804,19 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; }, /** + * Rearrange the dialog to its previous position or the middle of the window. + * @since 3.5 + */ + layout : function() + { + var viewSize = CKEDITOR.document.getWindow().getViewPaneSize(), + dialogSize = this.getSize(); + + this.move( this._.moved ? this._.position.x : ( viewSize.width - dialogSize.width ) / 2, + this._.moved ? this._.position.y : ( viewSize.height - dialogSize.height ) / 2 ); + }, + + /** * Executes a function for each UI element. * @param {Function} fn Function to execute for each UI element. * @returns {CKEDITOR.dialog} The current dialog object. @@ -690,7 +826,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; for ( var i in this._.contents ) { for ( var j in this._.contents[i] ) - fn( this._.contents[i][j]); + fn( this._.contents[i][j] ); } return this; }, @@ -703,7 +839,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; */ reset : (function() { - var fn = function( widget ){ if ( widget.reset ) widget.reset(); }; + var fn = function( widget ){ if ( widget.reset ) widget.reset( 1 ); }; return function(){ this.foreach( fn ); return this; }; })(), @@ -734,23 +870,24 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; */ hide : function() { + if ( !this.parts.dialog.isVisible() ) + return; + this.fire( 'hide', {} ); this._.editor.fire( 'dialogHide', this ); - - // Remove the dialog's element from the root document. var element = this._.element; - if ( !element.getParent() ) - return; - - element.remove(); + element.setStyle( 'display', 'none' ); this.parts.dialog.setStyle( 'visibility', 'hidden' ); - // Unregister all access keys associated with this dialog. unregisterAccessKey( this ); + // Close any child(top) dialogs first. + while( CKEDITOR.dialog._.currentTop != this ) + CKEDITOR.dialog._.currentTop.hide(); + // Maintain dialog ordering and remove cover if needed. if ( !this._.parentDialog ) - removeCover(); + hideCover(); else { var parentElement = this._.parentDialog.getElement().getFirst(); @@ -783,7 +920,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; else CKEDITOR.dialog._.currentZIndex -= 10; - + delete this._.parentDialog; // Reset the initial values of the dialog. this.foreach( function( contentObj ) { contentObj.resetInitValue && contentObj.resetInitValue(); } ); }, @@ -810,29 +947,32 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // Create the HTML for the tab and the content block. var page = CKEDITOR.dom.element.createFromHtml( pageHtml.join( '' ) ); - var tab = CKEDITOR.dom.element.createFromHtml( [ + page.setAttribute( 'role', 'tabpanel' ); + + var env = CKEDITOR.env; + var tabId = 'cke_' + contents.id + '_' + CKEDITOR.tools.getNextNumber(), + tab = CKEDITOR.dom.element.createFromHtml( [ ' 0 ? ' cke_last' : 'cke_first' ), titleHtml, ( !!contents.hidden ? ' style="display:none"' : '' ), - ' id="', contents.id + '_', CKEDITOR.tools.getNextNumber(), '"' + - ' href="javascript:void(0)"', - ' hidefocus="true">', + ' id="', tabId, '"', + env.gecko && env.version >= 10900 && !env.hc ? '' : ' href="javascript:void(0)"', + ' tabIndex="-1"', + ' hidefocus="true"', + ' role="tab">', contents.label, '' ].join( '' ) ); - // If only a single page exist, a different style is used in the central pane. - if ( this._.pageCount === 0 ) - this.parts.dialog.addClass( 'cke_single_page' ); - else - this.parts.dialog.removeClass( 'cke_single_page' ); + page.setAttribute( 'aria-labelledby', tabId ); // Take records for the tabs and elements created. this._.tabs[ contents.id ] = [ tab, page ]; this._.tabIdList.push( contents.id ); - this._.pageCount++; + !contents.hidden && this._.pageCount++; this._.lastTab = tab; + this.updateStyle(); var contentMap = this._.contents[ contents.id ] = {}, cursor, @@ -870,6 +1010,13 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; */ selectPage : function( id ) { + if ( this._.currentTabId == id ) + return; + + // Returning true means that the event has been canceled + if ( this.fire( 'selectPage', { page : id, currentPage : this._.currentTabId } ) === true ) + return; + // Hide the non-selected tabs and pages. for ( var i in this._.tabs ) { @@ -880,15 +1027,38 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; tab.removeClass( 'cke_dialog_tab_selected' ); page.hide(); } + page.setAttribute( 'aria-hidden', i != id ); } - var selected = this._.tabs[id]; - selected[0].addClass( 'cke_dialog_tab_selected' ); - selected[1].show(); + var selected = this._.tabs[ id ]; + selected[ 0 ].addClass( 'cke_dialog_tab_selected' ); + + // [IE] an invisible input[type='text'] will enlarge it's width + // if it's value is long when it shows, so we clear it's value + // before it shows and then recover it (#5649) + if ( CKEDITOR.env.ie6Compat || CKEDITOR.env.ie7Compat ) + { + clearOrRecoverTextInputValue( selected[ 1 ] ); + selected[ 1 ].show(); + setTimeout( function() + { + clearOrRecoverTextInputValue( selected[ 1 ], 1 ); + }, 0 ); + } + else + selected[ 1 ].show(); + this._.currentTabId = id; this._.currentTabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, id ); }, + // Dialog state-specific style updates. + updateStyle : function() + { + // If only a single page shown, a different style is used in the central pane. + this.parts.dialog[ ( this._.pageCount === 1 ? 'add' : 'remove' ) + 'Class' ]( 'cke_single_page' ); + }, + /** * Hides a page's tab away from the dialog. * @param {String} id The page's Id. @@ -898,9 +1068,15 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; hidePage : function( id ) { var tab = this._.tabs[id] && this._.tabs[id][0]; - if ( !tab ) + if ( !tab || this._.pageCount == 1 || !tab.isVisible() ) return; + // Switch to other tab first when we're hiding the active tab. + else if ( id == this._.currentTabId ) + this.selectPage( getPreviousVisibleTab.call( this ) ); + tab.hide(); + this._.pageCount--; + this.updateStyle(); }, /** @@ -915,6 +1091,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( !tab ) return; tab.show(); + this._.pageCount++; + this.updateStyle(); }, /** @@ -949,7 +1127,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; */ getContentElement : function( pageId, elementId ) { - return this._.contents[pageId][elementId]; + var page = this._.contents[ pageId ]; + return page && page[ elementId ]; }, /** @@ -1196,7 +1375,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; var defaultDialogDefinition = { - resizable : CKEDITOR.DIALOG_RESIZE_NONE, + resizable : CKEDITOR.DIALOG_RESIZE_BOTH, minWidth : 600, minHeight : 400, buttons : [ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ] @@ -1288,7 +1467,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // Transform the contents entries in contentObjects. var contents = dialogDefinition.contents; for ( var i = 0, content ; ( content = contents[i] ) ; i++ ) - contents[ i ] = new contentObject( dialog, content ); + contents[ i ] = content && new contentObject( dialog, content ); CKEDITOR.tools.extend( this, dialogDefinition ); }; @@ -1470,7 +1649,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( abstractDialogCoords.x + margins[3] < magnetDistance ) realX = - margins[3]; else if ( abstractDialogCoords.x - margins[1] > viewPaneSize.width - dialogSize.width - magnetDistance ) - realX = viewPaneSize.width - dialogSize.width + margins[1]; + realX = viewPaneSize.width - dialogSize.width + ( editor.lang.dir == 'rtl' ? 0 : margins[1] ); else realX = abstractDialogCoords.x; @@ -1481,7 +1660,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; else realY = abstractDialogCoords.y; - dialog.move( realX, realY ); + dialog.move( realX, realY, 1 ); evt.data.preventDefault(); } @@ -1493,7 +1672,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( CKEDITOR.env.ie6Compat ) { - var coverDoc = coverElement.getChild( 0 ).getFrameDocument(); + var coverDoc = currentCover.getChild( 0 ).getFrameDocument(); coverDoc.removeListener( 'mousemove', mouseMoveHandler ); coverDoc.removeListener( 'mouseup', mouseUpHandler ); } @@ -1501,8 +1680,6 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; dialog.parts.title.on( 'mousedown', function( evt ) { - dialog._.updateSize = true; - lastCoords = { x : evt.data.$.screenX, y : evt.data.$.screenY }; CKEDITOR.document.on( 'mousemove', mouseMoveHandler ); @@ -1511,7 +1688,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( CKEDITOR.env.ie6Compat ) { - var coverDoc = coverElement.getChild( 0 ).getFrameDocument(); + var coverDoc = currentCover.getChild( 0 ).getFrameDocument(); coverDoc.on( 'mousemove', mouseMoveHandler ); coverDoc.on( 'mouseup', mouseUpHandler ); } @@ -1522,167 +1699,166 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; function initResizeHandles( dialog ) { - var definition = dialog.definition, - minWidth = definition.minWidth || 0, - minHeight = definition.minHeight || 0, - resizable = definition.resizable, - margins = dialog.getParentEditor().skin.margins || [ 0, 0, 0, 0 ]; + var def = dialog.definition, + resizable = def.resizable; - function topSizer( coords, dy ) - { - coords.y += dy; - } + if ( resizable == CKEDITOR.DIALOG_RESIZE_NONE ) + return; - function rightSizer( coords, dx ) - { - coords.x2 += dx; - } + var editor = dialog.getParentEditor(); + var wrapperWidth, wrapperHeight, viewSize, origin, startSize; - function bottomSizer( coords, dy ) + function positionDialog( right ) { - coords.y2 += dy; + // Maintain righthand sizing in RTL. + if ( dialog._.moved && editor.lang.dir == 'rtl' ) + { + var element = dialog._.element.getFirst(); + element.setStyle( 'right', right + "px" ); + element.removeStyle( 'left' ); + } + else if ( !dialog._.moved ) + dialog.layout(); } - function leftSizer( coords, dx ) + var mouseDownFn = CKEDITOR.tools.addFunction( function( $event ) { - coords.x += dx; - } + startSize = dialog.getSize(); - var lastCoords = null, - abstractDialogCoords = null, - magnetDistance = dialog._.editor.config.magnetDistance, - parts = [ 'tl', 't', 'tr', 'l', 'r', 'bl', 'b', 'br' ]; + // Calculate the offset between content and chrome size. + wrapperHeight = startSize.height - dialog.parts.contents.getSize( 'height', ! ( CKEDITOR.env.gecko || CKEDITOR.env.opera || CKEDITOR.env.ie && CKEDITOR.env.quirks ) ); + wrapperWidth = startSize.width - dialog.parts.contents.getSize( 'width', 1 ); - function mouseDownHandler( evt ) - { - var partName = evt.listenerData.part, size = dialog.getSize(); - abstractDialogCoords = dialog.getPosition(); - CKEDITOR.tools.extend( abstractDialogCoords, - { - x2 : abstractDialogCoords.x + size.width, - y2 : abstractDialogCoords.y + size.height - } ); - lastCoords = { x : evt.data.$.screenX, y : evt.data.$.screenY }; + origin = { x : $event.screenX, y : $event.screenY }; - CKEDITOR.document.on( 'mousemove', mouseMoveHandler, dialog, { part : partName } ); - CKEDITOR.document.on( 'mouseup', mouseUpHandler, dialog, { part : partName } ); + viewSize = CKEDITOR.document.getWindow().getViewPaneSize(); + + CKEDITOR.document.on( 'mousemove', mouseMoveHandler ); + CKEDITOR.document.on( 'mouseup', mouseUpHandler ); if ( CKEDITOR.env.ie6Compat ) { - var coverDoc = coverElement.getChild( 0 ).getFrameDocument(); - coverDoc.on( 'mousemove', mouseMoveHandler, dialog, { part : partName } ); - coverDoc.on( 'mouseup', mouseUpHandler, dialog, { part : partName } ); + var coverDoc = currentCover.getChild( 0 ).getFrameDocument(); + coverDoc.on( 'mousemove', mouseMoveHandler ); + coverDoc.on( 'mouseup', mouseUpHandler ); } - evt.data.preventDefault(); - } + $event.preventDefault && $event.preventDefault(); + }); + + // Prepend the grip to the dialog. + dialog.on( 'load', function() + { + var direction = ''; + if ( resizable == CKEDITOR.DIALOG_RESIZE_WIDTH ) + direction = ' cke_resizer_horizontal'; + else if ( resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT ) + direction = ' cke_resizer_vertical'; + var resizer = CKEDITOR.dom.element.createFromHtml( '
' ); + dialog.parts.footer.append( resizer, 1 ); + }); + editor.on( 'destroy', function() { CKEDITOR.tools.removeFunction( mouseDownFn ); } ); function mouseMoveHandler( evt ) { - var x = evt.data.$.screenX, - y = evt.data.$.screenY, - dx = x - lastCoords.x, - dy = y - lastCoords.y, - viewPaneSize = CKEDITOR.document.getWindow().getViewPaneSize(), - partName = evt.listenerData.part; + var rtl = editor.lang.dir == 'rtl', + dx = ( evt.data.$.screenX - origin.x ) * ( rtl ? -1 : 1 ), + dy = evt.data.$.screenY - origin.y, + width = startSize.width, + height = startSize.height, + internalWidth = width + dx * ( dialog._.moved ? 1 : 2 ), + internalHeight = height + dy * ( dialog._.moved ? 1 : 2 ), + element = dialog._.element.getFirst(), + right = rtl && element.getComputedStyle( 'right' ), + position = dialog.getPosition(); - if ( partName.search( 't' ) != -1 ) - topSizer( abstractDialogCoords, dy ); - if ( partName.search( 'l' ) != -1 ) - leftSizer( abstractDialogCoords, dx ); - if ( partName.search( 'b' ) != -1 ) - bottomSizer( abstractDialogCoords, dy ); - if ( partName.search( 'r' ) != -1 ) - rightSizer( abstractDialogCoords, dx ); - - lastCoords = { x : x, y : y }; + // IE might return "auto", we need exact position. + if ( right ) + right = right == 'auto' ? viewSize.width - ( position.x || 0 ) - element.getSize( 'width' ) : parseInt( right, 10 ); - var realX, realY, realX2, realY2; - - if ( abstractDialogCoords.x + margins[3] < magnetDistance ) - realX = - margins[3]; - else if ( partName.search( 'l' ) != -1 && abstractDialogCoords.x2 - abstractDialogCoords.x < minWidth + magnetDistance ) - realX = abstractDialogCoords.x2 - minWidth; - else - realX = abstractDialogCoords.x; + if ( position.y + internalHeight > viewSize.height ) + internalHeight = viewSize.height - position.y; - if ( abstractDialogCoords.y + margins[0] < magnetDistance ) - realY = - margins[0]; - else if ( partName.search( 't' ) != -1 && abstractDialogCoords.y2 - abstractDialogCoords.y < minHeight + magnetDistance ) - realY = abstractDialogCoords.y2 - minHeight; - else - realY = abstractDialogCoords.y; + if ( ( rtl ? right : position.x ) + internalWidth > viewSize.width ) + internalWidth = viewSize.width - ( rtl ? right : position.x ); - if ( abstractDialogCoords.x2 - margins[1] > viewPaneSize.width - magnetDistance ) - realX2 = viewPaneSize.width + margins[1] ; - else if ( partName.search( 'r' ) != -1 && abstractDialogCoords.x2 - abstractDialogCoords.x < minWidth + magnetDistance ) - realX2 = abstractDialogCoords.x + minWidth; - else - realX2 = abstractDialogCoords.x2; + // Make sure the dialog will not be resized to the wrong side when it's in the leftmost position for RTL. + if ( ( resizable == CKEDITOR.DIALOG_RESIZE_WIDTH || resizable == CKEDITOR.DIALOG_RESIZE_BOTH ) && !( rtl && dx > 0 && !position.x ) ) + width = Math.max( def.minWidth || 0, internalWidth - wrapperWidth ); - if ( abstractDialogCoords.y2 - margins[2] > viewPaneSize.height - magnetDistance ) - realY2= viewPaneSize.height + margins[2] ; - else if ( partName.search( 'b' ) != -1 && abstractDialogCoords.y2 - abstractDialogCoords.y < minHeight + magnetDistance ) - realY2 = abstractDialogCoords.y + minHeight; - else - realY2 = abstractDialogCoords.y2 ; + if ( resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT || resizable == CKEDITOR.DIALOG_RESIZE_BOTH ) + height = Math.max( def.minHeight || 0, internalHeight - wrapperHeight ); - dialog.move( realX, realY ); - dialog.resize( realX2 - realX, realY2 - realY ); + dialog.resize( width, height ); + // The right property might get broken during resizing, so computing it before the resizing. + positionDialog( right ); evt.data.preventDefault(); } - function mouseUpHandler( evt ) + function mouseUpHandler() { CKEDITOR.document.removeListener( 'mouseup', mouseUpHandler ); CKEDITOR.document.removeListener( 'mousemove', mouseMoveHandler ); if ( CKEDITOR.env.ie6Compat ) { - var coverDoc = coverElement.getChild( 0 ).getFrameDocument(); + var coverDoc = currentCover.getChild( 0 ).getFrameDocument(); coverDoc.removeListener( 'mouseup', mouseUpHandler ); coverDoc.removeListener( 'mousemove', mouseMoveHandler ); } - } -// TODO : Simplify the resize logic, having just a single resize grip
. -// var widthTest = /[lr]/, -// heightTest = /[tb]/; -// for ( var i = 0 ; i < parts.length ; i++ ) -// { -// var element = dialog.parts[ parts[i] + '_resize' ]; -// if ( resizable == CKEDITOR.DIALOG_RESIZE_NONE || -// resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT && widthTest.test( parts[i] ) || -// resizable == CKEDITOR.DIALOG_RESIZE_WIDTH && heightTest.test( parts[i] ) ) -// { -// element.hide(); -// continue; -// } -// element.on( 'mousedown', mouseDownHandler, dialog, { part : parts[i] } ); -// } + // Switch back to use the left property, if RTL is used. + if ( editor.lang.dir == 'rtl' ) + { + var element = dialog._.element.getFirst(), + left = element.getComputedStyle( 'left' ); + + // IE might return "auto", we need exact position. + if ( left == 'auto' ) + left = viewSize.width - parseInt( element.getStyle( 'right' ), 10 ) - dialog.getSize().width; + else + left = parseInt( left, 10 ); + + element.removeStyle( 'right' ); + // Make sure the left property gets applied, even if it is the same as previously. + dialog._.position.x += 1; + dialog.move( left, dialog._.position.y ); + } + } } var resizeCover; - var coverElement; + // Caching resuable covers and allowing only one cover + // on screen. + var covers = {}, + currentCover; - var addCover = function( editor ) + function showCover( editor ) { var win = CKEDITOR.document.getWindow(); + var config = editor.config, + backgroundColorStyle = config.dialog_backgroundCoverColor || 'white', + backgroundCoverOpacity = config.dialog_backgroundCoverOpacity, + baseFloatZIndex = config.baseFloatZIndex, + coverKey = CKEDITOR.tools.genKey( + backgroundColorStyle, + backgroundCoverOpacity, + baseFloatZIndex ), + coverElement = covers[ coverKey ]; if ( !coverElement ) { - var backgroundColorStyle = editor.config.dialog_backgroundCoverColor || 'white'; - var html = [ '
' + '" class="cke_dialog_background_cover">' ]; - if ( CKEDITOR.env.ie6Compat ) { // Support for custom document.domain in IE. @@ -1718,14 +1894,19 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; html.push( '
' ); coverElement = CKEDITOR.dom.element.createFromHtml( html.join( '' ) ); - } + coverElement.setOpacity( backgroundCoverOpacity != undefined ? backgroundCoverOpacity : 0.5 ); - var element = coverElement; + coverElement.appendTo( CKEDITOR.document.getBody() ); + covers[ coverKey ] = coverElement; + } + else + coverElement. show(); + currentCover = coverElement; var resizeFunc = function() { var size = win.getViewPaneSize(); - element.setStyles( + coverElement.setStyles( { width : size.width + 'px', height : size.height + 'px' @@ -1736,7 +1917,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { var pos = win.getScrollPosition(), cursor = CKEDITOR.dialog._.currentTop; - element.setStyles( + coverElement.setStyles( { left : pos.x + 'px', top : pos.y + 'px' @@ -1746,7 +1927,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { var dialogPos = cursor.getPosition(); cursor.move( dialogPos.x, dialogPos.y ); - } while( ( cursor = cursor._.parentDialog ) ); + } while ( ( cursor = cursor._.parentDialog ) ); }; resizeCover = resizeFunc; @@ -1768,20 +1949,15 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; }, 0 ); scrollFunc(); } + } - var opacity = editor.config.dialog_backgroundCoverOpacity; - element.setOpacity( typeof opacity != 'undefined' ? opacity : 0.5 ); - - element.appendTo( CKEDITOR.document.getBody() ); - }; - - var removeCover = function() + function hideCover() { - if ( !coverElement ) + if ( !currentCover ) return; var win = CKEDITOR.document.getWindow(); - coverElement.remove(); + currentCover.hide(); win.removeListener( 'resize', resizeCover ); if ( CKEDITOR.env.ie6Compat ) @@ -1793,7 +1969,14 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; }, 0 ); } resizeCover = null; - }; + } + + function removeCovers() + { + for ( var coverId in covers ) + covers[ coverId ].remove(); + covers = {}; + } var accessKeyProcessors = {}; @@ -1937,8 +2120,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; html = [ '<', nodeName, ' ' ], styles = ( stylesArg && stylesArg.call ? stylesArg( elementDefinition ) : stylesArg ) || {}, attributes = ( attributesArg && attributesArg.call ? attributesArg( elementDefinition ) : attributesArg ) || {}, - innerHTML = ( contentsArg && contentsArg.call ? contentsArg( dialog, elementDefinition ) : contentsArg ) || '', - domId = this.domId = attributes.id || CKEDITOR.tools.getNextNumber() + '_uiElement', + innerHTML = ( contentsArg && contentsArg.call ? contentsArg.call( this, dialog, elementDefinition ) : contentsArg ) || '', + domId = this.domId = attributes.id || CKEDITOR.tools.getNextId() + '_uiElement', id = this.id = elementDefinition.id, i; @@ -2022,6 +2205,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // Register the object as a tab focus if it can be included. if ( this.keyboardFocusable ) { + this.tabIndex = elementDefinition.tabIndex || 0; + this.focusIndex = dialog._.focusList.push( this ) - 1; this.on( 'focus', function() { @@ -2084,18 +2269,18 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; className = 'cke_dialog_ui_hbox_first'; if ( i == childHtmlList.length - 1 ) className = 'cke_dialog_ui_hbox_last'; - html.push( ' 0 ) html.push( 'style="' + styles.join('; ') + '" ' ); html.push( '>', childHtmlList[i], '' ); @@ -2104,6 +2289,9 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; return html.join( '' ); }; + var attribs = { role : 'presentation' }; + elementDefinition && elementDefinition.align && ( attribs.align = elementDefinition.align ); + CKEDITOR.ui.dialog.uiElement.call( this, dialog, @@ -2111,7 +2299,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; htmlList, 'table', styles, - elementDefinition && elementDefinition.align && { align : elementDefinition.align } || null, + attribs, innerHTML ); }, @@ -2145,7 +2333,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; */ vbox : function( dialog, childObjList, childHtmlList, htmlList, elementDefinition ) { - if (arguments.length < 3 ) + if ( arguments.length < 3 ) return; this._ || ( this._ = {} ); @@ -2156,11 +2344,11 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; /** @ignore */ var innerHTML = function() { - var html = [ '' ); @@ -2185,7 +2373,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; html.push( '
0 ) html.push( 'style="', styles.join( '; ' ), '" ' ); html.push( ' class="cke_dialog_ui_vbox_child">', childHtmlList[i], '
' ); return html.join( '' ); }; - CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition || { type : 'vbox' }, htmlList, 'div', null, null, innerHTML ); + CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition || { type : 'vbox' }, htmlList, 'div', null, { role : 'presentation' }, innerHTML ); } }; })(); @@ -2231,14 +2419,15 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; /** * Sets the value of this dialog UI object. * @param {Object} value The new value. + * @param {Boolean} noChangeEvent Internal commit, to supress 'change' event on this element. * @returns {CKEDITOR.dialog.uiElement} The current UI element. * @example * uiElement.setValue( 'Dingo' ); */ - setValue : function( value ) + setValue : function( value, noChangeEvent ) { this.getInputElement().setValue( value ); - this.fire( 'change', { value : value } ); + !noChangeEvent && this.fire( 'change', { value : value } ); return this; }, @@ -2563,9 +2752,12 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { editor.openDialog( this.dialogName ); }, + // Dialog commands just open a dialog ui, thus require no undo logic, // undo support should dedicate to specific dialog implementation. - canUndo: false + canUndo: false, + + editorFocus : CKEDITOR.env.ie || CKEDITOR.env.webkit }; (function() @@ -2685,6 +2877,24 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; return this.functions( function( val ){ return val != value; }, msg ); } }; + + CKEDITOR.on( 'instanceDestroyed', function( evt ) + { + // Remove dialog cover on last instance destroy. + if ( CKEDITOR.tools.isEmpty( CKEDITOR.instances ) ) + { + var currentTopDialog; + while ( ( currentTopDialog = CKEDITOR.dialog._.currentTop ) ) + currentTopDialog.hide(); + removeCovers(); + } + + var dialogs = evt.editor._.storedDialogs; + for ( var name in dialogs ) + dialogs[ name ].destroy(); + + }); + })(); })(); @@ -2703,10 +2913,11 @@ CKEDITOR.tools.extend( CKEDITOR.editor.prototype, */ openDialog : function( dialogName, callback ) { - var dialogDefinitions = CKEDITOR.dialog._.dialogDefinitions[ dialogName ]; + var dialogDefinitions = CKEDITOR.dialog._.dialogDefinitions[ dialogName ], + dialogSkin = this.skin.dialog; // If the dialogDefinition is already loaded, open it immediately. - if ( typeof dialogDefinitions == 'function' ) + if ( typeof dialogDefinitions == 'function' && dialogSkin._isLoaded ) { var storedDialogs = this._.storedDialogs || ( this._.storedDialogs = {} ); @@ -2728,14 +2939,31 @@ CKEDITOR.tools.extend( CKEDITOR.editor.prototype, me = this; body.setStyle( 'cursor', 'wait' ); - CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( dialogDefinitions ), function() - { - // In case of plugin error, mark it as loading failed. - if ( typeof CKEDITOR.dialog._.dialogDefinitions[ dialogName ] != 'function' ) - CKEDITOR.dialog._.dialogDefinitions[ dialogName ] = 'failed'; - me.openDialog( dialogName, callback ); - body.setStyle( 'cursor', cursor ); - } ); + + function onDialogFileLoaded( success ) + { + var dialogDefinition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ], + skin = me.skin.dialog; + + // Check if both skin part and definition is loaded. + if ( !skin._isLoaded || loadDefinition && typeof success == 'undefined' ) + return; + + // In case of plugin error, mark it as loading failed. + if ( typeof dialogDefinition != 'function' ) + CKEDITOR.dialog._.dialogDefinitions[ dialogName ] = 'failed'; + + me.openDialog( dialogName, callback ); + body.setStyle( 'cursor', cursor ); + } + + if ( typeof dialogDefinitions == 'string' ) + { + var loadDefinition = 1; + CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( dialogDefinitions ), onDialogFileLoaded ); + } + + CKEDITOR.skins.load( this, 'dialog', onDialogFileLoaded ); return null; } @@ -2769,6 +2997,15 @@ CKEDITOR.plugins.add( 'dialog', */ /** + * If the dialog has more than one tab, put focus into the first tab as soon as dialog is opened. + * @name CKEDITOR.config.dialog_startupFocusTab + * @type Boolean + * @default false + * @example + * config.dialog_startupFocusTab = true; + */ + +/** * The distance of magnetic borders used in moving and resizing dialogs, * measured in pixels. * @name CKEDITOR.config.dialog_magnetDistance @@ -2777,3 +3014,54 @@ CKEDITOR.plugins.add( 'dialog', * @example * config.dialog_magnetDistance = 30; */ + +/** + * The guildeline to follow when generating the dialog buttons. There are 3 possible options: + * + * @name CKEDITOR.config.dialog_buttonsOrder + * @type String + * @default 'OS' + * @since 3.5 + * @example + * config.dialog_buttonsOrder = 'rtl'; + */ + +/** + * The dialog contents to removed. It's a string composed by dialog name and tab name with a colon between them. + * Separate each pair with semicolon (see example). + * Note: All names are case-sensitive. + * Note: Be cautious when specifying dialog tabs that are mandatory, like "info", dialog functionality might be broken because of this! + * @name CKEDITOR.config.removeDialogTabs + * @type String + * @since 3.5 + * @default '' + * @example + * config.removeDialogTabs = 'flash:advanced;image:Link'; + */ + +/** + * Fired when a dialog definition is about to be used to create a dialog into + * an editor instance. This event makes it possible to customize the definition + * before creating it. + *

Note that this event is called only the first time a specific dialog is + * opened. Successive openings will use the cached dialog, and this event will + * not get fired.

+ * @name CKEDITOR#dialogDefinition + * @event + * @param {CKEDITOR.dialog.dialogDefinition} data The dialog defination that + * is being loaded. + * @param {CKEDITOR.editor} editor The editor instance that will use the + * dialog. + */ + +/** + * Fired when a tab is going to be selected in a dialog + * @name dialog#selectPage + * @event + * @param String page The id of the page that it's gonna be selected. + * @param String currentPage The id of the current page. + */