+++ /dev/null
-/*\r
-Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.\r
-For licensing, see LICENSE.html or http://ckeditor.com/license\r
-*/\r
-\r
-/**\r
- * @fileOverview The floating dialog plugin.\r
- */\r
-\r
-/**\r
- * No resize for this dialog.\r
- * @constant\r
- */\r
-CKEDITOR.DIALOG_RESIZE_NONE = 0;\r
-\r
-/**\r
- * Only allow horizontal resizing for this dialog, disable vertical resizing.\r
- * @constant\r
- */\r
-CKEDITOR.DIALOG_RESIZE_WIDTH = 1;\r
-\r
-/**\r
- * Only allow vertical resizing for this dialog, disable horizontal resizing.\r
- * @constant\r
- */\r
-CKEDITOR.DIALOG_RESIZE_HEIGHT = 2;\r
-\r
-/*\r
- * Allow the dialog to be resized in both directions.\r
- * @constant\r
- */\r
-CKEDITOR.DIALOG_RESIZE_BOTH = 3;\r
-\r
-(function()\r
-{\r
- var cssLength = CKEDITOR.tools.cssLength;\r
- function isTabVisible( tabId )\r
- {\r
- return !!this._.tabs[ tabId ][ 0 ].$.offsetHeight;\r
- }\r
-\r
- function getPreviousVisibleTab()\r
- {\r
- var tabId = this._.currentTabId,\r
- length = this._.tabIdList.length,\r
- tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId ) + length;\r
-\r
- for ( var i = tabIndex - 1 ; i > tabIndex - length ; i-- )\r
- {\r
- if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) )\r
- return this._.tabIdList[ i % length ];\r
- }\r
-\r
- return null;\r
- }\r
-\r
- function getNextVisibleTab()\r
- {\r
- var tabId = this._.currentTabId,\r
- length = this._.tabIdList.length,\r
- tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId );\r
-\r
- for ( var i = tabIndex + 1 ; i < tabIndex + length ; i++ )\r
- {\r
- if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) )\r
- return this._.tabIdList[ i % length ];\r
- }\r
-\r
- return null;\r
- }\r
-\r
-\r
- function clearOrRecoverTextInputValue( container, isRecover )\r
- {\r
- var inputs = container.$.getElementsByTagName( 'input' );\r
- for ( var i = 0, length = inputs.length; i < length ; i++ )\r
- {\r
- var item = new CKEDITOR.dom.element( inputs[ i ] );\r
-\r
- if ( item.getAttribute( 'type' ).toLowerCase() == 'text' )\r
- {\r
- if ( isRecover )\r
- {\r
- item.setAttribute( 'value', item.getCustomData( 'fake_value' ) || '' );\r
- item.removeCustomData( 'fake_value' );\r
- }\r
- else\r
- {\r
- item.setCustomData( 'fake_value', item.getAttribute( 'value' ) );\r
- item.setAttribute( 'value', '' );\r
- }\r
- }\r
- }\r
- }\r
-\r
- // Handle dialog element validation state UI changes.\r
- function handleFieldValidated( isValid, msg )\r
- {\r
- var input = this.getInputElement();\r
- if ( input )\r
- {\r
- isValid ? input.removeAttribute( 'aria-invalid' )\r
- : input.setAttribute( 'aria-invalid', true );\r
- }\r
-\r
- if ( !isValid )\r
- {\r
- if ( this.select )\r
- this.select();\r
- else\r
- this.focus();\r
- }\r
-\r
- msg && alert( msg );\r
-\r
- this.fire( 'validated', { valid : isValid, msg : msg } );\r
- }\r
-\r
- function resetField()\r
- {\r
- var input = this.getInputElement();\r
- input && input.removeAttribute( 'aria-invalid' );\r
- }\r
-\r
-\r
- /**\r
- * This is the base class for runtime dialog objects. An instance of this\r
- * class represents a single named dialog for a single editor instance.\r
- * @param {Object} editor The editor which created the dialog.\r
- * @param {String} dialogName The dialog's registered name.\r
- * @constructor\r
- * @example\r
- * var dialogObj = new CKEDITOR.dialog( editor, 'smiley' );\r
- */\r
- CKEDITOR.dialog = function( editor, dialogName )\r
- {\r
- // Load the dialog definition.\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
- tabsToRemove = {},\r
- i,\r
- processed, stopPropagation;\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 ), defaultDefinition );\r
-\r
- // Clone a functionally independent copy for this dialog.\r
- definition = CKEDITOR.tools.clone( definition );\r
-\r
- // Create a complex definition object, extending it with the API\r
- // functions.\r
- definition = new definitionObject( this, definition );\r
-\r
- var doc = CKEDITOR.document;\r
-\r
- var themeBuilt = editor.theme.buildDialog( editor );\r
-\r
- // Initialize some basic parameters.\r
- this._ =\r
- {\r
- editor : editor,\r
- element : themeBuilt.element,\r
- name : dialogName,\r
- contentSize : { width : 0, height : 0 },\r
- size : { width : 0, height : 0 },\r
- contents : {},\r
- buttons : {},\r
- accessKeyMap : {},\r
-\r
- // Initialize the tab and page map.\r
- tabs : {},\r
- tabIdList : [],\r
- currentTabId : null,\r
- currentTabIndex : null,\r
- pageCount : 0,\r
- lastTab : null,\r
- tabBarMode : false,\r
-\r
- // Initialize the tab order array for input widgets.\r
- focusList : [],\r
- currentFocusIndex : 0,\r
- hasFocus : false\r
- };\r
-\r
- this.parts = themeBuilt.parts;\r
-\r
- CKEDITOR.tools.setTimeout( function()\r
- {\r
- editor.fire( 'ariaWidget', this.parts.contents );\r
- },\r
- 0, this );\r
-\r
- // Set the startup styles for the dialog, avoiding it enlarging the\r
- // page size on the dialog creation.\r
- var startStyles = {\r
- position : CKEDITOR.env.ie6Compat ? 'absolute' : 'fixed',\r
- top : 0,\r
- visibility : 'hidden'\r
- };\r
-\r
- startStyles[ dir == 'rtl' ? 'right' : 'left' ] = 0;\r
- this.parts.dialog.setStyles( startStyles );\r
-\r
-\r
- // Call the CKEDITOR.event constructor to initialize this instance.\r
- CKEDITOR.event.call( this );\r
-\r
- // Fire the "dialogDefinition" event, making it possible to customize\r
- // the dialog definition.\r
- this.definition = definition = CKEDITOR.fire( 'dialogDefinition',\r
- {\r
- name : dialogName,\r
- definition : definition\r
- }\r
- , editor ).definition;\r
-\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
-\r
- if ( definition.onShow )\r
- this.on( 'show', definition.onShow );\r
-\r
- if ( definition.onHide )\r
- this.on( 'hide', definition.onHide );\r
-\r
- if ( definition.onOk )\r
- {\r
- this.on( 'ok', function( evt )\r
- {\r
- // Dialog confirm might probably introduce content changes (#5415).\r
- editor.fire( 'saveSnapshot' );\r
- setTimeout( function () { editor.fire( 'saveSnapshot' ); }, 0 );\r
- if ( definition.onOk.call( this, evt ) === false )\r
- evt.data.hide = false;\r
- });\r
- }\r
-\r
- if ( definition.onCancel )\r
- {\r
- this.on( 'cancel', function( evt )\r
- {\r
- if ( definition.onCancel.call( this, evt ) === false )\r
- evt.data.hide = false;\r
- });\r
- }\r
-\r
- var me = this;\r
-\r
- // Iterates over all items inside all content in the dialog, calling a\r
- // function for each of them.\r
- var iterContents = function( func )\r
- {\r
- var contents = me._.contents,\r
- stop = false;\r
-\r
- for ( var i in contents )\r
- {\r
- for ( var j in contents[i] )\r
- {\r
- stop = func.call( this, contents[i][j] );\r
- if ( stop )\r
- return;\r
- }\r
- }\r
- };\r
-\r
- this.on( 'ok', function( evt )\r
- {\r
- iterContents( function( item )\r
- {\r
- if ( item.validate )\r
- {\r
- var retval = item.validate( this ),\r
- invalid = typeof ( retval ) == 'string' || retval === false;\r
-\r
- if ( invalid )\r
- {\r
- evt.data.hide = false;\r
- evt.stop();\r
- }\r
-\r
- handleFieldValidated.call( item, !invalid, typeof retval == 'string' ? retval : undefined );\r
- return invalid;\r
- }\r
- });\r
- }, this, null, 0 );\r
-\r
- this.on( 'cancel', function( evt )\r
- {\r
- iterContents( function( item )\r
- {\r
- if ( item.isChanged() )\r
- {\r
- if ( !confirm( editor.lang.common.confirmCancel ) )\r
- evt.data.hide = false;\r
- return true;\r
- }\r
- });\r
- }, this, null, 0 );\r
-\r
- this.parts.close.on( 'click', function( evt )\r
- {\r
- if ( this.fire( 'cancel', { hide : true } ).hide !== false )\r
- this.hide();\r
- evt.data.preventDefault();\r
- }, this );\r
-\r
- // Sort focus list according to tab order definitions.\r
- function setupFocus()\r
- {\r
- var focusList = me._.focusList;\r
- focusList.sort( function( a, b )\r
- {\r
- // Mimics browser tab order logics;\r
- if ( a.tabIndex != b.tabIndex )\r
- return b.tabIndex - a.tabIndex;\r
- // Sort is not stable in some browsers,\r
- // fall-back the comparator to 'focusIndex';\r
- else\r
- return a.focusIndex - b.focusIndex;\r
- });\r
-\r
- var size = focusList.length;\r
- for ( var i = 0; i < size; i++ )\r
- focusList[ i ].focusIndex = i;\r
- }\r
-\r
- function changeFocus( offset )\r
- {\r
- var focusList = me._.focusList;\r
- offset = offset || 0;\r
-\r
- if ( focusList.length < 1 )\r
- return;\r
-\r
- var current = me._.currentFocusIndex;\r
-\r
- // Trigger the 'blur' event of any input element before anything,\r
- // since certain UI updates may depend on it.\r
- try\r
- {\r
- focusList[ current ].getInputElement().$.blur();\r
- }\r
- catch( e ){}\r
-\r
- var startIndex = ( current + offset + focusList.length ) % focusList.length,\r
- currentIndex = startIndex;\r
- while ( offset && !focusList[ currentIndex ].isFocusable() )\r
- {\r
- currentIndex = ( currentIndex + offset + focusList.length ) % focusList.length;\r
- if ( currentIndex == startIndex )\r
- break;\r
- }\r
-\r
- focusList[ currentIndex ].focus();\r
-\r
- // Select whole field content.\r
- if ( focusList[ currentIndex ].type == 'text' )\r
- focusList[ currentIndex ].select();\r
- }\r
-\r
- this.changeFocus = changeFocus;\r
-\r
-\r
- function keydownHandler( evt )\r
- {\r
- // If I'm not the top dialog, ignore.\r
- if ( me != CKEDITOR.dialog._.currentTop )\r
- return;\r
-\r
- var keystroke = evt.data.getKeystroke(),\r
- rtl = editor.lang.dir == 'rtl',\r
- button;\r
-\r
- processed = stopPropagation = 0;\r
-\r
- if ( keystroke == 9 || keystroke == CKEDITOR.SHIFT + 9 )\r
- {\r
- var shiftPressed = ( keystroke == CKEDITOR.SHIFT + 9 );\r
-\r
- // Handling Tab and Shift-Tab.\r
- if ( me._.tabBarMode )\r
- {\r
- // Change tabs.\r
- var nextId = shiftPressed ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me );\r
- me.selectPage( nextId );\r
- me._.tabs[ nextId ][ 0 ].focus();\r
- }\r
- else\r
- {\r
- // Change the focus of inputs.\r
- changeFocus( shiftPressed ? -1 : 1 );\r
- }\r
-\r
- processed = 1;\r
- }\r
- else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode && me.getPageCount() > 1 )\r
- {\r
- // Alt-F10 puts focus into the current tab item in the tab bar.\r
- me._.tabBarMode = true;\r
- me._.tabs[ me._.currentTabId ][ 0 ].focus();\r
- processed = 1;\r
- }\r
- else if ( ( keystroke == 37 || keystroke == 39 ) && me._.tabBarMode )\r
- {\r
- // Arrow keys - used for changing tabs.\r
- nextId = ( keystroke == ( rtl ? 39 : 37 ) ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) );\r
- me.selectPage( nextId );\r
- me._.tabs[ nextId ][ 0 ].focus();\r
- processed = 1;\r
- }\r
- else if ( ( keystroke == 13 || keystroke == 32 ) && me._.tabBarMode )\r
- {\r
- this.selectPage( this._.currentTabId );\r
- this._.tabBarMode = false;\r
- this._.currentFocusIndex = -1;\r
- changeFocus( 1 );\r
- processed = 1;\r
- }\r
- // If user presses enter key in a text box, it implies clicking OK for the dialog.\r
- else if ( keystroke == 13 /*ENTER*/ )\r
- {\r
- // Don't do that for a target that handles ENTER.\r
- var target = evt.data.getTarget();\r
- if ( !target.is( 'a', 'button', 'select', 'textarea' ) && ( !target.is( 'input' ) || target.$.type != 'button' ) )\r
- {\r
- button = this.getButton( 'ok' );\r
- button && CKEDITOR.tools.setTimeout( button.click, 0, button );\r
- processed = 1;\r
- }\r
- stopPropagation = 1; // Always block the propagation (#4269)\r
- }\r
- else if ( keystroke == 27 /*ESC*/ )\r
- {\r
- button = this.getButton( 'cancel' );\r
-\r
- // If there's a Cancel button, click it, else just fire the cancel event and hide the dialog.\r
- if ( button )\r
- CKEDITOR.tools.setTimeout( button.click, 0, button );\r
- else\r
- {\r
- if ( this.fire( 'cancel', { hide : true } ).hide !== false )\r
- this.hide();\r
- }\r
- stopPropagation = 1; // Always block the propagation (#4269)\r
- }\r
- else\r
- return;\r
-\r
- keypressHandler( evt );\r
- }\r
-\r
- function keypressHandler( evt )\r
- {\r
- if ( processed )\r
- evt.data.preventDefault(1);\r
- else if ( stopPropagation )\r
- evt.data.stopPropagation();\r
- }\r
-\r
- var dialogElement = this._.element;\r
- // Add the dialog keyboard handlers.\r
- this.on( 'show', function()\r
- {\r
- dialogElement.on( 'keydown', keydownHandler, this );\r
-\r
- // Some browsers instead, don't cancel key events in the keydown, but in the\r
- // keypress. So we must do a longer trip in those cases. (#4531,#8985)\r
- if ( CKEDITOR.env.opera || CKEDITOR.env.gecko )\r
- dialogElement.on( 'keypress', keypressHandler, this );\r
-\r
- } );\r
- this.on( 'hide', function()\r
- {\r
- dialogElement.removeListener( 'keydown', keydownHandler );\r
- if ( CKEDITOR.env.opera || CKEDITOR.env.gecko )\r
- dialogElement.removeListener( 'keypress', keypressHandler );\r
-\r
- // Reset fields state when closing dialog.\r
- iterContents( function( item ) { resetField.apply( item ); } );\r
- } );\r
- this.on( 'iframeAdded', function( evt )\r
- {\r
- var doc = new CKEDITOR.dom.document( evt.data.iframe.$.contentWindow.document );\r
- doc.on( 'keydown', keydownHandler, this, null, 0 );\r
- } );\r
-\r
- // Auto-focus logic in dialog.\r
- this.on( 'show', function()\r
- {\r
- // Setup tabIndex on showing the dialog instead of on loading\r
- // to allow dynamic tab order happen in dialog definition.\r
- setupFocus();\r
-\r
- if ( editor.config.dialog_startupFocusTab\r
- && me._.pageCount > 1 )\r
- {\r
- me._.tabBarMode = true;\r
- me._.tabs[ me._.currentTabId ][ 0 ].focus();\r
- }\r
- else if ( !this._.hasFocus )\r
- {\r
- this._.currentFocusIndex = -1;\r
-\r
- // Decide where to put the initial focus.\r
- if ( definition.onFocus )\r
- {\r
- var initialFocus = definition.onFocus.call( this );\r
- // Focus the field that the user specified.\r
- initialFocus && initialFocus.focus();\r
- }\r
- // Focus the first field in layout order.\r
- else\r
- changeFocus( 1 );\r
-\r
- /*\r
- * IE BUG: If the initial focus went into a non-text element (e.g. button),\r
- * then IE would still leave the caret inside the editing area.\r
- */\r
- if ( this._.editor.mode == 'wysiwyg' && CKEDITOR.env.ie )\r
- {\r
- var $selection = editor.document.$.selection,\r
- $range = $selection.createRange();\r
-\r
- if ( $range )\r
- {\r
- if ( $range.parentElement && $range.parentElement().ownerDocument == editor.document.$\r
- || $range.item && $range.item( 0 ).ownerDocument == editor.document.$ )\r
- {\r
- var $myRange = document.body.createTextRange();\r
- $myRange.moveToElementText( this.getElement().getFirst().$ );\r
- $myRange.collapse( true );\r
- $myRange.select();\r
- }\r
- }\r
- }\r
- }\r
- }, this, null, 0xffffffff );\r
-\r
- // IE6 BUG: Text fields and text areas are only half-rendered the first time the dialog appears in IE6 (#2661).\r
- // This is still needed after [2708] and [2709] because text fields in hidden TR tags are still broken.\r
- if ( CKEDITOR.env.ie6Compat )\r
- {\r
- this.on( 'load', function( evt )\r
- {\r
- var outer = this.getElement(),\r
- inner = outer.getFirst();\r
- inner.remove();\r
- inner.appendTo( outer );\r
- }, this );\r
- }\r
-\r
- initDragAndDrop( this );\r
- initResizeHandles( this );\r
-\r
- // Insert the title.\r
- ( new CKEDITOR.dom.text( definition.title, CKEDITOR.document ) ).appendTo( this.parts.title );\r
-\r
- // Insert the tabs and contents.\r
- for ( i = 0 ; i < definition.contents.length ; i++ )\r
- {\r
- var page = definition.contents[i];\r
- page && this.addPage( page );\r
- }\r
-\r
- this.parts[ 'tabs' ].on( 'click', function( evt )\r
- {\r
- var target = evt.data.getTarget();\r
- // If we aren't inside a tab, bail out.\r
- if ( target.hasClass( 'cke_dialog_tab' ) )\r
- {\r
- // Get the ID of the tab, without the 'cke_' prefix and the unique number suffix.\r
- var id = target.$.id;\r
- this.selectPage( id.substring( 4, id.lastIndexOf( '_' ) ) );\r
-\r
- if ( this._.tabBarMode )\r
- {\r
- this._.tabBarMode = false;\r
- this._.currentFocusIndex = -1;\r
- changeFocus( 1 );\r
- }\r
- evt.data.preventDefault();\r
- }\r
- }, this );\r
-\r
- // Insert buttons.\r
- var buttonsHtml = [],\r
- buttons = CKEDITOR.dialog._.uiElementBuilders.hbox.build( this,\r
- {\r
- type : 'hbox',\r
- className : 'cke_dialog_footer_buttons',\r
- widths : [],\r
- children : definition.buttons\r
- }, buttonsHtml ).getChild();\r
- this.parts.footer.setHtml( buttonsHtml.join( '' ) );\r
-\r
- for ( i = 0 ; i < buttons.length ; i++ )\r
- this._.buttons[ buttons[i].id ] = buttons[i];\r
- };\r
-\r
- // Focusable interface. Use it via dialog.addFocusable.\r
- function Focusable( dialog, element, index )\r
- {\r
- this.element = element;\r
- this.focusIndex = index;\r
- // TODO: support tabIndex for focusables.\r
- this.tabIndex = 0;\r
- this.isFocusable = function()\r
- {\r
- return !element.getAttribute( 'disabled' ) && element.isVisible();\r
- };\r
- this.focus = function()\r
- {\r
- dialog._.currentFocusIndex = this.focusIndex;\r
- this.element.focus();\r
- };\r
- // Bind events\r
- element.on( 'keydown', function( e )\r
- {\r
- if ( e.data.getKeystroke() in { 32:1, 13:1 } )\r
- this.fire( 'click' );\r
- } );\r
- element.on( 'focus', function()\r
- {\r
- this.fire( 'mouseover' );\r
- } );\r
- element.on( 'blur', function()\r
- {\r
- this.fire( 'mouseout' );\r
- } );\r
- }\r
-\r
- // Re-layout the dialog on window resize.\r
- function resizeWithWindow( dialog )\r
- {\r
- var win = CKEDITOR.document.getWindow();\r
- function resizeHandler() { dialog.layout(); }\r
- win.on( 'resize', resizeHandler );\r
- dialog.on( 'hide', function() { win.removeListener( 'resize', resizeHandler ); } );\r
- }\r
-\r
- CKEDITOR.dialog.prototype =\r
- {\r
- destroy : function()\r
- {\r
- this.hide();\r
- this._.element.remove();\r
- },\r
-\r
- /**\r
- * Resizes the dialog.\r
- * @param {Number} width The width of the dialog in pixels.\r
- * @param {Number} height The height of the dialog in pixels.\r
- * @function\r
- * @example\r
- * dialogObj.resize( 800, 640 );\r
- */\r
- resize : (function()\r
- {\r
- return function( width, height )\r
- {\r
- if ( this._.contentSize && this._.contentSize.width == width && this._.contentSize.height == height )\r
- return;\r
-\r
- CKEDITOR.dialog.fire( 'resize',\r
- {\r
- dialog : this,\r
- skin : this._.editor.skinName,\r
- width : width,\r
- height : height\r
- }, this._.editor );\r
-\r
- this.fire( 'resize',\r
- {\r
- skin : this._.editor.skinName,\r
- width : width,\r
- height : height\r
- }, this._.editor );\r
-\r
- // Update dialog position when dimension get changed in RTL.\r
- if ( this._.editor.lang.dir == 'rtl' && this._.position )\r
- this._.position.x = CKEDITOR.document.getWindow().getViewPaneSize().width -\r
- this._.contentSize.width - parseInt( this._.element.getFirst().getStyle( 'right' ), 10 );\r
-\r
- this._.contentSize = { width : width, height : height };\r
- };\r
- })(),\r
-\r
- /**\r
- * Gets the current size of the dialog in pixels.\r
- * @returns {Object} An object with "width" and "height" properties.\r
- * @example\r
- * var width = dialogObj.getSize().width;\r
- */\r
- getSize : function()\r
- {\r
- var element = this._.element.getFirst();\r
- return { width : element.$.offsetWidth || 0, height : element.$.offsetHeight || 0};\r
- },\r
-\r
- /**\r
- * Moves the dialog to an (x, y) coordinate relative to the window.\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( 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
- var element = this._.element.getFirst(),\r
- rtl = this._.editor.lang.dir == 'rtl';\r
-\r
- var isFixed = element.getComputedStyle( 'position' ) == 'fixed';\r
-\r
- // (#8888) In some cases of a very small viewport, dialog is incorrectly\r
- // positioned in IE7. It also happens that it remains sticky and user cannot\r
- // scroll down/up to reveal dialog's content below/above the viewport; this is\r
- // cumbersome.\r
- // The only way to fix this is to move mouse out of the browser and\r
- // go back to see that dialog position is automagically fixed. No events,\r
- // no style change - pure magic. This is a IE7 rendering issue, which can be\r
- // fixed with dummy style redraw on each move.\r
- element.setStyle( 'zoom', '100%' );\r
-\r
- if ( isFixed && this._.position && this._.position.x == x && this._.position.y == y )\r
- return;\r
-\r
- // Save the current position.\r
- this._.position = { x : x, y : y };\r
-\r
- // If not fixed positioned, add scroll position to the coordinates.\r
- if ( !isFixed )\r
- {\r
- var scrollPosition = CKEDITOR.document.getWindow().getScrollPosition();\r
- x += scrollPosition.x;\r
- y += scrollPosition.y;\r
- }\r
-\r
- // Translate coordinate for RTL.\r
- if ( rtl )\r
- {\r
- var dialogSize = this.getSize(),\r
- viewPaneSize = CKEDITOR.document.getWindow().getViewPaneSize();\r
- x = viewPaneSize.width - dialogSize.width - x;\r
- }\r
-\r
- var styles = { 'top' : ( y > 0 ? y : 0 ) + 'px' };\r
- styles[ rtl ? 'right' : 'left' ] = ( x > 0 ? x : 0 ) + 'px';\r
-\r
- element.setStyles( styles );\r
-\r
- save && ( this._.moved = 1 );\r
- },\r
-\r
- /**\r
- * Gets the dialog's position in the window.\r
- * @returns {Object} An object with "x" and "y" properties.\r
- * @example\r
- * var dialogX = dialogObj.getPosition().x;\r
- */\r
- getPosition : function(){ return CKEDITOR.tools.extend( {}, this._.position ); },\r
-\r
- /**\r
- * Shows the dialog box.\r
- * @example\r
- * dialogObj.show();\r
- */\r
- show : function()\r
- {\r
- // Insert the dialog's element to the root document.\r
- var element = this._.element;\r
- var definition = this.definition;\r
- if ( !( element.getParent() && element.getParent().equals( CKEDITOR.document.getBody() ) ) )\r
- element.appendTo( CKEDITOR.document.getBody() );\r
- else\r
- element.setStyle( 'display', 'block' );\r
-\r
- // FIREFOX BUG: Fix vanishing caret for Firefox 2 or Gecko 1.8.\r
- if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 )\r
- {\r
- var dialogElement = this.parts.dialog;\r
- dialogElement.setStyle( 'position', 'absolute' );\r
- setTimeout( function()\r
- {\r
- dialogElement.setStyle( 'position', 'fixed' );\r
- }, 0 );\r
- }\r
-\r
-\r
- // First, set the dialog to an appropriate size.\r
- this.resize( this._.contentSize && this._.contentSize.width || definition.width || definition.minWidth,\r
- this._.contentSize && this._.contentSize.height || definition.height || definition.minHeight );\r
-\r
- // Reset all inputs back to their default value.\r
- this.reset();\r
-\r
- // Select the first tab by default.\r
- this.selectPage( this.definition.contents[0].id );\r
-\r
- // Set z-index.\r
- if ( CKEDITOR.dialog._.currentZIndex === null )\r
- CKEDITOR.dialog._.currentZIndex = this._.editor.config.baseFloatZIndex;\r
- this._.element.getFirst().setStyle( 'z-index', CKEDITOR.dialog._.currentZIndex += 10 );\r
-\r
- // Maintain the dialog ordering and dialog cover.\r
- if ( CKEDITOR.dialog._.currentTop === null )\r
- {\r
- CKEDITOR.dialog._.currentTop = this;\r
- this._.parentDialog = null;\r
- showCover( this._.editor );\r
-\r
- }\r
- else\r
- {\r
- this._.parentDialog = CKEDITOR.dialog._.currentTop;\r
- var parentElement = this._.parentDialog.getElement().getFirst();\r
- parentElement.$.style.zIndex -= Math.floor( this._.editor.config.baseFloatZIndex / 2 );\r
- CKEDITOR.dialog._.currentTop = this;\r
- }\r
-\r
- element.on( 'keydown', accessKeyDownHandler );\r
- element.on( CKEDITOR.env.opera ? 'keypress' : 'keyup', accessKeyUpHandler );\r
-\r
- // Reset the hasFocus state.\r
- this._.hasFocus = false;\r
-\r
- CKEDITOR.tools.setTimeout( function()\r
- {\r
- this.layout();\r
- resizeWithWindow( this );\r
-\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
- // Save the initial values of the dialog.\r
- this.foreach( function( contentObj ) { contentObj.setInitValue && contentObj.setInitValue(); } );\r
-\r
- },\r
- 100, this );\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 el = this.parts.dialog;\r
- var dialogSize = this.getSize();\r
- var win = CKEDITOR.document.getWindow(),\r
- viewSize = win.getViewPaneSize();\r
-\r
- var posX = ( viewSize.width - dialogSize.width ) / 2,\r
- posY = ( viewSize.height - dialogSize.height ) / 2;\r
-\r
- // Switch to absolute position when viewport is smaller than dialog size.\r
- if ( !CKEDITOR.env.ie6Compat )\r
- {\r
- if ( dialogSize.height + ( posY > 0 ? posY : 0 ) > viewSize.height ||\r
- dialogSize.width + ( posX > 0 ? posX : 0 ) > viewSize.width )\r
- el.setStyle( 'position', 'absolute' );\r
- else\r
- el.setStyle( 'position', 'fixed' );\r
- }\r
-\r
- this.move( this._.moved ? this._.position.x : posX,\r
- this._.moved ? this._.position.y : posY );\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
- */\r
- foreach : function( fn )\r
- {\r
- for ( var i in this._.contents )\r
- {\r
- for ( var j in this._.contents[i] )\r
- fn.call( this, this._.contents[i][j] );\r
- }\r
- return this;\r
- },\r
-\r
- /**\r
- * Resets all input values in the dialog.\r
- * @example\r
- * dialogObj.reset();\r
- * @returns {CKEDITOR.dialog} The current dialog object.\r
- */\r
- reset : (function()\r
- {\r
- var fn = function( widget ){ if ( widget.reset ) widget.reset( 1 ); };\r
- return function(){ this.foreach( fn ); return this; };\r
- })(),\r
-\r
-\r
- /**\r
- * Calls the {@link CKEDITOR.dialog.definition.uiElement#setup} method of each of the UI elements, with the arguments passed through it.\r
- * It is usually being called when the dialog is opened, to put the initial value inside the field.\r
- * @example\r
- * dialogObj.setupContent();\r
- * @example\r
- * var timestamp = ( new Date() ).valueOf();\r
- * dialogObj.setupContent( timestamp );\r
- */\r
- setupContent : function()\r
- {\r
- var args = arguments;\r
- this.foreach( function( widget )\r
- {\r
- if ( widget.setup )\r
- widget.setup.apply( widget, args );\r
- });\r
- },\r
-\r
- /**\r
- * Calls the {@link CKEDITOR.dialog.definition.uiElement#commit} method of each of the UI elements, with the arguments passed through it.\r
- * It is usually being called when the user confirms the dialog, to process the values.\r
- * @example\r
- * dialogObj.commitContent();\r
- * @example\r
- * var timestamp = ( new Date() ).valueOf();\r
- * dialogObj.commitContent( timestamp );\r
- */\r
- commitContent : function()\r
- {\r
- var args = arguments;\r
- this.foreach( function( widget )\r
- {\r
- // Make sure IE triggers "change" event on last focused input before closing the dialog. (#7915)\r
- if ( CKEDITOR.env.ie && this._.currentFocusIndex == widget.focusIndex )\r
- widget.getInputElement().$.blur();\r
-\r
- if ( widget.commit )\r
- widget.commit.apply( widget, args );\r
- });\r
- },\r
-\r
- /**\r
- * Hides the dialog box.\r
- * @example\r
- * dialogObj.hide();\r
- */\r
- hide : function()\r
- {\r
- if ( !this.parts.dialog.isVisible() )\r
- return;\r
-\r
- this.fire( 'hide', {} );\r
- this._.editor.fire( 'dialogHide', this );\r
- // Reset the tab page.\r
- this.selectPage( this._.tabIdList[ 0 ] );\r
- var element = this._.element;\r
- element.setStyle( 'display', 'none' );\r
- this.parts.dialog.setStyle( 'visibility', 'hidden' );\r
- // Unregister all access keys associated with this dialog.\r
- unregisterAccessKey( this );\r
-\r
- // Close any child(top) dialogs first.\r
- while( CKEDITOR.dialog._.currentTop != this )\r
- CKEDITOR.dialog._.currentTop.hide();\r
-\r
- // Maintain dialog ordering and remove cover if needed.\r
- if ( !this._.parentDialog )\r
- hideCover();\r
- else\r
- {\r
- var parentElement = this._.parentDialog.getElement().getFirst();\r
- parentElement.setStyle( 'z-index', parseInt( parentElement.$.style.zIndex, 10 ) + Math.floor( this._.editor.config.baseFloatZIndex / 2 ) );\r
- }\r
- CKEDITOR.dialog._.currentTop = this._.parentDialog;\r
-\r
- // Deduct or clear the z-index.\r
- if ( !this._.parentDialog )\r
- {\r
- CKEDITOR.dialog._.currentZIndex = null;\r
-\r
- // Remove access key handlers.\r
- element.removeListener( 'keydown', accessKeyDownHandler );\r
- element.removeListener( CKEDITOR.env.opera ? 'keypress' : 'keyup', accessKeyUpHandler );\r
-\r
- var editor = this._.editor;\r
- editor.focus();\r
-\r
- if ( editor.mode == 'wysiwyg' && CKEDITOR.env.ie )\r
- {\r
- var selection = editor.getSelection();\r
- selection && selection.unlock( true );\r
- }\r
- }\r
- else\r
- CKEDITOR.dialog._.currentZIndex -= 10;\r
-\r
- delete this._.parentDialog;\r
- // Reset the initial values of the dialog.\r
- this.foreach( function( contentObj ) { contentObj.resetInitValue && contentObj.resetInitValue(); } );\r
- },\r
-\r
- /**\r
- * Adds a tabbed page into the dialog.\r
- * @param {Object} contents Content definition.\r
- * @example\r
- */\r
- addPage : function( contents )\r
- {\r
- var pageHtml = [],\r
- titleHtml = contents.label ? ' title="' + CKEDITOR.tools.htmlEncode( contents.label ) + '"' : '',\r
- elements = contents.elements,\r
- vbox = CKEDITOR.dialog._.uiElementBuilders.vbox.build( this,\r
- {\r
- type : 'vbox',\r
- className : 'cke_dialog_page_contents',\r
- children : contents.elements,\r
- expand : !!contents.expand,\r
- padding : contents.padding,\r
- style : contents.style || 'width: 100%;height:100%'\r
- }, pageHtml );\r
-\r
- // Create the HTML for the tab and the content block.\r
- var page = CKEDITOR.dom.element.createFromHtml( pageHtml.join( '' ) );\r
- page.setAttribute( 'role', 'tabpanel' );\r
-\r
- var env = CKEDITOR.env;\r
- var tabId = 'cke_' + contents.id + '_' + CKEDITOR.tools.getNextNumber(),\r
- tab = CKEDITOR.dom.element.createFromHtml( [\r
- '<a class="cke_dialog_tab"',\r
- ( this._.pageCount > 0 ? ' cke_last' : 'cke_first' ),\r
- titleHtml,\r
- ( !!contents.hidden ? ' style="display:none"' : '' ),\r
- ' id="', tabId, '"',\r
- env.gecko && env.version >= 10900 && !env.hc ? '' : ' href="javascript:void(0)"',\r
- ' tabIndex="-1"',\r
- ' hidefocus="true"',\r
- ' role="tab">',\r
- contents.label,\r
- '</a>'\r
- ].join( '' ) );\r
-\r
- page.setAttribute( 'aria-labelledby', tabId );\r
-\r
- // Take records for the tabs and elements created.\r
- this._.tabs[ contents.id ] = [ tab, page ];\r
- this._.tabIdList.push( contents.id );\r
- !contents.hidden && this._.pageCount++;\r
- this._.lastTab = tab;\r
- this.updateStyle();\r
-\r
- var contentMap = this._.contents[ contents.id ] = {},\r
- cursor,\r
- children = vbox.getChild();\r
-\r
- while ( ( cursor = children.shift() ) )\r
- {\r
- contentMap[ cursor.id ] = cursor;\r
- if ( typeof( cursor.getChild ) == 'function' )\r
- children.push.apply( children, cursor.getChild() );\r
- }\r
-\r
- // Attach the DOM nodes.\r
-\r
- page.setAttribute( 'name', contents.id );\r
- page.appendTo( this.parts.contents );\r
-\r
- tab.unselectable();\r
- this.parts.tabs.append( tab );\r
-\r
- // Add access key handlers if access key is defined.\r
- if ( contents.accessKey )\r
- {\r
- registerAccessKey( this, this, 'CTRL+' + contents.accessKey,\r
- tabAccessKeyDown, tabAccessKeyUp );\r
- this._.accessKeyMap[ 'CTRL+' + contents.accessKey ] = contents.id;\r
- }\r
- },\r
-\r
- /**\r
- * Activates a tab page in the dialog by its id.\r
- * @param {String} id The id of the dialog tab to be activated.\r
- * @example\r
- * dialogObj.selectPage( 'tab_1' );\r
- */\r
- selectPage : function( id )\r
- {\r
- if ( this._.currentTabId == id )\r
- return;\r
-\r
- // Returning true means that the event has been canceled\r
- if ( this.fire( 'selectPage', { page : id, currentPage : this._.currentTabId } ) === true )\r
- return;\r
-\r
- // Hide the non-selected tabs and pages.\r
- for ( var i in this._.tabs )\r
- {\r
- var tab = this._.tabs[i][0],\r
- page = this._.tabs[i][1];\r
- if ( i != id )\r
- {\r
- tab.removeClass( 'cke_dialog_tab_selected' );\r
- page.hide();\r
- }\r
- page.setAttribute( 'aria-hidden', i != id );\r
- }\r
-\r
- var selected = this._.tabs[ id ];\r
- selected[ 0 ].addClass( 'cke_dialog_tab_selected' );\r
-\r
- // [IE] an invisible input[type='text'] will enlarge it's width\r
- // if it's value is long when it shows, so we clear it's value\r
- // before it shows and then recover it (#5649)\r
- if ( CKEDITOR.env.ie6Compat || CKEDITOR.env.ie7Compat )\r
- {\r
- clearOrRecoverTextInputValue( selected[ 1 ] );\r
- selected[ 1 ].show();\r
- setTimeout( function()\r
- {\r
- clearOrRecoverTextInputValue( selected[ 1 ], 1 );\r
- }, 0 );\r
- }\r
- else\r
- selected[ 1 ].show();\r
-\r
- this._.currentTabId = id;\r
- this._.currentTabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, id );\r
- },\r
-\r
- // Dialog state-specific style updates.\r
- updateStyle : function()\r
- {\r
- // If only a single page shown, a different style is used in the central pane.\r
- this.parts.dialog[ ( this._.pageCount === 1 ? 'add' : 'remove' ) + 'Class' ]( 'cke_single_page' );\r
- },\r
-\r
- /**\r
- * Hides a page's tab away from the dialog.\r
- * @param {String} id The page's Id.\r
- * @example\r
- * dialog.hidePage( 'tab_3' );\r
- */\r
- hidePage : function( id )\r
- {\r
- var tab = this._.tabs[id] && this._.tabs[id][0];\r
- if ( !tab || this._.pageCount == 1 || !tab.isVisible() )\r
- return;\r
- // Switch to other tab first when we're hiding the active tab.\r
- else if ( id == this._.currentTabId )\r
- this.selectPage( getPreviousVisibleTab.call( this ) );\r
-\r
- tab.hide();\r
- this._.pageCount--;\r
- this.updateStyle();\r
- },\r
-\r
- /**\r
- * Unhides a page's tab.\r
- * @param {String} id The page's Id.\r
- * @example\r
- * dialog.showPage( 'tab_2' );\r
- */\r
- showPage : function( id )\r
- {\r
- var tab = this._.tabs[id] && this._.tabs[id][0];\r
- if ( !tab )\r
- return;\r
- tab.show();\r
- this._.pageCount++;\r
- this.updateStyle();\r
- },\r
-\r
- /**\r
- * Gets the root DOM element of the dialog.\r
- * @returns {CKEDITOR.dom.element} The <span> element containing this dialog.\r
- * @example\r
- * var dialogElement = dialogObj.getElement().getFirst();\r
- * dialogElement.setStyle( 'padding', '5px' );\r
- */\r
- getElement : function()\r
- {\r
- return this._.element;\r
- },\r
-\r
- /**\r
- * Gets the name of the dialog.\r
- * @returns {String} The name of this dialog.\r
- * @example\r
- * var dialogName = dialogObj.getName();\r
- */\r
- getName : function()\r
- {\r
- return this._.name;\r
- },\r
-\r
- /**\r
- * Gets a dialog UI element object from a dialog page.\r
- * @param {String} pageId id of dialog page.\r
- * @param {String} elementId id of UI element.\r
- * @example\r
- * dialogObj.getContentElement( 'tabId', 'elementId' ).setValue( 'Example' );\r
- * @returns {CKEDITOR.ui.dialog.uiElement} The dialog UI element.\r
- */\r
- getContentElement : function( pageId, elementId )\r
- {\r
- var page = this._.contents[ pageId ];\r
- return page && page[ elementId ];\r
- },\r
-\r
- /**\r
- * Gets the value of a dialog UI element.\r
- * @param {String} pageId id of dialog page.\r
- * @param {String} elementId id of UI element.\r
- * @example\r
- * alert( dialogObj.getValueOf( 'tabId', 'elementId' ) );\r
- * @returns {Object} The value of the UI element.\r
- */\r
- getValueOf : function( pageId, elementId )\r
- {\r
- return this.getContentElement( pageId, elementId ).getValue();\r
- },\r
-\r
- /**\r
- * Sets the value of a dialog UI element.\r
- * @param {String} pageId id of the dialog page.\r
- * @param {String} elementId id of the UI element.\r
- * @param {Object} value The new value of the UI element.\r
- * @example\r
- * dialogObj.setValueOf( 'tabId', 'elementId', 'Example' );\r
- */\r
- setValueOf : function( pageId, elementId, value )\r
- {\r
- return this.getContentElement( pageId, elementId ).setValue( value );\r
- },\r
-\r
- /**\r
- * Gets the UI element of a button in the dialog's button row.\r
- * @param {String} id The id of the button.\r
- * @example\r
- * @returns {CKEDITOR.ui.dialog.button} The button object.\r
- */\r
- getButton : function( id )\r
- {\r
- return this._.buttons[ id ];\r
- },\r
-\r
- /**\r
- * Simulates a click to a dialog button in the dialog's button row.\r
- * @param {String} id The id of the button.\r
- * @example\r
- * @returns The return value of the dialog's "click" event.\r
- */\r
- click : function( id )\r
- {\r
- return this._.buttons[ id ].click();\r
- },\r
-\r
- /**\r
- * Disables a dialog button.\r
- * @param {String} id The id of the button.\r
- * @example\r
- */\r
- disableButton : function( id )\r
- {\r
- return this._.buttons[ id ].disable();\r
- },\r
-\r
- /**\r
- * Enables a dialog button.\r
- * @param {String} id The id of the button.\r
- * @example\r
- */\r
- enableButton : function( id )\r
- {\r
- return this._.buttons[ id ].enable();\r
- },\r
-\r
- /**\r
- * Gets the number of pages in the dialog.\r
- * @returns {Number} Page count.\r
- */\r
- getPageCount : function()\r
- {\r
- return this._.pageCount;\r
- },\r
-\r
- /**\r
- * Gets the editor instance which opened this dialog.\r
- * @returns {CKEDITOR.editor} Parent editor instances.\r
- */\r
- getParentEditor : function()\r
- {\r
- return this._.editor;\r
- },\r
-\r
- /**\r
- * Gets the element that was selected when opening the dialog, if any.\r
- * @returns {CKEDITOR.dom.element} The element that was selected, or null.\r
- */\r
- getSelectedElement : function()\r
- {\r
- return this.getParentEditor().getSelection().getSelectedElement();\r
- },\r
-\r
- /**\r
- * Adds element to dialog's focusable list.\r
- *\r
- * @param {CKEDITOR.dom.element} element\r
- * @param {Number} [index]\r
- */\r
- addFocusable: function( element, index ) {\r
- if ( typeof index == 'undefined' )\r
- {\r
- index = this._.focusList.length;\r
- this._.focusList.push( new Focusable( this, element, index ) );\r
- }\r
- else\r
- {\r
- this._.focusList.splice( index, 0, new Focusable( this, element, index ) );\r
- for ( var i = index + 1 ; i < this._.focusList.length ; i++ )\r
- this._.focusList[ i ].focusIndex++;\r
- }\r
- }\r
- };\r
-\r
- CKEDITOR.tools.extend( CKEDITOR.dialog,\r
- /**\r
- * @lends CKEDITOR.dialog\r
- */\r
- {\r
- /**\r
- * Registers a dialog.\r
- * @param {String} name The dialog's name.\r
- * @param {Function|String} dialogDefinition\r
- * A function returning the dialog's definition, or the URL to the .js file holding the function.\r
- * The function should accept an argument "editor" which is the current editor instance, and\r
- * return an object conforming to {@link CKEDITOR.dialog.definition}.\r
- * @see CKEDITOR.dialog.definition\r
- * @example\r
- * // Full sample plugin, which does not only register a dialog window but also adds an item to the context menu.\r
- * // To open the dialog window, choose "Open dialog" in the context menu.\r
- * CKEDITOR.plugins.add( 'myplugin',\r
- * {\r
- * init: function( editor )\r
- * {\r
- * editor.addCommand( 'mydialog',new CKEDITOR.dialogCommand( 'mydialog' ) );\r
- *\r
- * if ( editor.contextMenu )\r
- * {\r
- * editor.addMenuGroup( 'mygroup', 10 );\r
- * editor.addMenuItem( 'My Dialog',\r
- * {\r
- * label : 'Open dialog',\r
- * command : 'mydialog',\r
- * group : 'mygroup'\r
- * });\r
- * editor.contextMenu.addListener( function( element )\r
- * {\r
- * return { 'My Dialog' : CKEDITOR.TRISTATE_OFF };\r
- * });\r
- * }\r
- *\r
- * <strong>CKEDITOR.dialog.add</strong>( 'mydialog', function( api )\r
- * {\r
- * // CKEDITOR.dialog.definition\r
- * var <strong>dialogDefinition</strong> =\r
- * {\r
- * title : 'Sample dialog',\r
- * minWidth : 390,\r
- * minHeight : 130,\r
- * contents : [\r
- * {\r
- * id : 'tab1',\r
- * label : 'Label',\r
- * title : 'Title',\r
- * expand : true,\r
- * padding : 0,\r
- * elements :\r
- * [\r
- * {\r
- * type : 'html',\r
- * html : '<p>This is some sample HTML content.</p>'\r
- * },\r
- * {\r
- * type : 'textarea',\r
- * id : 'textareaId',\r
- * rows : 4,\r
- * cols : 40\r
- * }\r
- * ]\r
- * }\r
- * ],\r
- * buttons : [ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ],\r
- * onOk : function() {\r
- * // "this" is now a CKEDITOR.dialog object.\r
- * // Accessing dialog elements:\r
- * var textareaObj = this.<strong>getContentElement</strong>( 'tab1', 'textareaId' );\r
- * alert( "You have entered: " + textareaObj.getValue() );\r
- * }\r
- * };\r
- *\r
- * return dialogDefinition;\r
- * } );\r
- * }\r
- * } );\r
- *\r
- * CKEDITOR.replace( 'editor1', { extraPlugins : 'myplugin' } );\r
- */\r
- add : function( name, dialogDefinition )\r
- {\r
- // Avoid path registration from multiple instances override definition.\r
- if ( !this._.dialogDefinitions[name]\r
- || typeof dialogDefinition == 'function' )\r
- this._.dialogDefinitions[name] = dialogDefinition;\r
- },\r
-\r
- exists : function( name )\r
- {\r
- return !!this._.dialogDefinitions[ name ];\r
- },\r
-\r
- getCurrent : function()\r
- {\r
- return CKEDITOR.dialog._.currentTop;\r
- },\r
-\r
- /**\r
- * The default OK button for dialogs. Fires the "ok" event and closes the dialog if the event succeeds.\r
- * @static\r
- * @field\r
- * @example\r
- * @type Function\r
- */\r
- okButton : (function()\r
- {\r
- var retval = function( editor, override )\r
- {\r
- override = override || {};\r
- return CKEDITOR.tools.extend( {\r
- id : 'ok',\r
- type : 'button',\r
- label : editor.lang.common.ok,\r
- 'class' : 'cke_dialog_ui_button_ok',\r
- onClick : function( evt )\r
- {\r
- var dialog = evt.data.dialog;\r
- if ( dialog.fire( 'ok', { hide : true } ).hide !== false )\r
- dialog.hide();\r
- }\r
- }, override, true );\r
- };\r
- retval.type = 'button';\r
- retval.override = function( override )\r
- {\r
- return CKEDITOR.tools.extend( function( editor ){ return retval( editor, override ); },\r
- { type : 'button' }, true );\r
- };\r
- return retval;\r
- })(),\r
-\r
- /**\r
- * The default cancel button for dialogs. Fires the "cancel" event and closes the dialog if no UI element value changed.\r
- * @static\r
- * @field\r
- * @example\r
- * @type Function\r
- */\r
- cancelButton : (function()\r
- {\r
- var retval = function( editor, override )\r
- {\r
- override = override || {};\r
- return CKEDITOR.tools.extend( {\r
- id : 'cancel',\r
- type : 'button',\r
- label : editor.lang.common.cancel,\r
- 'class' : 'cke_dialog_ui_button_cancel',\r
- onClick : function( evt )\r
- {\r
- var dialog = evt.data.dialog;\r
- if ( dialog.fire( 'cancel', { hide : true } ).hide !== false )\r
- dialog.hide();\r
- }\r
- }, override, true );\r
- };\r
- retval.type = 'button';\r
- retval.override = function( override )\r
- {\r
- return CKEDITOR.tools.extend( function( editor ){ return retval( editor, override ); },\r
- { type : 'button' }, true );\r
- };\r
- return retval;\r
- })(),\r
-\r
- /**\r
- * Registers a dialog UI element.\r
- * @param {String} typeName The name of the UI element.\r
- * @param {Function} builder The function to build the UI element.\r
- * @example\r
- */\r
- addUIElement : function( typeName, builder )\r
- {\r
- this._.uiElementBuilders[ typeName ] = builder;\r
- }\r
- });\r
-\r
- CKEDITOR.dialog._ =\r
- {\r
- uiElementBuilders : {},\r
-\r
- dialogDefinitions : {},\r
-\r
- currentTop : null,\r
-\r
- currentZIndex : null\r
- };\r
-\r
- // "Inherit" (copy actually) from CKEDITOR.event.\r
- CKEDITOR.event.implementOn( CKEDITOR.dialog );\r
- CKEDITOR.event.implementOn( CKEDITOR.dialog.prototype, true );\r
-\r
- var defaultDialogDefinition =\r
- {\r
- resizable : CKEDITOR.DIALOG_RESIZE_BOTH,\r
- minWidth : 600,\r
- minHeight : 400,\r
- buttons : [ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ]\r
- };\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
- {\r
- for ( var i = 0, item ; ( item = array[ i ] ) ; i++ )\r
- {\r
- if ( item.id == id )\r
- return item;\r
- if ( recurse && item[ recurse ] )\r
- {\r
- var retval = getById( item[ recurse ], id, recurse ) ;\r
- if ( retval )\r
- return retval;\r
- }\r
- }\r
- return null;\r
- };\r
-\r
- // Tool function used to add an item into an array.\r
- var addById = function( array, newItem, nextSiblingId, recurse, nullIfNotFound )\r
- {\r
- if ( nextSiblingId )\r
- {\r
- for ( var i = 0, item ; ( item = array[ i ] ) ; i++ )\r
- {\r
- if ( item.id == nextSiblingId )\r
- {\r
- array.splice( i, 0, newItem );\r
- return newItem;\r
- }\r
-\r
- if ( recurse && item[ recurse ] )\r
- {\r
- var retval = addById( item[ recurse ], newItem, nextSiblingId, recurse, true );\r
- if ( retval )\r
- return retval;\r
- }\r
- }\r
-\r
- if ( nullIfNotFound )\r
- return null;\r
- }\r
-\r
- array.push( newItem );\r
- return newItem;\r
- };\r
-\r
- // Tool function used to remove an item from an array based on its id.\r
- var removeById = function( array, id, recurse )\r
- {\r
- for ( var i = 0, item ; ( item = array[ i ] ) ; i++ )\r
- {\r
- if ( item.id == id )\r
- return array.splice( i, 1 );\r
- if ( recurse && item[ recurse ] )\r
- {\r
- var retval = removeById( item[ recurse ], id, recurse );\r
- if ( retval )\r
- return retval;\r
- }\r
- }\r
- return null;\r
- };\r
-\r
- /**\r
- * This class is not really part of the API. It is the "definition" property value\r
- * passed to "dialogDefinition" event handlers.\r
- * @constructor\r
- * @name CKEDITOR.dialog.definitionObject\r
- * @extends CKEDITOR.dialog.definition\r
- * @example\r
- * CKEDITOR.on( 'dialogDefinition', function( evt )\r
- * {\r
- * var definition = evt.data.definition;\r
- * var content = definition.getContents( 'page1' );\r
- * ...\r
- * } );\r
- */\r
- var definitionObject = function( dialog, dialogDefinition )\r
- {\r
- // TODO : Check if needed.\r
- this.dialog = dialog;\r
-\r
- // Transform the contents entries in contentObjects.\r
- var contents = dialogDefinition.contents;\r
- for ( var i = 0, content ; ( content = contents[i] ) ; i++ )\r
- contents[ i ] = content && new contentObject( dialog, content );\r
-\r
- CKEDITOR.tools.extend( this, dialogDefinition );\r
- };\r
-\r
- definitionObject.prototype =\r
- /** @lends CKEDITOR.dialog.definitionObject.prototype */\r
- {\r
- /**\r
- * Gets a content definition.\r
- * @param {String} id The id of the content definition.\r
- * @returns {CKEDITOR.dialog.definition.content} The content definition\r
- * matching id.\r
- */\r
- getContents : function( id )\r
- {\r
- return getById( this.contents, id );\r
- },\r
-\r
- /**\r
- * Gets a button definition.\r
- * @param {String} id The id of the button definition.\r
- * @returns {CKEDITOR.dialog.definition.button} The button definition\r
- * matching id.\r
- */\r
- getButton : function( id )\r
- {\r
- return getById( this.buttons, id );\r
- },\r
-\r
- /**\r
- * Adds a content definition object under this dialog definition.\r
- * @param {CKEDITOR.dialog.definition.content} contentDefinition The\r
- * content definition.\r
- * @param {String} [nextSiblingId] The id of an existing content\r
- * definition which the new content definition will be inserted\r
- * before. Omit if the new content definition is to be inserted as\r
- * the last item.\r
- * @returns {CKEDITOR.dialog.definition.content} The inserted content\r
- * definition.\r
- */\r
- addContents : function( contentDefinition, nextSiblingId )\r
- {\r
- return addById( this.contents, contentDefinition, nextSiblingId );\r
- },\r
-\r
- /**\r
- * Adds a button definition object under this dialog definition.\r
- * @param {CKEDITOR.dialog.definition.button} buttonDefinition The\r
- * button definition.\r
- * @param {String} [nextSiblingId] The id of an existing button\r
- * definition which the new button definition will be inserted\r
- * before. Omit if the new button definition is to be inserted as\r
- * the last item.\r
- * @returns {CKEDITOR.dialog.definition.button} The inserted button\r
- * definition.\r
- */\r
- addButton : function( buttonDefinition, nextSiblingId )\r
- {\r
- return addById( this.buttons, buttonDefinition, nextSiblingId );\r
- },\r
-\r
- /**\r
- * Removes a content definition from this dialog definition.\r
- * @param {String} id The id of the content definition to be removed.\r
- * @returns {CKEDITOR.dialog.definition.content} The removed content\r
- * definition.\r
- */\r
- removeContents : function( id )\r
- {\r
- removeById( this.contents, id );\r
- },\r
-\r
- /**\r
- * Removes a button definition from the dialog definition.\r
- * @param {String} id The id of the button definition to be removed.\r
- * @returns {CKEDITOR.dialog.definition.button} The removed button\r
- * definition.\r
- */\r
- removeButton : function( id )\r
- {\r
- removeById( this.buttons, id );\r
- }\r
- };\r
-\r
- /**\r
- * This class is not really part of the API. It is the template of the\r
- * objects representing content pages inside the\r
- * CKEDITOR.dialog.definitionObject.\r
- * @constructor\r
- * @name CKEDITOR.dialog.definition.contentObject\r
- * @example\r
- * CKEDITOR.on( 'dialogDefinition', function( evt )\r
- * {\r
- * var definition = evt.data.definition;\r
- * var content = definition.getContents( 'page1' );\r
- * content.remove( 'textInput1' );\r
- * ...\r
- * } );\r
- */\r
- function contentObject( dialog, contentDefinition )\r
- {\r
- this._ =\r
- {\r
- dialog : dialog\r
- };\r
-\r
- CKEDITOR.tools.extend( this, contentDefinition );\r
- }\r
-\r
- contentObject.prototype =\r
- /** @lends CKEDITOR.dialog.definition.contentObject.prototype */\r
- {\r
- /**\r
- * Gets a UI element definition under the content definition.\r
- * @param {String} id The id of the UI element definition.\r
- * @returns {CKEDITOR.dialog.definition.uiElement}\r
- */\r
- get : function( id )\r
- {\r
- return getById( this.elements, id, 'children' );\r
- },\r
-\r
- /**\r
- * Adds a UI element definition to the content definition.\r
- * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition The\r
- * UI elemnet definition to be added.\r
- * @param {String} nextSiblingId The id of an existing UI element\r
- * definition which the new UI element definition will be inserted\r
- * before. Omit if the new button definition is to be inserted as\r
- * the last item.\r
- * @returns {CKEDITOR.dialog.definition.uiElement} The element\r
- * definition inserted.\r
- */\r
- add : function( elementDefinition, nextSiblingId )\r
- {\r
- return addById( this.elements, elementDefinition, nextSiblingId, 'children' );\r
- },\r
-\r
- /**\r
- * Removes a UI element definition from the content definition.\r
- * @param {String} id The id of the UI element definition to be\r
- * removed.\r
- * @returns {CKEDITOR.dialog.definition.uiElement} The element\r
- * definition removed.\r
- * @example\r
- */\r
- remove : function( id )\r
- {\r
- removeById( this.elements, id, 'children' );\r
- }\r
- };\r
-\r
- function initDragAndDrop( dialog )\r
- {\r
- var lastCoords = null,\r
- abstractDialogCoords = null,\r
- element = dialog.getElement().getFirst(),\r
- editor = dialog.getParentEditor(),\r
- magnetDistance = editor.config.dialog_magnetDistance,\r
- margins = editor.skin.margins || [ 0, 0, 0, 0 ];\r
-\r
- if ( typeof magnetDistance == 'undefined' )\r
- magnetDistance = 20;\r
-\r
- function mouseMoveHandler( evt )\r
- {\r
- var dialogSize = dialog.getSize(),\r
- viewPaneSize = CKEDITOR.document.getWindow().getViewPaneSize(),\r
- x = evt.data.$.screenX,\r
- y = evt.data.$.screenY,\r
- dx = x - lastCoords.x,\r
- dy = y - lastCoords.y,\r
- realX, realY;\r
-\r
- lastCoords = { x : x, y : y };\r
- abstractDialogCoords.x += dx;\r
- abstractDialogCoords.y += dy;\r
-\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 + ( editor.lang.dir == 'rtl' ? 0 : margins[1] );\r
- else\r
- realX = abstractDialogCoords.x;\r
-\r
- if ( abstractDialogCoords.y + margins[0] < magnetDistance )\r
- realY = - margins[0];\r
- else if ( abstractDialogCoords.y - margins[2] > viewPaneSize.height - dialogSize.height - magnetDistance )\r
- realY = viewPaneSize.height - dialogSize.height + margins[2];\r
- else\r
- realY = abstractDialogCoords.y;\r
-\r
- dialog.move( realX, realY, 1 );\r
-\r
- evt.data.preventDefault();\r
- }\r
-\r
- function mouseUpHandler( evt )\r
- {\r
- CKEDITOR.document.removeListener( 'mousemove', mouseMoveHandler );\r
- CKEDITOR.document.removeListener( 'mouseup', mouseUpHandler );\r
-\r
- if ( CKEDITOR.env.ie6Compat )\r
- {\r
- var coverDoc = currentCover.getChild( 0 ).getFrameDocument();\r
- coverDoc.removeListener( 'mousemove', mouseMoveHandler );\r
- coverDoc.removeListener( 'mouseup', mouseUpHandler );\r
- }\r
- }\r
-\r
- dialog.parts.title.on( 'mousedown', function( evt )\r
- {\r
- lastCoords = { x : evt.data.$.screenX, y : evt.data.$.screenY };\r
-\r
- CKEDITOR.document.on( 'mousemove', mouseMoveHandler );\r
- CKEDITOR.document.on( 'mouseup', mouseUpHandler );\r
- abstractDialogCoords = dialog.getPosition();\r
-\r
- if ( CKEDITOR.env.ie6Compat )\r
- {\r
- var coverDoc = currentCover.getChild( 0 ).getFrameDocument();\r
- coverDoc.on( 'mousemove', mouseMoveHandler );\r
- coverDoc.on( 'mouseup', mouseUpHandler );\r
- }\r
-\r
- evt.data.preventDefault();\r
- }, dialog );\r
- }\r
-\r
- function initResizeHandles( dialog )\r
- {\r
- var def = dialog.definition,\r
- resizable = def.resizable;\r
-\r
- if ( resizable == CKEDITOR.DIALOG_RESIZE_NONE )\r
- return;\r
-\r
- var editor = dialog.getParentEditor();\r
- var wrapperWidth, wrapperHeight,\r
- viewSize, origin, startSize,\r
- dialogCover;\r
-\r
- var mouseDownFn = CKEDITOR.tools.addFunction( function( $event )\r
- {\r
- startSize = dialog.getSize();\r
-\r
- var content = dialog.parts.contents,\r
- iframeDialog = content.$.getElementsByTagName( 'iframe' ).length;\r
-\r
- // Shim to help capturing "mousemove" over iframe.\r
- if ( iframeDialog )\r
- {\r
- dialogCover = CKEDITOR.dom.element.createFromHtml( '<div class="cke_dialog_resize_cover" style="height: 100%; position: absolute; width: 100%;"></div>' );\r
- content.append( dialogCover );\r
- }\r
-\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
- origin = { x : $event.screenX, y : $event.screenY };\r
-\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 );\r
- coverDoc.on( 'mouseup', mouseUpHandler );\r
- }\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' +\r
- ' class="cke_resizer' + direction + ' cke_resizer_' + editor.lang.dir + '"' +\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 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 ( position.y + internalHeight > viewSize.height )\r
- internalHeight = viewSize.height - position.y;\r
-\r
- if ( ( rtl ? right : position.x ) + internalWidth > viewSize.width )\r
- internalWidth = viewSize.width - ( rtl ? right : position.x );\r
-\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 ) )\r
- width = Math.max( def.minWidth || 0, internalWidth - wrapperWidth );\r
-\r
- if ( resizable == CKEDITOR.DIALOG_RESIZE_HEIGHT || resizable == CKEDITOR.DIALOG_RESIZE_BOTH )\r
- height = Math.max( def.minHeight || 0, internalHeight - wrapperHeight );\r
-\r
- dialog.resize( width, height );\r
-\r
- if ( !dialog._.moved )\r
- dialog.layout();\r
-\r
- evt.data.preventDefault();\r
- }\r
-\r
- function mouseUpHandler()\r
- {\r
- CKEDITOR.document.removeListener( 'mouseup', mouseUpHandler );\r
- CKEDITOR.document.removeListener( 'mousemove', mouseMoveHandler );\r
-\r
- if ( dialogCover )\r
- {\r
- dialogCover.remove();\r
- dialogCover = null;\r
- }\r
-\r
- if ( CKEDITOR.env.ie6Compat )\r
- {\r
- var coverDoc = currentCover.getChild( 0 ).getFrameDocument();\r
- coverDoc.removeListener( 'mouseup', mouseUpHandler );\r
- coverDoc.removeListener( 'mousemove', mouseMoveHandler );\r
- }\r
- }\r
- }\r
-\r
- var resizeCover;\r
- // Caching resuable covers and allowing only one cover\r
- // on screen.\r
- var covers = {},\r
- currentCover;\r
-\r
- function cancelEvent( ev )\r
- {\r
- ev.data.preventDefault(1);\r
- }\r
-\r
- function showCover( editor )\r
- {\r
- var win = CKEDITOR.document.getWindow();\r
- var config = editor.config,\r
- backgroundColorStyle = config.dialog_backgroundCoverColor || 'white',\r
- backgroundCoverOpacity = config.dialog_backgroundCoverOpacity,\r
- baseFloatZIndex = config.baseFloatZIndex,\r
- coverKey = CKEDITOR.tools.genKey(\r
- backgroundColorStyle,\r
- backgroundCoverOpacity,\r
- baseFloatZIndex ),\r
- coverElement = covers[ coverKey ];\r
-\r
- if ( !coverElement )\r
- {\r
- var html = [\r
- '<div tabIndex="-1" style="position: ', ( CKEDITOR.env.ie6Compat ? 'absolute' : 'fixed' ),\r
- '; z-index: ', baseFloatZIndex,\r
- '; top: 0px; left: 0px; ',\r
- ( !CKEDITOR.env.ie6Compat ? 'background-color: ' + backgroundColorStyle : '' ),\r
- '" class="cke_dialog_background_cover">'\r
- ];\r
-\r
- if ( CKEDITOR.env.ie6Compat )\r
- {\r
- // Support for custom document.domain in IE.\r
- var isCustomDomain = CKEDITOR.env.isCustomDomain(),\r
- iframeHtml = '<html><body style=\\\'background-color:' + backgroundColorStyle + ';\\\'></body></html>';\r
-\r
- html.push(\r
- '<iframe' +\r
- ' hidefocus="true"' +\r
- ' frameborder="0"' +\r
- ' id="cke_dialog_background_iframe"' +\r
- ' src="javascript:' );\r
-\r
- html.push( 'void((function(){' +\r
- 'document.open();' +\r
- ( isCustomDomain ? 'document.domain=\'' + document.domain + '\';' : '' ) +\r
- 'document.write( \'' + iframeHtml + '\' );' +\r
- 'document.close();' +\r
- '})())' );\r
-\r
- html.push(\r
- '"' +\r
- ' style="' +\r
- 'position:absolute;' +\r
- 'left:0;' +\r
- 'top:0;' +\r
- 'width:100%;' +\r
- 'height: 100%;' +\r
- 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)">' +\r
- '</iframe>' );\r
- }\r
-\r
- html.push( '</div>' );\r
-\r
- coverElement = CKEDITOR.dom.element.createFromHtml( html.join( '' ) );\r
- coverElement.setOpacity( backgroundCoverOpacity != undefined ? backgroundCoverOpacity : 0.5 );\r
-\r
- coverElement.on( 'keydown', cancelEvent );\r
- coverElement.on( 'keypress', cancelEvent );\r
- coverElement.on( 'keyup', cancelEvent );\r
-\r
- coverElement.appendTo( CKEDITOR.document.getBody() );\r
- covers[ coverKey ] = coverElement;\r
- }\r
- else\r
- coverElement. show();\r
-\r
- currentCover = coverElement;\r
- var resizeFunc = function()\r
- {\r
- var size = win.getViewPaneSize();\r
- coverElement.setStyles(\r
- {\r
- width : size.width + 'px',\r
- height : size.height + 'px'\r
- } );\r
- };\r
-\r
- var scrollFunc = function()\r
- {\r
- var pos = win.getScrollPosition(),\r
- cursor = CKEDITOR.dialog._.currentTop;\r
- coverElement.setStyles(\r
- {\r
- left : pos.x + 'px',\r
- top : pos.y + 'px'\r
- });\r
-\r
- if ( cursor )\r
- {\r
- do\r
- {\r
- var dialogPos = cursor.getPosition();\r
- cursor.move( dialogPos.x, dialogPos.y );\r
- } while ( ( cursor = cursor._.parentDialog ) );\r
- }\r
- };\r
-\r
- resizeCover = resizeFunc;\r
- win.on( 'resize', resizeFunc );\r
- resizeFunc();\r
- // Using Safari/Mac, focus must be kept where it is (#7027)\r
- if ( !( CKEDITOR.env.mac && CKEDITOR.env.webkit ) )\r
- coverElement.focus();\r
-\r
- if ( CKEDITOR.env.ie6Compat )\r
- {\r
- // IE BUG: win.$.onscroll assignment doesn't work.. it must be window.onscroll.\r
- // So we need to invent a really funny way to make it work.\r
- var myScrollHandler = function()\r
- {\r
- scrollFunc();\r
- arguments.callee.prevScrollHandler.apply( this, arguments );\r
- };\r
- win.$.setTimeout( function()\r
- {\r
- myScrollHandler.prevScrollHandler = window.onscroll || function(){};\r
- window.onscroll = myScrollHandler;\r
- }, 0 );\r
- scrollFunc();\r
- }\r
- }\r
-\r
- function hideCover()\r
- {\r
- if ( !currentCover )\r
- return;\r
-\r
- var win = CKEDITOR.document.getWindow();\r
- currentCover.hide();\r
- win.removeListener( 'resize', resizeCover );\r
-\r
- if ( CKEDITOR.env.ie6Compat )\r
- {\r
- win.$.setTimeout( function()\r
- {\r
- var prevScrollHandler = window.onscroll && window.onscroll.prevScrollHandler;\r
- window.onscroll = prevScrollHandler || null;\r
- }, 0 );\r
- }\r
- resizeCover = null;\r
- }\r
-\r
- function removeCovers()\r
- {\r
- for ( var coverId in covers )\r
- covers[ coverId ].remove();\r
- covers = {};\r
- }\r
-\r
- var accessKeyProcessors = {};\r
-\r
- var accessKeyDownHandler = function( evt )\r
- {\r
- var ctrl = evt.data.$.ctrlKey || evt.data.$.metaKey,\r
- alt = evt.data.$.altKey,\r
- shift = evt.data.$.shiftKey,\r
- key = String.fromCharCode( evt.data.$.keyCode ),\r
- keyProcessor = accessKeyProcessors[( ctrl ? 'CTRL+' : '' ) + ( alt ? 'ALT+' : '') + ( shift ? 'SHIFT+' : '' ) + key];\r
-\r
- if ( !keyProcessor || !keyProcessor.length )\r
- return;\r
-\r
- keyProcessor = keyProcessor[keyProcessor.length - 1];\r
- keyProcessor.keydown && keyProcessor.keydown.call( keyProcessor.uiElement, keyProcessor.dialog, keyProcessor.key );\r
- evt.data.preventDefault();\r
- };\r
-\r
- var accessKeyUpHandler = function( evt )\r
- {\r
- var ctrl = evt.data.$.ctrlKey || evt.data.$.metaKey,\r
- alt = evt.data.$.altKey,\r
- shift = evt.data.$.shiftKey,\r
- key = String.fromCharCode( evt.data.$.keyCode ),\r
- keyProcessor = accessKeyProcessors[( ctrl ? 'CTRL+' : '' ) + ( alt ? 'ALT+' : '') + ( shift ? 'SHIFT+' : '' ) + key];\r
-\r
- if ( !keyProcessor || !keyProcessor.length )\r
- return;\r
-\r
- keyProcessor = keyProcessor[keyProcessor.length - 1];\r
- if ( keyProcessor.keyup )\r
- {\r
- keyProcessor.keyup.call( keyProcessor.uiElement, keyProcessor.dialog, keyProcessor.key );\r
- evt.data.preventDefault();\r
- }\r
- };\r
-\r
- var registerAccessKey = function( uiElement, dialog, key, downFunc, upFunc )\r
- {\r
- var procList = accessKeyProcessors[key] || ( accessKeyProcessors[key] = [] );\r
- procList.push( {\r
- uiElement : uiElement,\r
- dialog : dialog,\r
- key : key,\r
- keyup : upFunc || uiElement.accessKeyUp,\r
- keydown : downFunc || uiElement.accessKeyDown\r
- } );\r
- };\r
-\r
- var unregisterAccessKey = function( obj )\r
- {\r
- for ( var i in accessKeyProcessors )\r
- {\r
- var list = accessKeyProcessors[i];\r
- for ( var j = list.length - 1 ; j >= 0 ; j-- )\r
- {\r
- if ( list[j].dialog == obj || list[j].uiElement == obj )\r
- list.splice( j, 1 );\r
- }\r
- if ( list.length === 0 )\r
- delete accessKeyProcessors[i];\r
- }\r
- };\r
-\r
- var tabAccessKeyUp = function( dialog, key )\r
- {\r
- if ( dialog._.accessKeyMap[key] )\r
- dialog.selectPage( dialog._.accessKeyMap[key] );\r
- };\r
-\r
- var tabAccessKeyDown = function( dialog, key )\r
- {\r
- };\r
-\r
- (function()\r
- {\r
- CKEDITOR.ui.dialog =\r
- {\r
- /**\r
- * The base class of all dialog UI elements.\r
- * @constructor\r
- * @param {CKEDITOR.dialog} dialog Parent dialog object.\r
- * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition Element\r
- * definition. Accepted fields:\r
- * <ul>\r
- * <li><strong>id</strong> (Required) The id of the UI element. See {@link\r
- * CKEDITOR.dialog#getContentElement}</li>\r
- * <li><strong>type</strong> (Required) The type of the UI element. The\r
- * value to this field specifies which UI element class will be used to\r
- * generate the final widget.</li>\r
- * <li><strong>title</strong> (Optional) The popup tooltip for the UI\r
- * element.</li>\r
- * <li><strong>hidden</strong> (Optional) A flag that tells if the element\r
- * should be initially visible.</li>\r
- * <li><strong>className</strong> (Optional) Additional CSS class names\r
- * to add to the UI element. Separated by space.</li>\r
- * <li><strong>style</strong> (Optional) Additional CSS inline styles\r
- * to add to the UI element. A semicolon (;) is required after the last\r
- * style declaration.</li>\r
- * <li><strong>accessKey</strong> (Optional) The alphanumeric access key\r
- * for this element. Access keys are automatically prefixed by CTRL.</li>\r
- * <li><strong>on*</strong> (Optional) Any UI element definition field that\r
- * starts with <em>on</em> followed immediately by a capital letter and\r
- * probably more letters is an event handler. Event handlers may be further\r
- * divided into registered event handlers and DOM event handlers. Please\r
- * refer to {@link CKEDITOR.ui.dialog.uiElement#registerEvents} and\r
- * {@link CKEDITOR.ui.dialog.uiElement#eventProcessors} for more\r
- * information.</li>\r
- * </ul>\r
- * @param {Array} htmlList\r
- * List of HTML code to be added to the dialog's content area.\r
- * @param {Function|String} nodeNameArg\r
- * A function returning a string, or a simple string for the node name for\r
- * the root DOM node. Default is 'div'.\r
- * @param {Function|Object} stylesArg\r
- * A function returning an object, or a simple object for CSS styles applied\r
- * to the DOM node. Default is empty object.\r
- * @param {Function|Object} attributesArg\r
- * A fucntion returning an object, or a simple object for attributes applied\r
- * to the DOM node. Default is empty object.\r
- * @param {Function|String} contentsArg\r
- * A function returning a string, or a simple string for the HTML code inside\r
- * the root DOM node. Default is empty string.\r
- * @example\r
- */\r
- uiElement : function( dialog, elementDefinition, htmlList, nodeNameArg, stylesArg, attributesArg, contentsArg )\r
- {\r
- if ( arguments.length < 4 )\r
- return;\r
-\r
- var nodeName = ( nodeNameArg.call ? nodeNameArg( elementDefinition ) : nodeNameArg ) || 'div',\r
- html = [ '<', nodeName, ' ' ],\r
- styles = ( stylesArg && stylesArg.call ? stylesArg( elementDefinition ) : stylesArg ) || {},\r
- attributes = ( attributesArg && attributesArg.call ? attributesArg( elementDefinition ) : attributesArg ) || {},\r
- innerHTML = ( contentsArg && contentsArg.call ? contentsArg.call( this, dialog, elementDefinition ) : contentsArg ) || '',\r
- domId = this.domId = attributes.id || CKEDITOR.tools.getNextId() + '_uiElement',\r
- id = this.id = elementDefinition.id,\r
- i;\r
-\r
- // Set the id, a unique id is required for getElement() to work.\r
- attributes.id = domId;\r
-\r
- // Set the type and definition CSS class names.\r
- var classes = {};\r
- if ( elementDefinition.type )\r
- classes[ 'cke_dialog_ui_' + elementDefinition.type ] = 1;\r
- if ( elementDefinition.className )\r
- classes[ elementDefinition.className ] = 1;\r
- if ( elementDefinition.disabled )\r
- classes[ 'cke_disabled' ] = 1;\r
-\r
- var attributeClasses = ( attributes['class'] && attributes['class'].split ) ? attributes['class'].split( ' ' ) : [];\r
- for ( i = 0 ; i < attributeClasses.length ; i++ )\r
- {\r
- if ( attributeClasses[i] )\r
- classes[ attributeClasses[i] ] = 1;\r
- }\r
- var finalClasses = [];\r
- for ( i in classes )\r
- finalClasses.push( i );\r
- attributes['class'] = finalClasses.join( ' ' );\r
-\r
- // Set the popup tooltop.\r
- if ( elementDefinition.title )\r
- attributes.title = elementDefinition.title;\r
-\r
- // Write the inline CSS styles.\r
- var styleStr = ( elementDefinition.style || '' ).split( ';' );\r
-\r
- // Element alignment support.\r
- if ( elementDefinition.align )\r
- {\r
- var align = elementDefinition.align;\r
- styles[ 'margin-left' ] = align == 'left' ? 0 : 'auto';\r
- styles[ 'margin-right' ] = align == 'right' ? 0 : 'auto';\r
- }\r
-\r
- for ( i in styles )\r
- styleStr.push( i + ':' + styles[i] );\r
- if ( elementDefinition.hidden )\r
- styleStr.push( 'display:none' );\r
- for ( i = styleStr.length - 1 ; i >= 0 ; i-- )\r
- {\r
- if ( styleStr[i] === '' )\r
- styleStr.splice( i, 1 );\r
- }\r
- if ( styleStr.length > 0 )\r
- attributes.style = ( attributes.style ? ( attributes.style + '; ' ) : '' ) + styleStr.join( '; ' );\r
-\r
- // Write the attributes.\r
- for ( i in attributes )\r
- html.push( i + '="' + CKEDITOR.tools.htmlEncode( attributes[i] ) + '" ');\r
-\r
- // Write the content HTML.\r
- html.push( '>', innerHTML, '</', nodeName, '>' );\r
-\r
- // Add contents to the parent HTML array.\r
- htmlList.push( html.join( '' ) );\r
-\r
- ( this._ || ( this._ = {} ) ).dialog = dialog;\r
-\r
- // Override isChanged if it is defined in element definition.\r
- if ( typeof( elementDefinition.isChanged ) == 'boolean' )\r
- this.isChanged = function(){ return elementDefinition.isChanged; };\r
- if ( typeof( elementDefinition.isChanged ) == 'function' )\r
- this.isChanged = elementDefinition.isChanged;\r
-\r
- // Overload 'get(set)Value' on definition.\r
- if ( typeof( elementDefinition.setValue ) == 'function' )\r
- {\r
- this.setValue = CKEDITOR.tools.override( this.setValue, function( org )\r
- {\r
- return function( val ){ org.call( this, elementDefinition.setValue.call( this, val ) ); };\r
- } );\r
- }\r
-\r
- if ( typeof( elementDefinition.getValue ) == 'function' )\r
- {\r
- this.getValue = CKEDITOR.tools.override( this.getValue, function( org )\r
- {\r
- return function(){ return elementDefinition.getValue.call( this, org.call( this ) ); };\r
- } );\r
- }\r
-\r
- // Add events.\r
- CKEDITOR.event.implementOn( this );\r
-\r
- this.registerEvents( elementDefinition );\r
- if ( this.accessKeyUp && this.accessKeyDown && elementDefinition.accessKey )\r
- registerAccessKey( this, dialog, 'CTRL+' + elementDefinition.accessKey );\r
-\r
- var me = this;\r
- dialog.on( 'load', function()\r
- {\r
- var input = me.getInputElement();\r
- if ( input )\r
- {\r
- var focusClass = me.type in { 'checkbox' : 1, 'ratio' : 1 } && CKEDITOR.env.ie && CKEDITOR.env.version < 8 ? 'cke_dialog_ui_focused' : '';\r
- input.on( 'focus', function()\r
- {\r
- dialog._.tabBarMode = false;\r
- dialog._.hasFocus = true;\r
- me.fire( 'focus' );\r
- focusClass && this.addClass( focusClass );\r
-\r
- });\r
-\r
- input.on( 'blur', function()\r
- {\r
- me.fire( 'blur' );\r
- focusClass && this.removeClass( focusClass );\r
- });\r
- }\r
- } );\r
-\r
- // Register the object as a tab focus if it can be included.\r
- if ( this.keyboardFocusable )\r
- {\r
- this.tabIndex = elementDefinition.tabIndex || 0;\r
-\r
- this.focusIndex = dialog._.focusList.push( this ) - 1;\r
- this.on( 'focus', function()\r
- {\r
- dialog._.currentFocusIndex = me.focusIndex;\r
- } );\r
- }\r
-\r
- // Completes this object with everything we have in the\r
- // definition.\r
- CKEDITOR.tools.extend( this, elementDefinition );\r
- },\r
-\r
- /**\r
- * Horizontal layout box for dialog UI elements, auto-expends to available width of container.\r
- * @constructor\r
- * @extends CKEDITOR.ui.dialog.uiElement\r
- * @param {CKEDITOR.dialog} dialog\r
- * Parent dialog object.\r
- * @param {Array} childObjList\r
- * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this\r
- * container.\r
- * @param {Array} childHtmlList\r
- * Array of HTML code that correspond to the HTML output of all the\r
- * objects in childObjList.\r
- * @param {Array} htmlList\r
- * Array of HTML code that this element will output to.\r
- * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition\r
- * The element definition. Accepted fields:\r
- * <ul>\r
- * <li><strong>widths</strong> (Optional) The widths of child cells.</li>\r
- * <li><strong>height</strong> (Optional) The height of the layout.</li>\r
- * <li><strong>padding</strong> (Optional) The padding width inside child\r
- * cells.</li>\r
- * <li><strong>align</strong> (Optional) The alignment of the whole layout\r
- * </li>\r
- * </ul>\r
- * @example\r
- */\r
- hbox : function( dialog, childObjList, childHtmlList, htmlList, elementDefinition )\r
- {\r
- if ( arguments.length < 4 )\r
- return;\r
-\r
- this._ || ( this._ = {} );\r
-\r
- var children = this._.children = childObjList,\r
- widths = elementDefinition && elementDefinition.widths || null,\r
- height = elementDefinition && elementDefinition.height || null,\r
- styles = {},\r
- i;\r
- /** @ignore */\r
- var innerHTML = function()\r
- {\r
- var html = [ '<tbody><tr class="cke_dialog_ui_hbox">' ];\r
- for ( i = 0 ; i < childHtmlList.length ; i++ )\r
- {\r
- var className = 'cke_dialog_ui_hbox_child',\r
- styles = [];\r
- if ( i === 0 )\r
- className = 'cke_dialog_ui_hbox_first';\r
- if ( i == childHtmlList.length - 1 )\r
- className = 'cke_dialog_ui_hbox_last';\r
- html.push( '<td class="', className, '" role="presentation" ' );\r
- if ( widths )\r
- {\r
- if ( widths[i] )\r
- styles.push( 'width:' + cssLength( widths[i] ) );\r
- }\r
- else\r
- styles.push( 'width:' + Math.floor( 100 / childHtmlList.length ) + '%' );\r
- if ( height )\r
- styles.push( 'height:' + cssLength( height ) );\r
- if ( elementDefinition && elementDefinition.padding != undefined )\r
- styles.push( 'padding:' + cssLength( elementDefinition.padding ) );\r
- // In IE Quirks alignment has to be done on table cells. (#7324)\r
- if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && children[ i ].align )\r
- styles.push( 'text-align:' + children[ i ].align );\r
- if ( styles.length > 0 )\r
- html.push( 'style="' + styles.join('; ') + '" ' );\r
- html.push( '>', childHtmlList[i], '</td>' );\r
- }\r
- html.push( '</tr></tbody>' );\r
- return html.join( '' );\r
- };\r
-\r
- var attribs = { role : 'presentation' };\r
- elementDefinition && elementDefinition.align && ( attribs.align = elementDefinition.align );\r
-\r
- CKEDITOR.ui.dialog.uiElement.call(\r
- this,\r
- dialog,\r
- elementDefinition || { type : 'hbox' },\r
- htmlList,\r
- 'table',\r
- styles,\r
- attribs,\r
- innerHTML );\r
- },\r
-\r
- /**\r
- * Vertical layout box for dialog UI elements.\r
- * @constructor\r
- * @extends CKEDITOR.ui.dialog.hbox\r
- * @param {CKEDITOR.dialog} dialog\r
- * Parent dialog object.\r
- * @param {Array} childObjList\r
- * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this\r
- * container.\r
- * @param {Array} childHtmlList\r
- * Array of HTML code that correspond to the HTML output of all the\r
- * objects in childObjList.\r
- * @param {Array} htmlList\r
- * Array of HTML code that this element will output to.\r
- * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition\r
- * The element definition. Accepted fields:\r
- * <ul>\r
- * <li><strong>width</strong> (Optional) The width of the layout.</li>\r
- * <li><strong>heights</strong> (Optional) The heights of individual cells.\r
- * </li>\r
- * <li><strong>align</strong> (Optional) The alignment of the layout.</li>\r
- * <li><strong>padding</strong> (Optional) The padding width inside child\r
- * cells.</li>\r
- * <li><strong>expand</strong> (Optional) Whether the layout should expand\r
- * vertically to fill its container.</li>\r
- * </ul>\r
- * @example\r
- */\r
- vbox : function( dialog, childObjList, childHtmlList, htmlList, elementDefinition )\r
- {\r
- if ( arguments.length < 3 )\r
- return;\r
-\r
- this._ || ( this._ = {} );\r
-\r
- var children = this._.children = childObjList,\r
- width = elementDefinition && elementDefinition.width || null,\r
- heights = elementDefinition && elementDefinition.heights || null;\r
- /** @ignore */\r
- var innerHTML = function()\r
- {\r
- var html = [ '<table role="presentation" cellspacing="0" border="0" ' ];\r
- html.push( 'style="' );\r
- if ( elementDefinition && elementDefinition.expand )\r
- html.push( 'height:100%;' );\r
- html.push( 'width:' + cssLength( width || '100%' ), ';' );\r
- html.push( '"' );\r
- html.push( 'align="', CKEDITOR.tools.htmlEncode(\r
- ( elementDefinition && elementDefinition.align ) || ( dialog.getParentEditor().lang.dir == 'ltr' ? 'left' : 'right' ) ), '" ' );\r
-\r
- html.push( '><tbody>' );\r
- for ( var i = 0 ; i < childHtmlList.length ; i++ )\r
- {\r
- var styles = [];\r
- html.push( '<tr><td role="presentation" ' );\r
- if ( width )\r
- styles.push( 'width:' + cssLength( width || '100%' ) );\r
- if ( heights )\r
- styles.push( 'height:' + cssLength( heights[i] ) );\r
- else if ( elementDefinition && elementDefinition.expand )\r
- styles.push( 'height:' + Math.floor( 100 / childHtmlList.length ) + '%' );\r
- if ( elementDefinition && elementDefinition.padding != undefined )\r
- styles.push( 'padding:' + cssLength( elementDefinition.padding ) );\r
- // In IE Quirks alignment has to be done on table cells. (#7324)\r
- if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && children[ i ].align )\r
- styles.push( 'text-align:' + children[ i ].align );\r
- if ( styles.length > 0 )\r
- html.push( 'style="', styles.join( '; ' ), '" ' );\r
- html.push( ' class="cke_dialog_ui_vbox_child">', childHtmlList[i], '</td></tr>' );\r
- }\r
- html.push( '</tbody></table>' );\r
- return html.join( '' );\r
- };\r
- CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition || { type : 'vbox' }, htmlList, 'div', null, { role : 'presentation' }, innerHTML );\r
- }\r
- };\r
- })();\r
-\r
- CKEDITOR.ui.dialog.uiElement.prototype =\r
- {\r
- /**\r
- * Gets the root DOM element of this dialog UI object.\r
- * @returns {CKEDITOR.dom.element} Root DOM element of UI object.\r
- * @example\r
- * uiElement.getElement().hide();\r
- */\r
- getElement : function()\r
- {\r
- return CKEDITOR.document.getById( this.domId );\r
- },\r
-\r
- /**\r
- * Gets the DOM element that the user inputs values.\r
- * This function is used by setValue(), getValue() and focus(). It should\r
- * be overrided in child classes where the input element isn't the root\r
- * element.\r
- * @returns {CKEDITOR.dom.element} The element where the user input values.\r
- * @example\r
- * var rawValue = textInput.getInputElement().$.value;\r
- */\r
- getInputElement : function()\r
- {\r
- return this.getElement();\r
- },\r
-\r
- /**\r
- * Gets the parent dialog object containing this UI element.\r
- * @returns {CKEDITOR.dialog} Parent dialog object.\r
- * @example\r
- * var dialog = uiElement.getDialog();\r
- */\r
- getDialog : function()\r
- {\r
- return this._.dialog;\r
- },\r
-\r
- /**\r
- * Sets the value of this dialog UI object.\r
- * @param {Object} value The new value.\r
- * @param {Boolean} noChangeEvent Internal commit, to supress 'change' event on this element.\r
- * @returns {CKEDITOR.dialog.uiElement} The current UI element.\r
- * @example\r
- * uiElement.setValue( 'Dingo' );\r
- */\r
- setValue : function( value, noChangeEvent )\r
- {\r
- this.getInputElement().setValue( value );\r
- !noChangeEvent && this.fire( 'change', { value : value } );\r
- return this;\r
- },\r
-\r
- /**\r
- * Gets the current value of this dialog UI object.\r
- * @returns {Object} The current value.\r
- * @example\r
- * var myValue = uiElement.getValue();\r
- */\r
- getValue : function()\r
- {\r
- return this.getInputElement().getValue();\r
- },\r
-\r
- /**\r
- * Tells whether the UI object's value has changed.\r
- * @returns {Boolean} true if changed, false if not changed.\r
- * @example\r
- * if ( uiElement.isChanged() )\r
- * confirm( 'Value changed! Continue?' );\r
- */\r
- isChanged : function()\r
- {\r
- // Override in input classes.\r
- return false;\r
- },\r
-\r
- /**\r
- * Selects the parent tab of this element. Usually called by focus() or overridden focus() methods.\r
- * @returns {CKEDITOR.dialog.uiElement} The current UI element.\r
- * @example\r
- * focus : function()\r
- * {\r
- * this.selectParentTab();\r
- * // do something else.\r
- * }\r
- */\r
- selectParentTab : function()\r
- {\r
- var element = this.getInputElement(),\r
- cursor = element,\r
- tabId;\r
- while ( ( cursor = cursor.getParent() ) && cursor.$.className.search( 'cke_dialog_page_contents' ) == -1 )\r
- { /*jsl:pass*/ }\r
-\r
- // Some widgets don't have parent tabs (e.g. OK and Cancel buttons).\r
- if ( !cursor )\r
- return this;\r
-\r
- tabId = cursor.getAttribute( 'name' );\r
- // Avoid duplicate select.\r
- if ( this._.dialog._.currentTabId != tabId )\r
- this._.dialog.selectPage( tabId );\r
- return this;\r
- },\r
-\r
- /**\r
- * Puts the focus to the UI object. Switches tabs if the UI object isn't in the active tab page.\r
- * @returns {CKEDITOR.dialog.uiElement} The current UI element.\r
- * @example\r
- * uiElement.focus();\r
- */\r
- focus : function()\r
- {\r
- this.selectParentTab().getInputElement().focus();\r
- return this;\r
- },\r
-\r
- /**\r
- * Registers the on* event handlers defined in the element definition.\r
- * The default behavior of this function is:\r
- * <ol>\r
- * <li>\r
- * If the on* event is defined in the class's eventProcesors list,\r
- * then the registration is delegated to the corresponding function\r
- * in the eventProcessors list.\r
- * </li>\r
- * <li>\r
- * If the on* event is not defined in the eventProcessors list, then\r
- * register the event handler under the corresponding DOM event of\r
- * the UI element's input DOM element (as defined by the return value\r
- * of {@link CKEDITOR.ui.dialog.uiElement#getInputElement}).\r
- * </li>\r
- * </ol>\r
- * This function is only called at UI element instantiation, but can\r
- * be overridded in child classes if they require more flexibility.\r
- * @param {CKEDITOR.dialog.definition.uiElement} definition The UI element\r
- * definition.\r
- * @returns {CKEDITOR.dialog.uiElement} The current UI element.\r
- * @example\r
- */\r
- registerEvents : function( definition )\r
- {\r
- var regex = /^on([A-Z]\w+)/,\r
- match;\r
-\r
- var registerDomEvent = function( uiElement, dialog, eventName, func )\r
- {\r
- dialog.on( 'load', function()\r
- {\r
- uiElement.getInputElement().on( eventName, func, uiElement );\r
- });\r
- };\r
-\r
- for ( var i in definition )\r
- {\r
- if ( !( match = i.match( regex ) ) )\r
- continue;\r
- if ( this.eventProcessors[i] )\r
- this.eventProcessors[i].call( this, this._.dialog, definition[i] );\r
- else\r
- registerDomEvent( this, this._.dialog, match[1].toLowerCase(), definition[i] );\r
- }\r
-\r
- return this;\r
- },\r
-\r
- /**\r
- * The event processor list used by\r
- * {@link CKEDITOR.ui.dialog.uiElement#getInputElement} at UI element\r
- * instantiation. The default list defines three on* events:\r
- * <ol>\r
- * <li>onLoad - Called when the element's parent dialog opens for the\r
- * first time</li>\r
- * <li>onShow - Called whenever the element's parent dialog opens.</li>\r
- * <li>onHide - Called whenever the element's parent dialog closes.</li>\r
- * </ol>\r
- * @field\r
- * @type Object\r
- * @example\r
- * // This connects the 'click' event in CKEDITOR.ui.dialog.button to onClick\r
- * // handlers in the UI element's definitions.\r
- * CKEDITOR.ui.dialog.button.eventProcessors = CKEDITOR.tools.extend( {},\r
- * CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors,\r
- * { onClick : function( dialog, func ) { this.on( 'click', func ); } },\r
- * true );\r
- */\r
- eventProcessors :\r
- {\r
- onLoad : function( dialog, func )\r
- {\r
- dialog.on( 'load', func, this );\r
- },\r
-\r
- onShow : function( dialog, func )\r
- {\r
- dialog.on( 'show', func, this );\r
- },\r
-\r
- onHide : function( dialog, func )\r
- {\r
- dialog.on( 'hide', func, this );\r
- }\r
- },\r
-\r
- /**\r
- * The default handler for a UI element's access key down event, which\r
- * tries to put focus to the UI element.<br />\r
- * Can be overridded in child classes for more sophisticaed behavior.\r
- * @param {CKEDITOR.dialog} dialog The parent dialog object.\r
- * @param {String} key The key combination pressed. Since access keys\r
- * are defined to always include the CTRL key, its value should always\r
- * include a 'CTRL+' prefix.\r
- * @example\r
- */\r
- accessKeyDown : function( dialog, key )\r
- {\r
- this.focus();\r
- },\r
-\r
- /**\r
- * The default handler for a UI element's access key up event, which\r
- * does nothing.<br />\r
- * Can be overridded in child classes for more sophisticated behavior.\r
- * @param {CKEDITOR.dialog} dialog The parent dialog object.\r
- * @param {String} key The key combination pressed. Since access keys\r
- * are defined to always include the CTRL key, its value should always\r
- * include a 'CTRL+' prefix.\r
- * @example\r
- */\r
- accessKeyUp : function( dialog, key )\r
- {\r
- },\r
-\r
- /**\r
- * Disables a UI element.\r
- * @example\r
- */\r
- disable : function()\r
- {\r
- var element = this.getElement(),\r
- input = this.getInputElement();\r
- input.setAttribute( 'disabled', 'true' );\r
- element.addClass( 'cke_disabled' );\r
- },\r
-\r
- /**\r
- * Enables a UI element.\r
- * @example\r
- */\r
- enable : function()\r
- {\r
- var element = this.getElement(),\r
- input = this.getInputElement();\r
- input.removeAttribute( 'disabled' );\r
- element.removeClass( 'cke_disabled' );\r
- },\r
-\r
- /**\r
- * Determines whether an UI element is enabled or not.\r
- * @returns {Boolean} Whether the UI element is enabled.\r
- * @example\r
- */\r
- isEnabled : function()\r
- {\r
- return !this.getElement().hasClass( 'cke_disabled' );\r
- },\r
-\r
- /**\r
- * Determines whether an UI element is visible or not.\r
- * @returns {Boolean} Whether the UI element is visible.\r
- * @example\r
- */\r
- isVisible : function()\r
- {\r
- return this.getInputElement().isVisible();\r
- },\r
-\r
- /**\r
- * Determines whether an UI element is focus-able or not.\r
- * Focus-able is defined as being both visible and enabled.\r
- * @returns {Boolean} Whether the UI element can be focused.\r
- * @example\r
- */\r
- isFocusable : function()\r
- {\r
- if ( !this.isEnabled() || !this.isVisible() )\r
- return false;\r
- return true;\r
- }\r
- };\r
-\r
- CKEDITOR.ui.dialog.hbox.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement,\r
- /**\r
- * @lends CKEDITOR.ui.dialog.hbox.prototype\r
- */\r
- {\r
- /**\r
- * Gets a child UI element inside this container.\r
- * @param {Array|Number} indices An array or a single number to indicate the child's\r
- * position in the container's descendant tree. Omit to get all the children in an array.\r
- * @returns {Array|CKEDITOR.ui.dialog.uiElement} Array of all UI elements in the container\r
- * if no argument given, or the specified UI element if indices is given.\r
- * @example\r
- * var checkbox = hbox.getChild( [0,1] );\r
- * checkbox.setValue( true );\r
- */\r
- getChild : function( indices )\r
- {\r
- // If no arguments, return a clone of the children array.\r
- if ( arguments.length < 1 )\r
- return this._.children.concat();\r
-\r
- // If indices isn't array, make it one.\r
- if ( !indices.splice )\r
- indices = [ indices ];\r
-\r
- // Retrieve the child element according to tree position.\r
- if ( indices.length < 2 )\r
- return this._.children[ indices[0] ];\r
- else\r
- return ( this._.children[ indices[0] ] && this._.children[ indices[0] ].getChild ) ?\r
- this._.children[ indices[0] ].getChild( indices.slice( 1, indices.length ) ) :\r
- null;\r
- }\r
- }, true );\r
-\r
- CKEDITOR.ui.dialog.vbox.prototype = new CKEDITOR.ui.dialog.hbox();\r
-\r
-\r
-\r
- (function()\r
- {\r
- var commonBuilder = {\r
- build : function( dialog, elementDefinition, output )\r
- {\r
- var children = elementDefinition.children,\r
- child,\r
- childHtmlList = [],\r
- childObjList = [];\r
- for ( var i = 0 ; ( i < children.length && ( child = children[i] ) ) ; i++ )\r
- {\r
- var childHtml = [];\r
- childHtmlList.push( childHtml );\r
- childObjList.push( CKEDITOR.dialog._.uiElementBuilders[ child.type ].build( dialog, child, childHtml ) );\r
- }\r
- return new CKEDITOR.ui.dialog[elementDefinition.type]( dialog, childObjList, childHtmlList, output, elementDefinition );\r
- }\r
- };\r
-\r
- CKEDITOR.dialog.addUIElement( 'hbox', commonBuilder );\r
- CKEDITOR.dialog.addUIElement( 'vbox', commonBuilder );\r
- })();\r
-\r
- /**\r
- * Generic dialog command. It opens a specific dialog when executed.\r
- * @constructor\r
- * @augments CKEDITOR.commandDefinition\r
- * @param {string} dialogName The name of the dialog to open when executing\r
- * this command.\r
- * @example\r
- * // Register the "link" command, which opens the "link" dialog.\r
- * editor.addCommand( 'link', <b>new CKEDITOR.dialogCommand( 'link' )</b> );\r
- */\r
- CKEDITOR.dialogCommand = function( dialogName )\r
- {\r
- this.dialogName = dialogName;\r
- };\r
-\r
- CKEDITOR.dialogCommand.prototype =\r
- {\r
- /** @ignore */\r
- exec : function( editor )\r
- {\r
- // Special treatment for Opera. (#8031)\r
- CKEDITOR.env.opera ?\r
- CKEDITOR.tools.setTimeout( function() { editor.openDialog( this.dialogName ); }, 0, this )\r
- : editor.openDialog( this.dialogName );\r
- },\r
-\r
- // Dialog commands just open a dialog ui, thus require no undo logic,\r
- // undo support should dedicate to specific dialog implementation.\r
- canUndo: false,\r
-\r
- editorFocus : CKEDITOR.env.ie || CKEDITOR.env.webkit\r
- };\r
-\r
- (function()\r
- {\r
- var notEmptyRegex = /^([a]|[^a])+$/,\r
- integerRegex = /^\d*$/,\r
- numberRegex = /^\d*(?:\.\d+)?$/,\r
- htmlLengthRegex = /^(((\d*(\.\d+))|(\d*))(px|\%)?)?$/,\r
- cssLengthRegex = /^(((\d*(\.\d+))|(\d*))(px|em|ex|in|cm|mm|pt|pc|\%)?)?$/i,\r
- inlineStyleRegex = /^(\s*[\w-]+\s*:\s*[^:;]+(?:;|$))*$/;\r
-\r
- CKEDITOR.VALIDATE_OR = 1;\r
- CKEDITOR.VALIDATE_AND = 2;\r
-\r
- CKEDITOR.dialog.validate =\r
- {\r
- functions : function()\r
- {\r
- var args = arguments;\r
- return function()\r
- {\r
- /**\r
- * It's important for validate functions to be able to accept the value\r
- * as argument in addition to this.getValue(), so that it is possible to\r
- * combine validate functions together to make more sophisticated\r
- * validators.\r
- */\r
- var value = this && this.getValue ? this.getValue() : args[ 0 ];\r
-\r
- var msg = undefined,\r
- relation = CKEDITOR.VALIDATE_AND,\r
- functions = [], i;\r
-\r
- for ( i = 0 ; i < args.length ; i++ )\r
- {\r
- if ( typeof( args[i] ) == 'function' )\r
- functions.push( args[i] );\r
- else\r
- break;\r
- }\r
-\r
- if ( i < args.length && typeof( args[i] ) == 'string' )\r
- {\r
- msg = args[i];\r
- i++;\r
- }\r
-\r
- if ( i < args.length && typeof( args[i]) == 'number' )\r
- relation = args[i];\r
-\r
- var passed = ( relation == CKEDITOR.VALIDATE_AND ? true : false );\r
- for ( i = 0 ; i < functions.length ; i++ )\r
- {\r
- if ( relation == CKEDITOR.VALIDATE_AND )\r
- passed = passed && functions[i]( value );\r
- else\r
- passed = passed || functions[i]( value );\r
- }\r
-\r
- return !passed ? msg : true;\r
- };\r
- },\r
-\r
- regex : function( regex, msg )\r
- {\r
- /*\r
- * Can be greatly shortened by deriving from functions validator if code size\r
- * turns out to be more important than performance.\r
- */\r
- return function()\r
- {\r
- var value = this && this.getValue ? this.getValue() : arguments[0];\r
- return !regex.test( value ) ? msg : true;\r
- };\r
- },\r
-\r
- notEmpty : function( msg )\r
- {\r
- return this.regex( notEmptyRegex, msg );\r
- },\r
-\r
- integer : function( msg )\r
- {\r
- return this.regex( integerRegex, msg );\r
- },\r
-\r
- 'number' : function( msg )\r
- {\r
- return this.regex( numberRegex, msg );\r
- },\r
-\r
- 'cssLength' : function( msg )\r
- {\r
- return this.functions( function( val ){ return cssLengthRegex.test( CKEDITOR.tools.trim( val ) ); }, msg );\r
- },\r
-\r
- 'htmlLength' : function( msg )\r
- {\r
- return this.functions( function( val ){ return htmlLengthRegex.test( CKEDITOR.tools.trim( val ) ); }, msg );\r
- },\r
-\r
- 'inlineStyle' : function( msg )\r
- {\r
- return this.functions( function( val ){ return inlineStyleRegex.test( CKEDITOR.tools.trim( val ) ); }, msg );\r
- },\r
-\r
- equals : function( value, msg )\r
- {\r
- return this.functions( function( val ){ return val == value; }, msg );\r
- },\r
-\r
- notEqual : function( value, msg )\r
- {\r
- return this.functions( function( val ){ return val != value; }, msg );\r
- }\r
- };\r
-\r
- CKEDITOR.on( 'instanceDestroyed', function( evt )\r
- {\r
- // Remove dialog cover on last instance destroy.\r
- if ( CKEDITOR.tools.isEmpty( CKEDITOR.instances ) )\r
- {\r
- var currentTopDialog;\r
- while ( ( currentTopDialog = CKEDITOR.dialog._.currentTop ) )\r
- currentTopDialog.hide();\r
- removeCovers();\r
- }\r
-\r
- var dialogs = evt.editor._.storedDialogs;\r
- for ( var name in dialogs )\r
- dialogs[ name ].destroy();\r
-\r
- });\r
-\r
- })();\r
-\r
- // Extend the CKEDITOR.editor class with dialog specific functions.\r
- CKEDITOR.tools.extend( CKEDITOR.editor.prototype,\r
- /** @lends CKEDITOR.editor.prototype */\r
- {\r
- /**\r
- * Loads and opens a registered dialog.\r
- * @param {String} dialogName The registered name of the dialog.\r
- * @param {Function} callback The function to be invoked after dialog instance created.\r
- * @see CKEDITOR.dialog.add\r
- * @example\r
- * CKEDITOR.instances.editor1.openDialog( 'smiley' );\r
- * @returns {CKEDITOR.dialog} The dialog object corresponding to the dialog displayed. null if the dialog name is not registered.\r
- */\r
- openDialog : function( dialogName, callback )\r
- {\r
- if ( this.mode == 'wysiwyg' && CKEDITOR.env.ie )\r
- {\r
- var selection = this.getSelection();\r
- selection && selection.lock();\r
- }\r
-\r
- var dialogDefinitions = CKEDITOR.dialog._.dialogDefinitions[ dialogName ],\r
- dialogSkin = this.skin.dialog;\r
-\r
- if ( CKEDITOR.dialog._.currentTop === null )\r
- showCover( this );\r
-\r
- // If the dialogDefinition is already loaded, open it immediately.\r
- if ( typeof dialogDefinitions == 'function' && dialogSkin._isLoaded )\r
- {\r
- var storedDialogs = this._.storedDialogs ||\r
- ( this._.storedDialogs = {} );\r
-\r
- var dialog = storedDialogs[ dialogName ] ||\r
- ( storedDialogs[ dialogName ] = new CKEDITOR.dialog( this, dialogName ) );\r
-\r
- callback && callback.call( dialog, dialog );\r
- dialog.show();\r
-\r
- return dialog;\r
- }\r
- else if ( dialogDefinitions == 'failed' )\r
- {\r
- hideCover();\r
- throw new Error( '[CKEDITOR.dialog.openDialog] Dialog "' + dialogName + '" failed when loading definition.' );\r
- }\r
-\r
- var me = this;\r
-\r
- function onDialogFileLoaded( success )\r
- {\r
- var dialogDefinition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ],\r
- skin = me.skin.dialog;\r
-\r
- // Check if both skin part and definition is loaded.\r
- if ( !skin._isLoaded || loadDefinition && typeof success == 'undefined' )\r
- return;\r
-\r
- // In case of plugin error, mark it as loading failed.\r
- if ( typeof dialogDefinition != 'function' )\r
- CKEDITOR.dialog._.dialogDefinitions[ dialogName ] = 'failed';\r
-\r
- me.openDialog( dialogName, callback );\r
- }\r
-\r
- if ( typeof dialogDefinitions == 'string' )\r
- {\r
- var loadDefinition = 1;\r
- CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( dialogDefinitions ), onDialogFileLoaded, null, 0, 1 );\r
- }\r
-\r
- CKEDITOR.skins.load( this, 'dialog', onDialogFileLoaded );\r
-\r
- return null;\r
- }\r
- });\r
-})();\r
-\r
-CKEDITOR.plugins.add( 'dialog',\r
- {\r
- requires : [ 'dialogui' ]\r
- });\r
-\r
-// Dialog related configurations.\r
-\r
-/**\r
- * The color of the dialog background cover. It should be a valid CSS color\r
- * string.\r
- * @name CKEDITOR.config.dialog_backgroundCoverColor\r
- * @type String\r
- * @default 'white'\r
- * @example\r
- * config.dialog_backgroundCoverColor = 'rgb(255, 254, 253)';\r
- */\r
-\r
-/**\r
- * The opacity of the dialog background cover. It should be a number within the\r
- * range [0.0, 1.0].\r
- * @name CKEDITOR.config.dialog_backgroundCoverOpacity\r
- * @type Number\r
- * @default 0.5\r
- * @example\r
- * config.dialog_backgroundCoverOpacity = 0.7;\r
- */\r
-\r
-/**\r
- * If the dialog has more than one tab, put focus into the first tab as soon as dialog is opened.\r
- * @name CKEDITOR.config.dialog_startupFocusTab\r
- * @type Boolean\r
- * @default false\r
- * @example\r
- * config.dialog_startupFocusTab = true;\r
- */\r
-\r
-/**\r
- * The distance of magnetic borders used in moving and resizing dialogs,\r
- * measured in pixels.\r
- * @name CKEDITOR.config.dialog_magnetDistance\r
- * @type Number\r
- * @default 20\r
- * @example\r
- * config.dialog_magnetDistance = 30;\r
- */\r
-\r
-/**\r
- * The guideline 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
- * <p>Note that this event is called only the first time a specific dialog is\r
- * opened. Successive openings will use the cached dialog, and this event will\r
- * not get fired.</p>\r
- * @name CKEDITOR#dialogDefinition\r
- * @event\r
- * @param {CKEDITOR.dialog.definition} data The dialog defination that\r
- * is being loaded.\r
- * @param {CKEDITOR.editor} editor The editor instance that will use the\r
- * dialog.\r
- */\r
-\r
-/**\r
- * Fired when a tab is going to be selected in a dialog\r
- * @name CKEDITOR.dialog#selectPage\r
- * @event\r
- * @param {String} page The id of the page that it's gonna be selected.\r
- * @param {String} currentPage The id of the current page.\r
- */\r
-\r
-/**\r
- * Fired when the user tries to dismiss a dialog\r
- * @name CKEDITOR.dialog#cancel\r
- * @event\r
- * @param {Boolean} hide Whether the event should proceed or not.\r
- */\r
-\r
-/**\r
- * Fired when the user tries to confirm a dialog\r
- * @name CKEDITOR.dialog#ok\r
- * @event\r
- * @param {Boolean} hide Whether the event should proceed or not.\r
- */\r
-\r
-/**\r
- * Fired when a dialog is shown\r
- * @name CKEDITOR.dialog#show\r
- * @event\r
- */\r
-\r
-/**\r
- * Fired when a dialog is shown\r
- * @name CKEDITOR.editor#dialogShow\r
- * @event\r
- */\r
-\r
-/**\r
- * Fired when a dialog is hidden\r
- * @name CKEDITOR.dialog#hide\r
- * @event\r
- */\r
-\r
-/**\r
- * Fired when a dialog is hidden\r
- * @name CKEDITOR.editor#dialogHide\r
- * @event\r
- */\r
-\r
-/**\r
- * Fired when a dialog is being resized. The event is fired on\r
- * both the 'CKEDITOR.dialog' object and the dialog instance\r
- * since 3.5.3, previously it's available only in the global object.\r
- * @name CKEDITOR.dialog#resize\r
- * @since 3.5\r
- * @event\r
- * @param {CKEDITOR.dialog} dialog The dialog being resized (if\r
- * it's fired on the dialog itself, this parameter isn't sent).\r
- * @param {String} skin The skin name.\r
- * @param {Number} width The new width.\r
- * @param {Number} height The new height.\r
- */\r