Ticket #3309: 3309_2.patch
File 3309_2.patch, 7.7 KB (added by , 15 years ago) |
---|
-
_source/core/dom/documentfragment.js
43 43 'getDocument' : 1, 44 44 'getChildCount' : 1, 45 45 'getChild' : 1, 46 'getChildren' : 1 46 'getChildren' : 1, 47 'type' : 1 47 48 } ); -
_source/plugins/styles/plugin.js
510 510 */ 511 511 range.enlarge( CKEDITOR.ENLARGE_ELEMENT ); 512 512 513 var bookmark = range.createBookmark( true),514 startNode = range.document.getById( bookmark.startNode );513 var bookmark = range.createBookmark(), 514 startNode = bookmark.startNode; 515 515 516 516 if ( range.collapsed ) 517 517 { 518 /* 519 * If the range is collapsed, try to remove the style from all ancestor 520 * elements, until a block boundary is reached. 521 */ 522 var startPath = new CKEDITOR.dom.elementPath( startNode.getParent() ); 523 for ( var i = 0, element ; i < startPath.elements.length && ( element = startPath.elements[i] ) ; i++ ) 524 { 518 519 var startPath = new CKEDITOR.dom.elementPath( startNode.getParent() ), 520 // The topmost element in elementspatch which we should jump out of. 521 boundaryElement; 522 523 524 for ( var i = 0, element ; i < startPath.elements.length 525 && ( element = startPath.elements[i] ) ; i++ ) 526 { 527 /* 528 * 1. If it's collaped inside text nodes, try to remove the style from the whole element. 529 * 530 * 2. Otherwise if it's collapsed on element boundaries, moving the selection 531 * outside the styles instead of removing the whole tag, 532 * also makre sure other inner styles were well preserverd.(#3309) 533 */ 525 534 if ( element == startPath.block || element == startPath.blockLimit ) 526 535 break; 527 536 528 537 if ( this.checkElementRemovable( element ) ) 529 538 { 530 /* 531 * Before removing the style node, there may be a sibling to the style node 532 * that's exactly the same to the one to be removed. To the user, it makes 533 * no difference that they're separate entities in the DOM tree. So, merge 534 * them before removal. 535 */ 536 mergeSiblings( element ); 537 removeFromElement( this, element ); 538 } 539 } 540 } 541 else 539 var startOfElement = range.checkBoundaryOfElement( element, CKEDITOR.START_OF_ELEMENT ), 540 endOfElement = range.checkBoundaryOfElement( element, CKEDITOR.END_OF_ELEMENT ); 541 if ( startOfElement || endOfElement ) 542 { 543 boundaryElement = element; 544 boundaryElement.isStart = startOfElement; 545 } 546 else 547 { 548 /* 549 * Before removing the style node, there may be a sibling to the style node 550 * that's exactly the same to the one to be removed. To the user, it makes 551 * no difference that they're separate entities in the DOM tree. So, merge 552 * them before removal. 553 */ 554 mergeSiblings( element ); 555 removeFromElement( this, element ); 556 557 } 558 } 559 } 560 561 if ( boundaryElement ) 562 { 563 // Range is guaranteed to be collapsed inside the inner-most inline element, 564 // so simply start from a cloned range. 565 var newStyleRange = range.clone(); 566 567 // Include it in the new range. 568 newStyleRange[ boundaryElement.isStart ? 569 'setStartBefore' : 'setEndAfter'].call( newStyleRange, boundaryElement ); 570 571 var styleElements = newStyleRange.cloneContents(); 572 573 // We need build a temp node here for 'removeFromInsideElement'. 574 var temp = range.document.createElement( 'div' ); 575 temp.append( styleElements ); 576 removeFromInsideElement( this, temp ); 577 578 // It's guaranteed that style elements is single rooted. 579 styleElements = temp.getFirst(); 580 581 // Start from the new position right before/after the topmost target style element. 582 newStyleRange.collapse( boundaryElement.isStart ? true : false ); 583 584 // Continue with the inner styles. 585 if ( styleElements ) 586 { 587 newStyleRange.insertNode( styleElements ); 588 mergeSiblings( styleElements ); 589 // Destroy the bookmark node. 590 startNode.remove(); 591 range.moveToElementEditStart( styleElements ); 592 return; 593 } 594 else 595 // No inner styles found, simply jump out of boundary element. 596 newStyleRange.insertNode( bookmark.startNode ); 597 } 598 } 599 else 542 600 { 543 601 /* 544 602 * Now our range isn't collapsed. Lets walk from the start node to the end -
_source/core/dom/range.js
135 135 136 136 while( currentNode ) 137 137 { 138 // Avoid cloning bookmark nodes. 139 if ( action == 2 && 140 currentNode.hasAttribute && currentNode.hasAttribute( '_fck_bookmark' ) ) 141 { 142 currentNode = currentSibling; 143 continue; 144 } 138 145 // Stop processing when the current node matches a node in the 139 146 // endParents tree or if it is the endNode. 140 147 if ( currentNode.equals( endParents[ j ] ) || currentNode.equals( endNode ) ) … … 182 189 183 190 while( currentNode ) 184 191 { 192 // Avoid cloning bookmark nodes. 193 if ( action == 2 && 194 currentNode.hasAttribute && currentNode.hasAttribute( '_fck_bookmark' ) ) 195 { 196 currentNode = currentSibling; 197 continue; 198 } 185 199 // Stop processing when the current node matches a node in the 186 200 // startParents tree or if it is the startNode. 187 201 if ( currentNode.equals( startParents[ k ] ) || currentNode.equals( startNode ) ) … … 292 306 }; 293 307 } 294 308 309 // Evaluator for CKEDITOR.dom.element::checkBoundaryOfElement, reject all text type node, 310 // while ignore bookmark node inner text. 311 function elementBoundaryEval( node ) 312 { 313 // Reject any text node unless it's being bookmark. 314 return node.type != CKEDITOR.NODE_TEXT || node.getParent().hasAttribute( '_fck_bookmark' ); 315 }; 316 295 317 CKEDITOR.dom.range.prototype = 296 318 { 297 319 clone : function() … … 1427 1449 }; 1428 1450 }, 1429 1451 1452 /** 1453 * Whether range is on the boundary of an element node. 1454 * @param {Number} checkType ( CKEDITOR.START_OF_ELEMENT|CKEDITOR.END_OF_ELEMENT) 1455 * Specify check the range is at the start OR end of the element. 1456 */ 1457 checkBoundaryOfElement : function( element, checkType ) 1458 { 1459 var matched = false; 1460 var walkerRange = this.clone(); 1461 // Expand the range clockwise. 1462 walkerRange[ checkType == CKEDITOR.START_OF_ELEMENT ? 1463 'setStartBefore' : 'setEndAfter'].call( 1464 walkerRange, this.document.getBody() ); 1465 var walker = new CKEDITOR.dom.walker( walkerRange ), 1466 retval = false; 1467 walker.evaluator = elementBoundaryEval; 1468 // Try to match among all the found boundary elements. 1469 walker.guard = function( node ) 1470 { 1471 if ( node.type == CKEDITOR.NODE_ELEMENT && element.equals( node ) ) 1472 matched = true; 1473 }; 1474 1475 walker[ checkType == CKEDITOR.START_OF_ELEMENT ? 1476 'checkBackward' : 'checkForward' ].call( walker ); 1477 return matched; 1478 }, 1479 1430 1480 // Calls to this function may produce changes to the DOM. The range may 1431 1481 // be updated to reflect such changes. 1432 1482 checkStartOfBlock : function() … … 1553 1603 CKEDITOR.ENLARGE_ELEMENT = 1; 1554 1604 CKEDITOR.ENLARGE_BLOCK_CONTENTS = 2; 1555 1605 CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS = 3; 1606 1607 /** 1608 * Check boundary types. 1609 * @see CKEDITOR.dom.range::checkBoundaryOfElement 1610 */ 1611 CKEDITOR.START_OF_ELEMENT = 1; 1612 CKEDITOR.END_OF_ELEMENT = 2; 1613 CKEDITOR.STARTEND_OF_ELEMENT = 3;