Skip to content

Commit

Permalink
Merge branch 't/13142c'
Browse files Browse the repository at this point in the history
  • Loading branch information
Piotr Jasiun committed Aug 20, 2015
2 parents c17876f + 208a743 commit 89d54d8
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ CKEditor 4 Changelog

## CKEditor 4.5.4

Fixed Issues:

* [#13142](http://dev.ckeditor.com/ticket/13142): [Edge] Fixed: CTRL+A, backspace results in an empty div.

## CKEditor 4.5.3

Expand Down
58 changes: 38 additions & 20 deletions plugins/wysiwygarea/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,27 +152,13 @@
this.setup();
this.fixInitialSelection();

if ( CKEDITOR.env.ie ) {
doc.getDocumentElement().addClass( doc.$.compatMode );

// Prevent IE from leaving new paragraph after deleting all contents in body. (#6966)
editor.config.enterMode != CKEDITOR.ENTER_P && this.attachListener( doc, 'selectionchange', function() {
var body = doc.getBody(),
sel = editor.getSelection(),
range = sel && sel.getRanges()[ 0 ];
var editable = this;

if ( range && body.getHtml().match( /^<p>(?:&nbsp;|<br>)<\/p>$/i ) && range.startContainer.equals( body ) ) {
// Avoid the ambiguity from a real user cursor position.
setTimeout( function() {
range = editor.getSelection().getRanges()[ 0 ];
if ( !range.startContainer.equals( 'body' ) ) {
body.getFirst().remove( 1 );
range.moveToElementEditEnd( body );
range.select();
}
}, 0 );
}
} );
// Prevent IE/Edge from leaving a new paragraph/div after deleting all contents in body. (#6966, #13142)
if ( CKEDITOR.env.ie && !CKEDITOR.env.edge && editor.enterMode != CKEDITOR.ENTER_P ) {
removeSuperfluousElement( 'p' );
} else if ( CKEDITOR.env.edge && editor.enterMode != CKEDITOR.ENTER_DIV ) {
removeSuperfluousElement( 'div' );
}

// Fix problem with cursor not appearing in Webkit and IE11+ when clicking below the body (#10945, #10906).
Expand Down Expand Up @@ -276,6 +262,38 @@
editor.fire( 'dataReady' );
}, 0 );
}, 0, this );

function removeSuperfluousElement( tagName ) {
var lockRetain = false;

// Superfluous elements appear after keydown
// and before keyup, so the procedure is as follows:
// 1. On first keydown mark all elements with
// a specified tag name as non-superfluous.
editable.attachListener( editable, 'keydown', function() {
var body = doc.getBody(),
retained = body.getElementsByTag( tagName );

if ( !lockRetain ) {
for ( var i = 0; i < retained.count(); i++ ) {
retained.getItem( i ).setCustomData( 'retain', true );
}
lockRetain = true;
}
}, null, null, 1 );

// 2. On keyup remove all elements that were not marked
// as non-superfluous (which means they must have had appeared in the meantime).
editable.attachListener( editable, 'keyup', function() {
var elements = doc.getElementsByTag( tagName );
if ( lockRetain ) {
if ( elements.count() == 1 && !elements.getItem( 0 ).getCustomData( 'retain' ) ) {
elements.getItem( 0 ).remove( 1 );
}
lockRetain = false;
}
} );
}
}

