+\r
+ // Handled backspace/del key to join list items. (#8248,#9080)\r
+ editor.on( 'key', function( evt )\r
+ {\r
+ var key = evt.data.keyCode;\r
+\r
+ // DEl/BACKSPACE\r
+ if ( editor.mode == 'wysiwyg' && key in { 8 : 1, 46 : 1 } )\r
+ {\r
+ var sel = editor.getSelection(),\r
+ range = sel.getRanges()[ 0 ];\r
+\r
+ if ( !range.collapsed )\r
+ return;\r
+\r
+ var isBackspace = key == 8;\r
+ var body = editor.document.getBody();\r
+ var walker = new CKEDITOR.dom.walker( range.clone() );\r
+ walker.evaluator = function( node ) { return nonEmpty( node ) && !blockBogus( node ); };\r
+\r
+ var cursor = range.clone();\r
+\r
+ if ( isBackspace )\r
+ {\r
+ var previous, joinWith;\r
+\r
+ var path = new CKEDITOR.dom.elementPath( range.startContainer );\r
+\r
+ // Join a sub list's first line, with the previous visual line in parent.\r
+ if ( ( previous = path.contains( listNodeNames ) ) &&\r
+ range.checkBoundaryOfElement( previous, CKEDITOR.START ) &&\r
+ ( previous = previous.getParent() ) && previous.is( 'li' ) &&\r
+ ( previous = getSubList( previous ) ) )\r
+ {\r
+ joinWith = previous;\r
+ previous = previous.getPrevious( nonEmpty );\r
+ // Place cursor before the nested list.\r
+ cursor.moveToPosition(\r
+ previous && blockBogus( previous ) ? previous : joinWith,\r
+ CKEDITOR.POSITION_BEFORE_START );\r
+ }\r
+ // Join any line following a list, with the last visual line of the list.\r
+ else\r
+ {\r
+ walker.range.setStartAt( body, CKEDITOR.POSITION_AFTER_START );\r
+ walker.range.setEnd( range.startContainer, range.startOffset );\r
+ previous = walker.previous();\r
+\r
+ if ( previous && previous.type == CKEDITOR.NODE_ELEMENT &&\r
+ ( previous.getName() in listNodeNames || previous.is( 'li' ) ) )\r
+ {\r
+ if ( !previous.is( 'li' ) )\r
+ {\r
+ walker.range.selectNodeContents( previous );\r
+ walker.reset();\r
+ walker.evaluator = isTextBlock;\r
+ previous = walker.previous();\r
+ }\r
+\r
+ joinWith = previous;\r
+ // Place cursor at the end of previous block.\r
+ cursor.moveToElementEditEnd( joinWith );\r
+ }\r
+ }\r
+\r
+ if ( joinWith )\r
+ {\r
+ joinNextLineToCursor( editor, cursor, range );\r
+ evt.cancel();\r
+ }\r
+ }\r
+ else\r
+ {\r
+ var li = range.startContainer.getAscendant( 'li', 1 );\r
+ if ( li )\r
+ {\r
+ walker.range.setEndAt( body, CKEDITOR.POSITION_BEFORE_END );\r
+\r
+ var last = li.getLast( nonEmpty );\r
+ var block = last && isTextBlock( last ) ? last : li;\r
+\r
+ // Indicate cursor at the visual end of an list item.\r
+ var isAtEnd = 0;\r
+\r
+ var next = walker.next();\r
+\r
+ // When list item contains a sub list.\r
+ if ( next && next.type == CKEDITOR.NODE_ELEMENT &&\r
+ next.getName() in listNodeNames\r
+ && next.equals( last ) )\r
+ {\r
+ isAtEnd = 1;\r
+\r
+ // Move to the first item in sub list.\r
+ next = walker.next();\r
+ }\r
+ // Right at the end of list item.\r
+ else if ( range.checkBoundaryOfElement( block, CKEDITOR.END ) )\r
+ isAtEnd = 1;\r
+\r
+\r
+ if ( isAtEnd && next )\r
+ {\r
+ // Put cursor range there.\r
+ var nextLine = range.clone();\r
+ nextLine.moveToElementEditStart( next );\r
+\r
+ joinNextLineToCursor( editor, cursor, nextLine );\r
+ evt.cancel();\r
+ }\r
+ }\r
+ }\r
+\r
+ // The backspace/del could potentially put cursor at a bad position,\r
+ // being it handled or not, check immediately the selection to have it fixed.\r
+ setTimeout( function() { editor.selectionChange( 1 ); } );\r
+ }\r
+ } );\r