X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Fdialog%2Fplugin.js;h=ee8d0e6d1c151dd8b668dc53e8275a0a9a423168;hb=e7789c1ad838194d45eeee6ac2eb6e55f5cf35a1;hp=c052120dcb0c6119e0aff1dd9ee387e97097ae27;hpb=ea7e3453c7b0f023b050aca6d9f83ab372860d91;p=ckeditor.git diff --git a/_source/plugins/dialog/plugin.js b/_source/plugins/dialog/plugin.js index c052120..ee8d0e6 100644 --- a/_source/plugins/dialog/plugin.js +++ b/_source/plugins/dialog/plugin.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -7,11 +7,6 @@ For licensing, see LICENSE.html or http://ckeditor.com/license * @fileOverview The floating dialog plugin. */ -CKEDITOR.plugins.add( 'dialog', - { - requires : [ 'dialogui' ] - }); - /** * No resize for this dialog. * @constant @@ -73,9 +68,6 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; return null; } - // Stores dialog related data from skin definitions. e.g. margin sizes. - var skinData = {}; - /** * This is the base class for runtime dialog objects. An instance of this * class represents a single named dialog for a single editor instance. @@ -89,11 +81,6 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; { // Load the dialog definition. var definition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ]; - if ( !definition ) - { - console.log( 'Error: The dialog "' + dialogName + '" is not defined.' ); - return; - } // Completes the definition with the default values. definition = CKEDITOR.tools.extend( definition( editor ), defaultDialogDefinition ); @@ -105,14 +92,6 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // functions. definition = new definitionObject( this, definition ); - // Fire the "dialogDefinition" event, making it possible to customize - // the dialog definition. - this.definition = definition = CKEDITOR.fire( 'dialogDefinition', - { - name : dialogName, - definition : definition - } - , editor ).definition; var doc = CKEDITOR.document; @@ -148,6 +127,12 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; this.parts = themeBuilt.parts; + CKEDITOR.tools.setTimeout( function() + { + editor.fire( 'ariaWidget', this.parts.contents ); + }, + 0, this ); + // Set the startup styles for the dialog, avoiding it enlarging the // page size on the dialog creation. this.parts.dialog.setStyles( @@ -161,6 +146,14 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // Call the CKEDITOR.event constructor to initialize this instance. CKEDITOR.event.call( this ); + // Fire the "dialogDefinition" event, making it possible to customize + // the dialog definition. + this.definition = definition = CKEDITOR.fire( 'dialogDefinition', + { + name : dialogName, + definition : definition + } + , editor ).definition; // Initialize load, show, hide, ok and cancel events. if ( definition.onLoad ) this.on( 'load', definition.onLoad ); @@ -257,6 +250,26 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; this.hide(); }, this ); + // Sort focus list according to tab order definitions. + function setupFocus() + { + var focusList = me._.focusList; + focusList.sort( function( a, b ) + { + // Mimics browser tab order logics; + if ( a.tabIndex != b.tabIndex ) + return b.tabIndex - a.tabIndex; + // Sort is not stable in some browsers, + // fall-back the comparator to 'focusIndex'; + else + return a.focusIndex - b.focusIndex; + }); + + var size = focusList.length; + for ( var i = 0; i < size; i++ ) + focusList[ i ].focusIndex = i; + } + function changeFocus( forward ) { var focusList = me._.focusList, @@ -264,24 +277,44 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; if ( focusList.length < 1 ) return; - var currentIndex = ( me._.currentFocusIndex + offset + focusList.length ) % focusList.length; + var current = me._.currentFocusIndex; + + // Trigger the 'blur' event of any input element before anything, + // since certain UI updates may depend on it. + try + { + focusList[ current ].getInputElement().$.blur(); + } + catch( e ){} + + var startIndex = ( current + offset + focusList.length ) % focusList.length, + currentIndex = startIndex; while ( !focusList[ currentIndex ].isFocusable() ) { currentIndex = ( currentIndex + offset + focusList.length ) % focusList.length; - if ( currentIndex == me._.currentFocusIndex ) + if ( currentIndex == startIndex ) break; } focusList[ currentIndex ].focus(); + + // Select whole field content. + if ( focusList[ currentIndex ].type == 'text' ) + focusList[ currentIndex ].select(); } + this.changeFocus = changeFocus; + + var processed; + function focusKeydownHandler( evt ) { // If I'm not the top dialog, ignore. if ( me != CKEDITOR.dialog._.currentTop ) return; - var keystroke = evt.data.getKeystroke(), - processed = false; + var keystroke = evt.data.getKeystroke(); + + processed = 0; if ( keystroke == 9 || keystroke == CKEDITOR.SHIFT + 9 ) { var shiftPressed = ( keystroke == CKEDITOR.SHIFT + 9 ); @@ -300,14 +333,14 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; changeFocus( !shiftPressed ); } - processed = true; + processed = 1; } - else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode ) + else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode && me.getPageCount() > 1 ) { // Alt-F10 puts focus into the current tab item in the tab bar. me._.tabBarMode = true; me._.tabs[ me._.currentTabId ][ 0 ].focus(); - processed = true; + processed = 1; } else if ( ( keystroke == 37 || keystroke == 39 ) && me._.tabBarMode ) { @@ -315,7 +348,15 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; nextId = ( keystroke == 37 ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) ); me.selectPage( nextId ); me._.tabs[ nextId ][ 0 ].focus(); - processed = true; + processed = 1; + } + else if ( ( keystroke == 13 || keystroke == 32 ) && me._.tabBarMode ) + { + this.selectPage( this._.currentTabId ); + this._.tabBarMode = false; + this._.currentFocusIndex = -1; + changeFocus( true ); + processed = 1; } if ( processed ) @@ -325,10 +366,20 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; } } + function focusKeyPressHandler( evt ) + { + processed && evt.data.preventDefault(); + } + + var dialogElement = this._.element; // Add the dialog keyboard handlers. this.on( 'show', function() { - CKEDITOR.document.on( 'keydown', focusKeydownHandler, this, null, 0 ); + dialogElement.on( 'keydown', focusKeydownHandler, this, null, 0 ); + // Some browsers instead, don't cancel key events in the keydown, but in the + // keypress. So we must do a longer trip in those cases. (#4531) + if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) ) + dialogElement.on( 'keypress', focusKeyPressHandler, this ); if ( CKEDITOR.env.ie6Compat ) { @@ -338,7 +389,9 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; } ); this.on( 'hide', function() { - CKEDITOR.document.removeListener( 'keydown', focusKeydownHandler ); + dialogElement.removeListener( 'keydown', focusKeydownHandler ); + if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) ) + dialogElement.removeListener( 'keypress', focusKeyPressHandler ); } ); this.on( 'iframeAdded', function( evt ) { @@ -349,10 +402,30 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; // Auto-focus logic in dialog. this.on( 'show', function() { - if ( !this._.hasFocus ) + // Setup tabIndex on showing the dialog instead of on loading + // to allow dynamic tab order happen in dialog definition. + setupFocus(); + + if ( editor.config.dialog_startupFocusTab + && me._.tabIdList.length > 1 ) + { + me._.tabBarMode = true; + me._.tabs[ me._.currentTabId ][ 0 ].focus(); + } + else if ( !this._.hasFocus ) { this._.currentFocusIndex = -1; - changeFocus( true ); + + // Decide where to put the initial focus. + if ( definition.onFocus ) + { + var initialFocus = definition.onFocus.call( this ); + // Focus the field that the user specified. + initialFocus && initialFocus.focus(); + } + // Focus the first field in layout order. + else + changeFocus( true ); /* * IE BUG: If the initial focus went into a non-text element (e.g. button), @@ -401,28 +474,22 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3; for ( var i = 0 ; i < definition.contents.length ; i++ ) this.addPage( definition.contents[i] ); - var tabRegex = /cke_dialog_tab(\s|$|_)/, - tabOuterRegex = /cke_dialog_tab(\s|$)/; this.parts['tabs'].on( 'click', function( evt ) { - var target = evt.data.getTarget(), firstNode = target, id, page; - + var target = evt.data.getTarget(); // If we aren't inside a tab, bail out. - if ( !( tabRegex.test( target.$.className ) || target.getName() == 'a' ) ) - return; - - // Find the outer