var framedWysiwyg = CKEDITOR.tools.createClass( {
Expand Down
8 changes: 8 additions & 0 deletions tests/core/editable/manual/_assets/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
div {
border: 1px solid red;
margin: 1px;
}

p {
border: 1px solid green;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<link rel="stylesheet" type="text/css" href="_assets/styles.css" />
<script>
CKEDITOR.disableAutoInline = true;
</script>
<h2>Inline editor</h2>
<h1 id="editor0" contenteditable="true">
Blockless inline editor
</h1>

<h2>Enter mode: P</h2>
<textarea name="editor1">
CKEditor instance.
</textarea>

<h2>Enter mode: DIV</h2>
<textarea name="editor2">
<div>Test</div>
</textarea>

<h2>Enter mode: BR</h2>
<textarea name="editor3">
CKEditor instance.
</textarea>
<script>
( function() {
var cfg = {
contentsCss: '_assets/styles.css',
extraPlugins: 'wysiwygarea,sourcearea,htmlwriter,entities,toolbar,elementspath,undo,clipboard,format,basicstyles,enterkey,div'
};

CKEDITOR.inline( 'editor0', {
plugins: 'toolbar,basicstyles,floatingspace,undo,format,stylescombo,enterkey'
} );

cfg.enterMode = CKEDITOR.ENTER_P;
CKEDITOR.replace( 'editor1', cfg );

cfg.enterMode = CKEDITOR.ENTER_DIV;
CKEDITOR.replace( 'editor2', cfg );

cfg.enterMode = CKEDITOR.ENTER_BR;
CKEDITOR.replace( 'editor3', cfg );
} )();
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@bender-tags: 4.5.4, tc, 13142
@bender-ui: collapsed
@bender-ckeditor-plugins: format, stylescombo, toolbar, wysiwygarea, undo

----

For each editor instance:

1. Choose one and create:
1. Empty paragraph.
2. Single paragraph with one line of text.
3. Multiple paragraphs with text.
2. Select it using Ctrl+A.
3. Press one:
1. backspace
2. delete
3. alphanumeric key
4. enter key
5. start typing some text.
4. Repeat.

**Expected result:** The editable should contain only elements typical for their respective enter modes.

Notes:

- &lt;p&gt; elements are colored green and &lt;div&gt; elements are colored red.
- You may experience a flashing &lt;div&gt; (Edge) or &lt;p&gt; (IE) element in all but the blockless inline editor.
- On Edge and Firefox an extra paragraph is created when you select all and press `Enter` it is a known bug.
181 changes: 181 additions & 0 deletions tests/plugins/wysiwygarea/superfluouselement.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/* bender-tags: 13142 */
/* bender-ckeditor-plugins: enterkey,wysiwygarea */

// This test simulates the situation that occurs when the user selects
// the whole content and presses backspace/delete or starts typing.
// Both IE and Edge tend to insert a superfluous element
// (<p> and <div> respectively) into the empty editable.

'use strict';

bender.editor = {
creator: 'replace',
config: {
enterMode: CKEDITOR.ENTER_BR
}
};

bender.test( {
'Test removing superfluous <p> inserted by IE11': function() {
if ( !CKEDITOR.env.ie || CKEDITOR.env.edge ) {
assert.ignore();
}

var editor = this.editor;

editor.setData( '', function() {
resume( function() {

bender.tools.setHtmlWithSelection( editor, '^' );

editor.editable().fire( 'keydown', new CKEDITOR.dom.event( {
keyCode: 8,
ctrlKey: false,
shiftKey: false
} ) );

bender.tools.setHtmlWithSelection( editor, '<p>^</p>' );

editor.editable().fire( 'keyup' );

assert.isInnerHtmlMatching( '^', bender.tools.getHtmlWithSelection( editor ) );
} );
} );
wait();
},

'Test removing superfluous <div> inserted by Edge': function() {
if ( !CKEDITOR.env.edge ) {
assert.ignore();
}

var editor = this.editor;

editor.setData( '', function() {
resume( function() {

editor.editable().fire( 'keydown', new CKEDITOR.dom.event( {
keyCode: 75,
ctrlKey: false,
shiftKey: false
} ) );

bender.tools.setHtmlWithSelection( editor, '<div>k^</div>' );

editor.editable().fire( 'keyup' );

assert.isInnerHtmlMatching( 'k^', bender.tools.getHtmlWithSelection( editor ) );
} );
} );
wait();
},

'Test not removing non-superfluous <div> in Edge': function() {
if ( !CKEDITOR.env.edge ) {
assert.ignore();
}

var editor = this.editor;

editor.setData( '', function() {
resume( function() {
bender.tools.setHtmlWithSelection( editor, '<div>^</div>' );

editor.editable().fire( 'keydown', new CKEDITOR.dom.event( {
keyCode: 75,
ctrlKey: false,
shiftKey: false
} ) );

editor.editable().fire( 'keyup' );

assert.isInnerHtmlMatching( '<div>^&nbsp;</div>', bender.tools.getHtmlWithSelection( editor ) );
} );
} );
wait();
},

'Test removing superfluous <div> when typing': function() {
if ( !CKEDITOR.env.edge ) {
assert.ignore();
}

var editor = this.editor;

editor.setData( '', function() {
resume( function() {
bender.tools.setHtmlWithSelection( editor, '^' );

// Expected behaviour:
// keydown <- mark divs for retention, disable marking
// keydown <- do nothing
// ...
// keyup <- remove not marked divs, enable marking
// keyup <- do nothing
// ...
editor.editable().fire( 'keydown', new CKEDITOR.dom.event( {
keyCode: 75,
ctrlKey: false,
shiftKey: false
} ) );

bender.tools.setHtmlWithSelection( editor, '<div>k^</div>' );

editor.editable().fire( 'keydown', new CKEDITOR.dom.event( {
keyCode: 76,
ctrlKey: false,
shiftKey: false
} ) );

editor.editable().fire( 'keydown', new CKEDITOR.dom.event( {
keyCode: 77,
ctrlKey: false,
shiftKey: false
} ) );

editor.editable().fire( 'keyup' );

editor.editable().fire( 'keyup' );

editor.editable().fire( 'keyup' );

assert.isInnerHtmlMatching( 'k^', bender.tools.getHtmlWithSelection( editor ) );
} );
} );
wait();
},

'Test not removing non-superfluous <div> when typing': function() {
if ( !CKEDITOR.env.edge ) {
assert.ignore();
}

var editor = this.editor;

editor.setData( '', function() {
resume( function() {
bender.tools.setHtmlWithSelection( editor, '<div>^</div>' );

editor.editable().fire( 'keydown', new CKEDITOR.dom.event( {
keyCode: 75,
ctrlKey: false,
shiftKey: false
} ) );

editor.editable().fire( 'keydown', new CKEDITOR.dom.event( {
keyCode: 76,
ctrlKey: false,
shiftKey: false
} ) );

editor.editable().fire( 'keyup' );

editor.editable().fire( 'keyup' );

assert.isInnerHtmlMatching( '<div>^&nbsp;</div>', bender.tools.getHtmlWithSelection( editor ) );
} );
} );
wait();
}

} );

0 comments on commit 89d54d8

Please sign in to comment.