CKEDITOR.dialog = function( editor, dialogName )\r
{\r
// Load the dialog definition.\r
- var definition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ];\r
+ var definition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ],\r
+ defaultDefinition = CKEDITOR.tools.clone( defaultDialogDefinition ),\r
+ buttonsOrder = editor.config.dialog_buttonsOrder || 'OS',\r
+ dir = editor.lang.dir;\r
+\r
+ if ( ( buttonsOrder == 'OS' && CKEDITOR.env.mac ) || // The buttons in MacOS Apps are in reverse order (#4750)\r
+ ( buttonsOrder == 'rtl' && dir == 'ltr' ) ||\r
+ ( buttonsOrder == 'ltr' && dir == 'rtl' ) )\r
+ defaultDefinition.buttons.reverse();\r
+\r
\r
// Completes the definition with the default values.\r
- definition = CKEDITOR.tools.extend( definition( editor ), defaultDialogDefinition );\r
+ definition = CKEDITOR.tools.extend( definition( editor ), defaultDefinition );\r
\r
// Clone a functionally independent copy for this dialog.\r
definition = CKEDITOR.tools.clone( definition );\r
// functions.\r
definition = new definitionObject( this, definition );\r
\r
-\r
var doc = CKEDITOR.document;\r
\r
var themeBuilt = editor.theme.buildDialog( editor );\r
name : dialogName,\r
contentSize : { width : 0, height : 0 },\r
size : { width : 0, height : 0 },\r
- updateSize : false,\r
contents : {},\r
buttons : {},\r
accessKeyMap : {},\r
definition : definition\r
}\r
, editor ).definition;\r
+\r
+ var tabsToRemove = {};\r
+ // Cache tabs that should be removed.\r
+ if ( !( 'removeDialogTabs' in editor._ ) && editor.config.removeDialogTabs )\r
+ {\r
+ var removeContents = editor.config.removeDialogTabs.split( ';' );\r
+\r
+ for ( i = 0; i < removeContents.length; i++ )\r
+ {\r
+ var parts = removeContents[ i ].split( ':' );\r
+ if ( parts.length == 2 )\r
+ {\r
+ var removeDialogName = parts[ 0 ];\r
+ if ( !tabsToRemove[ removeDialogName ] )\r
+ tabsToRemove[ removeDialogName ] = [];\r
+ tabsToRemove[ removeDialogName ].push( parts[ 1 ] );\r
+ }\r
+ }\r
+ editor._.removeDialogTabs = tabsToRemove;\r
+ }\r
+\r
+ // Remove tabs of this dialog.\r
+ if ( editor._.removeDialogTabs && ( tabsToRemove = editor._.removeDialogTabs[ dialogName ] ) )\r
+ {\r
+ for ( i = 0; i < tabsToRemove.length; i++ )\r
+ definition.removeContents( tabsToRemove[ i ] );\r
+ }\r
+\r
// Initialize load, show, hide, ok and cancel events.\r
if ( definition.onLoad )\r
this.on( 'load', definition.onLoad );\r
}, this._.editor );\r
\r
this._.contentSize = { width : width, height : height };\r
- this._.updateSize = true;\r
};\r
})(),\r
\r
*/\r
getSize : function()\r
{\r
- if ( !this._.updateSize )\r
- return this._.size;\r
var element = this._.element.getFirst();\r
- var size = this._.size = { width : element.$.offsetWidth || 0, height : element.$.offsetHeight || 0};\r
-\r
- // If either the offsetWidth or offsetHeight is 0, the element isn't visible.\r
- this._.updateSize = !size.width || !size.height;\r
-\r
- return size;\r
+ return { width : element.$.offsetWidth || 0, height : element.$.offsetHeight || 0};\r
},\r
\r
/**\r
* @function\r
* @param {Number} x The target x-coordinate.\r
* @param {Number} y The target y-coordinate.\r
+ * @param {Boolean} save Flag indicate whether the dialog position should be remembered on next open up.\r
* @example\r
* dialogObj.move( 10, 40 );\r
*/\r
move : (function()\r
{\r
var isFixed;\r
- return function( x, y )\r
+ return function( x, y, save )\r
{\r
// The dialog may be fixed positioned or absolute positioned. Ask the\r
// browser what is the current situation first.\r
'left' : ( x > 0 ? x : 0 ) + 'px',\r
'top' : ( y > 0 ? y : 0 ) + 'px'\r
});\r
+\r
+ save && ( this._.moved = 1 );\r
};\r
})(),\r
\r
\r
\r
// First, set the dialog to an appropriate size.\r
- this.resize( definition.minWidth, definition.minHeight );\r
+ this.resize( this._.contentSize && this._.contentSize.width || definition.minWidth,\r
+ this._.contentSize && this._.contentSize.height || definition.minHeight );\r
\r
// Reset all inputs back to their default value.\r
this.reset();\r
// Reset the hasFocus state.\r
this._.hasFocus = false;\r
\r
- // Rearrange the dialog to the middle of the window.\r
CKEDITOR.tools.setTimeout( function()\r
{\r
- var viewSize = CKEDITOR.document.getWindow().getViewPaneSize();\r
- var dialogSize = this.getSize();\r
-\r
- // We're using definition size for initial position because of\r
- // offten corrupted data in offsetWidth at this point. (#4084)\r
- this.move( ( viewSize.width - definition.minWidth ) / 2, ( viewSize.height - dialogSize.height ) / 2 );\r
-\r
+ this.layout();\r
this.parts.dialog.setStyle( 'visibility', '' );\r
\r
// Execute onLoad for the first show.\r
this.fireOnce( 'load', {} );\r
+ CKEDITOR.ui.fire( 'ready', this );\r
+\r
this.fire( 'show', {} );\r
this._.editor.fire( 'dialogShow', this );\r
\r
},\r
\r
/**\r
+ * Rearrange the dialog to its previous position or the middle of the window.\r
+ * @since 3.5\r
+ */\r
+ layout : function()\r
+ {\r
+ var viewSize = CKEDITOR.document.getWindow().getViewPaneSize(),\r
+ dialogSize = this.getSize();\r
+\r
+ this.move( this._.moved ? this._.position.x : ( viewSize.width - dialogSize.width ) / 2,\r
+ this._.moved ? this._.position.y : ( viewSize.height - dialogSize.height ) / 2 );\r
+ },\r
+\r
+ /**\r
* Executes a function for each UI element.\r
* @param {Function} fn Function to execute for each UI element.\r
* @returns {CKEDITOR.dialog} The current dialog object.\r
children : contents.elements,\r
expand : !!contents.expand,\r
padding : contents.padding,\r
- style : contents.style || 'width: 100%; height: 100%;'\r
+ style : contents.style || 'width: 100%;'\r
}, pageHtml );\r
\r
// Create the HTML for the tab and the content block.\r
buttons : [ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ]\r
};\r
\r
- // The buttons in MacOS Apps are in reverse order #4750\r
- CKEDITOR.env.mac && defaultDialogDefinition.buttons.reverse();\r
-\r
// Tool function used to return an item from an array based on its id\r
// property.\r
var getById = function( array, id, recurse )\r
if ( abstractDialogCoords.x + margins[3] < magnetDistance )\r
realX = - margins[3];\r
else if ( abstractDialogCoords.x - margins[1] > viewPaneSize.width - dialogSize.width - magnetDistance )\r
- realX = viewPaneSize.width - dialogSize.width + margins[1];\r
+ realX = viewPaneSize.width - dialogSize.width + ( editor.lang.dir == 'rtl' ? 0 : margins[1] );\r
else\r
realX = abstractDialogCoords.x;\r
\r
else\r
realY = abstractDialogCoords.y;\r
\r
- dialog.move( realX, realY );\r
+ dialog.move( realX, realY, 1 );\r
\r
evt.data.preventDefault();\r
}\r
\r
dialog.parts.title.on( 'mousedown', function( evt )\r
{\r
- dialog._.updateSize = true;\r
-\r
lastCoords = { x : evt.data.$.screenX, y : evt.data.$.screenY };\r
\r
CKEDITOR.document.on( 'mousemove', mouseMoveHandler );\r
\r
function initResizeHandles( dialog )\r
{\r
- var definition = dialog.definition,\r
- minWidth = definition.minWidth || 0,\r
- minHeight = definition.minHeight || 0,\r
- resizable = definition.resizable,\r
- margins = dialog.getParentEditor().skin.margins || [ 0, 0, 0, 0 ];\r
+ var def = dialog.definition,\r
+ resizable = def.resizable;\r
\r
- function topSizer( coords, dy )\r
- {\r
- coords.y += dy;\r
- }\r
+ if ( resizable == CKEDITOR.DIALOG_RESIZE_NONE )\r
+ return;\r
\r
- function rightSizer( coords, dx )\r
- {\r
- coords.x2 += dx;\r
- }\r
+ var editor = dialog.getParentEditor();\r
+ var wrapperWidth, wrapperHeight, viewSize, origin, startSize;\r
\r
- function bottomSizer( coords, dy )\r
+ function positionDialog( right )\r
{\r
- coords.y2 += dy;\r
+ // Maintain righthand sizing in RTL.\r
+ if ( dialog._.moved && editor.lang.dir == 'rtl' )\r
+ {\r
+ var element = dialog._.element.getFirst();\r
+ element.setStyle( 'right', right + "px" );\r
+ element.removeStyle( 'left' );\r
+ }\r
+ else if ( !dialog._.moved )\r
+ dialog.layout();\r
}\r
\r
- function leftSizer( coords, dx )\r
+ var mouseDownFn = CKEDITOR.tools.addFunction( function( $event )\r
{\r
- coords.x += dx;\r
- }\r
+ startSize = dialog.getSize();\r
\r
- var lastCoords = null,\r
- abstractDialogCoords = null,\r
- magnetDistance = dialog._.editor.config.magnetDistance,\r
- parts = [ 'tl', 't', 'tr', 'l', 'r', 'bl', 'b', 'br' ];\r
+ // Calculate the offset between content and chrome size.\r
+ wrapperHeight = startSize.height - dialog.parts.contents.getSize( 'height', ! ( CKEDITOR.env.gecko || CKEDITOR.env.opera || CKEDITOR.env.ie && CKEDITOR.env.quirks ) );\r
+ wrapperWidth = startSize.width - dialog.parts.contents.getSize( 'width', 1 );\r
\r
- function mouseDownHandler( evt )\r
- {\r
- var partName = evt.listenerData.part, size = dialog.getSize();\r
- abstractDialogCoords = dialog.getPosition();\r
- CKEDITOR.tools.extend( abstractDialogCoords,\r
- {\r
- x2 : abstractDialogCoords.x + size.width,\r
- y2 : abstractDialogCoords.y + size.height\r
- } );\r
- lastCoords = { x : evt.data.$.screenX, y : evt.data.$.screenY };\r
+ origin = { x : $event.screenX, y : $event.screenY };\r
\r
- CKEDITOR.document.on( 'mousemove', mouseMoveHandler, dialog, { part : partName } );\r
- CKEDITOR.document.on( 'mouseup', mouseUpHandler, dialog, { part : partName } );\r
+ viewSize = CKEDITOR.document.getWindow().getViewPaneSize();\r
+\r
+ CKEDITOR.document.on( 'mousemove', mouseMoveHandler );\r
+ CKEDITOR.document.on( 'mouseup', mouseUpHandler );\r
\r
if ( CKEDITOR.env.ie6Compat )\r
{\r
var coverDoc = currentCover.getChild( 0 ).getFrameDocument();\r
- coverDoc.on( 'mousemove', mouseMoveHandler, dialog, { part : partName } );\r
- coverDoc.on( 'mouseup', mouseUpHandler, dialog, { part : partName } );\r
+ coverDoc.on( 'mousemove', mouseMoveHandler );\r
+ coverDoc.on( 'mouseup', mouseUpHandler );\r
}\r
\r
- evt.data.preventDefault();\r
- }\r
+ $event.preventDefault && $event.preventDefault();\r
+ });\r
+\r
+ // Prepend the grip to the dialog.\r
+ dialog.on( 'load', function()\r
+ {\r
+ var direction = '';\r
+ if ( resizable == CKEDITOR.DIALOG_RESIZE_WIDTH )\r
+ direction = ' cke_resizer_horizontal';\r
+ else if ( resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT )\r
+ direction = ' cke_resizer_vertical';\r
+ var resizer = CKEDITOR.dom.element.createFromHtml( '<div class="cke_resizer' + direction + '"' +\r
+ ' title="' + CKEDITOR.tools.htmlEncode( editor.lang.resize ) + '"' +\r
+ ' onmousedown="CKEDITOR.tools.callFunction(' + mouseDownFn + ', event )"></div>' );\r
+ dialog.parts.footer.append( resizer, 1 );\r
+ });\r
+ editor.on( 'destroy', function() { CKEDITOR.tools.removeFunction( mouseDownFn ); } );\r
\r
function mouseMoveHandler( evt )\r
{\r
- var x = evt.data.$.screenX,\r
- y = evt.data.$.screenY,\r
- dx = x - lastCoords.x,\r
- dy = y - lastCoords.y,\r
- viewPaneSize = CKEDITOR.document.getWindow().getViewPaneSize(),\r
- partName = evt.listenerData.part;\r
+ var rtl = editor.lang.dir == 'rtl',\r
+ dx = ( evt.data.$.screenX - origin.x ) * ( rtl ? -1 : 1 ),\r
+ dy = evt.data.$.screenY - origin.y,\r
+ width = startSize.width,\r
+ height = startSize.height,\r
+ internalWidth = width + dx * ( dialog._.moved ? 1 : 2 ),\r
+ internalHeight = height + dy * ( dialog._.moved ? 1 : 2 ),\r
+ element = dialog._.element.getFirst(),\r
+ right = rtl && element.getComputedStyle( 'right' ),\r
+ position = dialog.getPosition();\r
\r
- if ( partName.search( 't' ) != -1 )\r
- topSizer( abstractDialogCoords, dy );\r
- if ( partName.search( 'l' ) != -1 )\r
- leftSizer( abstractDialogCoords, dx );\r
- if ( partName.search( 'b' ) != -1 )\r
- bottomSizer( abstractDialogCoords, dy );\r
- if ( partName.search( 'r' ) != -1 )\r
- rightSizer( abstractDialogCoords, dx );\r
+ // IE might return "auto", we need exact position.\r
+ if ( right )\r
+ right = right == 'auto' ? viewSize.width - ( position.x || 0 ) - element.getSize( 'width' ) : parseInt( right, 10 );\r
\r
- lastCoords = { x : x, y : y };\r
+ if ( position.y + internalHeight > viewSize.height )\r
+ internalHeight = viewSize.height - position.y;\r
\r
- var realX, realY, realX2, realY2;\r
+ if ( ( rtl ? right : position.x ) + internalWidth > viewSize.width )\r
+ internalWidth = viewSize.width - ( rtl ? right : position.x );\r
\r
- if ( abstractDialogCoords.x + margins[3] < magnetDistance )\r
- realX = - margins[3];\r
- else if ( partName.search( 'l' ) != -1 && abstractDialogCoords.x2 - abstractDialogCoords.x < minWidth + magnetDistance )\r
- realX = abstractDialogCoords.x2 - minWidth;\r
- else\r
- realX = abstractDialogCoords.x;\r
+ // Make sure the dialog will not be resized to the wrong side when it's in the leftmost position for RTL.\r
+ if ( ( resizable == CKEDITOR.DIALOG_RESIZE_WIDTH || resizable == CKEDITOR.DIALOG_RESIZE_BOTH ) && !( rtl && dx > 0 && !position.x ) )\r
+ width = Math.max( def.minWidth || 0, internalWidth - wrapperWidth );\r
\r
- if ( abstractDialogCoords.y + margins[0] < magnetDistance )\r
- realY = - margins[0];\r
- else if ( partName.search( 't' ) != -1 && abstractDialogCoords.y2 - abstractDialogCoords.y < minHeight + magnetDistance )\r
- realY = abstractDialogCoords.y2 - minHeight;\r
- else\r
- realY = abstractDialogCoords.y;\r
+ if ( resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT || resizable == CKEDITOR.DIALOG_RESIZE_BOTH )\r
+ height = Math.max( def.minHeight || 0, internalHeight - wrapperHeight );\r
\r
- if ( abstractDialogCoords.x2 - margins[1] > viewPaneSize.width - magnetDistance )\r
- realX2 = viewPaneSize.width + margins[1] ;\r
- else if ( partName.search( 'r' ) != -1 && abstractDialogCoords.x2 - abstractDialogCoords.x < minWidth + magnetDistance )\r
- realX2 = abstractDialogCoords.x + minWidth;\r
- else\r
- realX2 = abstractDialogCoords.x2;\r
-\r
- if ( abstractDialogCoords.y2 - margins[2] > viewPaneSize.height - magnetDistance )\r
- realY2= viewPaneSize.height + margins[2] ;\r
- else if ( partName.search( 'b' ) != -1 && abstractDialogCoords.y2 - abstractDialogCoords.y < minHeight + magnetDistance )\r
- realY2 = abstractDialogCoords.y + minHeight;\r
- else\r
- realY2 = abstractDialogCoords.y2 ;\r
-\r
- dialog.move( realX, realY );\r
- dialog.resize( realX2 - realX, realY2 - realY );\r
+ dialog.resize( width, height );\r
+ // The right property might get broken during resizing, so computing it before the resizing.\r
+ positionDialog( right );\r
\r
evt.data.preventDefault();\r
}\r
\r
- function mouseUpHandler( evt )\r
+ function mouseUpHandler()\r
{\r
CKEDITOR.document.removeListener( 'mouseup', mouseUpHandler );\r
CKEDITOR.document.removeListener( 'mousemove', mouseMoveHandler );\r
coverDoc.removeListener( 'mouseup', mouseUpHandler );\r
coverDoc.removeListener( 'mousemove', mouseMoveHandler );\r
}\r
- }\r
\r
-// TODO : Simplify the resize logic, having just a single resize grip <div>.\r
-// var widthTest = /[lr]/,\r
-// heightTest = /[tb]/;\r
-// for ( var i = 0 ; i < parts.length ; i++ )\r
-// {\r
-// var element = dialog.parts[ parts[i] + '_resize' ];\r
-// if ( resizable == CKEDITOR.DIALOG_RESIZE_NONE ||\r
-// resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT && widthTest.test( parts[i] ) ||\r
-// resizable == CKEDITOR.DIALOG_RESIZE_WIDTH && heightTest.test( parts[i] ) )\r
-// {\r
-// element.hide();\r
-// continue;\r
-// }\r
-// element.on( 'mousedown', mouseDownHandler, dialog, { part : parts[i] } );\r
-// }\r
+ // Switch back to use the left property, if RTL is used.\r
+ if ( editor.lang.dir == 'rtl' )\r
+ {\r
+ var element = dialog._.element.getFirst(),\r
+ left = element.getComputedStyle( 'left' );\r
+\r
+ // IE might return "auto", we need exact position.\r
+ if ( left == 'auto' )\r
+ left = viewSize.width - parseInt( element.getStyle( 'right' ), 10 ) - dialog.getSize().width;\r
+ else\r
+ left = parseInt( left, 10 );\r
+\r
+ element.removeStyle( 'right' );\r
+ // Make sure the left property gets applied, even if it is the same as previously.\r
+ dialog._.position.x += 1;\r
+ dialog.move( left, dialog._.position.y );\r
+ }\r
+ }\r
}\r
\r
var resizeCover;\r
*/\r
\r
/**\r
+ * The guildeline to follow when generating the dialog buttons. There are 3 possible options:\r
+ * <ul>\r
+ * <li>'OS' - the buttons will be displayed in the default order of the user's OS;</li>\r
+ * <li>'ltr' - for Left-To-Right order;</li>\r
+ * <li>'rtl' - for Right-To-Left order.</li>\r
+ * </ul>\r
+ * @name CKEDITOR.config.dialog_buttonsOrder\r
+ * @type String\r
+ * @default 'OS'\r
+ * @since 3.5\r
+ * @example\r
+ * config.dialog_buttonsOrder = 'rtl';\r
+ */\r
+\r
+/**\r
+ * The dialog contents to removed. It's a string composed by dialog name and tab name with a colon between them.\r
+ * Separate each pair with semicolon (see example).\r
+ * <b>Note: All names are case-sensitive.</b>\r
+ * <b>Note: Be cautious when specifying dialog tabs that are mandatory, like "info", dialog functionality might be broken because of this!<b>\r
+ * @name CKEDITOR.config.removeDialogTabs\r
+ * @type String\r
+ * @since 3.5\r
+ * @default ''\r
+ * @example\r
+ * config.removeDialogTabs = 'flash:advanced;image:Link';\r
+ */\r
+\r
+/**\r
* Fired when a dialog definition is about to be used to create a dialog into\r
* an editor instance. This event makes it possible to customize the definition\r
* before creating it.\r