\r
function rangeRequiresFix( range )\r
{\r
- function isInlineCt( node )\r
+ function isTextCt( node, isAtEnd )\r
{\r
- return node && node.type == CKEDITOR.NODE_ELEMENT\r
- && node.getName() in CKEDITOR.dtd.$removeEmpty;\r
- }\r
+ if ( !node || node.type == CKEDITOR.NODE_TEXT )\r
+ return false;\r
\r
- function singletonBlock( node )\r
- {\r
- var body = range.document.getBody();\r
- return !node.is( 'body' ) && body.getChildCount() == 1;\r
+ var testRng = range.clone();\r
+ return testRng[ 'moveToElementEdit' + ( isAtEnd ? 'End' : 'Start' ) ]( node );\r
}\r
\r
- var start = range.startContainer,\r
- offset = range.startOffset;\r
+ var ct = range.startContainer;\r
+\r
+ var previous = range.getPreviousNode( isVisible, null, ct ),\r
+ next = range.getNextNode( isVisible, null, ct );\r
\r
- if ( start.type == CKEDITOR.NODE_TEXT )\r
- return false;\r
+ // Any adjacent text container may absorb the cursor, e.g.\r
+ // <p><strong>text</strong>^foo</p>\r
+ // <p>foo^<strong>text</strong></p>\r
+ // <div>^<p>foo</p></div>\r
+ if ( isTextCt( previous ) || isTextCt( next, 1 ) )\r
+ return true;\r
\r
- // 1. Empty inline element. <span>^</span>\r
- // 2. Adjoin to inline element. <p><strong>text</strong>^</p>\r
- // 3. The only empty block in document. <body><p>^</p></body> (#7222)\r
- return !CKEDITOR.tools.trim( start.getHtml() ) ? isInlineCt( start ) || singletonBlock( start )\r
- : isInlineCt( start.getChild( offset - 1 ) ) || isInlineCt( start.getChild( offset ) );\r
+ // Empty block/inline element is also affected. <span>^</span>, <p>^</p> (#7222)\r
+ if ( !( previous || next ) && !( ct.type == CKEDITOR.NODE_ELEMENT && ct.isBlockBoundary() && ct.getBogus() ) )\r
+ return true;\r
+\r
+ return false;\r
}\r
\r
var selectAllCmd =\r
editor.on( 'contentDom', function()\r
{\r
var doc = editor.document,\r
+ outerDoc = CKEDITOR.document,\r
body = doc.getBody(),\r
html = doc.getDocumentElement();\r
\r
saveSelection();\r
});\r
\r
- // When content doc is in standards mode, IE doesn't focus the editor when\r
- // clicking at the region below body (on html element) content, we emulate\r
- // the normal behavior on old IEs. (#1659, #7932)\r
- if ( ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat )\r
- && doc.$.compatMode != 'BackCompat' )\r
+ // When content doc is in standards mode, IE doesn't produce text selection\r
+ // when click on the region outside of body, we emulate\r
+ // the correct behavior here. (#1659, #7932, # 9097)\r
+ if ( doc.$.compatMode != 'BackCompat' )\r
{\r
- html.on( 'mousedown', function( evt )\r
+ if ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat )\r
{\r
- evt = evt.data.$;\r
-\r
- // Expand the text range along with mouse move.\r
- function onHover( evt )\r
+ function moveRangeToPoint( range, x, y )\r
{\r
- evt = evt.data.$;\r
- if ( textRng )\r
- {\r
- // Read the current cursor.\r
- var rngEnd = body.$.createTextRange();\r
- rngEnd.moveToPoint( evt.x, evt.y );\r
-\r
- // Handle drag directions.\r
- textRng.setEndPoint(\r
- textRng.compareEndPoints( 'StartToStart', rngEnd ) < 0 ?\r
- 'EndToEnd' :\r
- 'StartToStart',\r
- rngEnd );\r
-\r
- // Update selection with new range.\r
- textRng.select();\r
- }\r
+ // Error prune in IE7. (#9034, #9110)\r
+ try { range.moveToPoint( x, y ); } catch ( e ) {}\r
}\r
\r
- // We're sure that the click happens at the region\r
- // below body, but not on scrollbar.\r
- if ( evt.y < html.$.clientHeight\r
- && evt.y > body.$.offsetTop + body.$.clientHeight\r
- && evt.x < html.$.clientWidth )\r
+ html.on( 'mousedown', function( evt )\r
{\r
- // Start to build the text range.\r
- var textRng = body.$.createTextRange();\r
- textRng.moveToPoint( evt.x, evt.y );\r
- textRng.select();\r
+ // Expand the text range along with mouse move.\r
+ function onHover( evt )\r
+ {\r
+ evt = evt.data.$;\r
+ if ( textRng )\r
+ {\r
+ // Read the current cursor.\r
+ var rngEnd = body.$.createTextRange();\r
+\r
+ moveRangeToPoint( rngEnd, evt.x, evt.y );\r
+\r
+ // Handle drag directions.\r
+ textRng.setEndPoint(\r
+ startRng.compareEndPoints( 'StartToStart', rngEnd ) < 0 ?\r
+ 'EndToEnd' :\r
+ 'StartToStart',\r
+ rngEnd );\r
+\r
+ // Update selection with new range.\r
+ textRng.select();\r
+ }\r
+ }\r
\r
- html.on( 'mousemove', onHover );\r
+ function removeListeners()\r
+ {\r
+ outerDoc.removeListener( 'mouseup', onSelectEnd );\r
+ html.removeListener( 'mouseup', onSelectEnd );\r
+ }\r
\r
- html.on( 'mouseup', function( evt )\r
+ function onSelectEnd()\r
{\r
+\r
html.removeListener( 'mousemove', onHover );\r
- evt.removeListener();\r
+ removeListeners();\r
+\r
+ // Make it in effect on mouse up. (#9022)\r
textRng.select();\r
- textRng = null;\r
- } );\r
- }\r
- });\r
- }\r
+ }\r
\r
- // It's much simpler for IE8, we just need to reselect the reported range.\r
- if ( CKEDITOR.env.ie8 )\r
- {\r
- html.on( 'mouseup', function( evt )\r
+ evt = evt.data;\r
+\r
+ // We're sure that the click happens at the region\r
+ // outside body, but not on scrollbar.\r
+ if ( evt.getTarget().is( 'html' ) &&\r
+ evt.$.x < html.$.clientWidth &&\r
+ evt.$.y < html.$.clientHeight )\r
+ {\r
+ // Start to build the text range.\r
+ var textRng = body.$.createTextRange();\r
+ moveRangeToPoint( textRng, evt.$.x, evt.$.y );\r
+ // Records the dragging start of the above text range.\r
+ var startRng = textRng.duplicate();\r
+\r
+ html.on( 'mousemove', onHover );\r
+ outerDoc.on( 'mouseup', onSelectEnd );\r
+ html.on( 'mouseup', onSelectEnd );\r
+ }\r
+ });\r
+ }\r
+\r
+ // It's much simpler for IE > 8, we just need to reselect the reported range.\r
+ if ( CKEDITOR.env.ie8 )\r
{\r
- // The event is not fired when clicking on the scrollbars,\r
- // so we can safely check the following to understand\r
- // whether the empty space following <body> has been clicked.\r
- if ( evt.data.getTarget().getName() == 'html' )\r
+ html.on( 'mousedown', function( evt )\r
+ {\r
+ if ( evt.data.getTarget().is( 'html' ) )\r
+ {\r
+ // Limit the text selection mouse move inside of editable. (#9715)\r
+ outerDoc.on( 'mouseup', onSelectEnd );\r
+ html.on( 'mouseup', onSelectEnd );\r
+ }\r
+\r
+ });\r
+\r
+ function removeListeners()\r
{\r
- var sel = CKEDITOR.document.$.selection,\r
- range = sel.createRange();\r
- // The selection range is reported on host, but actually it should applies to the content doc.\r
- if ( sel.type != 'None' && range.parentElement().ownerDocument == doc.$ )\r
- range.select();\r
+ outerDoc.removeListener( 'mouseup', onSelectEnd );\r
+ html.removeListener( 'mouseup', onSelectEnd );\r
}\r
- } );\r
- }\r
\r
+ function onSelectEnd()\r
+ {\r
+ removeListeners();\r
+\r
+ // The event is not fired when clicking on the scrollbars,\r
+ // so we can safely check the following to understand\r
+ // whether the empty space following <body> has been clicked.\r
+ var sel = CKEDITOR.document.$.selection,\r
+ range = sel.createRange();\r
+ // The selection range is reported on host, but actually it should applies to the content doc.\r
+ if ( sel.type != 'None' && range.parentElement().ownerDocument == doc.$ )\r
+ range.select();\r
+ }\r
+ }\r
+\r
+ }\r
// IE is the only to provide the "selectionchange"\r
// event.\r
doc.on( 'selectionchange', saveSelection );\r
return;\r
}\r
\r
- savedRange = nativeSel && sel.getRanges()[ 0 ];\r
+ // Not break because of this. (#9132)\r
+ try{ savedRange = nativeSel && sel.getRanges()[ 0 ]; } catch( er ) {}\r
\r
checkSelectionChangeTimeout.call( editor );\r
}\r
\r
if ( CKEDITOR.env.webkit )\r
{\r
+ // Before keystroke is handled by editor, check to remove the filling char.\r
doc.on( 'keydown', function( evt )\r
{\r
var key = evt.data.getKey();\r
removeFillingChar( editor.document );\r
}\r
\r
- }, null, null, 10 );\r
+ }, null, null, -1 );\r
}\r
});\r
\r
command : 'selectAll'\r
});\r
\r
- editor.selectionChange = checkSelectionChangeTimeout;\r
+ /**\r
+ * Check if to fire the {@link CKEDITOR.editor#selectionChange} event\r
+ * for the current editor instance.\r
+ *\r
+ * @param {Boolean} checkNow Check immediately without any delay.\r
+ */\r
+ editor.selectionChange = function( checkNow )\r
+ {\r
+ ( checkNow ? checkSelectionChange : checkSelectionChangeTimeout ).call( this );\r
+ };\r
\r
// IE9 might cease to work if there's an object selection inside the iframe (#7639).\r
CKEDITOR.env.ie9Compat && editor.on( 'destroy', function()\r
this.isLocked = 0;\r
this.reset();\r
\r
- doc.getBody().focus();\r
-\r
if ( selectedElement )\r
this.selectElement( selectedElement );\r
else\r
start.scrollIntoView();\r
}\r
};\r
-})();\r
\r
-( function()\r
-{\r
var notWhitespaces = CKEDITOR.dom.walker.whitespaces( true ),\r
+ isVisible = CKEDITOR.dom.walker.invisible( 1 ),\r
fillerTextRegex = /\ufeff|\u00a0/,\r
nonCells = { table:1,tbody:1,tr:1 };\r
\r