Ticket #2909: 2909_3.patch
File 2909_3.patch, 13.1 KB (added by , 16 years ago) |
---|
-
_source/core/dom/document.js
87 87 return $ ? new CKEDITOR.dom.element( $ ) : null; 88 88 }, 89 89 90 getByAddress : function( address, normalized ) 91 { 92 var $ = this.$.documentElement; 93 94 for ( var i = 0 ; $ && i < address.length ; i++ ) 95 { 96 var target = address[ i ]; 97 98 if ( !normalized ) 99 { 100 $ = $.childNodes[ target ]; 101 continue; 102 } 103 104 var currentIndex = -1; 105 106 for (var j = 0 ; j < $.childNodes.length ; j++ ) 107 { 108 var candidate = $.childNodes[ j ]; 109 110 if ( normalized === true && 111 candidate.nodeType == 3 && 112 candidate.previousSibling && 113 candidate.previousSibling.nodeType == 3 ) 114 { 115 continue; 116 } 117 118 currentIndex++; 119 120 if ( currentIndex == target ) 121 { 122 $ = candidate; 123 break; 124 } 125 } 126 } 127 128 return $ ? new CKEDITOR.dom.node( $ ) : null; 129 }, 130 90 131 /** 91 132 * Gets the <head> element for this document. 92 133 * @returns {CKEDITOR.dom.element} The <head> element. -
_source/core/dom/node.js
149 149 }, 150 150 151 151 /** 152 * Retrieves a uniquely identifiable tree address for this node. 153 * The tree address returns is an array of integers, with each integer 154 * indicating a child index of a DOM node, starting from 155 * document.documentElement. 156 * 157 * For example, assuming <body> is the second child from <html> (<head> 158 * being the first), and we'd like to address the third child under the 159 * fourth child of body, the tree address returned would be: 160 * [1, 3, 2] 161 * 162 * The tree address cannot be used for finding back the DOM tree node once 163 * the DOM tree structure has been modified. 164 */ 165 getAddress : function( normalized ) 166 { 167 var address = []; 168 var $documentElement = this.getDocument().$.documentElement; 169 var node = this.$; 170 171 while ( node && node != $documentElement ) 172 { 173 var parentNode = node.parentNode; 174 var currentIndex = -1; 175 176 for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) 177 { 178 var candidate = parentNode.childNodes[i]; 179 180 if ( normalized && 181 candidate.nodeType == 3 && 182 candidate.previousSibling && 183 candidate.previousSibling.nodeType == 3 ) 184 { 185 continue; 186 } 187 188 currentIndex++; 189 190 if ( candidate == node ) 191 break; 192 } 193 194 address.unshift( currentIndex ); 195 196 node = node.parentNode; 197 } 198 199 return address; 200 }, 201 202 /** 152 203 * Gets a DOM tree descendant under the current node. 153 204 * @param {Array|Number} indices The child index or array of child indices under the node. 154 205 * @returns {CKEDITOR.dom.node} The specified DOM child under the current node. Null if child does not exist. -
_source/core/dom/range.js
409 409 }; 410 410 }, 411 411 412 /** 413 * Creates a "non intrusive" and "mutation sensible" bookmark. This 414 * kind of bookmark should be used only when the DOM is supposed to 415 * remain stable after its creation. 416 * @param {Boolean} [normalized] Indicates that the bookmark must 417 * normalized. When normalized, the successive text nodes are 418 * considered a single node. To sucessful load a normalized 419 * bookmark, the DOM tree must be also normalized before calling 420 * moveToBookmark. 421 * @returns {Object} An object representing the bookmark. 422 */ 423 createBookmark2 : function( normalized ) 424 { 425 var startContainer = this.startContainer, 426 endContainer = this.endContainer; 427 428 var startOffset = this.startOffset, 429 endOffset = this.endOffset; 430 431 var child, previous; 432 433 // If there is no range then get out of here. 434 // It happens on initial load in Safari #962 and if the editor it's 435 // hidden also in Firefox 436 if ( !startContainer || !endContainer ) 437 return { start : 0, end : 0 }; 438 439 if ( normalized ) 440 { 441 // Find out if the start is pointing to a text node that will 442 // be normalized. 443 if ( startContainer.type == CKEDITOR.NODE_ELEMENT ) 444 { 445 var child = startContainer.getChild( startOffset ); 446 447 // In this case, move the start information to that text 448 // node. 449 if ( child && child.type == CKEDITOR.NODE_TEXT && child.getPrevious().type == CKEDITOR.NODE_TEXT ) 450 { 451 startContainer = child; 452 startOffset = 0; 453 } 454 } 455 456 // Normalize the start. 457 while ( startContainer.type == CKEDITOR.NODE_TEXT 458 && ( previous = startContainer.getPrevious() ) 459 && previous.type == CKEDITOR.NODE_TEXT ) 460 { 461 startContainer = previous; 462 startOffset += previous.getLength(); 463 } 464 465 // Process the end only if not normalized. 466 if ( !this.isCollapsed ) 467 { 468 // Find out if the start is pointing to a text node that 469 // will be normalized. 470 if ( endContainer.type == CKEDITOR.NODE_ELEMENT ) 471 { 472 child = endContainer.getChild( endOffset ); 473 474 // In this case, move the start information to that 475 // text node. 476 if ( child && child.type == CKEDITOR.NODE_TEXT && child.getPrevious().type == CKEDITOR.NODE_TEXT ) 477 { 478 endContainer = child; 479 endOffset = 0; 480 } 481 } 482 483 // Normalize the end. 484 while ( endContainer.type == CKEDITOR.NODE_TEXT 485 && ( previous = endContainer.getPrevious() ) 486 && previous.type == CKEDITOR.NODE_TEXT ) 487 { 488 endContainer = previous; 489 endOffset += previous.getLength(); 490 } 491 } 492 } 493 494 return { 495 start : startContainer.getAddress( normalized ), 496 end : this.isCollapsed ? null : endContainer.getAddress( normalized ), 497 startOffset : startOffset, 498 endOffset : endOffset, 499 normalized : normalized, 500 is2 : true // It's a createBookmark2 bookmark. 501 }; 502 }, 503 412 504 moveToBookmark : function( bookmark ) 413 505 { 414 // Set the range start at the bookmark start node position. 415 this.setStartBefore( bookmark.startNode ); 506 if ( bookmark.is2 ) // Created with createBookmark2(). 507 { 508 // Get the start information. 509 var startContainer = this.document.getByAddress( bookmark.start, bookmark.normalized ), 510 startOffset = bookmark.startOffset; 416 511 417 // Remove it, because it may interfere in the setEndBefore call. 418 bookmark.startNode.remove(); 512 // Get the end information. 513 var endContainer = bookmark.end && this.document.getByAddress( bookmark.end, bookmark.normalized ), 514 endOffset = bookmark.endOffset; 419 515 420 // Set the range end at the bookmark end node position, or simply 421 // collapse it if it is not available. 422 var endNode = bookmark.endNode; 423 if ( endNode ) 516 // Set the start boundary. 517 this.setStart( startContainer, startOffset ); 518 519 // Set the end boundary. If not available, collapse it. 520 if ( endContainer ) 521 this.setEnd( endContainer, endOffset ); 522 else 523 this.collapse( true ); 524 } 525 else // Created with createBookmark(). 424 526 { 425 this.setEndBefore( endNode ); 426 endNode.remove(); 527 // Set the range start at the bookmark start node position. 528 this.setStartBefore( bookmark.startNode ); 529 530 // Remove it, because it may interfere in the setEndBefore call. 531 bookmark.startNode.remove(); 532 533 // Set the range end at the bookmark end node position, or simply 534 // collapse it if it is not available. 535 var endNode = bookmark.endNode; 536 if ( endNode ) 537 { 538 this.setEndBefore( endNode ); 539 endNode.remove(); 540 } 541 else 542 this.collapse( true ); 427 543 } 428 else429 this.collapse( true );430 544 }, 431 545 432 546 getBoundaryNodes : function() -
_source/tests/core/dom/range.html
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 3 <head> 4 4 <title>CKEDITOR.dom.range</title> … … 11 11 //<![CDATA[ 12 12 13 13 var html1, html2; 14 var tests; 14 15 15 16 CKEDITOR.test.addTestCase( (function() 16 17 { … … 20 21 21 22 var doc = new CKEDITOR.dom.document( document ); 22 23 23 return {24 return tests = { 24 25 test__constructor : function() 25 26 { 26 27 var range = new CKEDITOR.dom.range( doc ); … … 1510 1511 assert.isFalse( range.collapsed, 'range.collapsed' ); 1511 1512 }, 1512 1513 1514 test_createBookmark2_1 : function() 1515 { 1516 doc.getById( 'playground' ).setHtml( '<p id="P">This is <b id="B">a test</b></p>' ); 1517 1518 var range = new CKEDITOR.dom.range( doc ); 1519 1520 range.setStart( doc.getById( 'P' ), 0 ); 1521 range.setEnd( doc.getById( 'B' ).getFirst(), 3 ); 1522 1523 var bookmark = range.createBookmark2(); 1524 1525 range = new CKEDITOR.dom.range( doc ); 1526 range.moveToBookmark( bookmark ); 1527 1528 assert.areSame( document.getElementById('P'), range.startContainer.$, 'range.startContainer' ); 1529 assert.areSame( 0, range.startOffset, 'range.startOffset' ); 1530 assert.areSame( document.getElementById('B').firstChild, range.endContainer.$, 'range.endContainer' ); 1531 assert.areSame( 3, range.endOffset, 'range.endOffset' ); 1532 assert.isFalse( range.collapsed, 'range.collapsed' ); 1533 }, 1534 1535 // This test is just like test_createBookmark2_3, but uses a "non 1536 // normalized" bookmark. 1537 test_createBookmark2_2 : function() 1538 { 1539 var html = '<p id="P">A B <b>C </b>D E</p>'; 1540 1541 doc.getById( 'playground' ).setHtml( html ); 1542 1543 var p = doc.getById( 'P' ); 1544 1545 // Split the text nodes. 1546 p.getFirst().split( 2 ); // Right before "B" 1547 p.getChild( 3 ).split( 2 ); // Right before "E" 1548 1549 assert.areSame( 5, p.getChildCount(), 'The number of nodes after split doesn\'t match' ); 1550 1551 var range = new CKEDITOR.dom.range( doc ); 1552 1553 // Create a range that enbraces "E". 1554 range.setStartBefore( p.getChild( 4 ) ); 1555 range.setEndAfter( p.getChild( 4 ) ); 1556 1557 var bookmark = range.createBookmark2(); 1558 1559 range = new CKEDITOR.dom.range( doc ); 1560 range.moveToBookmark( bookmark ); 1561 1562 assert.areSame( document.getElementById('P'), range.startContainer.$, 'range.startContainer' ); 1563 assert.areSame( 4, range.startOffset, 'range.startOffset' ); 1564 assert.areSame( document.getElementById('P'), range.endContainer.$, 'range.endContainer' ); 1565 assert.areSame( 5, range.endOffset, 'range.endOffset' ); 1566 assert.isFalse( range.collapsed, 'range.collapsed' ); 1567 }, 1568 1569 test_createBookmark2_3 : function() 1570 { 1571 var html = '<p id="P">A B <b>C </b>D E</p>'; 1572 1573 doc.getById( 'playground' ).setHtml( html ); 1574 1575 var p = doc.getById( 'P' ); 1576 1577 // Split the text nodes. 1578 p.getFirst().split( 2 ); // Right before "B" 1579 p.getChild( 3 ).split( 2 ); // Right before "E" 1580 1581 assert.areSame( 5, p.getChildCount(), 'The number of nodes after split doesn\'t match' ); 1582 1583 var range = new CKEDITOR.dom.range( doc ); 1584 1585 // Create a range that enbraces "E". 1586 range.setStartBefore( p.getChild( 4 ) ); 1587 range.setEndAfter( p.getChild( 4 ) ); 1588 1589 var bookmark = range.createBookmark2( true ); 1590 1591 // Normalize the contents. 1592 doc.getById( 'playground' ).setHtml( html ); 1593 1594 range = new CKEDITOR.dom.range( doc ); 1595 range.moveToBookmark( bookmark ); 1596 1597 assert.areSame( document.getElementById('P').childNodes[2], range.startContainer.$, 'range.startContainer' ); 1598 assert.areSame( 2, range.startOffset, 'range.startOffset' ); 1599 assert.areSame( document.getElementById('P'), range.endContainer.$, 'range.endContainer' ); 1600 1601 // Note that the endOffset doesn't get normalized as it's not 1602 // needed. Any offset pointing over the container size is meant to 1603 // be at the end of it. 1604 assert.areSame( 5, range.endOffset, 'range.endOffset' ); 1605 assert.isFalse( range.collapsed, 'range.collapsed' ); 1606 }, 1607 1513 1608 ///////////// 1514 1609 1515 1610 setUp : function() … … 1524 1619 1525 1620 //window.onload = function() 1526 1621 //{ 1527 // // Local references. 1528 // var assert = CKEDITOR.test.assert; 1529 // var getInnerHtml = CKEDITOR.test.getInnerHtml; 1530 1531 // var doc = new CKEDITOR.dom.document( document ); 1532 1533 // doc.getById( '_EnlargeP' ).setHtml( 'this <i>is some </i>sample text' ); 1534 1535 // var range = new CKEDITOR.dom.range( doc ); 1536 // range.setStart( doc.getById( '_EnlargeP' ), 0 ); 1537 // range.setEnd( doc.getById( '_EnlargeP' ).getChild( 1 ), 0 ); 1538 1539 // range.enlarge( CKEDITOR.ENLARGE_ELEMENT ); 1622 // tests.test_createBookmark2_3(); 1540 1623 //} 1541 1624 1542 1625 //]]>