X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Fdialog%2Fplugin.js;h=13f632719684082337990ceab0de6d28c1aa0105;hb=039a051ccf3901311661022a30afd60fc38130c9;hp=ee8d0e6d1c151dd8b668dc53e8275a0a9a423168;hpb=e7789c1ad838194d45eeee6ac2eb6e55f5cf35a1;p=ckeditor.git diff --git a/_source/plugins/dialog/plugin.js b/_source/plugins/dialog/plugin.js index ee8d0e6..13f6327 100644 --- a/_source/plugins/dialog/plugin.js +++ b/_source/plugins/dialog/plugin.js @@ -33,6 +33,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; (function() { + var cssLength = CKEDITOR.tools.cssLength; function isTabVisible( tabId ) { return !!this._.tabs[ tabId ][ 0 ].$.offsetHeight; @@ -68,6 +69,30 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; return null; } + + function clearOrRecoverTextInputValue( container, isRecover ) + { + var inputs = container.$.getElementsByTagName( 'input' ); + for ( var i = 0, length = inputs.length; i < length ; i++ ) + { + var item = new CKEDITOR.dom.element( inputs[ i ] ); + + if ( item.getAttribute( 'type' ).toLowerCase() == 'text' ) + { + if ( isRecover ) + { + item.setAttribute( 'value', item.getCustomData( 'fake_value' ) || '' ); + item.removeCustomData( 'fake_value' ); + } + else + { + item.setCustomData( 'fake_value', item.getAttribute( 'value' ) ); + item.setAttribute( 'value', '' ); + } + } + } + } + /** * This is the base class for runtime dialog objects. An instance of this * class represents a single named dialog for a single editor instance. @@ -168,6 +193,9 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { this.on( 'ok', function( evt ) { + // Dialog confirm might probably introduce content changes (#5415). + editor.fire( 'saveSnapshot' ); + setTimeout( function () { editor.fire( 'saveSnapshot' ); }, 0 ); if ( definition.onOk.call( this, evt ) === false ) evt.data.hide = false; }); @@ -248,6 +276,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { if ( this.fire( 'cancel', { hide : true } ).hide !== false ) this.hide(); + evt.data.preventDefault(); }, this ); // Sort focus list according to tab order definitions. @@ -312,7 +341,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( me != CKEDITOR.dialog._.currentTop ) return; - var keystroke = evt.data.getKeystroke(); + var keystroke = evt.data.getKeystroke(), + rtl = editor.lang.dir == 'rtl'; processed = 0; if ( keystroke == 9 || keystroke == CKEDITOR.SHIFT + 9 ) @@ -345,7 +375,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; else if ( ( keystroke == 37 || keystroke == 39 ) && me._.tabBarMode ) { // Arrow keys - used for changing tabs. - nextId = ( keystroke == 37 ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) ); + nextId = ( keystroke == ( rtl ? 39 : 37 ) ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) ); me.selectPage( nextId ); me._.tabs[ nextId ][ 0 ].focus(); processed = 1; @@ -381,11 +411,6 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) ) dialogElement.on( 'keypress', focusKeyPressHandler, this ); - if ( CKEDITOR.env.ie6Compat ) - { - var coverDoc = coverElement.getChild( 0 ).getFrameDocument(); - coverDoc.on( 'keydown', focusKeydownHandler, this, null, 0 ); - } } ); this.on( 'hide', function() { @@ -407,7 +432,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; setupFocus(); if ( editor.config.dialog_startupFocusTab - && me._.tabIdList.length > 1 ) + && me._.pageCount > 1 ) { me._.tabBarMode = true; me._.tabs[ me._.currentTabId ][ 0 ].focus(); @@ -472,16 +497,21 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // Insert the tabs and contents. for ( var i = 0 ; i < definition.contents.length ; i++ ) - this.addPage( definition.contents[i] ); + { + var page = definition.contents[i]; + page && this.addPage( page ); + } - this.parts['tabs'].on( 'click', function( evt ) + this.parts[ 'tabs' ].on( 'click', function( evt ) { var target = evt.data.getTarget(); // If we aren't inside a tab, bail out. if ( target.hasClass( 'cke_dialog_tab' ) ) { + // Get the ID of the tab, without the 'cke_' prefix and the unique number suffix. var id = target.$.id; - this.selectPage( id.substr( 0, id.lastIndexOf( '_' ) ) ); + this.selectPage( id.substring( 4, id.lastIndexOf( '_' ) ) ); + if ( this._.tabBarMode ) { this._.tabBarMode = false; @@ -541,6 +571,12 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; CKEDITOR.dialog.prototype = { + destroy : function() + { + this.hide(); + this._.element.remove(); + }, + /** * Resizes the dialog. * @param {Number} width The width of the dialog in pixels. @@ -657,7 +693,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( !( element.getParent() && element.getParent().equals( CKEDITOR.document.getBody() ) ) ) element.appendTo( CKEDITOR.document.getBody() ); else - return; + element.setStyle( 'display', 'block' ); // FIREFOX BUG: Fix vanishing caret for Firefox 2 or Gecko 1.8. if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 ) @@ -674,12 +710,12 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // First, set the dialog to an appropriate size. this.resize( definition.minWidth, definition.minHeight ); - // Select the first tab by default. - this.selectPage( this.definition.contents[0].id ); - // Reset all inputs back to their default value. this.reset(); + // Select the first tab by default. + this.selectPage( this.definition.contents[0].id ); + // Set z-index. if ( CKEDITOR.dialog._.currentZIndex === null ) CKEDITOR.dialog._.currentZIndex = this._.editor.config.baseFloatZIndex; @@ -691,7 +727,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { CKEDITOR.dialog._.currentTop = this; this._.parentDialog = null; - addCover( this._.editor ); + showCover( this._.editor ); element.on( 'keydown', accessKeyDownHandler ); element.on( CKEDITOR.env.opera ? 'keypress' : 'keyup', accessKeyUpHandler ); @@ -751,7 +787,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; for ( var i in this._.contents ) { for ( var j in this._.contents[i] ) - fn( this._.contents[i][j]); + fn( this._.contents[i][j] ); } return this; }, @@ -764,7 +800,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; */ reset : (function() { - var fn = function( widget ){ if ( widget.reset ) widget.reset(); }; + var fn = function( widget ){ if ( widget.reset ) widget.reset( 1 ); }; return function(){ this.foreach( fn ); return this; }; })(), @@ -795,23 +831,24 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; */ hide : function() { + if ( !this.parts.dialog.isVisible() ) + return; + this.fire( 'hide', {} ); this._.editor.fire( 'dialogHide', this ); - - // Remove the dialog's element from the root document. var element = this._.element; - if ( !element.getParent() ) - return; - - element.remove(); + element.setStyle( 'display', 'none' ); this.parts.dialog.setStyle( 'visibility', 'hidden' ); - // Unregister all access keys associated with this dialog. unregisterAccessKey( this ); + // Close any child(top) dialogs first. + while( CKEDITOR.dialog._.currentTop != this ) + CKEDITOR.dialog._.currentTop.hide(); + // Maintain dialog ordering and remove cover if needed. if ( !this._.parentDialog ) - removeCover(); + hideCover(); else { var parentElement = this._.parentDialog.getElement().getFirst(); @@ -844,7 +881,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; else CKEDITOR.dialog._.currentZIndex -= 10; - + delete this._.parentDialog; // Reset the initial values of the dialog. this.foreach( function( contentObj ) { contentObj.resetInitValue && contentObj.resetInitValue(); } ); }, @@ -874,7 +911,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; page.setAttribute( 'role', 'tabpanel' ); var env = CKEDITOR.env; - var tabId = contents.id + '_' + CKEDITOR.tools.getNextNumber(), + var tabId = 'cke_' + contents.id + '_' + CKEDITOR.tools.getNextNumber(), tab = CKEDITOR.dom.element.createFromHtml( [ ' 0 ? ' cke_last' : 'cke_first' ), @@ -934,6 +971,13 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; */ selectPage : function( id ) { + if ( this._.currentTabId == id ) + return; + + // Returning true means that the event has been canceled + if ( this.fire( 'selectPage', { page : id, currentPage : this._.currentTabId } ) === true ) + return; + // Hide the non-selected tabs and pages. for ( var i in this._.tabs ) { @@ -947,9 +991,24 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; page.setAttribute( 'aria-hidden', i != id ); } - var selected = this._.tabs[id]; - selected[0].addClass( 'cke_dialog_tab_selected' ); - selected[1].show(); + var selected = this._.tabs[ id ]; + selected[ 0 ].addClass( 'cke_dialog_tab_selected' ); + + // [IE] an invisible input[type='text'] will enlarge it's width + // if it's value is long when it shows, so we clear it's value + // before it shows and then recover it (#5649) + if ( CKEDITOR.env.ie6Compat || CKEDITOR.env.ie7Compat ) + { + clearOrRecoverTextInputValue( selected[ 1 ] ); + selected[ 1 ].show(); + setTimeout( function() + { + clearOrRecoverTextInputValue( selected[ 1 ], 1 ); + }, 0 ); + } + else + selected[ 1 ].show(); + this._.currentTabId = id; this._.currentTabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, id ); }, @@ -1372,7 +1431,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // Transform the contents entries in contentObjects. var contents = dialogDefinition.contents; for ( var i = 0, content ; ( content = contents[i] ) ; i++ ) - contents[ i ] = new contentObject( dialog, content ); + contents[ i ] = content && new contentObject( dialog, content ); CKEDITOR.tools.extend( this, dialogDefinition ); }; @@ -1577,7 +1636,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( CKEDITOR.env.ie6Compat ) { - var coverDoc = coverElement.getChild( 0 ).getFrameDocument(); + var coverDoc = currentCover.getChild( 0 ).getFrameDocument(); coverDoc.removeListener( 'mousemove', mouseMoveHandler ); coverDoc.removeListener( 'mouseup', mouseUpHandler ); } @@ -1595,7 +1654,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( CKEDITOR.env.ie6Compat ) { - var coverDoc = coverElement.getChild( 0 ).getFrameDocument(); + var coverDoc = currentCover.getChild( 0 ).getFrameDocument(); coverDoc.on( 'mousemove', mouseMoveHandler ); coverDoc.on( 'mouseup', mouseUpHandler ); } @@ -1653,7 +1712,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( CKEDITOR.env.ie6Compat ) { - var coverDoc = coverElement.getChild( 0 ).getFrameDocument(); + var coverDoc = currentCover.getChild( 0 ).getFrameDocument(); coverDoc.on( 'mousemove', mouseMoveHandler, dialog, { part : partName } ); coverDoc.on( 'mouseup', mouseUpHandler, dialog, { part : partName } ); } @@ -1724,7 +1783,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( CKEDITOR.env.ie6Compat ) { - var coverDoc = coverElement.getChild( 0 ).getFrameDocument(); + var coverDoc = currentCover.getChild( 0 ).getFrameDocument(); coverDoc.removeListener( 'mouseup', mouseUpHandler ); coverDoc.removeListener( 'mousemove', mouseMoveHandler ); } @@ -1748,25 +1807,34 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; } var resizeCover; - var coverElement; + // Caching resuable covers and allowing only one cover + // on screen. + var covers = {}, + currentCover; - var addCover = function( editor ) + function showCover( editor ) { var win = CKEDITOR.document.getWindow(); + var config = editor.config, + backgroundColorStyle = config.dialog_backgroundCoverColor || 'white', + backgroundCoverOpacity = config.dialog_backgroundCoverOpacity, + baseFloatZIndex = config.baseFloatZIndex, + coverKey = CKEDITOR.tools.genKey( + backgroundColorStyle, + backgroundCoverOpacity, + baseFloatZIndex ), + coverElement = covers[ coverKey ]; if ( !coverElement ) { - var backgroundColorStyle = editor.config.dialog_backgroundCoverColor || 'white'; - var html = [ '
' + '" class="cke_dialog_background_cover">' ]; - if ( CKEDITOR.env.ie6Compat ) { // Support for custom document.domain in IE. @@ -1802,14 +1870,19 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; html.push( '
' ); coverElement = CKEDITOR.dom.element.createFromHtml( html.join( '' ) ); - } + coverElement.setOpacity( backgroundCoverOpacity != undefined ? backgroundCoverOpacity : 0.5 ); - var element = coverElement; + coverElement.appendTo( CKEDITOR.document.getBody() ); + covers[ coverKey ] = coverElement; + } + else + coverElement. show(); + currentCover = coverElement; var resizeFunc = function() { var size = win.getViewPaneSize(); - element.setStyles( + coverElement.setStyles( { width : size.width + 'px', height : size.height + 'px' @@ -1820,7 +1893,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { var pos = win.getScrollPosition(), cursor = CKEDITOR.dialog._.currentTop; - element.setStyles( + coverElement.setStyles( { left : pos.x + 'px', top : pos.y + 'px' @@ -1852,20 +1925,15 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; }, 0 ); scrollFunc(); } + } - var opacity = editor.config.dialog_backgroundCoverOpacity; - element.setOpacity( typeof opacity != 'undefined' ? opacity : 0.5 ); - - element.appendTo( CKEDITOR.document.getBody() ); - }; - - var removeCover = function() + function hideCover() { - if ( !coverElement ) + if ( !currentCover ) return; var win = CKEDITOR.document.getWindow(); - coverElement.remove(); + currentCover.hide(); win.removeListener( 'resize', resizeCover ); if ( CKEDITOR.env.ie6Compat ) @@ -1877,7 +1945,14 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; }, 0 ); } resizeCover = null; - }; + } + + function removeCovers() + { + for ( var coverId in covers ) + covers[ coverId ].remove(); + covers = {}; + } var accessKeyProcessors = {}; @@ -2022,7 +2097,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; styles = ( stylesArg && stylesArg.call ? stylesArg( elementDefinition ) : stylesArg ) || {}, attributes = ( attributesArg && attributesArg.call ? attributesArg( elementDefinition ) : attributesArg ) || {}, innerHTML = ( contentsArg && contentsArg.call ? contentsArg.call( this, dialog, elementDefinition ) : contentsArg ) || '', - domId = this.domId = attributes.id || CKEDITOR.tools.getNextNumber() + '_uiElement', + domId = this.domId = attributes.id || CKEDITOR.tools.getNextId() + '_uiElement', id = this.id = elementDefinition.id, i; @@ -2174,14 +2249,14 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( widths ) { if ( widths[i] ) - styles.push( 'width:' + CKEDITOR.tools.cssLength( widths[i] ) ); + styles.push( 'width:' + cssLength( widths[i] ) ); } else styles.push( 'width:' + Math.floor( 100 / childHtmlList.length ) + '%' ); if ( height ) - styles.push( 'height:' + CKEDITOR.tools.cssLength( height ) ); + styles.push( 'height:' + cssLength( height ) ); if ( elementDefinition && elementDefinition.padding != undefined ) - styles.push( 'padding:' + CKEDITOR.tools.cssLength( elementDefinition.padding ) ); + styles.push( 'padding:' + cssLength( elementDefinition.padding ) ); if ( styles.length > 0 ) html.push( 'style="' + styles.join('; ') + '" ' ); html.push( '>', childHtmlList[i], '' ); @@ -2234,7 +2309,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; */ vbox : function( dialog, childObjList, childHtmlList, htmlList, elementDefinition ) { - if (arguments.length < 3 ) + if ( arguments.length < 3 ) return; this._ || ( this._ = {} ); @@ -2249,7 +2324,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; html.push( 'style="' ); if ( elementDefinition && elementDefinition.expand ) html.push( 'height:100%;' ); - html.push( 'width:' + CKEDITOR.tools.cssLength( width || '100%' ), ';' ); + html.push( 'width:' + cssLength( width || '100%' ), ';' ); html.push( '"' ); html.push( 'align="', CKEDITOR.tools.htmlEncode( ( elementDefinition && elementDefinition.align ) || ( dialog.getParentEditor().lang.dir == 'ltr' ? 'left' : 'right' ) ), '" ' ); @@ -2260,13 +2335,13 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; var styles = []; html.push( ' 0 ) html.push( 'style="', styles.join( '; ' ), '" ' ); html.push( ' class="cke_dialog_ui_vbox_child">', childHtmlList[i], '' ); @@ -2320,14 +2395,15 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; /** * Sets the value of this dialog UI object. * @param {Object} value The new value. + * @param {Boolean} noChangeEvent Internal commit, to supress 'change' event on this element. * @returns {CKEDITOR.dialog.uiElement} The current UI element. * @example * uiElement.setValue( 'Dingo' ); */ - setValue : function( value ) + setValue : function( value, noChangeEvent ) { this.getInputElement().setValue( value ); - this.fire( 'change', { value : value } ); + !noChangeEvent && this.fire( 'change', { value : value } ); return this; }, @@ -2657,7 +2733,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // undo support should dedicate to specific dialog implementation. canUndo: false, - editorFocus : CKEDITOR.env.ie + editorFocus : CKEDITOR.env.ie || CKEDITOR.env.webkit }; (function() @@ -2777,6 +2853,24 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; return this.functions( function( val ){ return val != value; }, msg ); } }; + + CKEDITOR.on( 'instanceDestroyed', function( evt ) + { + // Remove dialog cover on last instance destroy. + if ( CKEDITOR.tools.isEmpty( CKEDITOR.instances ) ) + { + var currentTopDialog; + while ( ( currentTopDialog = CKEDITOR.dialog._.currentTop ) ) + currentTopDialog.hide(); + removeCovers(); + } + + var dialogs = evt.editor._.storedDialogs; + for ( var name in dialogs ) + dialogs[ name ].destroy(); + + }); + })(); })(); @@ -2911,3 +3005,11 @@ CKEDITOR.plugins.add( 'dialog', * @param {CKEDITOR.editor} editor The editor instance that will use the * dialog. */ + +/** + * Fired when a tab is going to be selected in a dialog + * @name dialog#selectPage + * @event + * @param String page The id of the page that it's gonna be selected. + * @param String currentPage The id of the current page. + */