Skip to content
Permalink
Browse files

Merge branch 't/11861'

  • Loading branch information...
Reinmar committed May 12, 2014
2 parents 8837211 + c9e4b15 commit 11e6c221d670a25c2a850f9dde7b8965ef4e7e0d
Showing with 120 additions and 4 deletions.
  1. +1 −0 CHANGES.md
  2. +5 −1 core/dom/walker.js
  3. +94 −1 core/editable.js
  4. +17 −1 core/keystrokehandler.js
  5. +3 −1 plugins/list/plugin.js
@@ -9,6 +9,7 @@ New Features:

Fixed Issues:

* [#11861](http://dev.ckeditor.com/ticket/11861): Fixed: [Webkit/Blink] Span elements created while joining adjacent elements. **Note:** Only a case when *Backspace* or *Delete* is pressed on collapsed (empty) selection is covered by this patch. The remaining case, with a non-empty selection, will be fixed in next release.
* [#10714](http://dev.ckeditor.com/ticket/10714): Fixed: [iOS] Selection and drop-downs are broken if touch listener is used due to [Webkit bug](https://bugs.webkit.org/show_bug.cgi?id=128924). Thanks to [Arty Gus](https://github.com/artygus)!
* [#11911](http://dev.ckeditor.com/ticket/11911): Fixed setting the `dir` attribute for preloaded language in [CKEDITOR.lang](http://docs.ckeditor.com/#!/api/CKEDITOR.lang). Thanks to [Akash Mohapatra](https://github.com/akashmohapatra)!
* [#11223](http://dev.ckeditor.com/ticket/11223): Fixed: issue when [Protected Source](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-protectedSource) was not working in the title element.
@@ -556,8 +556,10 @@

if ( node.type == CKEDITOR.NODE_ELEMENT ) {
// All inline and non-editable elements are valid editable places.
// Note: the <hr> is currently the only element in CKEDITOR.dtd.$empty and CKEDITOR.dtd.$block,
// but generally speaking we need an intersection of these two sets.
// Note: non-editable block has to be treated differently (should be selected entirely).
if ( node.is( CKEDITOR.dtd.$inline ) || node.getAttribute( 'contenteditable' ) == 'false' )
if ( node.is( CKEDITOR.dtd.$inline ) || node.is( 'hr' ) || node.getAttribute( 'contenteditable' ) == 'false' )
return true;

// Empty blocks are editable on IE.
@@ -577,6 +579,8 @@
*
* * text nodes (but not whitespaces),
* * inline elements,
* * intersection of {@link CKEDITOR.dtd#$empty} and {@link CKEDITOR.dtd#$block} (currenly
* it's only `<hr>`),
* * non-editable blocks (special case - such blocks cannot be containers nor
* siblings, they need to be selected entirely),
* * empty blocks which can contain text (IE only).
@@ -636,7 +636,10 @@
if ( editor.readOnly )
return true;

var keyCode = evt.data.keyCode, isHandled;
// Use getKey directly in order to ignore modifiers.
// Justification: http://dev.ckeditor.com/ticket/11861#comment:13
var keyCode = evt.data.domEvent.getKey(),
isHandled;

// Backspace OR Delete.
if ( keyCode in backspaceOrDelete ) {
@@ -796,6 +799,96 @@
ev.data.preventDefault();
} );
}

// Prevent Webkit/Blink from going rogue when joining
// blocks on BACKSPACE/DEL (#11861,#9998).
if ( CKEDITOR.env.webkit ) {
this.attachListener( editor, 'key', function( evt ) {
// Use getKey directly in order to ignore modifiers.
// Justification: http://dev.ckeditor.com/ticket/11861#comment:13
var key = evt.data.domEvent.getKey();

if ( !( key in backspaceOrDelete ) )
return;

var backspace = key == 8,
selection = editor.getSelection(),
range = selection.getRanges()[ 0 ],
startPath = range.startPath(),
startBlock = startPath.block;

// Selection must be collapsed and to be anchored in a block.
if ( !range.collapsed || !startBlock )
return;

// Exclude cases where, i.e. if pressed arrow key, selection
// would move within the same block (merge inside a block).
if ( !range[ backspace ? 'checkStartOfBlock' : 'checkEndOfBlock' ]() )
return;

// Make sure, there's an editable position to put selection,
// which i.e. would be used if pressed arrow key, but abort
// if such position exists but means a selected non-editable element.
if ( !range.moveToClosestEditablePosition( startBlock, !backspace ) || !range.collapsed )
return;

// Handle special case, when block's sibling is a <hr>. Delete it and keep selection
// in the same place (http://dev.ckeditor.com/ticket/11861#comment:9).
if ( range.startContainer.type == CKEDITOR.NODE_ELEMENT ) {
var touched = range.startContainer.getChild( range.startOffset - ( backspace ? 1 : 0 ) );
if ( touched && touched.type == CKEDITOR.NODE_ELEMENT && touched.is( 'hr' ) ) {
editor.fire( 'saveSnapshot' );
touched.remove();
editor.fire( 'saveSnapshot' );
return false;
}
}

var siblingBlock = range.startPath().block;

// Abort if an editable position exists, but either it's not
// in a block or that block is the parent of the start block
// (merging child into parent).
if ( !siblingBlock || ( siblingBlock && siblingBlock.contains( startBlock ) ) )
return;

editor.fire( 'saveSnapshot' );

var commonParent = startBlock.getCommonAncestor( siblingBlock ),
node = backspace ? startBlock : siblingBlock,
removableParent = node;

// Find an element (DOM branch), which contains the block
// to be merged but nothing else, so if removed, it will
// leave no empty parents.
while ( ( node = node.getParent() ) && !commonParent.equals( node ) && node.getChildCount() == 1 )
removableParent = node;

// Remove bogus to avoid duplicated boguses.
var bogus;
if ( ( bogus = ( backspace ? siblingBlock : startBlock ).getBogus() ) )
bogus.remove();

// Save selection. It will be restored.
var bookmarks = selection.createBookmarks();

// Merge blocks.
( backspace ? startBlock : siblingBlock ).moveChildren( backspace ? siblingBlock : startBlock, false );

// Also merge children along with parents.
startPath.lastElement.mergeSiblings();

// Cut off removable branch of the DOM tree.
removableParent.remove();

// Restore selection.
selection.selectBookmarks( bookmarks );

editor.fire( 'saveSnapshot' );

return false;
}, this, null, 100 ); // Later is better – do not override existing listeners.
}
}
},

@@ -48,7 +48,7 @@ CKEDITOR.keystrokeHandler = function( editor ) {
var command = this.keystrokes[ keyCombination ];
var editor = this._.editor;

cancel = ( editor.fire( 'key', { keyCode: keyCombination } ) === false );
cancel = ( editor.fire( 'key', { keyCode: keyCombination, domEvent: event } ) === false );

if ( !cancel ) {
if ( command ) {
@@ -143,11 +143,27 @@ CKEDITOR.keystrokeHandler = function( editor ) {
/**
* Fired when any keyboard key (or combination) is pressed into the editing area.
*
* editor.on( 'key', function( evt ) {
* if ( evt.data.keyCode == CKEDITOR.CTRL + 90 ) {
* // Do something...
*
* // Cancel the event, so other listeners won't be executed and
* // keydown's default behavior will be prevented.
* evt.cancel();
* }
* } );
*
* Usually you'll want to use the {@link CKEDITOR.editor#setKeystroke} method or
* the {@link CKEDITOR.config#keystrokes} option to attach a keystroke to some {@link CKEDITOR.command command}.
* Key event listeners are usuful when some action should be executed conditionally, based
* for example on precise selection location.
*
* @event key
* @member CKEDITOR.editor
* @param data
* @param {Number} data.keyCode A number representing the key code (or combination).
* It is the sum of the current key code and the {@link CKEDITOR#CTRL}, {@link CKEDITOR#SHIFT}
* and {@link CKEDITOR#ALT} constants, if those are pressed.
* @param {CKEDITOR.dom.event} data.domEvent A `keydown` DOM event instance. Available since CKEditor 4.4.1.
* @param {CKEDITOR.editor} editor This editor instance.
*/
@@ -848,7 +848,9 @@

// Handled backspace/del key to join list items. (#8248,#9080)
editor.on( 'key', function( evt ) {
var key = evt.data.keyCode;
// Use getKey directly in order to ignore modifiers.
// Justification: http://dev.ckeditor.com/ticket/11861#comment:13
var key = evt.data.domEvent.getKey();

// DEl/BACKSPACE
if ( editor.mode == 'wysiwyg' && key in { 8: 1, 46: 1 } ) {

0 comments on commit 11e6c22

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