diff options
Diffstat (limited to 'sources/core/dom')
-rw-r--r-- | sources/core/dom/document.js | 2 | ||||
-rw-r--r-- | sources/core/dom/domobject.js | 4 | ||||
-rw-r--r-- | sources/core/dom/element.js | 36 | ||||
-rw-r--r-- | sources/core/dom/elementpath.js | 22 | ||||
-rw-r--r-- | sources/core/dom/iterator.js | 20 | ||||
-rw-r--r-- | sources/core/dom/node.js | 10 | ||||
-rw-r--r-- | sources/core/dom/nodelist.js | 17 | ||||
-rw-r--r-- | sources/core/dom/range.js | 200 | ||||
-rw-r--r-- | sources/core/dom/rangelist.js | 2 | ||||
-rw-r--r-- | sources/core/dom/text.js | 2 | ||||
-rw-r--r-- | sources/core/dom/walker.js | 10 |
11 files changed, 237 insertions, 88 deletions
diff --git a/sources/core/dom/document.js b/sources/core/dom/document.js index 51c5b19..ebf0bab 100644 --- a/sources/core/dom/document.js +++ b/sources/core/dom/document.js | |||
@@ -262,7 +262,7 @@ CKEDITOR.tools.extend( CKEDITOR.dom.document.prototype, { | |||
262 | * @param {String} html The HTML defining the document content. | 262 | * @param {String} html The HTML defining the document content. |
263 | */ | 263 | */ |
264 | write: function( html ) { | 264 | write: function( html ) { |
265 | // Don't leave any history log in IE. (#5657) | 265 | // Don't leave any history log in IE. (http://dev.ckeditor.com/ticket/5657) |
266 | this.$.open( 'text/html', 'replace' ); | 266 | this.$.open( 'text/html', 'replace' ); |
267 | 267 | ||
268 | // Support for custom document.domain in IE. | 268 | // Support for custom document.domain in IE. |
diff --git a/sources/core/dom/domobject.js b/sources/core/dom/domobject.js index 4c593ff..f4e258a 100644 --- a/sources/core/dom/domobject.js +++ b/sources/core/dom/domobject.js | |||
@@ -41,7 +41,7 @@ CKEDITOR.dom.domObject.prototype = ( function() { | |||
41 | return function( domEvent ) { | 41 | return function( domEvent ) { |
42 | // In FF, when reloading the page with the editor focused, it may | 42 | // In FF, when reloading the page with the editor focused, it may |
43 | // throw an error because the CKEDITOR global is not anymore | 43 | // throw an error because the CKEDITOR global is not anymore |
44 | // available. So, we check it here first. (#2923) | 44 | // available. So, we check it here first. (http://dev.ckeditor.com/ticket/2923) |
45 | if ( typeof CKEDITOR != 'undefined' ) | 45 | if ( typeof CKEDITOR != 'undefined' ) |
46 | domObject.fire( eventName, new CKEDITOR.dom.event( domEvent ) ); | 46 | domObject.fire( eventName, new CKEDITOR.dom.event( domEvent ) ); |
47 | }; | 47 | }; |
@@ -138,7 +138,7 @@ CKEDITOR.dom.domObject.prototype = ( function() { | |||
138 | } | 138 | } |
139 | 139 | ||
140 | // Remove events from events object so fire() method will not call | 140 | // Remove events from events object so fire() method will not call |
141 | // listeners (#11400). | 141 | // listeners (http://dev.ckeditor.com/ticket/11400). |
142 | CKEDITOR.event.prototype.removeAllListeners.call( this ); | 142 | CKEDITOR.event.prototype.removeAllListeners.call( this ); |
143 | } | 143 | } |
144 | }; | 144 | }; |
diff --git a/sources/core/dom/element.js b/sources/core/dom/element.js index e02ff17..31451f9 100644 --- a/sources/core/dom/element.js +++ b/sources/core/dom/element.js | |||
@@ -308,7 +308,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
308 | */ | 308 | */ |
309 | appendText: function( text ) { | 309 | appendText: function( text ) { |
310 | // On IE8 it is impossible to append node to script tag, so we use its text. | 310 | // On IE8 it is impossible to append node to script tag, so we use its text. |
311 | // On the contrary, on Safari the text property is unpredictable in links. (#13232) | 311 | // On the contrary, on Safari the text property is unpredictable in links. (http://dev.ckeditor.com/ticket/13232) |
312 | if ( this.$.text != null && CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) | 312 | if ( this.$.text != null && CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) |
313 | this.$.text += text; | 313 | this.$.text += text; |
314 | else | 314 | else |
@@ -377,7 +377,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
377 | 377 | ||
378 | // In case of Internet Explorer, we must check if there is no background-color | 378 | // In case of Internet Explorer, we must check if there is no background-color |
379 | // added to the element. In such case, we have to overwrite it to prevent "switching it off" | 379 | // added to the element. In such case, we have to overwrite it to prevent "switching it off" |
380 | // by a browser (#14667). | 380 | // by a browser (http://dev.ckeditor.com/ticket/14667). |
381 | if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) { | 381 | if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) { |
382 | tmpElement = new CKEDITOR.dom.element( 'div' ); | 382 | tmpElement = new CKEDITOR.dom.element( 'div' ); |
383 | 383 | ||
@@ -452,7 +452,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
452 | */ | 452 | */ |
453 | getHtml: function() { | 453 | getHtml: function() { |
454 | var retval = this.$.innerHTML; | 454 | var retval = this.$.innerHTML; |
455 | // Strip <?xml:namespace> tags in IE. (#3341). | 455 | // Strip <?xml:namespace> tags in IE. (http://dev.ckeditor.com/ticket/3341). |
456 | return CKEDITOR.env.ie ? retval.replace( /<\?[^>]*>/g, '' ) : retval; | 456 | return CKEDITOR.env.ie ? retval.replace( /<\?[^>]*>/g, '' ) : retval; |
457 | }, | 457 | }, |
458 | 458 | ||
@@ -467,7 +467,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
467 | getOuterHtml: function() { | 467 | getOuterHtml: function() { |
468 | if ( this.$.outerHTML ) { | 468 | if ( this.$.outerHTML ) { |
469 | // IE includes the <?xml:namespace> tag in the outerHTML of | 469 | // IE includes the <?xml:namespace> tag in the outerHTML of |
470 | // namespaced element. So, we must strip it here. (#3341) | 470 | // namespaced element. So, we must strip it here. (http://dev.ckeditor.com/ticket/3341) |
471 | return this.$.outerHTML.replace( /<\?[^>]*>/, '' ); | 471 | return this.$.outerHTML.replace( /<\?[^>]*>/, '' ); |
472 | } | 472 | } |
473 | 473 | ||
@@ -618,7 +618,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
618 | return this.$[ name ]; | 618 | return this.$[ name ]; |
619 | 619 | ||
620 | case 'style': | 620 | case 'style': |
621 | // IE does not return inline styles via getAttribute(). See #2947. | 621 | // IE does not return inline styles via getAttribute(). See http://dev.ckeditor.com/ticket/2947. |
622 | return this.$.style.cssText; | 622 | return this.$.style.cssText; |
623 | 623 | ||
624 | case 'contenteditable': | 624 | case 'contenteditable': |
@@ -679,7 +679,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
679 | function( propertyName ) { | 679 | function( propertyName ) { |
680 | var style = this.getWindow().$.getComputedStyle( this.$, null ); | 680 | var style = this.getWindow().$.getComputedStyle( this.$, null ); |
681 | 681 | ||
682 | // Firefox may return null if we call the above on a hidden iframe. (#9117) | 682 | // Firefox may return null if we call the above on a hidden iframe. (http://dev.ckeditor.com/ticket/9117) |
683 | return style ? style.getPropertyValue( propertyName ) : ''; | 683 | return style ? style.getPropertyValue( propertyName ) : ''; |
684 | } : function( propertyName ) { | 684 | } : function( propertyName ) { |
685 | return this.$.currentStyle[ CKEDITOR.tools.cssStyleToDomStyle( propertyName ) ]; | 685 | return this.$.currentStyle[ CKEDITOR.tools.cssStyleToDomStyle( propertyName ) ]; |
@@ -972,7 +972,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
972 | elementWindow, elementWindowFrame; | 972 | elementWindow, elementWindowFrame; |
973 | 973 | ||
974 | // Webkit and Opera report non-zero offsetHeight despite that | 974 | // Webkit and Opera report non-zero offsetHeight despite that |
975 | // element is inside an invisible iframe. (#4542) | 975 | // element is inside an invisible iframe. (http://dev.ckeditor.com/ticket/4542) |
976 | if ( isVisible && CKEDITOR.env.webkit ) { | 976 | if ( isVisible && CKEDITOR.env.webkit ) { |
977 | elementWindow = this.getWindow(); | 977 | elementWindow = this.getWindow(); |
978 | 978 | ||
@@ -1033,7 +1033,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
1033 | // attribute, which will be marked as "specified", even if the | 1033 | // attribute, which will be marked as "specified", even if the |
1034 | // outerHTML of the element is not displaying the class attribute. | 1034 | // outerHTML of the element is not displaying the class attribute. |
1035 | // Note : I was not able to reproduce it outside the editor, | 1035 | // Note : I was not able to reproduce it outside the editor, |
1036 | // but I've faced it while working on the TC of #1391. | 1036 | // but I've faced it while working on the TC of http://dev.ckeditor.com/ticket/1391. |
1037 | if ( this.getAttribute( 'class' ) ) { | 1037 | if ( this.getAttribute( 'class' ) ) { |
1038 | return true; | 1038 | return true; |
1039 | } | 1039 | } |
@@ -1057,7 +1057,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
1057 | var attrs = this.$.attributes, | 1057 | var attrs = this.$.attributes, |
1058 | attrsNum = attrs.length; | 1058 | attrsNum = attrs.length; |
1059 | 1059 | ||
1060 | // The _moz_dirty attribute might get into the element after pasting (#5455) | 1060 | // The _moz_dirty attribute might get into the element after pasting (http://dev.ckeditor.com/ticket/5455) |
1061 | var execludeAttrs = { 'data-cke-expando': 1, _moz_dirty: 1 }; | 1061 | var execludeAttrs = { 'data-cke-expando': 1, _moz_dirty: 1 }; |
1062 | 1062 | ||
1063 | return attrsNum > 0 && ( attrsNum > 2 || !execludeAttrs[ attrs[ 0 ].nodeName ] || ( attrsNum == 2 && !execludeAttrs[ attrs[ 1 ].nodeName ] ) ); | 1063 | return attrsNum > 0 && ( attrsNum > 2 || !execludeAttrs[ attrs[ 0 ].nodeName ] || ( attrsNum == 2 && !execludeAttrs[ attrs[ 1 ].nodeName ] ) ); |
@@ -1164,7 +1164,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
1164 | function mergeElements( element, sibling, isNext ) { | 1164 | function mergeElements( element, sibling, isNext ) { |
1165 | if ( sibling && sibling.type == CKEDITOR.NODE_ELEMENT ) { | 1165 | if ( sibling && sibling.type == CKEDITOR.NODE_ELEMENT ) { |
1166 | // Jumping over bookmark nodes and empty inline elements, e.g. <b><i></i></b>, | 1166 | // Jumping over bookmark nodes and empty inline elements, e.g. <b><i></i></b>, |
1167 | // queuing them to be moved later. (#5567) | 1167 | // queuing them to be moved later. (http://dev.ckeditor.com/ticket/5567) |
1168 | var pendingNodes = []; | 1168 | var pendingNodes = []; |
1169 | 1169 | ||
1170 | while ( sibling.data( 'cke-bookmark' ) || sibling.isEmptyInlineRemoveable() ) { | 1170 | while ( sibling.data( 'cke-bookmark' ) || sibling.isEmptyInlineRemoveable() ) { |
@@ -1194,7 +1194,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
1194 | } | 1194 | } |
1195 | 1195 | ||
1196 | return function( inlineOnly ) { | 1196 | return function( inlineOnly ) { |
1197 | // Merge empty links and anchors also. (#5567) | 1197 | // Merge empty links and anchors also. (http://dev.ckeditor.com/ticket/5567) |
1198 | if ( !( inlineOnly === false || CKEDITOR.dtd.$removeEmpty[ this.getName() ] || this.is( 'a' ) ) ) { | 1198 | if ( !( inlineOnly === false || CKEDITOR.dtd.$removeEmpty[ this.getName() ] || this.is( 'a' ) ) ) { |
1199 | return; | 1199 | return; |
1200 | } | 1200 | } |
@@ -1253,7 +1253,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
1253 | }; | 1253 | }; |
1254 | } else if ( CKEDITOR.env.ie8Compat && CKEDITOR.env.secure ) { | 1254 | } else if ( CKEDITOR.env.ie8Compat && CKEDITOR.env.secure ) { |
1255 | return function( name, value ) { | 1255 | return function( name, value ) { |
1256 | // IE8 throws error when setting src attribute to non-ssl value. (#7847) | 1256 | // IE8 throws error when setting src attribute to non-ssl value. (http://dev.ckeditor.com/ticket/7847) |
1257 | if ( name == 'src' && value.match( /^http:\/\// ) ) { | 1257 | if ( name == 'src' && value.match( /^http:\/\// ) ) { |
1258 | try { | 1258 | try { |
1259 | standard.apply( this, arguments ); | 1259 | standard.apply( this, arguments ); |
@@ -1501,7 +1501,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
1501 | clientLeft = $docElem.clientLeft || body.$.clientLeft || 0, | 1501 | clientLeft = $docElem.clientLeft || body.$.clientLeft || 0, |
1502 | needAdjustScrollAndBorders = true; | 1502 | needAdjustScrollAndBorders = true; |
1503 | 1503 | ||
1504 | // #3804: getBoundingClientRect() works differently on IE and non-IE | 1504 | // http://dev.ckeditor.com/ticket/3804: getBoundingClientRect() works differently on IE and non-IE |
1505 | // browsers, regarding scroll positions. | 1505 | // browsers, regarding scroll positions. |
1506 | // | 1506 | // |
1507 | // On IE, the top position of the <html> element is always 0, no matter | 1507 | // On IE, the top position of the <html> element is always 0, no matter |
@@ -1516,12 +1516,12 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
1516 | needAdjustScrollAndBorders = ( quirks && inBody ) || ( !quirks && inDocElem ); | 1516 | needAdjustScrollAndBorders = ( quirks && inBody ) || ( !quirks && inDocElem ); |
1517 | } | 1517 | } |
1518 | 1518 | ||
1519 | // #12747. | 1519 | // http://dev.ckeditor.com/ticket/12747. |
1520 | if ( needAdjustScrollAndBorders ) { | 1520 | if ( needAdjustScrollAndBorders ) { |
1521 | var scrollRelativeLeft, | 1521 | var scrollRelativeLeft, |
1522 | scrollRelativeTop; | 1522 | scrollRelativeTop; |
1523 | 1523 | ||
1524 | // See #12758 to know more about document.(documentElement|body).scroll(Left|Top) in Webkit. | 1524 | // See http://dev.ckeditor.com/ticket/12758 to know more about document.(documentElement|body).scroll(Left|Top) in Webkit. |
1525 | if ( CKEDITOR.env.webkit || ( CKEDITOR.env.ie && CKEDITOR.env.version >= 12 ) ) { | 1525 | if ( CKEDITOR.env.webkit || ( CKEDITOR.env.ie && CKEDITOR.env.version >= 12 ) ) { |
1526 | scrollRelativeLeft = body.$.scrollLeft || $docElem.scrollLeft; | 1526 | scrollRelativeLeft = body.$.scrollLeft || $docElem.scrollLeft; |
1527 | scrollRelativeTop = body.$.scrollTop || $docElem.scrollTop; | 1527 | scrollRelativeTop = body.$.scrollTop || $docElem.scrollTop; |
@@ -1603,7 +1603,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
1603 | parent.$.clientHeight && parent.$.clientHeight < parent.$.scrollHeight; | 1603 | parent.$.clientHeight && parent.$.clientHeight < parent.$.scrollHeight; |
1604 | 1604 | ||
1605 | // Skip body element, which will report wrong clientHeight when containing | 1605 | // Skip body element, which will report wrong clientHeight when containing |
1606 | // floated content. (#9523) | 1606 | // floated content. (http://dev.ckeditor.com/ticket/9523) |
1607 | if ( overflowed && !parent.is( 'body' ) ) | 1607 | if ( overflowed && !parent.is( 'body' ) ) |
1608 | this.scrollIntoParent( parent, alignToTop, 1 ); | 1608 | this.scrollIntoParent( parent, alignToTop, 1 ); |
1609 | 1609 | ||
@@ -1677,7 +1677,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
1677 | } | 1677 | } |
1678 | 1678 | ||
1679 | // [WebKit] Reset stored scrollTop value to not break scrollIntoView() method flow. | 1679 | // [WebKit] Reset stored scrollTop value to not break scrollIntoView() method flow. |
1680 | // Scrolling breaks when range.select() is used right after element.scrollIntoView(). (#14659) | 1680 | // Scrolling breaks when range.select() is used right after element.scrollIntoView(). (http://dev.ckeditor.com/ticket/14659) |
1681 | if ( CKEDITOR.env.webkit ) { | 1681 | if ( CKEDITOR.env.webkit ) { |
1682 | var editor = this.getEditor( false ); | 1682 | var editor = this.getEditor( false ); |
1683 | 1683 | ||
@@ -1857,7 +1857,7 @@ CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatab | |||
1857 | this.getParent( true ) && this.$.parentNode.replaceChild( newNode.$, this.$ ); | 1857 | this.getParent( true ) && this.$.parentNode.replaceChild( newNode.$, this.$ ); |
1858 | newNode.$[ 'data-cke-expando' ] = this.$[ 'data-cke-expando' ]; | 1858 | newNode.$[ 'data-cke-expando' ] = this.$[ 'data-cke-expando' ]; |
1859 | this.$ = newNode.$; | 1859 | this.$ = newNode.$; |
1860 | // Bust getName's cache. (#8663) | 1860 | // Bust getName's cache. (http://dev.ckeditor.com/ticket/8663) |
1861 | delete this.getName; | 1861 | delete this.getName; |
1862 | }, | 1862 | }, |
1863 | 1863 | ||
diff --git a/sources/core/dom/elementpath.js b/sources/core/dom/elementpath.js index 1a3aed0..dd50f10 100644 --- a/sources/core/dom/elementpath.js +++ b/sources/core/dom/elementpath.js | |||
@@ -57,6 +57,11 @@ | |||
57 | // Backward compact. | 57 | // Backward compact. |
58 | root = root || startNode.getDocument().getBody(); | 58 | root = root || startNode.getDocument().getBody(); |
59 | 59 | ||
60 | // Assign root value if startNode is null (#424)(https://dev.ckeditor.com/ticket/17028). | ||
61 | if ( !e ) { | ||
62 | e = root; | ||
63 | } | ||
64 | |||
60 | do { | 65 | do { |
61 | if ( e.type == CKEDITOR.NODE_ELEMENT ) { | 66 | if ( e.type == CKEDITOR.NODE_ELEMENT ) { |
62 | elements.push( e ); | 67 | elements.push( e ); |
@@ -84,7 +89,7 @@ | |||
84 | block = e; | 89 | block = e; |
85 | 90 | ||
86 | if ( pathBlockLimitElements[ elementName ] ) { | 91 | if ( pathBlockLimitElements[ elementName ] ) { |
87 | // End level DIV is considered as the block, if no block is available. (#525) | 92 | // End level DIV is considered as the block, if no block is available. (http://dev.ckeditor.com/ticket/525) |
88 | // But it must NOT be the root element (checked above). | 93 | // But it must NOT be the root element (checked above). |
89 | if ( !block && elementName == 'div' && !checkHasBlock( e ) ) | 94 | if ( !block && elementName == 'div' && !checkHasBlock( e ) ) |
90 | block = e; | 95 | block = e; |
@@ -181,7 +186,9 @@ CKEDITOR.dom.elementPath.prototype = { | |||
181 | * @returns {CKEDITOR.dom.element} The first matched dom element or `null`. | 186 | * @returns {CKEDITOR.dom.element} The first matched dom element or `null`. |
182 | */ | 187 | */ |
183 | contains: function( query, excludeRoot, fromTop ) { | 188 | contains: function( query, excludeRoot, fromTop ) { |
184 | var evaluator; | 189 | var i = 0, |
190 | evaluator; | ||
191 | |||
185 | if ( typeof query == 'string' ) | 192 | if ( typeof query == 'string' ) |
186 | evaluator = function( node ) { | 193 | evaluator = function( node ) { |
187 | return node.getName() == query; | 194 | return node.getName() == query; |
@@ -203,14 +210,21 @@ CKEDITOR.dom.elementPath.prototype = { | |||
203 | 210 | ||
204 | var elements = this.elements, | 211 | var elements = this.elements, |
205 | length = elements.length; | 212 | length = elements.length; |
206 | excludeRoot && length--; | 213 | |
214 | if ( excludeRoot ) { | ||
215 | if ( !fromTop ) { | ||
216 | length -= 1; | ||
217 | } else { | ||
218 | i += 1; | ||
219 | } | ||
220 | } | ||
207 | 221 | ||
208 | if ( fromTop ) { | 222 | if ( fromTop ) { |
209 | elements = Array.prototype.slice.call( elements, 0 ); | 223 | elements = Array.prototype.slice.call( elements, 0 ); |
210 | elements.reverse(); | 224 | elements.reverse(); |
211 | } | 225 | } |
212 | 226 | ||
213 | for ( var i = 0; i < length; i++ ) { | 227 | for ( ; i < length; i++ ) { |
214 | if ( evaluator( elements[ i ] ) ) | 228 | if ( evaluator( elements[ i ] ) ) |
215 | return elements[ i ]; | 229 | return elements[ i ]; |
216 | } | 230 | } |
diff --git a/sources/core/dom/iterator.js b/sources/core/dom/iterator.js index 50056ec..9176e33 100644 --- a/sources/core/dom/iterator.js +++ b/sources/core/dom/iterator.js | |||
@@ -45,7 +45,7 @@ | |||
45 | */ | 45 | */ |
46 | this.forceBrBreak = 0; | 46 | this.forceBrBreak = 0; |
47 | 47 | ||
48 | // (#3730). | 48 | // (http://dev.ckeditor.com/ticket/3730). |
49 | /** | 49 | /** |
50 | * Whether to include `<br>` elements in the enlarged range. Should be | 50 | * Whether to include `<br>` elements in the enlarged range. Should be |
51 | * set to `false` when using the iterator in the {@link CKEDITOR#ENTER_BR} mode. | 51 | * set to `false` when using the iterator in the {@link CKEDITOR#ENTER_BR} mode. |
@@ -85,7 +85,7 @@ | |||
85 | */ | 85 | */ |
86 | 86 | ||
87 | var beginWhitespaceRegex = /^[\r\n\t ]+$/, | 87 | var beginWhitespaceRegex = /^[\r\n\t ]+$/, |
88 | // Ignore bookmark nodes.(#3783) | 88 | // Ignore bookmark nodes.(http://dev.ckeditor.com/ticket/3783) |
89 | bookmarkGuard = CKEDITOR.dom.walker.bookmark( false, true ), | 89 | bookmarkGuard = CKEDITOR.dom.walker.bookmark( false, true ), |
90 | whitespacesGuard = CKEDITOR.dom.walker.whitespaces( true ), | 90 | whitespacesGuard = CKEDITOR.dom.walker.whitespaces( true ), |
91 | skipGuard = function( node ) { | 91 | skipGuard = function( node ) { |
@@ -191,12 +191,12 @@ | |||
191 | } | 191 | } |
192 | 192 | ||
193 | // The range must finish right before the boundary, | 193 | // The range must finish right before the boundary, |
194 | // including possibly skipped empty spaces. (#1603) | 194 | // including possibly skipped empty spaces. (http://dev.ckeditor.com/ticket/1603) |
195 | if ( range ) { | 195 | if ( range ) { |
196 | range.setEndAt( currentNode, CKEDITOR.POSITION_BEFORE_START ); | 196 | range.setEndAt( currentNode, CKEDITOR.POSITION_BEFORE_START ); |
197 | 197 | ||
198 | // The found boundary must be set as the next one at this | 198 | // The found boundary must be set as the next one at this |
199 | // point. (#1717) | 199 | // point. (http://dev.ckeditor.com/ticket/1717) |
200 | if ( nodeName != 'br' ) { | 200 | if ( nodeName != 'br' ) { |
201 | this._.nextNode = currentNode; | 201 | this._.nextNode = currentNode; |
202 | } | 202 | } |
@@ -244,7 +244,7 @@ | |||
244 | closeRange = 1; | 244 | closeRange = 1; |
245 | includeNode = 0; | 245 | includeNode = 0; |
246 | isLast = isLast || ( parentNode.equals( lastNode ) ); | 246 | isLast = isLast || ( parentNode.equals( lastNode ) ); |
247 | // Make sure range includes bookmarks at the end of the block. (#7359) | 247 | // Make sure range includes bookmarks at the end of the block. (http://dev.ckeditor.com/ticket/7359) |
248 | range.setEndAt( parentNode, CKEDITOR.POSITION_BEFORE_END ); | 248 | range.setEndAt( parentNode, CKEDITOR.POSITION_BEFORE_END ); |
249 | break; | 249 | break; |
250 | } | 250 | } |
@@ -377,7 +377,7 @@ | |||
377 | // Here we are checking in guard function whether current element | 377 | // Here we are checking in guard function whether current element |
378 | // reach lastNode(default behaviour) and root node to prevent against | 378 | // reach lastNode(default behaviour) and root node to prevent against |
379 | // getting out of editor instance root DOM object. | 379 | // getting out of editor instance root DOM object. |
380 | // #12484 | 380 | // http://dev.ckeditor.com/ticket/12484 |
381 | function guardFunction( node ) { | 381 | function guardFunction( node ) { |
382 | return !( node.equals( lastNode ) || node.equals( rootNode ) ); | 382 | return !( node.equals( lastNode ) || node.equals( rootNode ) ); |
383 | } | 383 | } |
@@ -397,7 +397,7 @@ | |||
397 | // Indicate at least one of the range boundaries is inside a preformat block. | 397 | // Indicate at least one of the range boundaries is inside a preformat block. |
398 | touchPre, | 398 | touchPre, |
399 | 399 | ||
400 | // (#12178) | 400 | // (http://dev.ckeditor.com/ticket/12178) |
401 | // Remember if following situation takes place: | 401 | // Remember if following situation takes place: |
402 | // * startAtInnerBoundary: <p>foo[</p>... | 402 | // * startAtInnerBoundary: <p>foo[</p>... |
403 | // * endAtInnerBoundary: ...<p>]bar</p> | 403 | // * endAtInnerBoundary: ...<p>]bar</p> |
@@ -405,13 +405,13 @@ | |||
405 | // Note that we test only if path block exist, because we must properly shrink | 405 | // Note that we test only if path block exist, because we must properly shrink |
406 | // range containing table and/or table cells. | 406 | // range containing table and/or table cells. |
407 | // Note: When range is collapsed there's no way it can be shrinked. | 407 | // Note: When range is collapsed there's no way it can be shrinked. |
408 | // By checking if range is collapsed we also prevent #12308. | 408 | // By checking if range is collapsed we also prevent http://dev.ckeditor.com/ticket/12308. |
409 | startPath = range.startPath(), | 409 | startPath = range.startPath(), |
410 | endPath = range.endPath(), | 410 | endPath = range.endPath(), |
411 | startAtInnerBoundary = !range.collapsed && rangeAtInnerBlockBoundary( range, startPath.block ), | 411 | startAtInnerBoundary = !range.collapsed && rangeAtInnerBlockBoundary( range, startPath.block ), |
412 | endAtInnerBoundary = !range.collapsed && rangeAtInnerBlockBoundary( range, endPath.block, 1 ); | 412 | endAtInnerBoundary = !range.collapsed && rangeAtInnerBlockBoundary( range, endPath.block, 1 ); |
413 | 413 | ||
414 | // Shrink the range to exclude harmful "noises" (#4087, #4450, #5435). | 414 | // Shrink the range to exclude harmful "noises" (http://dev.ckeditor.com/ticket/4087, http://dev.ckeditor.com/ticket/4450, http://dev.ckeditor.com/ticket/5435). |
415 | range.shrink( CKEDITOR.SHRINK_ELEMENT, true ); | 415 | range.shrink( CKEDITOR.SHRINK_ELEMENT, true ); |
416 | 416 | ||
417 | if ( startAtInnerBoundary ) | 417 | if ( startAtInnerBoundary ) |
@@ -437,7 +437,7 @@ | |||
437 | 437 | ||
438 | // We may have an empty text node at the end of block due to [3770]. | 438 | // We may have an empty text node at the end of block due to [3770]. |
439 | // If that node is the lastNode, it would cause our logic to leak to the | 439 | // If that node is the lastNode, it would cause our logic to leak to the |
440 | // next block.(#3887) | 440 | // next block.(http://dev.ckeditor.com/ticket/3887) |
441 | if ( this._.lastNode && this._.lastNode.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.trim( this._.lastNode.getText() ) && this._.lastNode.getParent().isBlockBoundary() ) { | 441 | if ( this._.lastNode && this._.lastNode.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.trim( this._.lastNode.getText() ) && this._.lastNode.getParent().isBlockBoundary() ) { |
442 | var testRange = this.range.clone(); | 442 | var testRange = this.range.clone(); |
443 | testRange.moveToPosition( this._.lastNode, CKEDITOR.POSITION_AFTER_END ); | 443 | testRange.moveToPosition( this._.lastNode, CKEDITOR.POSITION_AFTER_END ); |
diff --git a/sources/core/dom/node.js b/sources/core/dom/node.js index 51bba18..69b223e 100644 --- a/sources/core/dom/node.js +++ b/sources/core/dom/node.js | |||
@@ -200,7 +200,7 @@ CKEDITOR.tools.extend( CKEDITOR.dom.node.prototype, { | |||
200 | } | 200 | } |
201 | 201 | ||
202 | // IE8 rename HTML5 nodes by adding `:` at the begging of the tag name when the node is cloned, | 202 | // IE8 rename HTML5 nodes by adding `:` at the begging of the tag name when the node is cloned, |
203 | // so `<figure>` will be `<:figure>` after 'cloneNode'. We need to fix it (#13101). | 203 | // so `<figure>` will be `<:figure>` after 'cloneNode'. We need to fix it (http://dev.ckeditor.com/ticket/13101). |
204 | function renameNodes( node ) { | 204 | function renameNodes( node ) { |
205 | if ( node.type != CKEDITOR.NODE_ELEMENT && node.type != CKEDITOR.NODE_DOCUMENT_FRAGMENT ) | 205 | if ( node.type != CKEDITOR.NODE_ELEMENT && node.type != CKEDITOR.NODE_DOCUMENT_FRAGMENT ) |
206 | return; | 206 | return; |
@@ -804,7 +804,7 @@ CKEDITOR.tools.extend( CKEDITOR.dom.node.prototype, { | |||
804 | } else if ( trimmed.length < originalLength ) { | 804 | } else if ( trimmed.length < originalLength ) { |
805 | child.split( originalLength - trimmed.length ); | 805 | child.split( originalLength - trimmed.length ); |
806 | 806 | ||
807 | // IE BUG: child.remove() may raise JavaScript errors here. (#81) | 807 | // IE BUG: child.remove() may raise JavaScript errors here. (http://dev.ckeditor.com/ticket/81) |
808 | this.$.removeChild( this.$.firstChild ); | 808 | this.$.removeChild( this.$.firstChild ); |
809 | } | 809 | } |
810 | } | 810 | } |
@@ -829,7 +829,7 @@ CKEDITOR.tools.extend( CKEDITOR.dom.node.prototype, { | |||
829 | child.split( trimmed.length ); | 829 | child.split( trimmed.length ); |
830 | 830 | ||
831 | // IE BUG: child.getNext().remove() may raise JavaScript errors here. | 831 | // IE BUG: child.getNext().remove() may raise JavaScript errors here. |
832 | // (#81) | 832 | // (http://dev.ckeditor.com/ticket/81) |
833 | this.$.lastChild.parentNode.removeChild( this.$.lastChild ); | 833 | this.$.lastChild.parentNode.removeChild( this.$.lastChild ); |
834 | } | 834 | } |
835 | } | 835 | } |
@@ -840,7 +840,7 @@ CKEDITOR.tools.extend( CKEDITOR.dom.node.prototype, { | |||
840 | child = this.$.lastChild; | 840 | child = this.$.lastChild; |
841 | 841 | ||
842 | if ( child && child.type == 1 && child.nodeName.toLowerCase() == 'br' ) { | 842 | if ( child && child.type == 1 && child.nodeName.toLowerCase() == 'br' ) { |
843 | // Use "eChildNode.parentNode" instead of "node" to avoid IE bug (#324). | 843 | // Use "eChildNode.parentNode" instead of "node" to avoid IE bug (http://dev.ckeditor.com/ticket/324). |
844 | child.parentNode.removeChild( child ); | 844 | child.parentNode.removeChild( child ); |
845 | } | 845 | } |
846 | } | 846 | } |
@@ -874,7 +874,7 @@ CKEDITOR.tools.extend( CKEDITOR.dom.node.prototype, { | |||
874 | if ( this.type != CKEDITOR.NODE_ELEMENT ) | 874 | if ( this.type != CKEDITOR.NODE_ELEMENT ) |
875 | element = this.getParent(); | 875 | element = this.getParent(); |
876 | 876 | ||
877 | // Prevent Edge crash (#13609, #13919). | 877 | // Prevent Edge crash (http://dev.ckeditor.com/ticket/13609, http://dev.ckeditor.com/ticket/13919). |
878 | if ( CKEDITOR.env.edge && element && element.is( 'textarea', 'input' ) ) { | 878 | if ( CKEDITOR.env.edge && element && element.is( 'textarea', 'input' ) ) { |
879 | checkOnlyAttributes = true; | 879 | checkOnlyAttributes = true; |
880 | } | 880 | } |
diff --git a/sources/core/dom/nodelist.js b/sources/core/dom/nodelist.js index 165a415..07af314 100644 --- a/sources/core/dom/nodelist.js +++ b/sources/core/dom/nodelist.js | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | /** | 6 | /** |
7 | * Represents a list of {@link CKEDITOR.dom.node} objects. | 7 | * Represents a list of {@link CKEDITOR.dom.node} objects. |
8 | * It's a wrapper for native nodes list. | 8 | * It is a wrapper for a native nodes list. |
9 | * | 9 | * |
10 | * var nodeList = CKEDITOR.document.getBody().getChildren(); | 10 | * var nodeList = CKEDITOR.document.getBody().getChildren(); |
11 | * alert( nodeList.count() ); // number [0;N] | 11 | * alert( nodeList.count() ); // number [0;N] |
@@ -20,7 +20,7 @@ CKEDITOR.dom.nodeList = function( nativeList ) { | |||
20 | 20 | ||
21 | CKEDITOR.dom.nodeList.prototype = { | 21 | CKEDITOR.dom.nodeList.prototype = { |
22 | /** | 22 | /** |
23 | * Get count of nodes in this list. | 23 | * Gets the count of nodes in this list. |
24 | * | 24 | * |
25 | * @returns {Number} | 25 | * @returns {Number} |
26 | */ | 26 | */ |
@@ -29,7 +29,7 @@ CKEDITOR.dom.nodeList.prototype = { | |||
29 | }, | 29 | }, |
30 | 30 | ||
31 | /** | 31 | /** |
32 | * Get node from the list. | 32 | * Gets the node from the list. |
33 | * | 33 | * |
34 | * @returns {CKEDITOR.dom.node} | 34 | * @returns {CKEDITOR.dom.node} |
35 | */ | 35 | */ |
@@ -39,5 +39,16 @@ CKEDITOR.dom.nodeList.prototype = { | |||
39 | 39 | ||
40 | var $node = this.$[ index ]; | 40 | var $node = this.$[ index ]; |
41 | return $node ? new CKEDITOR.dom.node( $node ) : null; | 41 | return $node ? new CKEDITOR.dom.node( $node ) : null; |
42 | }, | ||
43 | |||
44 | /** | ||
45 | * Returns a node list as an array. | ||
46 | * | ||
47 | * @returns {CKEDITOR.dom.node[]} | ||
48 | */ | ||
49 | toArray: function() { | ||
50 | return CKEDITOR.tools.array.map( this.$, function( nativeEl ) { | ||
51 | return new CKEDITOR.dom.node( nativeEl ); | ||
52 | } ); | ||
42 | } | 53 | } |
43 | }; | 54 | }; |
diff --git a/sources/core/dom/range.js b/sources/core/dom/range.js index 6407074..742c24c 100644 --- a/sources/core/dom/range.js +++ b/sources/core/dom/range.js | |||
@@ -204,9 +204,14 @@ CKEDITOR.dom.range = function( root ) { | |||
204 | // This allows us to not think about startNode == endNode case later on. | 204 | // This allows us to not think about startNode == endNode case later on. |
205 | // We do that only when cloning, because in other cases we can safely split this text node | 205 | // We do that only when cloning, because in other cases we can safely split this text node |
206 | // and hence we can easily handle this case as many others. | 206 | // and hence we can easily handle this case as many others. |
207 | if ( isClone && endNode.type == CKEDITOR.NODE_TEXT && startNode.equals( endNode ) ) { | 207 | |
208 | startNode = range.document.createText( startNode.substring( startOffset, endOffset ) ); | 208 | // We need to handle situation when selection startNode is type of NODE_ELEMENT (#426). |
209 | docFrag.append( startNode ); | 209 | if ( isClone && |
210 | endNode.type == CKEDITOR.NODE_TEXT && | ||
211 | ( startNode.equals( endNode ) || ( startNode.type === CKEDITOR.NODE_ELEMENT && startNode.getFirst().equals( endNode ) ) ) ) { | ||
212 | |||
213 | // Here we should always be inside one text node. | ||
214 | docFrag.append( range.document.createText( endNode.substring( startOffset, endOffset ) ) ); | ||
210 | return; | 215 | return; |
211 | } | 216 | } |
212 | 217 | ||
@@ -214,7 +219,7 @@ CKEDITOR.dom.range = function( root ) { | |||
214 | // second part. The removal will be handled by the rest of the code. | 219 | // second part. The removal will be handled by the rest of the code. |
215 | if ( endNode.type == CKEDITOR.NODE_TEXT ) { | 220 | if ( endNode.type == CKEDITOR.NODE_TEXT ) { |
216 | // If Extract or Delete we can split the text node, | 221 | // If Extract or Delete we can split the text node, |
217 | // but if Clone (2), then we cannot modify the DOM (#11586) so we mark the text node for cloning. | 222 | // but if Clone (2), then we cannot modify the DOM (http://dev.ckeditor.com/ticket/11586) so we mark the text node for cloning. |
218 | if ( !isClone ) { | 223 | if ( !isClone ) { |
219 | endNode = endNode.split( endOffset ); | 224 | endNode = endNode.split( endOffset ); |
220 | } else { | 225 | } else { |
@@ -243,7 +248,7 @@ CKEDITOR.dom.range = function( root ) { | |||
243 | // be handled by the rest of the code . | 248 | // be handled by the rest of the code . |
244 | if ( startNode.type == CKEDITOR.NODE_TEXT ) { | 249 | if ( startNode.type == CKEDITOR.NODE_TEXT ) { |
245 | // If Extract or Delete we can split the text node, | 250 | // If Extract or Delete we can split the text node, |
246 | // but if Clone (2), then we cannot modify the DOM (#11586) so we mark | 251 | // but if Clone (2), then we cannot modify the DOM (http://dev.ckeditor.com/ticket/11586) so we mark |
247 | // the text node for cloning. | 252 | // the text node for cloning. |
248 | if ( !isClone ) { | 253 | if ( !isClone ) { |
249 | startNode.split( startOffset ); | 254 | startNode.split( startOffset ); |
@@ -373,7 +378,7 @@ CKEDITOR.dom.range = function( root ) { | |||
373 | // If we don't do that, in next iterations nodes will be appended to wrong parent. | 378 | // If we don't do that, in next iterations nodes will be appended to wrong parent. |
374 | // | 379 | // |
375 | // We can just take first child because the algorithm guarantees | 380 | // We can just take first child because the algorithm guarantees |
376 | // that this will be the only child on this level. (#13568) | 381 | // that this will be the only child on this level. (http://dev.ckeditor.com/ticket/13568) |
377 | levelParent = levelParent.getChild( 0 ); | 382 | levelParent = levelParent.getChild( 0 ); |
378 | } | 383 | } |
379 | } | 384 | } |
@@ -405,7 +410,7 @@ CKEDITOR.dom.range = function( root ) { | |||
405 | 410 | ||
406 | // When Extracting, move the removed node to the docFrag. | 411 | // When Extracting, move the removed node to the docFrag. |
407 | if ( isExtract ) { | 412 | if ( isExtract ) { |
408 | newParent.append( node ); | 413 | newParent.append( node, toStart ); |
409 | } | 414 | } |
410 | } | 415 | } |
411 | 416 | ||
@@ -574,7 +579,7 @@ CKEDITOR.dom.range = function( root ) { | |||
574 | // Tolerant bogus br when checking at the end of block. | 579 | // Tolerant bogus br when checking at the end of block. |
575 | // Reject any text node unless it's being bookmark | 580 | // Reject any text node unless it's being bookmark |
576 | // OR it's spaces. | 581 | // OR it's spaces. |
577 | // Reject any element unless it's being invisible empty. (#3883) | 582 | // Reject any element unless it's being invisible empty. (http://dev.ckeditor.com/ticket/3883) |
578 | return !checkStart && isBogus( node ) || | 583 | return !checkStart && isBogus( node ) || |
579 | node.type == CKEDITOR.NODE_ELEMENT && | 584 | node.type == CKEDITOR.NODE_ELEMENT && |
580 | node.is( CKEDITOR.dtd.$removeEmpty ); | 585 | node.is( CKEDITOR.dtd.$removeEmpty ); |
@@ -1052,7 +1057,7 @@ CKEDITOR.dom.range = function( root ) { | |||
1052 | } | 1057 | } |
1053 | 1058 | ||
1054 | // Sometimes the endNode will come right before startNode for collapsed | 1059 | // Sometimes the endNode will come right before startNode for collapsed |
1055 | // ranges. Fix it. (#3780) | 1060 | // ranges. Fix it. (http://dev.ckeditor.com/ticket/3780) |
1056 | if ( startNode.getPosition( endNode ) & CKEDITOR.POSITION_FOLLOWING ) | 1061 | if ( startNode.getPosition( endNode ) & CKEDITOR.POSITION_FOLLOWING ) |
1057 | startNode = endNode; | 1062 | startNode = endNode; |
1058 | 1063 | ||
@@ -1324,13 +1329,13 @@ CKEDITOR.dom.range = function( root ) { | |||
1324 | 1329 | ||
1325 | isWhiteSpace = /[\s\ufeff]$/.test( siblingText ); | 1330 | isWhiteSpace = /[\s\ufeff]$/.test( siblingText ); |
1326 | } else { | 1331 | } else { |
1327 | // #12221 (Chrome) plus #11111 (Safari). | 1332 | // http://dev.ckeditor.com/ticket/12221 (Chrome) plus http://dev.ckeditor.com/ticket/11111 (Safari). |
1328 | var offsetWidth0 = CKEDITOR.env.webkit ? 1 : 0; | 1333 | var offsetWidth0 = CKEDITOR.env.webkit ? 1 : 0; |
1329 | 1334 | ||
1330 | // If this is a visible element. | 1335 | // If this is a visible element. |
1331 | // We need to check for the bookmark attribute because IE insists on | 1336 | // We need to check for the bookmark attribute because IE insists on |
1332 | // rendering the display:none nodes we use for bookmarks. (#3363) | 1337 | // rendering the display:none nodes we use for bookmarks. (http://dev.ckeditor.com/ticket/3363) |
1333 | // Line-breaks (br) are rendered with zero width, which we don't want to include. (#7041) | 1338 | // Line-breaks (br) are rendered with zero width, which we don't want to include. (http://dev.ckeditor.com/ticket/7041) |
1334 | if ( ( sibling.$.offsetWidth > offsetWidth0 || excludeBrs && sibling.is( 'br' ) ) && !sibling.data( 'cke-bookmark' ) ) { | 1339 | if ( ( sibling.$.offsetWidth > offsetWidth0 || excludeBrs && sibling.is( 'br' ) ) && !sibling.data( 'cke-bookmark' ) ) { |
1335 | // We'll accept it only if we need | 1340 | // We'll accept it only if we need |
1336 | // whitespace, and this is an inline | 1341 | // whitespace, and this is an inline |
@@ -1399,7 +1404,7 @@ CKEDITOR.dom.range = function( root ) { | |||
1399 | 1404 | ||
1400 | // Process the end boundary. This is basically the same | 1405 | // Process the end boundary. This is basically the same |
1401 | // code used for the start boundary, with small changes to | 1406 | // code used for the start boundary, with small changes to |
1402 | // make it work in the oposite side (to the right). This | 1407 | // make it work in the opposite side (to the right). This |
1403 | // makes it difficult to reuse the code here. So, fixes to | 1408 | // makes it difficult to reuse the code here. So, fixes to |
1404 | // the above code are likely to be replicated here. | 1409 | // the above code are likely to be replicated here. |
1405 | 1410 | ||
@@ -1482,7 +1487,7 @@ CKEDITOR.dom.range = function( root ) { | |||
1482 | } | 1487 | } |
1483 | } | 1488 | } |
1484 | } else { | 1489 | } else { |
1485 | // Get the node right after the boudary to be checked | 1490 | // Get the node right after the boundary to be checked |
1486 | // first. | 1491 | // first. |
1487 | sibling = container.getChild( offset ); | 1492 | sibling = container.getChild( offset ); |
1488 | 1493 | ||
@@ -1525,8 +1530,8 @@ CKEDITOR.dom.range = function( root ) { | |||
1525 | } else if ( sibling.type == CKEDITOR.NODE_ELEMENT ) { | 1530 | } else if ( sibling.type == CKEDITOR.NODE_ELEMENT ) { |
1526 | // If this is a visible element. | 1531 | // If this is a visible element. |
1527 | // We need to check for the bookmark attribute because IE insists on | 1532 | // We need to check for the bookmark attribute because IE insists on |
1528 | // rendering the display:none nodes we use for bookmarks. (#3363) | 1533 | // rendering the display:none nodes we use for bookmarks. (http://dev.ckeditor.com/ticket/3363) |
1529 | // Line-breaks (br) are rendered with zero width, which we don't want to include. (#7041) | 1534 | // Line-breaks (br) are rendered with zero width, which we don't want to include. (http://dev.ckeditor.com/ticket/7041) |
1530 | if ( ( sibling.$.offsetWidth > 0 || excludeBrs && sibling.is( 'br' ) ) && !sibling.data( 'cke-bookmark' ) ) { | 1535 | if ( ( sibling.$.offsetWidth > 0 || excludeBrs && sibling.is( 'br' ) ) && !sibling.data( 'cke-bookmark' ) ) { |
1531 | // We'll accept it only if we need | 1536 | // We'll accept it only if we need |
1532 | // whitespace, and this is an inline | 1537 | // whitespace, and this is an inline |
@@ -1617,7 +1622,7 @@ CKEDITOR.dom.range = function( root ) { | |||
1617 | boundaryGuard = function( node ) { | 1622 | boundaryGuard = function( node ) { |
1618 | // We should not check contents of non-editable elements. It may happen | 1623 | // We should not check contents of non-editable elements. It may happen |
1619 | // that inline widget has display:table child which should not block range#enlarge. | 1624 | // that inline widget has display:table child which should not block range#enlarge. |
1620 | // When encoutered non-editable element... | 1625 | // When encountered non-editable element... |
1621 | if ( node.type == CKEDITOR.NODE_ELEMENT && node.getAttribute( 'contenteditable' ) == 'false' ) { | 1626 | if ( node.type == CKEDITOR.NODE_ELEMENT && node.getAttribute( 'contenteditable' ) == 'false' ) { |
1622 | if ( inNonEditable ) { | 1627 | if ( inNonEditable ) { |
1623 | // ... in which we already were, reset it (because we're leaving it) and return. | 1628 | // ... in which we already were, reset it (because we're leaving it) and return. |
@@ -1639,7 +1644,7 @@ CKEDITOR.dom.range = function( root ) { | |||
1639 | blockBoundary = node; | 1644 | blockBoundary = node; |
1640 | return retval; | 1645 | return retval; |
1641 | }, | 1646 | }, |
1642 | // Record the encounted 'tailBr' for later use. | 1647 | // Record the encountered 'tailBr' for later use. |
1643 | tailBrGuard = function( node ) { | 1648 | tailBrGuard = function( node ) { |
1644 | var retval = boundaryGuard( node ); | 1649 | var retval = boundaryGuard( node ); |
1645 | if ( !retval && node.is && node.is( 'br' ) ) | 1650 | if ( !retval && node.is && node.is( 'br' ) ) |
@@ -1660,7 +1665,7 @@ CKEDITOR.dom.range = function( root ) { | |||
1660 | this.setStartAt( blockBoundary, !blockBoundary.is( 'br' ) && ( !enlargeable && this.checkStartOfBlock() || | 1665 | this.setStartAt( blockBoundary, !blockBoundary.is( 'br' ) && ( !enlargeable && this.checkStartOfBlock() || |
1661 | enlargeable && blockBoundary.contains( enlargeable ) ) ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_AFTER_END ); | 1666 | enlargeable && blockBoundary.contains( enlargeable ) ) ? CKEDITOR.POSITION_AFTER_START : CKEDITOR.POSITION_AFTER_END ); |
1662 | 1667 | ||
1663 | // Avoid enlarging the range further when end boundary spans right after the BR. (#7490) | 1668 | // Avoid enlarging the range further when end boundary spans right after the BR. (http://dev.ckeditor.com/ticket/7490) |
1664 | if ( unit == CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS ) { | 1669 | if ( unit == CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS ) { |
1665 | var theRange = this.clone(); | 1670 | var theRange = this.clone(); |
1666 | walker = new CKEDITOR.dom.walker( theRange ); | 1671 | walker = new CKEDITOR.dom.walker( theRange ); |
@@ -1715,18 +1720,28 @@ CKEDITOR.dom.range = function( root ) { | |||
1715 | }, | 1720 | }, |
1716 | 1721 | ||
1717 | /** | 1722 | /** |
1718 | * Descrease the range to make sure that boundaries | 1723 | * Decreases the range to make sure that boundaries |
1719 | * always anchor beside text nodes or innermost element. | 1724 | * always anchor beside text nodes or the innermost element. |
1720 | * | 1725 | * |
1721 | * @param {Number} mode The shrinking mode ({@link CKEDITOR#SHRINK_ELEMENT} or {@link CKEDITOR#SHRINK_TEXT}). | 1726 | * @param {Number} mode The shrinking mode ({@link CKEDITOR#SHRINK_ELEMENT} or {@link CKEDITOR#SHRINK_TEXT}). |
1722 | * | 1727 | * |
1723 | * * {@link CKEDITOR#SHRINK_ELEMENT} - Shrink the range boundaries to the edge of the innermost element. | 1728 | * * {@link CKEDITOR#SHRINK_ELEMENT} – Shrinks the range boundaries to the edge of the innermost element. |
1724 | * * {@link CKEDITOR#SHRINK_TEXT} - Shrink the range boudaries to anchor by the side of enclosed text | 1729 | * * {@link CKEDITOR#SHRINK_TEXT} – Shrinks the range boundaries to anchor by the side of enclosed text |
1725 | * node, range remains if there's no text nodes on boundaries at all. | 1730 | * node. The range remains if there are no text nodes available on boundaries. |
1726 | * | 1731 | * |
1727 | * @param {Boolean} selectContents Whether result range anchors at the inner OR outer boundary of the node. | 1732 | * @param {Boolean} [selectContents=false] Whether the resulting range anchors at the inner OR outer boundary of the node. |
1733 | * @param {Boolean/Object} [options=true] If this parameter is of a Boolean type, it is treated as | ||
1734 | * `options.shrinkOnBlockBoundary`. This parameter was added in 4.7.0. | ||
1735 | * @param {Boolean} [options.shrinkOnBlockBoundary=true] Whether the block boundary should be included in | ||
1736 | * the shrunk range. | ||
1737 | * @param {Boolean} [options.skipBogus=false] Whether bogus `<br>` elements should be ignored while | ||
1738 | * `mode` is set to {@link CKEDITOR#SHRINK_TEXT}. This option was added in 4.7.0. | ||
1728 | */ | 1739 | */ |
1729 | shrink: function( mode, selectContents, shrinkOnBlockBoundary ) { | 1740 | shrink: function( mode, selectContents, options ) { |
1741 | var shrinkOnBlockBoundary = typeof options === 'boolean' ? options : | ||
1742 | ( options && typeof options.shrinkOnBlockBoundary === 'boolean' ? options.shrinkOnBlockBoundary : true ), | ||
1743 | skipBogus = options && options.skipBogus; | ||
1744 | |||
1730 | // Unable to shrink a collapsed range. | 1745 | // Unable to shrink a collapsed range. |
1731 | if ( !this.collapsed ) { | 1746 | if ( !this.collapsed ) { |
1732 | mode = mode || CKEDITOR.SHRINK_TEXT; | 1747 | mode = mode || CKEDITOR.SHRINK_TEXT; |
@@ -1749,7 +1764,7 @@ CKEDITOR.dom.range = function( root ) { | |||
1749 | walkerRange.setStartAfter( startContainer ); | 1764 | walkerRange.setStartAfter( startContainer ); |
1750 | else { | 1765 | else { |
1751 | // Enlarge the range properly to avoid walker making | 1766 | // Enlarge the range properly to avoid walker making |
1752 | // DOM changes caused by triming the text nodes later. | 1767 | // DOM changes caused by trimming the text nodes later. |
1753 | walkerRange.setStartBefore( startContainer ); | 1768 | walkerRange.setStartBefore( startContainer ); |
1754 | moveStart = 0; | 1769 | moveStart = 0; |
1755 | } | 1770 | } |
@@ -1767,7 +1782,8 @@ CKEDITOR.dom.range = function( root ) { | |||
1767 | } | 1782 | } |
1768 | 1783 | ||
1769 | var walker = new CKEDITOR.dom.walker( walkerRange ), | 1784 | var walker = new CKEDITOR.dom.walker( walkerRange ), |
1770 | isBookmark = CKEDITOR.dom.walker.bookmark(); | 1785 | isBookmark = CKEDITOR.dom.walker.bookmark(), |
1786 | isBogus = CKEDITOR.dom.walker.bogus(); | ||
1771 | 1787 | ||
1772 | walker.evaluator = function( node ) { | 1788 | walker.evaluator = function( node ) { |
1773 | return node.type == ( mode == CKEDITOR.SHRINK_ELEMENT ? CKEDITOR.NODE_ELEMENT : CKEDITOR.NODE_TEXT ); | 1789 | return node.type == ( mode == CKEDITOR.SHRINK_ELEMENT ? CKEDITOR.NODE_ELEMENT : CKEDITOR.NODE_TEXT ); |
@@ -1775,6 +1791,11 @@ CKEDITOR.dom.range = function( root ) { | |||
1775 | 1791 | ||
1776 | var currentElement; | 1792 | var currentElement; |
1777 | walker.guard = function( node, movingOut ) { | 1793 | walker.guard = function( node, movingOut ) { |
1794 | // Skipping bogus before other cases (http://dev.ckeditor.com/ticket/17010). | ||
1795 | if ( skipBogus && isBogus( node ) ) { | ||
1796 | return true; | ||
1797 | } | ||
1798 | |||
1778 | if ( isBookmark( node ) ) | 1799 | if ( isBookmark( node ) ) |
1779 | return true; | 1800 | return true; |
1780 | 1801 | ||
@@ -1816,7 +1837,7 @@ CKEDITOR.dom.range = function( root ) { | |||
1816 | 1837 | ||
1817 | /** | 1838 | /** |
1818 | * Inserts a node at the start of the range. The range will be expanded | 1839 | * Inserts a node at the start of the range. The range will be expanded |
1819 | * the contain the node. | 1840 | * to contain the node. |
1820 | * | 1841 | * |
1821 | * @param {CKEDITOR.dom.node} node | 1842 | * @param {CKEDITOR.dom.node} node |
1822 | */ | 1843 | */ |
@@ -1843,7 +1864,7 @@ CKEDITOR.dom.range = function( root ) { | |||
1843 | }, | 1864 | }, |
1844 | 1865 | ||
1845 | /** | 1866 | /** |
1846 | * Moves the range to given position according to specified node. | 1867 | * Moves the range to a given position according to the specified node. |
1847 | * | 1868 | * |
1848 | * // HTML: <p>Foo <b>bar</b></p> | 1869 | * // HTML: <p>Foo <b>bar</b></p> |
1849 | * range.moveToPosition( elB, CKEDITOR.POSITION_BEFORE_START ); | 1870 | * range.moveToPosition( elB, CKEDITOR.POSITION_BEFORE_START ); |
@@ -1851,7 +1872,7 @@ CKEDITOR.dom.range = function( root ) { | |||
1851 | * | 1872 | * |
1852 | * See also {@link #setStartAt} and {@link #setEndAt}. | 1873 | * See also {@link #setStartAt} and {@link #setEndAt}. |
1853 | * | 1874 | * |
1854 | * @param {CKEDITOR.dom.node} node The node according to which position will be set. | 1875 | * @param {CKEDITOR.dom.node} node The node according to which the position will be set. |
1855 | * @param {Number} position One of {@link CKEDITOR#POSITION_BEFORE_START}, | 1876 | * @param {Number} position One of {@link CKEDITOR#POSITION_BEFORE_START}, |
1856 | * {@link CKEDITOR#POSITION_AFTER_START}, {@link CKEDITOR#POSITION_BEFORE_END}, | 1877 | * {@link CKEDITOR#POSITION_AFTER_START}, {@link CKEDITOR#POSITION_BEFORE_END}, |
1857 | * {@link CKEDITOR#POSITION_AFTER_END}. | 1878 | * {@link CKEDITOR#POSITION_AFTER_END}. |
@@ -2118,7 +2139,7 @@ CKEDITOR.dom.range = function( root ) { | |||
2118 | // So even if the initial range was placed before the bogus <br>, after creating the bookmark it | 2139 | // So even if the initial range was placed before the bogus <br>, after creating the bookmark it |
2119 | // is placed before the bookmark. | 2140 | // is placed before the bookmark. |
2120 | // Fortunately, getBogus() is able to skip the bookmark so it finds the bogus <br> in this case. | 2141 | // Fortunately, getBogus() is able to skip the bookmark so it finds the bogus <br> in this case. |
2121 | // We remove incorrectly placed one and add a brand new one. (#13001) | 2142 | // We remove incorrectly placed one and add a brand new one. (http://dev.ckeditor.com/ticket/13001) |
2122 | var bogus = fixedBlock.getBogus(); | 2143 | var bogus = fixedBlock.getBogus(); |
2123 | if ( bogus ) { | 2144 | if ( bogus ) { |
2124 | bogus.remove(); | 2145 | bogus.remove(); |
@@ -2340,7 +2361,7 @@ CKEDITOR.dom.range = function( root ) { | |||
2340 | this.trim( 0, 1 ); | 2361 | this.trim( 0, 1 ); |
2341 | } | 2362 | } |
2342 | 2363 | ||
2343 | // Antecipate the trim() call here, so the walker will not make | 2364 | // Anticipate the trim() call here, so the walker will not make |
2344 | // changes to the DOM, which would not get reflected into this | 2365 | // changes to the DOM, which would not get reflected into this |
2345 | // range otherwise. | 2366 | // range otherwise. |
2346 | this.trim(); | 2367 | this.trim(); |
@@ -2379,7 +2400,7 @@ CKEDITOR.dom.range = function( root ) { | |||
2379 | this.trim( 1, 0 ); | 2400 | this.trim( 1, 0 ); |
2380 | } | 2401 | } |
2381 | 2402 | ||
2382 | // Antecipate the trim() call here, so the walker will not make | 2403 | // Anticipate the trim() call here, so the walker will not make |
2383 | // changes to the DOM, which would not get reflected into this | 2404 | // changes to the DOM, which would not get reflected into this |
2384 | // range otherwise. | 2405 | // range otherwise. |
2385 | this.trim(); | 2406 | this.trim(); |
@@ -2636,7 +2657,7 @@ CKEDITOR.dom.range = function( root ) { | |||
2636 | getEnclosedNode: function() { | 2657 | getEnclosedNode: function() { |
2637 | var walkerRange = this.clone(); | 2658 | var walkerRange = this.clone(); |
2638 | 2659 | ||
2639 | // Optimize and analyze the range to avoid DOM destructive nature of walker. (#5780) | 2660 | // Optimize and analyze the range to avoid DOM destructive nature of walker. (http://dev.ckeditor.com/ticket/5780) |
2640 | walkerRange.optimize(); | 2661 | walkerRange.optimize(); |
2641 | if ( walkerRange.startContainer.type != CKEDITOR.NODE_ELEMENT || walkerRange.endContainer.type != CKEDITOR.NODE_ELEMENT ) | 2662 | if ( walkerRange.startContainer.type != CKEDITOR.NODE_ELEMENT || walkerRange.endContainer.type != CKEDITOR.NODE_ELEMENT ) |
2642 | return null; | 2663 | return null; |
@@ -2703,6 +2724,53 @@ CKEDITOR.dom.range = function( root ) { | |||
2703 | getPreviousEditableNode: getNextEditableNode( 1 ), | 2724 | getPreviousEditableNode: getNextEditableNode( 1 ), |
2704 | 2725 | ||
2705 | /** | 2726 | /** |
2727 | * Returns any table element, like `td`, `tbody`, `table` etc. from a given range. The element | ||
2728 | * is returned only if the range is contained within one table (might be a nested | ||
2729 | * table, but it cannot be two different tables on the same DOM level). | ||
2730 | * | ||
2731 | * @private | ||
2732 | * @since 4.7 | ||
2733 | * @param {Object} [tableElements] Mapping of element names that should be considered. | ||
2734 | * @returns {CKEDITOR.dom.element/null} | ||
2735 | */ | ||
2736 | _getTableElement: function( tableElements ) { | ||
2737 | tableElements = tableElements || { | ||
2738 | td: 1, | ||
2739 | th: 1, | ||
2740 | tr: 1, | ||
2741 | tbody: 1, | ||
2742 | thead: 1, | ||
2743 | tfoot: 1, | ||
2744 | table: 1 | ||
2745 | }; | ||
2746 | |||
2747 | var start = this.startContainer, | ||
2748 | end = this.endContainer, | ||
2749 | startTable = start.getAscendant( 'table', true ), | ||
2750 | endTable = end.getAscendant( 'table', true ); | ||
2751 | |||
2752 | // Super weird edge case in Safari: if there is a table with only one cell inside and that cell | ||
2753 | // is selected, then the end boundary of the table is moved into editor's editable. | ||
2754 | // That case is also present when selecting the last cell inside nested table. | ||
2755 | if ( CKEDITOR.env.safari && startTable && end.equals( this.root ) ) { | ||
2756 | return start.getAscendant( tableElements, true ); | ||
2757 | } | ||
2758 | |||
2759 | if ( this.getEnclosedNode() ) { | ||
2760 | return this.getEnclosedNode().getAscendant( tableElements, true ); | ||
2761 | } | ||
2762 | |||
2763 | // Ensure that selection starts and ends in the same table or one of the table is inside the other. | ||
2764 | if ( startTable && endTable && ( startTable.equals( endTable ) || startTable.contains( endTable ) || | ||
2765 | endTable.contains( startTable ) ) ) { | ||
2766 | |||
2767 | return start.getAscendant( tableElements, true ); | ||
2768 | } | ||
2769 | |||
2770 | return null; | ||
2771 | }, | ||
2772 | |||
2773 | /** | ||
2706 | * Scrolls the start of current range into view. | 2774 | * Scrolls the start of current range into view. |
2707 | */ | 2775 | */ |
2708 | scrollIntoView: function() { | 2776 | scrollIntoView: function() { |
@@ -2819,10 +2887,10 @@ CKEDITOR.dom.range = function( root ) { | |||
2819 | continue; | 2887 | continue; |
2820 | } | 2888 | } |
2821 | 2889 | ||
2822 | // It's not enough to get elements from common ancestor, because it migth contain too many matches. | 2890 | // It's not enough to get elements from common ancestor, because it might contain too many matches. |
2823 | // We need to ensure that returned items are between boundary points. | 2891 | // We need to ensure that returned items are between boundary points. |
2824 | isStartGood = ( curItem.getPosition( boundaries.startNode ) & CKEDITOR.POSITION_FOLLOWING ) || boundaries.startNode.equals( curItem ); | 2892 | isStartGood = ( curItem.getPosition( boundaries.startNode ) & CKEDITOR.POSITION_FOLLOWING ) || boundaries.startNode.equals( curItem ); |
2825 | isEndGood = ( curItem.getPosition( boundaries.endNode ) & ( CKEDITOR.POSITION_PRECEDING + CKEDITOR.POSITION_IS_CONTAINED ) ); | 2893 | isEndGood = ( curItem.getPosition( boundaries.endNode ) & ( CKEDITOR.POSITION_PRECEDING + CKEDITOR.POSITION_IS_CONTAINED ) ) || boundaries.endNode.equals( curItem ); |
2826 | 2894 | ||
2827 | if ( isStartGood && isEndGood ) { | 2895 | if ( isStartGood && isEndGood ) { |
2828 | ret.push( curItem ); | 2896 | ret.push( curItem ); |
@@ -2834,6 +2902,62 @@ CKEDITOR.dom.range = function( root ) { | |||
2834 | } | 2902 | } |
2835 | }; | 2903 | }; |
2836 | 2904 | ||
2905 | /** | ||
2906 | * Merges every subsequent range in given set, returning a smaller array of ranges. | ||
2907 | * | ||
2908 | * Note that each range in the returned value will be enlarged with `CKEDITOR.ENLARGE_ELEMENT` value. | ||
2909 | * | ||
2910 | * @since 4.7.0 | ||
2911 | * @static | ||
2912 | * @param {CKEDITOR.dom.range[]} ranges | ||
2913 | * @returns {CKEDITOR.dom.range[]} Set of merged ranges. | ||
2914 | * @member CKEDITOR.dom.range | ||
2915 | */ | ||
2916 | CKEDITOR.dom.range.mergeRanges = function( ranges ) { | ||
2917 | return CKEDITOR.tools.array.reduce( ranges, function( ret, rng ) { | ||
2918 | // Last range ATM. | ||
2919 | var lastRange = ret[ ret.length - 1 ], | ||
2920 | isContinuation = false; | ||
2921 | |||
2922 | // Make a clone, we don't want to modify input. | ||
2923 | rng = rng.clone(); | ||
2924 | rng.enlarge( CKEDITOR.ENLARGE_ELEMENT ); | ||
2925 | |||
2926 | if ( lastRange ) { | ||
2927 | // The trick is to create a range spanning the gap between the two ranges. Then iterate over | ||
2928 | // each node found in this gap. If it contains anything other than whitespace, then it means it | ||
2929 | // is not a continuation. | ||
2930 | var gapRange = new CKEDITOR.dom.range( rng.root ), | ||
2931 | walker = new CKEDITOR.dom.walker( gapRange ), | ||
2932 | isWhitespace = CKEDITOR.dom.walker.whitespaces(), | ||
2933 | nodeInBetween; | ||
2934 | |||
2935 | gapRange.setStart( lastRange.endContainer, lastRange.endOffset ); | ||
2936 | gapRange.setEnd( rng.startContainer, rng.startOffset ); | ||
2937 | |||
2938 | nodeInBetween = walker.next(); | ||
2939 | |||
2940 | while ( isWhitespace( nodeInBetween ) || rng.endContainer.equals( nodeInBetween ) ) { | ||
2941 | // We don't care about whitespaces, and range container. Also we skip the endContainer, | ||
2942 | // as it will also be provided by the iterator (as it visits it's opening tag). | ||
2943 | nodeInBetween = walker.next(); | ||
2944 | } | ||
2945 | |||
2946 | // Simply, if anything has been found there's a content in between the two. | ||
2947 | isContinuation = !nodeInBetween; | ||
2948 | } | ||
2949 | |||
2950 | if ( isContinuation ) { | ||
2951 | // If last range ends, where the current range starts, then let's merge it. | ||
2952 | lastRange.setEnd( rng.endContainer, rng.endOffset ); | ||
2953 | } else { | ||
2954 | // In other case just push cur range into the stack. | ||
2955 | ret.push( rng ); | ||
2956 | } | ||
2957 | |||
2958 | return ret; | ||
2959 | }, [] ); | ||
2960 | }; | ||
2837 | 2961 | ||
2838 | } )(); | 2962 | } )(); |
2839 | 2963 | ||
diff --git a/sources/core/dom/rangelist.js b/sources/core/dom/rangelist.js index 250dfd9..15ccb88 100644 --- a/sources/core/dom/rangelist.js +++ b/sources/core/dom/rangelist.js | |||
@@ -164,7 +164,7 @@ | |||
164 | }; | 164 | }; |
165 | 165 | ||
166 | // Update the specified range which has been mangled by previous insertion of | 166 | // Update the specified range which has been mangled by previous insertion of |
167 | // range bookmark nodes.(#3256) | 167 | // range bookmark nodes.(http://dev.ckeditor.com/ticket/3256) |
168 | function updateDirtyRange( bookmark, dirtyRange, checkEnd ) { | 168 | function updateDirtyRange( bookmark, dirtyRange, checkEnd ) { |
169 | var serializable = bookmark.serializable, | 169 | var serializable = bookmark.serializable, |
170 | container = dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ], | 170 | container = dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ], |
diff --git a/sources/core/dom/text.js b/sources/core/dom/text.js index ce20ffe..e77a3d9 100644 --- a/sources/core/dom/text.js +++ b/sources/core/dom/text.js | |||
@@ -106,7 +106,7 @@ CKEDITOR.tools.extend( CKEDITOR.dom.text.prototype, { | |||
106 | retval.insertAfter( this ); | 106 | retval.insertAfter( this ); |
107 | } else { | 107 | } else { |
108 | // IE BUG: IE8+ does not update the childNodes array in DOM after splitText(), | 108 | // IE BUG: IE8+ does not update the childNodes array in DOM after splitText(), |
109 | // we need to make some DOM changes to make it update. (#3436) | 109 | // we need to make some DOM changes to make it update. (http://dev.ckeditor.com/ticket/3436) |
110 | var workaround = doc.createText( '' ); | 110 | var workaround = doc.createText( '' ); |
111 | workaround.insertAfter( retval ); | 111 | workaround.insertAfter( retval ); |
112 | workaround.remove(); | 112 | workaround.remove(); |
diff --git a/sources/core/dom/walker.js b/sources/core/dom/walker.js index cec4574..8665909 100644 --- a/sources/core/dom/walker.js +++ b/sources/core/dom/walker.js | |||
@@ -319,7 +319,7 @@ | |||
319 | */ | 319 | */ |
320 | CKEDITOR.dom.element.prototype.isBlockBoundary = function( customNodeNames ) { | 320 | CKEDITOR.dom.element.prototype.isBlockBoundary = function( customNodeNames ) { |
321 | // Whether element is in normal page flow. Floated or positioned elements are out of page flow. | 321 | // Whether element is in normal page flow. Floated or positioned elements are out of page flow. |
322 | // Don't consider floated or positioned formatting as block boundary, fall back to dtd check in that case. (#6297) | 322 | // Don't consider floated or positioned formatting as block boundary, fall back to dtd check in that case. (http://dev.ckeditor.com/ticket/6297) |
323 | var inPageFlow = this.getComputedStyle( 'float' ) == 'none' && !( this.getComputedStyle( 'position' ) in outOfFlowPositions ); | 323 | var inPageFlow = this.getComputedStyle( 'float' ) == 'none' && !( this.getComputedStyle( 'position' ) in outOfFlowPositions ); |
324 | 324 | ||
325 | if ( inPageFlow && blockBoundaryDisplayMatch[ this.getComputedStyle( 'display' ) ] ) | 325 | if ( inPageFlow && blockBoundaryDisplayMatch[ this.getComputedStyle( 'display' ) ] ) |
@@ -388,7 +388,7 @@ | |||
388 | return function( node ) { | 388 | return function( node ) { |
389 | var isWhitespace; | 389 | var isWhitespace; |
390 | if ( node && node.type == CKEDITOR.NODE_TEXT ) { | 390 | if ( node && node.type == CKEDITOR.NODE_TEXT ) { |
391 | // Whitespace, as well as the Filling Char Sequence text node used in Webkit. (#9384, #13816) | 391 | // Whitespace, as well as the Filling Char Sequence text node used in Webkit. (http://dev.ckeditor.com/ticket/9384, http://dev.ckeditor.com/ticket/13816) |
392 | isWhitespace = !CKEDITOR.tools.trim( node.getText() ) || | 392 | isWhitespace = !CKEDITOR.tools.trim( node.getText() ) || |
393 | CKEDITOR.env.webkit && node.getText() == CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE; | 393 | CKEDITOR.env.webkit && node.getText() == CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE; |
394 | } | 394 | } |
@@ -406,7 +406,7 @@ | |||
406 | */ | 406 | */ |
407 | CKEDITOR.dom.walker.invisible = function( isReject ) { | 407 | CKEDITOR.dom.walker.invisible = function( isReject ) { |
408 | var whitespace = CKEDITOR.dom.walker.whitespaces(), | 408 | var whitespace = CKEDITOR.dom.walker.whitespaces(), |
409 | // #12221 (Chrome) plus #11111 (Safari). | 409 | // http://dev.ckeditor.com/ticket/12221 (Chrome) plus http://dev.ckeditor.com/ticket/11111 (Safari). |
410 | offsetWidth0 = CKEDITOR.env.webkit ? 1 : 0; | 410 | offsetWidth0 = CKEDITOR.env.webkit ? 1 : 0; |
411 | 411 | ||
412 | return function( node ) { | 412 | return function( node ) { |
@@ -422,7 +422,7 @@ | |||
422 | // Nodes that take no spaces in wysiwyg: | 422 | // Nodes that take no spaces in wysiwyg: |
423 | // 1. White-spaces but not including NBSP. | 423 | // 1. White-spaces but not including NBSP. |
424 | // 2. Empty inline elements, e.g. <b></b>. | 424 | // 2. Empty inline elements, e.g. <b></b>. |
425 | // 3. <br> elements (bogus, surrounded by text) (#12423). | 425 | // 3. <br> elements (bogus, surrounded by text) (http://dev.ckeditor.com/ticket/12423). |
426 | invisible = node.$.offsetWidth <= offsetWidth0; | 426 | invisible = node.$.offsetWidth <= offsetWidth0; |
427 | } | 427 | } |
428 | 428 | ||
@@ -636,7 +636,7 @@ | |||
636 | * @returns {CKEDITOR.dom.node/Boolean} Bogus node or `false`. | 636 | * @returns {CKEDITOR.dom.node/Boolean} Bogus node or `false`. |
637 | */ | 637 | */ |
638 | CKEDITOR.dom.element.prototype.getBogus = function() { | 638 | CKEDITOR.dom.element.prototype.getBogus = function() { |
639 | // Bogus are not always at the end, e.g. <p><a>text<br /></a></p> (#7070). | 639 | // Bogus are not always at the end, e.g. <p><a>text<br /></a></p> (http://dev.ckeditor.com/ticket/7070). |
640 | var tail = this; | 640 | var tail = this; |
641 | do { | 641 | do { |
642 | tail = tail.getPreviousSourceNode(); | 642 | tail = tail.getPreviousSourceNode(); |