Skip to content
Permalink
Browse files

Merge branch 't/16804' into major

  • Loading branch information...
Comandeer committed Feb 28, 2017
2 parents f8e830b + a702759 commit 61a610820e9d3ae94ec8e970779ddaccdb8c8334
@@ -21,6 +21,7 @@ Fixed Issues:
* [#16777](https://dev.ckeditor.com/ticket/16777): [Edge] Fixed: [Clipboard](http://ckeditor.com/addon/clipboard) plugin doesn't allow to drop widgets into editor.
* [#14894](https://dev.ckeditor.com/ticket/14894): [Chrome] Fixed: Editor scrolls to top after focusing or when a dialog is opened.
* [#14769](https://dev.ckeditor.com/ticket/14769): Fixed: URLs with '-' in host are not detected by [Autolink](http://ckeditor.com/addon/autolink) plugin.
* [#16804](https://dev.ckeditor.com/ticket/16804): Fixed: Focus is not on the first menu item when user opens [Context Menu](http://ckeditor.com/addon/contextmenu) or combobox from editor's toolbar.

## CKEditor 4.6.2

@@ -85,7 +85,8 @@ CKEDITOR.plugins.add( 'colorbutton', {

function addButton( name, type, title, order, options ) {
var style = new CKEDITOR.style( config[ 'colorButton_' + type + 'Style' ] ),
colorBoxId = CKEDITOR.tools.getNextId() + '_colorBox';
colorBoxId = CKEDITOR.tools.getNextId() + '_colorBox',
panelBlock;

options = options || {};

@@ -105,6 +106,8 @@ CKEDITOR.plugins.add( 'colorbutton', {
},

onBlock: function( panel, block ) {
panelBlock = block;

block.autoSize = true;
block.element.addClass( 'cke_colorblock' );
block.element.setHtml( renderColors( panel, type, colorBoxId ) );
@@ -135,7 +138,7 @@ CKEDITOR.plugins.add( 'colorbutton', {
var selection = editor.getSelection(),
block = selection && selection.getStartElement(),
path = editor.elementPath( block ),
color;
automaticColor;

if ( !path )
return;
@@ -145,19 +148,46 @@ CKEDITOR.plugins.add( 'colorbutton', {

// The background color might be transparent. In that case, look up the color in the DOM tree.
do {
color = block && block.getComputedStyle( type == 'back' ? 'background-color' : 'color' ) || 'transparent';
automaticColor = block && block.getComputedStyle( type == 'back' ? 'background-color' : 'color' ) || 'transparent';
}
while ( type == 'back' && color == 'transparent' && block && ( block = block.getParent() ) );
while ( type == 'back' && automaticColor == 'transparent' && block && ( block = block.getParent() ) );

// The box should never be transparent.
if ( !color || color == 'transparent' )
color = '#ffffff';
if ( !automaticColor || automaticColor == 'transparent' )
automaticColor = '#ffffff';

if ( config.colorButton_enableAutomatic !== false ) {
this._.panel._.iframe.getFrameDocument().getById( colorBoxId ).setStyle( 'background-color', color );
this._.panel._.iframe.getFrameDocument().getById( colorBoxId ).setStyle( 'background-color', automaticColor );
}

return color;
var range = selection && selection.getRanges()[ 0 ];

if ( range ) {
var walker = new CKEDITOR.dom.walker( range ),
element = range.collapsed ? range.startContainer : walker.next(),
finalColor = '',
currentColor;

while ( element ) {
if ( element.type === CKEDITOR.NODE_TEXT ) {
element = element.getParent();
}

currentColor = normalizeColor( element.getComputedStyle( type == 'back' ? 'background-color' : 'color' ) );
finalColor = finalColor || currentColor;

if ( finalColor !== currentColor ) {
finalColor = '';
break;
}

element = walker.next();
}

selectColor( panelBlock, finalColor );
}

return automaticColor;
}
} );
}
@@ -255,6 +285,7 @@ CKEDITOR.plugins.add( 'colorbutton', {
' title="', colorLabel, '"' +
' onclick="CKEDITOR.tools.callFunction(', clickFn, ',\'', colorName, '\',\'', type, '\'); return false;"' +
' href="javascript:void(\'', colorLabel, '\')"' +
' data-value="' + colorCode + '"' +
' role="option" aria-posinset="', ( i + 2 ), '" aria-setsize="', total, '">' +
'<span class="cke_colorbox" style="background-color:#', colorCode, '"></span>' +
'</a>' +
@@ -281,6 +312,36 @@ CKEDITOR.plugins.add( 'colorbutton', {
function isUnstylable( ele ) {
return ( ele.getAttribute( 'contentEditable' ) == 'false' ) || ele.getAttribute( 'data-nostyle' );
}

/**
* Selects the specified color in the specified panel block.
*
* @param block
* @param color
*/
function selectColor( block, color ) {
var items = block._.getItems();

for ( var i = 0; i < items.count(); i++ ) {
var item = items.getItem( i );

item.removeAttribute( 'aria-selected' );

if ( color && color == normalizeColor( item.getAttribute( 'data-value' ) ) ) {
item.setAttribute( 'aria-selected', true );
}
}
}

/**
* Converts a CSS color value to an easily comparable form.
*
* @param {string} color
* @returns {string}
*/
function normalizeColor( color ) {
return CKEDITOR.tools.convertRgbToHex( color || '' ).replace( /#/, '' ).toLowerCase();
}
}
} );

@@ -416,6 +416,16 @@ CKEDITOR.plugins.add( 'floatpanel', {

// We need this get fired manually because of unfired focus() function.
this.allowBlur( true );

// Ensure that the first item is focused (#16804).
if ( CKEDITOR.env.ie ) {
CKEDITOR.tools.setTimeout( function() {
block.markFirstDisplayed ? block.markFirstDisplayed() : block._.markFirstDisplayed();
}, 0 );
} else {
block.markFirstDisplayed ? block.markFirstDisplayed() : block._.markFirstDisplayed();
}

this._.editor.fire( 'panelShow', this );
}, 0, this );
}, CKEDITOR.env.air ? 200 : 0, this );
@@ -180,6 +180,14 @@ CKEDITOR.plugins.add( 'listblock', {
this.onMark && this.onMark( item );
},

markFirstDisplayed: function() {
var context = this;
this._.markFirstDisplayed( function() {
if ( !context.multiSelect )
context.unmarkAll();
} );
},

unmark: function( value ) {
var doc = this.element.getDocument(),
itemId = this._.items[ value ],
@@ -307,6 +307,61 @@
item.focus();

this.onMark && this.onMark( item );
},

/**
* Marks the first visible item or the one who's `aria-selected` attribute is set to `true`.
* The latter has priority over the former.
*
* @private
* @param beforeMark function to be executed just before marking.
* Used in cases when any preparatory cleanup(like unmarking all items) would simultaneously
* destroy the information that's needed to determine the focused item.
*/
markFirstDisplayed: function( beforeMark ) {
var notDisplayed = function( element ) {
return element.type == CKEDITOR.NODE_ELEMENT && element.getStyle( 'display' ) == 'none';
},
links = this._.getItems(),
item, focused;

for ( var i = links.count() - 1; i >= 0; i-- ) {
item = links.getItem( i );

if ( !item.getAscendant( notDisplayed ) ) {
focused = item;
this._.focusIndex = i;
}

if ( item.getAttribute( 'aria-selected' ) == 'true' ) {
focused = item;
this._.focusIndex = i;
break;
}
}

if ( !focused ) {
return;
}

if ( beforeMark ) {
beforeMark();
}

if ( CKEDITOR.env.webkit )
focused.getDocument().getWindow().focus();
focused.focus();

this.onMark && this.onMark( focused );
},

/**
* Returns a `CKEDITOR.dom.nodeList` of block items.
*
* @returns {*|CKEDITOR.dom.nodeList}
*/
getItems: function() {
return this.element.getElementsByTag( 'a' );
}
},

@@ -189,15 +189,6 @@ CKEDITOR.plugins.add( 'richcombo', {

var keystroke = ev.getKeystroke();

// ARROW-DOWN
// This call is duplicated in plugins/toolbar/plugin.js in itemKeystroke().
// Move focus to the first element after drop down was opened by the arrow down key.
if ( keystroke == 40 ) {
editor.once( 'panelShow', function( evt ) {
evt.data._.panel._.currentBlock.onKeyDown( 40 );
} );
}

switch ( keystroke ) {
case 13: // ENTER
case 32: // SPACE
@@ -266,12 +257,6 @@ CKEDITOR.plugins.add( 'richcombo', {

if ( me.onOpen )
me.onOpen();

// The "panelShow" event is fired assinchronously, after the
// onShow method call.
editor.once( 'panelShow', function() {
list.focus( !list.multiSelect && me.getValue() );
} );
};

panel.onHide = function( preventOnClose ) {
@@ -118,10 +118,6 @@
return false;
case 40: // DOWN-ARROW
if ( item.button && item.button.hasArrow ) {
// Note: code is duplicated in plugins\richcombo\plugin.js in keyDownFn().
editor.once( 'panelShow', function( evt ) {
evt.data._.panel._.currentBlock.onKeyDown( 40 );
} );
item.execute();
} else {
// Send left arrow key.
@@ -0,0 +1,83 @@
/* bender-tags: editor,unit,panel */
/* bender-ckeditor-plugins: pagebreak,toolbar,clipboard,panel */

( function() {
'use strict';

bender.editor = {
creator: 'replace'
};

function createBlock() {
var parent = new CKEDITOR.dom.element( 'div' );
CKEDITOR.document.getBody().append( parent );

var block = new CKEDITOR.ui.panel.block( parent, { attributes: {} } );

for ( var i = 0; i < 4; i++ ) {
var item = new CKEDITOR.dom.element( 'p' );
var link = new CKEDITOR.dom.element( 'a' );
item.append( link );
block.element.append( item );
}
block.show();

return block;
}

bender.test( {
'test mark first panel block item': function() {
var block = createBlock(),
timeout = CKEDITOR.tools.setTimeout;

block.onMark = sinon.spy();

CKEDITOR.tools.setTimeout = function( callback ) {
callback();
};

block._.markFirstDisplayed();

CKEDITOR.tools.setTimeout = timeout;

assert.isTrue( block.onMark.calledWith( block.element.getElementsByTag( 'a' ).getItem( 0 ) ) );
},

'test mark first displayed panel block item': function() {
var block = createBlock(),
timeout = CKEDITOR.tools.setTimeout;

block.onMark = sinon.spy();
block.element.getElementsByTag( 'p' ).getItem( 0 ).setStyle( 'display', 'none' );

CKEDITOR.tools.setTimeout = function( callback ) {
callback();
};

block._.markFirstDisplayed();

CKEDITOR.tools.setTimeout = timeout;

assert.isTrue( block.onMark.calledWith( block.element.getElementsByTag( 'a' ).getItem( 1 ) ) );
},

'test mark first displayed item with aria-selected': function() {
var block = createBlock(),
itemIndex = 2,
timeout = CKEDITOR.tools.setTimeout;

block.onMark = sinon.spy();
block.element.getElementsByTag( 'a' ).getItem( itemIndex ).setAttribute( 'aria-selected', true );

CKEDITOR.tools.setTimeout = function( callback ) {
callback();
};

block._.markFirstDisplayed();

CKEDITOR.tools.setTimeout = timeout;

assert.isTrue( block.onMark.calledWith( block.element.getElementsByTag( 'a' ).getItem( itemIndex ) ) );
}
} );
} )();
@@ -0,0 +1,12 @@
<div id="editor">
<table>
<tr>
<td>Check the cell's properties</td>
<td></td>
</tr>
</table>
</div>

<script>
CKEDITOR.replace( 'editor' );
</script>
@@ -0,0 +1,16 @@
@bender-tags: 4.7.0, tc, 16804
@bender-ui: collapsed
@bender-ckeditor-plugins: wysiwygarea,toolbar,elementspath,floatpanel,panel,menu,contextmenu,clipboard,a11yhelp,table,tabletools

### Test Scenario

1. Focus the editor and press `Ctrl + Shift + F10` to open the context menu.
2. Navigate through the menu.

#### Expected

In each opened menu or submenu the first active element is focused.

#### Unexpected

The first element is not focused.
@@ -0,0 +1,6 @@
<div id="editor">
</div>

<script>
CKEDITOR.replace( 'editor' );
</script>

0 comments on commit 61a6108

Please sign in to comment.
You can’t perform that action at this time.