Ticket #3074: 3074_2.patch

File 3074_2.patch, 18.9 KB (added by Martin Kou, 12 years ago)
  • _source/plugins/dialogui/plugin.js

     
    208208                                        attributes.size = elementDefinition.size;
    209209
    210210                                // If user presses Enter in a text box, it implies clicking OK for the dialog.
    211                                 var me = this;
     211                                var me = this, keyPressedOnMe = false;
    212212                                dialog.on( 'load', function()
    213213                                        {
     214                                                me.getInputElement().on( 'keydown', function( evt )
     215                                                        {
     216                                                                if ( evt.data.getKeystroke() == 13 )
     217                                                                        keyPressedOnMe = true;
     218                                                        } );
    214219                                                me.getInputElement().on( 'keyup', function( evt )
    215220                                                        {
    216                                                                 if ( evt.data.$.keyCode == 13 )
     221                                                                if ( evt.data.getKeystroke() == 13 && keyPressedOnMe )
     222                                                                {
    217223                                                                        dialog.getButton( 'ok' ) && dialog.getButton( 'ok' ).click();
     224                                                                        keyPressedOnMe = false;
     225                                                                }
    218226                                                        } );
    219227                                        } );
    220228
     
    436444                                /** @ignore */
    437445                                var innerHTML = function()
    438446                                {
    439                                         return [ '<tbody><tr><td class="cke_dialog_ui_button_txt">',
    440                                                    CKEDITOR.tools.htmlEncode( elementDefinition.label ),
    441                                                    '</td></tr></tbody>' ].join( '' );
     447                                        var styles = [],
     448                                                align = elementDefinition.align || ( dialog.getParentEditor().lang.dir == 'ltr' ? 'left' : 'right' );
     449
     450                                        if ( elementDefinition.style )
     451                                        {
     452                                                var defStyle = CKEDITOR.tools.trim( elementDefinition.style );
     453                                                styles.push( defStyle );
     454                                                if ( defStyle.charAt( defStyle.length - 1 ) != ';' )
     455                                                        styles.push( ';' );
     456                                        }
     457
     458                                        // IE6 & 7 BUG: Need to set margin as well as align.
     459                                        if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 )
     460                                        {
     461                                                styles.push( [
     462                                                        'margin:',
     463                                                        'auto',
     464                                                        align == 'right' ? '0px' : 'auto',
     465                                                        'auto',
     466                                                        align == 'left' ? '0px' : 'auto' ].join( ' ' ), ';' );
     467                                        }
     468
     469                                        return [
     470                                                '<table align="', align, '" ', styles.length > 0 ? 'style="' + styles.join( '' ) + '">' : '>',
     471                                                '<tbody><tr><td class="cke_dialog_ui_button_txt">',
     472                                                CKEDITOR.tools.htmlEncode( elementDefinition.label ),
     473                                                '</td></tr></tbody></table>'
     474                                        ].join( '' );
    442475                                };
    443476
    444477                                // Add OnClick event to this input.
     
    449482                                dialog.on( 'load', function( eventInfo )
    450483                                                {
    451484                                                        var element = this.getElement();
    452                                                         element.on( 'mousedown', function( evt )
    453                                                                 {
    454                                                                         // If button is disabled, don't do anything.
    455                                                                         if ( me._.disabled )
    456                                                                                 return;
     485                                                        (function()
     486                                                        {
     487                                                                element.on( 'mousedown', function( evt )
     488                                                                        {
     489                                                                                // If button is disabled, don't do anything.
     490                                                                                if ( me._.disabled )
     491                                                                                        return;
    457492
    458                                                                         // Change styles to indicate the button is being clicked.
    459                                                                         me.getElement().addClass( 'active' );
     493                                                                                // Store the currently active button.
     494                                                                                CKEDITOR.ui.dialog.button._.activeButton = [ me, me.getElement() ];
     495                                                                        } );
    460496
    461                                                                         // Store the currently active button.
    462                                                                         CKEDITOR.ui.dialog.button._.activeButton = [ me, me.getElement() ];
    463                                                                 });
     497                                                                element.on( 'keydown', function( evt )
     498                                                                        {
     499                                                                                // Click if Enter is pressed.
     500                                                                                if ( evt.data.$.keyCode == 13 )
     501                                                                                {
     502                                                                                        me.fire( 'click', { dialog : me.getDialog() } );
     503                                                                                        evt.data.preventDefault();
     504                                                                                }
     505                                                                        } );
     506                                                        })();
    464507
    465508                                                        // IE BUG: Padding attributes are ignored for <td> cells.
    466509                                                        if ( CKEDITOR.env.ie )
    467                                                                 element.getChild( [0, 0, 0] ).$.innerHTML += '';
     510                                                                element.getChild( [0, 0, 0, 0] ).$.innerHTML += '';
    468511
    469512                                                        if ( !eventInfo.data.buttonHandlerRegistered )
    470513                                                        {
     
    477520                                                                                if ( !activeButton )
    478521                                                                                        return;
    479522
    480                                                                                 // Change styles to remove active status.
    481                                                                                 activeButton[1].removeClass( 'active' );
    482 
    483523                                                                                // Fire the click event - but only if the
    484524                                                                                // active button is the same as target.
    485                                                                                 if ( activeButton[1].equals( target.getAscendant( 'table' ) ) )
     525                                                                                if ( activeButton[1].equals( target.getAscendant( 'a' ) ) )
    486526                                                                                        activeButton[0].fire( 'click', { dialog : activeButton[0].getDialog() } );
    487527
    488528                                                                                // Clear active button flag.
    489529                                                                                CKEDITOR.ui.dialog.button._.activeButton = null;
    490                                                                         });
     530                                                                        } );
    491531
    492532                                                                eventInfo.data.buttonHandlerRegistered = true;
    493533                                                        }
    494534
    495                                                         this.getElement().unselectable();
     535                                                        this.getElement().getFirst().unselectable();
    496536                                                }, this );
    497537
    498                                 var styles = {},
    499                                         align = elementDefinition.align || ( dialog.getParentEditor().lang.dir == 'ltr' ? 'left' : 'right' );
     538                                var outerDefinition = CKEDITOR.tools.extend( {}, elementDefinition );
     539                                delete outerDefinition.style;
    500540
    501                                 // IE6 & 7 BUG: Need to set margin as well as align.
    502                                 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 )
    503                                 {
    504                                         styles.margin = [
    505                                                 'auto',
    506                                                 align == 'right' ? '0px' : 'auto',
    507                                                 'auto',
    508                                                 align == 'left' ? '0px' : 'auto' ].join( ' ' );
    509                                 }
    510 
    511                                 CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, htmlList, 'table', styles,
    512                                                 { align : align }, innerHTML );
     541                                CKEDITOR.ui.dialog.uiElement.call( this, dialog, outerDefinition, htmlList, 'a', { display : 'block', outline : 'none' },
     542                                                { href : 'javascript:void(0);', title : elementDefinition.label, hidefocus : 'true' },
     543                                                innerHTML );
    513544                        },
    514545
    515546                        /**
     
    779810                                {
    780811                                        if ( !this._.disabled )
    781812                                                return this.fire( 'click', { dialog : this._.dialog } );
     813                                        this.getElement().$.blur();
    782814                                },
    783815
    784816                                /**
     
    801833                                        this.getElement().addClass( 'disabled' );
    802834                                },
    803835
     836                                isVisible : function()
     837                                {
     838                                        return !!this.getElement().$.firstChild.offsetHeight;
     839                                },
     840
     841                                isEnabled : function()
     842                                {
     843                                        return !this._.disabled;
     844                                },
     845
    804846                                /**
    805847                                 * Defines the onChange event and onClick for button element definitions.
    806848                                 * @field
     
    823865                                 */
    824866                                accessKeyUp : function()
    825867                                {
    826                                         this.getElement().removeClass( 'active' );
    827868                                        this.click();
    828869                                },
    829870
     
    834875                                 */
    835876                                accessKeyDown : function()
    836877                                {
    837                                         this.getElement().addClass( 'active' );
    838                                 }
     878                                        this.focus();
     879                                },
     880
     881                                keyboardFocusable : true
    839882                        }, true );
    840883
    841884        CKEDITOR.ui.dialog.textInput.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.labeledElement,
     
    896939                                {
    897940                                        value = value || '';
    898941                                        return CKEDITOR.ui.dialog.uiElement.prototype.setValue.call( this, value );
    899                                 }
     942                                },
     943
     944                                keyboardFocusable : true
    900945                        }, commonPrototype, true );
    901946
    902947        CKEDITOR.ui.dialog.textarea.prototype = new CKEDITOR.ui.dialog.textInput();
     
    9661011                                        while ( selectElement.length > 0 )
    9671012                                                selectElement.remove( 0 );
    9681013                                        return this;
    969                                 }
     1014                                },
     1015
     1016                                keyboardFocusable : true
    9701017                        }, commonPrototype, true );
    9711018
    9721019        CKEDITOR.ui.dialog.checkbox.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement,
     
    10401087                                                }
    10411088                                                return null;
    10421089                                        }
    1043                                 }
     1090                                },
     1091
     1092                                keyboardFocusable : true
    10441093                        }, commonPrototype, true );
    10451094
    10461095        CKEDITOR.ui.dialog.radio.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement,
     
    11281177                                                }
    11291178                                                return null;
    11301179                                        }
    1131                                 }
     1180                                },
     1181
     1182                                keyboardFocusable : true
    11321183                        }, commonPrototype, true );
    11331184
    11341185        CKEDITOR.ui.dialog.file.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.labeledElement,
     
    11931244                                 * @type Object
    11941245                                 * @example
    11951246                                 */
    1196                                 eventProcessors : commonEventProcessors
     1247                                eventProcessors : commonEventProcessors,
     1248
     1249                                keyboardFocusable : true
    11971250                        }, true );
    11981251
    11991252        CKEDITOR.ui.dialog.fileButton.prototype = new CKEDITOR.ui.dialog.button;
  • _source/plugins/dialog/plugin.js

     
    3838
    3939(function()
    4040{
     41        function isTabVisible( tabId )
     42        {
     43                return !!this._.tabs[ tabId ][ 0 ].$.offsetHeight;
     44        }
     45
     46        function getPreviousVisibleTab()
     47        {
     48                var tabId = this._.currentTabId,
     49                        length = this._.tabIdList.length,
     50                        tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId ) + length;
     51
     52                for ( var i = tabIndex - 1 ; i > tabIndex - length ; i-- )
     53                {
     54                        if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) )
     55                                return this._.tabIdList[ i % length ];
     56                }
     57
     58                return null;
     59        }
     60
     61        function getNextVisibleTab()
     62        {
     63                var tabId = this._.currentTabId,
     64                        length = this._.tabIdList.length,
     65                        tabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, tabId );
     66
     67                for ( var i = tabIndex + 1 ; i < tabIndex + length ; i++ )
     68                {
     69                        if ( isTabVisible.call( this, this._.tabIdList[ i % length ] ) )
     70                                return this._.tabIdList[ i % length ];
     71                }
     72
     73                return null;
     74        }
     75       
    4176        /**
    4277         * This is the base class for runtime dialog objects. An instance of this
    4378         * class represents a single named dialog for a single editor instance.
     
    88123
    89124                        // Initialize the tab and page map.
    90125                        tabs : {},
     126                        tabIdList : [],
     127                        currentTabId : null,
     128                        currentTabIndex : null,
    91129                        pageCount : 0,
    92                         lastTab : null
     130                        lastTab : null,
     131                        tabBarMode : false,
     132
     133                        // Initialize the tab order array for input widgets.
     134                        focusList : [],
     135                        currentFocusIndex : 0,
     136                        hasFocus : false
    93137                };
    94138
    95139                /**
     
    251295                                                this.hide();
    252296                                }, this );
    253297
     298                function changeFocus( forward )
     299                {
     300                        var focusList = me._.focusList,
     301                                offset = forward ? 1 : -1;
     302                        if ( focusList.length < 1 )
     303                                return;
     304
     305                        var currentIndex = ( me._.currentFocusIndex + offset + focusList.length ) % focusList.length;
     306                        while ( !focusList[ currentIndex ].isFocusable() )
     307                        {
     308                                currentIndex = ( currentIndex + offset + focusList.length ) % focusList.length;
     309                                if ( currentIndex == me._.currentFocusIndex )
     310                                        break;
     311                        }
     312                        focusList[ currentIndex ].focus();
     313                }
     314
     315                function focusKeydownHandler( evt )
     316                {
     317                        // If I'm not the top dialog, ignore.
     318                        if ( me != CKEDITOR.dialog._.currentTop )
     319                                return;
     320
     321                        var keystroke = evt.data.getKeystroke(),
     322                                processed = false;
     323                        if ( keystroke == 9 || keystroke == CKEDITOR.SHIFT + 9 )
     324                        {
     325                                var shiftPressed = ( keystroke == CKEDITOR.SHIFT + 9 );
     326
     327                                // Handling Tab and Shift-Tab.
     328                                if ( me._.tabBarMode )
     329                                {
     330                                        // Change tabs.
     331                                        var nextId = shiftPressed ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me );
     332                                        me.selectPage( nextId );
     333                                        me._.tabs[ nextId ][ 0 ].getFirst().focus();
     334                                }
     335                                else
     336                                {
     337                                        // Change the focus of inputs.
     338                                        changeFocus( !shiftPressed );
     339                                }
     340                               
     341                                processed = true;
     342                        }
     343                        else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode )
     344                        {
     345                                // Alt-F10 puts focus into the current tab item in the tab bar.
     346                                me._.tabBarMode = true;
     347                                me._.tabs[ me._.currentTabId ][ 0 ].getFirst().focus();
     348                                processed = true;
     349                        }
     350                        else if ( ( keystroke == 37 || keystroke == 39 ) && me._.tabBarMode )
     351                        {
     352                                // Arrow keys - used for changing tabs.
     353                                var nextId = ( keystroke == 37 ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) );
     354                                me.selectPage( nextId );
     355                                me._.tabs[ nextId ][ 0 ].getFirst().focus();
     356                                processed = true;
     357                        }
     358
     359                        if ( processed )
     360                        {
     361                                evt.stop();
     362                                evt.data.preventDefault();
     363                        }
     364                }
     365
     366                // Add the dialog keyboard handlers.
     367                this.on( 'show', function()
     368                        {
     369                                CKEDITOR.document.on( 'keydown', focusKeydownHandler, this, null, 0 );
     370                                if ( CKEDITOR.env.ie6Compat )
     371                                {
     372                                        var coverDoc = new CKEDITOR.dom.document( frames( 'cke_dialog_background_iframe' ).document );
     373                                        coverDoc.on( 'keydown', focusKeydownHandler, this, null, 0 );
     374                                }
     375                        } );
     376                this.on( 'hide', function()
     377                        {
     378                                CKEDITOR.document.removeListener( 'keydown', focusKeydownHandler );
     379                        } );
     380
     381                // Auto-focus logic in dialog.
     382                this.on( 'show', function()
     383                        {
     384                                if ( !this._.hasFocus )
     385                                {
     386                                        this._.currentFocusIndex = -1;
     387                                        changeFocus( true );
     388                                }
     389                        }, this, null, 0xffffffff );
     390
    254391                // IE6 BUG: Text fields and text areas are only half-rendered the first time the dialog appears in IE6 (#2661).
    255392                // This is still needed after [2708] and [2709] because text fields in hidden TR tags are still broken.
    256393                if ( CKEDITOR.env.ie6Compat )
     
    281418                                        var target = evt.data.getTarget(), firstNode = target, id, page;
    282419
    283420                                        // If we aren't inside a tab, bail out.
    284                                         if ( !tabRegex.test( target.$.className ) )
     421                                        if ( !( tabRegex.test( target.$.className ) || target.getName() == 'a' ) )
    285422                                                return;
    286423
    287424                                        // Find the outer <td> container of the tab.
     
    291428                                        }
    292429                                        id = target.$.id.substr( 0, target.$.id.lastIndexOf( '_' ) );
    293430                                        this.selectPage( id );
     431
     432                                        if ( this._.tabBarMode )
     433                                        {
     434                                                this._.tabBarMode = false;
     435                                                this._.currentFocusIndex = -1;
     436                                                changeFocus( true );
     437                                        }
    294438                                }, this );
    295439
    296440                // Insert buttons.
     
    466610                        this._.dummyText.focus();
    467611                        this._.dummyText.$.select();
    468612
     613                        // Reset the hasFocus state.
     614                        this._.hasFocus = false;
     615
    469616                        // Execute onLoad for the first show.
    470617                        this.fireOnce( 'load', {} );
    471618                        this.fire( 'show', {} );
     
    577724                addPage : function( contents )
    578725                {
    579726                        var pageHtml = [],
    580                                 titleHtml = contents.title ? 'title="' + CKEDITOR.tools.htmlEncode( contents.title ) + '" ' : '',
     727                                titleHtml = contents.label ? ' title="' + CKEDITOR.tools.htmlEncode( contents.label ) + '"' : '',
    581728                                elements = contents.elements,
    582729                                vbox = CKEDITOR.dialog._.uiElementBuilders.vbox.build( this,
    583730                                                {
     
    590737                        // Create the HTML for the tab and the content block.
    591738                        var page = CKEDITOR.dom.element.createFromHtml( pageHtml.join( '' ) );
    592739                        var tab = CKEDITOR.dom.element.createFromHtml( [
    593                                         '<table><tbody><tr><td class="cke_dialog_tab" ', titleHtml, '>',
     740                                        '<table><tbody><tr><td class="cke_dialog_tab">',
     741                                        '<a href="javascript: void(0)"', titleHtml, ' style="display: block; outline: none;" hidefocus="true">',
    594742                                        '<table border="0" cellspacing="0" cellpadding="0"><tbody><tr>',
    595743                                                '<td class="cke_dialog_tab_left"></td>',
    596744                                                '<td class="cke_dialog_tab_center">',
    597745                                                        CKEDITOR.tools.htmlEncode( contents.label.replace( / /g, '\xa0' ) ),
    598746                                                '</td>',
    599747                                                '<td class="cke_dialog_tab_right"></td>',
    600                                         '</tr></tbody></table></td></tr></tbody></table>'
     748                                        '</tr></tbody></table></a></td></tr></tbody></table>'
    601749                                ].join( '' ) );
    602750                        tab = tab.getChild( [0,0,0] );
    603751
     
    614762
    615763                        // Take records for the tabs and elements created.
    616764                        this._.tabs[ contents.id ] = [ tab, page ];
     765                        this._.tabIdList.push( contents.id );
    617766                        this._.pageCount++;
    618767                        this._.lastTab = tab;
    619768                        var contentMap = this._.contents[ contents.id ] = {},
     
    665814                        var selected = this._.tabs[id];
    666815                        selected[0].addClass( 'cke_dialog_tab_selected' );
    667816                        selected[1].show();
    668                         var me = this;
     817                        this._.currentTabId = id;
     818                        this._.currentTabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, id );
    669819                },
    670820
    671821                /**
     
    16711821                         */
    16721822                        uiElement : function( dialog, elementDefinition, htmlList, nodeNameArg, stylesArg, attributesArg, contentsArg )
    16731823                        {
    1674                                 if (arguments.length < 4 )
     1824                                if ( arguments.length < 4 )
    16751825                                        return;
    16761826
    16771827                                var nodeName = ( nodeNameArg.call ? nodeNameArg( elementDefinition ) : nodeNameArg ) || 'div',
     
    17441894                                if ( this.accessKeyUp && this.accessKeyDown && elementDefinition.accessKey )
    17451895                                        registerAccessKey( this, dialog, 'CTRL+' + elementDefinition.accessKey );
    17461896
     1897                                var me = this;
     1898                                dialog.on( 'load', function()
     1899                                        {
     1900                                                if ( me.getInputElement() )
     1901                                                {
     1902                                                        me.getInputElement().on( 'focus', function()
     1903                                                                {
     1904                                                                        dialog._.tabBarMode = false;
     1905                                                                        dialog._.hasFocus = true;
     1906                                                                        me.fire( 'focus' );
     1907                                                                }, me );
     1908                                                }
     1909                                        } );
     1910
     1911                                // Register the object as a tab focus if it can be included.
     1912                                if ( this.keyboardFocusable )
     1913                                {
     1914                                        this.focusIndex = dialog._.focusList.push( this ) - 1;
     1915                                        this.on( 'focus', function()
     1916                                                {
     1917                                                        dialog._.currentFocusIndex = me.focusIndex;
     1918                                                } );
     1919                                }
     1920
    17471921                                // Completes this object with everything we have in the
    17481922                                // definition.
    17491923                                CKEDITOR.tools.extend( this, elementDefinition );
     
    19932167                        while ( ( cursor = cursor.getParent() ) && cursor.$.className.search( 'cke_dialog_page_contents' ) == -1 )
    19942168                        { /*jsl:pass*/ }
    19952169
     2170                        // Some widgets don't have parent tabs (e.g. OK and Cancel buttons).
     2171                        if ( !cursor )
     2172                                return this;
     2173
    19962174                        tabId = cursor.getAttribute( 'name' );
    19972175
    19982176                        this._.dialog.selectPage( tabId );
     
    21472325                        var element = this.getInputElement();
    21482326                        element.removeAttribute( 'disabled' );
    21492327                        element.removeClass( 'cke_disabled' );
     2328                },
     2329
     2330                /**
     2331                 * Determines whether an UI element is enabled or not.
     2332                 * @returns {Boolean} Whether the UI element is enabled.
     2333                 * @example
     2334                 */
     2335                isEnabled : function()
     2336                {
     2337                        return !this.getInputElement().getAttribute( 'disabled' );
     2338                },
     2339
     2340                /**
     2341                 * Determines whether an UI element is visible or not.
     2342                 * @returns {Boolean} Whether the UI element is visible.
     2343                 * @example
     2344                 */
     2345                isVisible : function()
     2346                {
     2347                        return !!this.getInputElement().$.offsetHeight;
     2348                },
     2349
     2350                /**
     2351                 * Determines whether an UI element is focus-able or not.
     2352                 * Focus-able is defined as being both visible and enabled.
     2353                 * @returns {Boolean} Whether the UI element can be focused.
     2354                 * @example
     2355                 */
     2356                isFocusable : function()
     2357                {
     2358                        if ( !this.isEnabled() || !this.isVisible() )
     2359                                return false;
     2360                        return true;
    21502361                }
    21512362        };
    21522363
  • _source/skins/default/dialog.css

     
    375375        vertical-align: top;
    376376}
    377377
    378 .cke_skin_default .cke_dialog_ui_button
     378.cke_skin_default .cke_dialog_ui_button table
    379379{
    380380        border: #737357 1px solid;
    381381}
    382382
    383 .cke_skin_default .cke_dialog_ui_button.disabled
     383.cke_skin_default .cke_dialog_ui_button.disabled table
    384384{
    385385        border: #898980 1px solid;
    386386}
     
    399399        background-color: #c5c5b3;
    400400}
    401401
    402 .cke_skin_default .cke_dialog_ui_button.active .cke_dialog_ui_button_txt
     402.cke_skin_default a:focus.cke_dialog_ui_button .cke_dialog_ui_button_txt,
     403.cke_skin_default a:active.cke_dialog_ui_button .cke_dialog_ui_button_txt
    403404{
    404405        background-color: #e3e3c7;
    405406}
© 2003 – 2021 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy