Skip to content

Commit

Permalink
Merge branch 't/14407' into major
Browse files Browse the repository at this point in the history
  • Loading branch information
Comandeer committed Mar 1, 2017
2 parents 56e6fda + 324d696 commit a3b2b66
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGES.md
Expand Up @@ -24,6 +24,7 @@ Fixed Issues:
* [#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.
* [#14407](https://dev.ckeditor.com/ticket/14407): [IE] Fixed: Non-editable widgets can be edited.

## CKEditor 4.6.2

Expand Down
20 changes: 20 additions & 0 deletions core/selection.js
Expand Up @@ -704,6 +704,14 @@
// 2. After the accomplish of keyboard and mouse events.
editable.attachListener( editable, 'selectionchange', checkSelectionChange, editor );
editable.attachListener( editable, 'keyup', checkSelectionChangeTimeout, editor );
// #14407 - Don't even let anything happen if the selection is in a non-editable element.
editable.attachListener( editable, 'keydown', function( evt ) {
var sel = this.getSelection( 1 );
if ( nonEditableAscendant( sel ) ) {
sel.selectElement( nonEditableAscendant( sel ) );
evt.data.preventDefault();
}
}, editor );
// Always fire the selection change on focus gain.
// On Webkit do this on DOMFocusIn, because the selection is unlocked on it too and
// we need synchronization between those listeners to not lost cached editor._.previousActive property
Expand Down Expand Up @@ -788,6 +796,18 @@
if ( sel.type != 'None' && range.parentElement().ownerDocument == doc.$ )
range.select();
}

function nonEditableAscendant( sel ) {
if ( CKEDITOR.env.ie ) {
var range = sel.getRanges()[ 0 ],
ascendant = range ? range.startContainer.getAscendant( function( parent ) {
return parent.type == CKEDITOR.NODE_ELEMENT &&
( parent.getAttribute( 'contenteditable' ) == 'false' || parent.getAttribute( 'contenteditable' ) == 'true' );
}, true ) : null ;

return range && ascendant.getAttribute( 'contenteditable' ) == 'false' && ascendant;
}
}
} );

editor.on( 'setData', function() {
Expand Down
36 changes: 36 additions & 0 deletions tests/core/selection/manual/iecontenteditablefalse.html
@@ -0,0 +1,36 @@

<textarea name="editor1" id="editor1" cols="30" rows="10">
<p>Put caret here first.</p>
</textarea>

<script>

CKEDITOR.plugins.add( 'noneditablewidget', {
requires: 'widget',
init: function ( editor ) {
editor.widgets.add( 'noneditablewidget', {
button: 'Non-editable widget',
order: 1,
template: '<div class="noneditable">' +
'<div>This part shouldn\'t be editable.</div>' +
'</div>',
allowedContent: 'div(noneditable)',
requiredContent: 'div',
upcast: function( element ) {
return element.name == 'div' && element.hasClass( 'noneditable' );
}
} );
}
} );

if ( !CKEDITOR.env.ie ) {
bender.ignore();
}

CKEDITOR.replace( 'editor1', {
extraPlugins: 'noneditablewidget',
extraAllowedContent: 'div'
} );


</script>
23 changes: 23 additions & 0 deletions tests/core/selection/manual/iecontenteditablefalse.md
@@ -0,0 +1,23 @@
@bender-tags: tc, 4.7.0, 14407, selection, widget
@bender-ui: collapsed
@bender-ckeditor-plugins: wysiwygarea, toolbar, sourcearea, elementspath

## Test scenario

1. There's an empty button at the start of the second row in the toolbar - use it to add a non-editable widget
above the paragraph already present there.
2. Put the caret at the start of the paragraph and press the `up arrow` key.

** Alternatively: **
1. Create the non-editable widget.
2. Make the editor lose focus.
3. Place the cursor over the widget so that its icon is `text` and its upper-left corner is exactly at the dot in "editable."
4. Click to try to place the caret inside the editable or drag the mouse to create a range.

## Expected

The selection is inside the non-editable area, but once you press any key the whole widget gets selected.

## Unexpected

The widget is not selected when you press a key.
45 changes: 44 additions & 1 deletion tests/core/selection/selection.js
Expand Up @@ -652,5 +652,48 @@ bender.test( {
sel.getType();

assert.areSame( initialRev, sel.rev, 'Revision has not been modified' );
},

'test IE editable contenteditable="false" handling 1': function() {
if ( !CKEDITOR.env.ie ) {
assert.ignore();
}
var preventSpy = sinon.spy();

bender.tools.setHtmlWithSelection( this.editor, '<span contenteditable="false">^bar</span>' );

var selection = this.editor.getSelection(),
range = selection.getRanges()[ 0 ];

// Selection was moved somehow.
if ( range && range.startContainer.getName() !== 'span' ) {
assert.ignore();
}

this.editor.editable().fire( 'keydown', {
preventDefault: preventSpy,
getKeystroke: function() {},
getKey: function() {}
} );

assert.isTrue( preventSpy.called, 'preventDefault() on keydown was called' );
},

'test IE editable contenteditable="false" handling 2': function() {
if ( !CKEDITOR.env.ie ) {
assert.ignore();
}
var preventSpy = sinon.spy();

bender.tools.setHtmlWithSelection( this.editor, '<span contenteditable="false">' +
'<span contenteditable="true">^bar</span></span>' );

this.editor.editable().fire( 'keydown', {
preventDefault: preventSpy,
getKeystroke: function() {},
getKey: function() {}
} );

assert.isFalse( preventSpy.called, 'preventDefault() on keydown was called' );
}
} );
} );

0 comments on commit a3b2b66

Please sign in to comment.