Ticket #5309: 5309_4.patch
File 5309_4.patch, 16.4 KB (added by , 13 years ago) |
---|
-
_source/plugins/htmldataprocessor/plugin.js
263 263 defaultHtmlFilterRules.elements[ i ] = unprotectReadyOnly; 264 264 } 265 265 266 // Disallow structural blocks without sub nodes. 267 var removeIfEmptyBlocks = { table:1, thead:1,tfoot:1,tbody:1, tr:1 }, 268 removeIfEmptyFilterRules = { elements : {} }, 269 removeIfEmtpyFilter = function( element ){ if ( !element.children.length ) return false; }; 270 271 for ( i in removeIfEmptyBlocks ) 272 removeIfEmptyFilterRules.elements[ i ] = removeIfEmtpyFilter; 273 266 274 var protectAttributeRegex = /<((?:a|area|img|input)[\s\S]*?\s)((href|src|name)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+)))([^>]*)>/gi, 267 275 findSavedSrcRegex = /\s_cke_saved_src\s*=/; 268 276 … … 397 405 398 406 dataProcessor.dataFilter.addRules( defaultDataFilterRules ); 399 407 dataProcessor.dataFilter.addRules( defaultDataBlockFilterRules ); 408 dataProcessor.dataFilter.addRules( removeIfEmptyFilterRules ); 400 409 dataProcessor.htmlFilter.addRules( defaultHtmlFilterRules ); 401 410 dataProcessor.htmlFilter.addRules( defaultHtmlBlockFilterRules ); 411 dataProcessor.htmlFilter.addRules( removeIfEmptyFilterRules ); 402 412 } 403 413 }); 404 414 -
_source/core/htmlparser/cdata.js
38 38 writeHtml : function( writer ) 39 39 { 40 40 writer.write( this.value ); 41 }, 42 43 toDom : function( doc ) 44 { 45 return new CKEDITOR.dom.text( this.value, doc ); 41 46 } 42 47 }; 43 48 })(); -
_source/core/dom/element.js
254 254 }, 255 255 256 256 /** 257 * Retrieve block element's filler node if existed. 258 */ 259 getBogus : function() 260 { 261 if ( !this.isBlockBoundary() ) 262 return; 263 264 var lastChild = this.getLast() ; 265 266 // Ignore empty/spaces text. 267 while ( lastChild && lastChild.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.rtrim( lastChild.getText() ) ) 268 lastChild = lastChild.getPrevious(); 269 270 if ( lastChild && 271 ( CKEDITOR.env.ie && lastChild.type == CKEDITOR.NODE_TEXT && CKEDITOR.tools.trim( lastChild.getText() ).match( /^(?: |\xa0)$/ ) 272 || CKEDITOR.env.gecko && CKEDITOR.env.webkit && lastChild.is( 'br' ) ) ) 273 { 274 return lastChild; 275 } 276 }, 277 278 /** 257 279 * Breaks one of the ancestor element in the element position, moving 258 280 * this element between the broken parts. 259 281 * @param {CKEDITOR.dom.element} parent The anscestor element to get broken. -
_source/core/htmlparser/fragment.js
492 492 { 493 493 for ( var i = 0 ; i < this.children.length ; i++ ) 494 494 this.children[i].writeHtml( writer, filter ); 495 }, 496 497 toDom : function( doc ) 498 { 499 var fragment = new CKEDITOR.dom.documentFragment( doc ); 500 for ( var i = 0, count = this.children.length; i < count; i++ ) 501 fragment.append( this.children[ i ].toDom( doc ) ); 502 503 return fragment; 495 504 } 496 505 }; 497 506 })(); -
_source/core/htmlparser/element.js
235 235 // Send children. 236 236 CKEDITOR.htmlParser.fragment.prototype.writeChildrenHtml.apply( this, arguments ); 237 237 238 }, 239 240 toDom : function( doc ) 241 { 242 var element = new CKEDITOR.dom.element( this.name, doc ); 243 element.setAttributes( this.attributes ); 244 245 for ( var i = 0, count = this.children.length; i < count; i++ ) 246 element.append( this.children[ i ].toDom() ); 247 248 return element; 238 249 } 239 250 }; 240 251 })(); -
_source/core/htmlparser/comment.js
56 56 } 57 57 58 58 writer.comment( comment ); 59 }, 60 61 toDom : function( doc ) 62 { 63 return new CKEDITOR.dom.comment( this.value, doc ); 59 64 } 65 60 66 }; -
_source/core/htmlparser/text.js
50 50 return; 51 51 52 52 writer.text( text ); 53 }, 54 55 toDom : function( doc ) 56 { 57 // DON'T use CKEDITOR.dom.text, it's not handling entities.. 58 return CKEDITOR.dom.element.createFromHtml( this.value ); 53 59 } 54 60 }; 55 61 })(); -
_source/plugins/wysiwygarea/plugin.js
36 36 if ( checkReadOnly( selection ) ) 37 37 return; 38 38 39 var data = evt.data; 39 var ranges = selection.getRanges( true ), 40 data = evt.data; 40 41 this.fire( 'saveSnapshot' ); 41 42 42 43 if ( this.dataProcessor ) 43 44 data = this.dataProcessor.toHtml( data ); 44 45 45 if ( CKEDITOR.env.ie ) 46 // Process the ranges counter-clockwise to avoid any impacts among them. 47 for ( var i = ranges.length - 1 ; i >= 0 ; i-- ) 46 48 { 47 var selIsLocked = selection.isLocked; 49 var range = ranges[ i ], 50 previousRange = ranges[ i - 1 ]; 48 51 49 if ( selIsLocked ) 50 selection.unlock(); 51 52 var $sel = selection.getNative(); 53 54 // Delete control selections to avoid IE bugs on pasteHTML. 55 if ( $sel.type == 'Control' ) 56 $sel.clear(); 57 else if ( selection.getType() == CKEDITOR.SELECTION_TEXT ) 52 // Merge next sibling range when possible, it's not a common case, 53 // but necessary for situation like multiple table cell selection in Firefox. 54 if ( previousRange ) 58 55 { 59 // Due to IE bugs on handling contenteditable=false blocks 60 // (#6005), we need to make some checks and eventually 61 // delete the selection first. 62 63 var range = selection.getRanges()[0], 64 endContainer = range && range.endContainer; 65 66 if ( endContainer && 67 endContainer.type == CKEDITOR.NODE_ELEMENT && 68 endContainer.getAttribute( 'contenteditable' ) == 'false' && 69 range.checkBoundaryOfElement( endContainer, CKEDITOR.END ) ) 56 if ( previousRange.endContainer.equals( range.startContainer ) 57 && previousRange.endOffset == range.startOffset ) 70 58 { 71 range.setEndAfter( range.endContainer ); 72 range.deleteContents(); 59 previousRange.endContainer = range.endContainer; 60 previousRange.endOffset = range.endOffset; 61 ranges.splice( i, 1 ); 62 continue; 73 63 } 74 64 } 75 65 76 try 66 // Pasting should only go into the first range. 67 if ( i == 0 ) 68 range.pasteHtml( data ); 69 else 77 70 { 78 $sel.createRange().pasteHTML( data ); 71 range.enlarge( CKEDITOR.NODE_ELEMENT ); 72 // Drop the range after selected content is deleted. 73 range.extractContents(); 74 ranges.length--; 79 75 } 80 catch (e) {}81 82 if ( selIsLocked )83 this.getSelection().lock();84 76 } 85 else86 this.document.$.execCommand( 'inserthtml', false, data );87 77 88 // Webkit does not scroll to the cursor position after pasting (#5558) 89 if ( CKEDITOR.env.webkit ) 90 { 91 this.document.$.execCommand( 'inserthtml', false, '<span id="cke_paste_marker" cke_temp="1"></span>' ); 92 var marker = this.document.getById( 'cke_paste_marker' ); 93 marker.scrollIntoView(); 94 marker.remove(); 95 } 78 selection.selectRanges( ranges ); 79 !CKEDITOR.env.ie && selection.scrollIntoView(); 96 80 97 81 CKEDITOR.tools.setTimeout( function() 98 82 { -
_source/core/dom/range.js
317 317 return !whitespaceEval( node ) && !bookmarkEval( node ); 318 318 } 319 319 320 321 function collectValidChildren( element, parentName ) 322 { 323 var next = element, isValid, 324 candidates = []; 325 326 while ( ( next = next.getNextSourceNode( isValid, CKEDITOR.NODE_ELEMENT ) ) ) 327 { 328 if ( isValid = next.getName() in CKEDITOR.dtd[ parentName ] ) 329 candidates.push( next ); 330 } 331 332 var fragment = new CKEDITOR.dom.documentFragment(); 333 for ( var i = 0, count = candidates.length; i < count; i++ ) 334 fragment.append( candidates[ i ] ); 335 return fragment; 336 } 337 338 var emptyspaces = CKEDITOR.dom.walker.whitespaces(), 339 bookmarks = CKEDITOR.dom.walker.bookmark(); 340 320 341 CKEDITOR.dom.range.prototype = 321 342 { 322 343 clone : function() … … 671 692 }, 672 693 673 694 /** 695 * Paste the give HTML at the start of the range, and replacing any previously selected nodes within the range. 696 * Note: This method might alter the specified HTML to make it fit the given range context. For example, when pasting a table 697 * when actually a table row is selected (a DTD violation), instead of inserting the table, it results in only the cells of the table 698 * getting pasted into the row. 699 * For predictable results, paste only well-formed HTML that fits at the given range context. 700 * @param {String} html Valid HTML string to paste into the range. 701 */ 702 pasteHtml : function ( html ) 703 { 704 // Create a fragment of nodes without context that represents the structure to paste. (W3C Spec) 705 var fragment = CKEDITOR.htmlParser.fragment.fromHtml( html, false ), 706 nodeList = fragment.children; 707 708 if ( !this.collapsed ) 709 { 710 // Avoid resulting in dummy element after the deletion. 711 this.enlarge( CKEDITOR.NODE_ELEMENT ); 712 this.extractContents(); 713 } 714 715 // Split up text node at position. 716 if ( this.startContainer.type == CKEDITOR.NODE_TEXT ) 717 this.trim(); 718 719 // If we're at end of block, remove any bogus node, because: 720 // 1. It's not needed any more due to the incomming content. 721 // 2. It will get doubled (visible) if the to be inserted node is a bogus too. 722 var block; 723 if ( block = this.checkEndOfBlock() ) 724 { 725 var bogus = block.getBogus(); 726 bogus && bogus.remove(); 727 } 728 729 var targetNode, targetNodeOffset, targetName, path, 730 updateTarget = CKEDITOR.tools.bind( function () 731 { 732 targetNode = this.startContainer, 733 targetNodeOffset = this.startOffset, 734 targetName = targetNode.getName(); 735 path = new CKEDITOR.dom.elementPath( targetNode ); 736 }, this ); 737 738 updateTarget(); 739 for ( var i = 0, count = nodeList.length; i < count; i++ ) 740 { 741 var node = nodeList[ i ], 742 nodeName = node.type == CKEDITOR.NODE_ELEMENT ? node.name : '#'; 743 744 // If we have a list to insert, and we're actually standing inside a list item, 745 // insert the appropriate children instead, in short, merge the lists 746 // instead of pasting in a sublist. 747 if ( nodeName in CKEDITOR.dtd.$list 748 && path.block && path.block.getName() in CKEDITOR.dtd.$listItem ) 749 { 750 this.splitElement( path.block ); 751 updateTarget(); 752 } 753 754 // The to be inserted node fails DTD examination. 755 while ( !CKEDITOR.dtd[ targetName ][ nodeName ] ) 756 { 757 // If the failure is caused by pasting table/list inside a table/list 758 // structure, instead of splitting up the element, just insert the 759 // appropriate children. 760 if ( nodeName == 'table' && targetName in { table:1, tfoot:1,thead:1,tbody:1,tr:1 } 761 || nodeName in { ul:1, ol:1, dl:1 } && targetName in { ul:1, ol:1, dl:1 } ) 762 { 763 node = collectValidChildren( node.toDom(), targetName ); 764 break; 765 } 766 767 // Users are more likely want to paste content intead of the element, e.g. pre, headings. 768 if ( ( targetName == nodeName ) 769 && ( nodeName == 'pre' || nodeName.match( /^h[1-6]$/ ) ) ) 770 { 771 Array.prototype.splice.apply( nodeList, [ i, 1 ].concat( node.children ) ); 772 node = nodeList[ i ]; 773 break; 774 } 775 776 // Ok, it's our last option, split up or move out of current element. 777 this.splitElement( targetNode ); 778 updateTarget(); 779 } 780 781 var domNode = node.$ ? node : node.toDom(); 782 // Where to put the cursor? 783 var anchorNode = domNode.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ? 784 domNode.getLast() : domNode; 785 786 this.insertNode( domNode ); 787 788 // Try to place cursor at the end of the last pasted node, 789 // with the only exception that we should discontinue any pasted link, 790 // If that fails, simply collapse by the end of last node. 791 if ( !( i == count - 1 && anchorNode.type == CKEDITOR.NODE_ELEMENT 792 && !anchorNode.is( 'a' ) && this.moveToElementEditEnd( anchorNode ) ) ) 793 this.collapse(); 794 } 795 }, 796 797 /** 674 798 * Transforms the startContainer and endContainer properties from text 675 799 * nodes to element nodes, whenever possible. This is actually possible 676 800 * if either of the boundary containers point to a text node, and its … … 871 995 { 872 996 // If we reached the common ancestor, mark the flag 873 997 // for it. 874 if ( !commonReached && enlargeable.equals( commonAncestor) )998 if ( !commonReached && ( enlargeable.contains( commonAncestor ) || enlargeable.equals( commonAncestor ) ) ) 875 999 commonReached = true; 876 1000 877 1001 if ( !body.contains( enlargeable ) ) … … 1041 1165 { 1042 1166 if ( enlargeable && !sibling ) 1043 1167 { 1044 if ( !commonReached && enlargeable.equals( commonAncestor) )1168 if ( !commonReached && ( enlargeable.contains( commonAncestor ) || enlargeable.equals( commonAncestor ) ) ) 1045 1169 commonReached = true; 1046 1170 1047 1171 if ( !body.contains( enlargeable ) ) … … 1354 1478 var startContainer = this.startContainer; 1355 1479 var startOffset = this.startOffset; 1356 1480 1481 var count = node.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ? 1482 node.getChildren().count() : 1; 1483 1484 var anchorNode = node.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT ? 1485 node.getChildren().getItem( 0 ) : node; 1486 1357 1487 var nextNode = startContainer.getChild( startOffset ); 1358 1488 1359 1489 if ( nextNode ) … … 1362 1492 startContainer.append( node ); 1363 1493 1364 1494 // Check if we need to update the end boundary. 1365 if ( node.getParent().equals( this.endContainer ) )1366 this.endOffset ++;1495 if ( startContainer.equals( this.endContainer ) ) 1496 this.endOffset += count; 1367 1497 1368 1498 // Expand the range to embrace the new node. 1369 this.setStartBefore( node );1499 this.setStartBefore( anchorNode ); 1370 1500 }, 1371 1501 1372 1502 moveToPosition : function( node, position ) … … 1621 1751 if ( !this.collapsed ) 1622 1752 return null; 1623 1753 1754 var testRange = this.clone(), 1755 walker = new CKEDITOR.dom.walker( testRange ); 1756 1757 walker.evaluator = function( node ) 1758 { 1759 return !!( emptyspaces( node ) || bookmarks( node ) ); 1760 }; 1761 1762 testRange.setEndAfter( toSplit ); 1763 if ( walker.checkForward() ) 1764 { 1765 this.moveToPosition( toSplit, CKEDITOR.POSITION_AFTER_END ); 1766 return null; 1767 } 1768 else 1769 { 1770 testRange = this.clone(); 1771 testRange.setStartBefore( toSplit ); 1772 walker.reset(); 1773 walker.range = testRange; 1774 if ( walker.checkBackward() ) 1775 { 1776 this.moveToPosition( toSplit, CKEDITOR.POSITION_BEFORE_START ); 1777 return null; 1778 } 1779 } 1780 1624 1781 // Extract the contents of the block from the selection point to the end 1625 1782 // of its contents. 1626 1783 this.setEndAt( toSplit, CKEDITOR.POSITION_BEFORE_END ); … … 1729 1886 // Creates a range starting at the block start until the range start. 1730 1887 var walkerRange = this.clone(); 1731 1888 walkerRange.collapse( false ); 1732 walkerRange.setEndAt( path.block || path.blockLimit, CKEDITOR.POSITION_BEFORE_END ); 1889 var pathBlock = path.block || path.blockLimit; 1890 walkerRange.setEndAt( pathBlock, CKEDITOR.POSITION_BEFORE_END ); 1733 1891 1734 1892 var walker = new CKEDITOR.dom.walker( walkerRange ); 1735 1893 walker.evaluator = getCheckStartEndBlockEvalFunction( false ); 1736 1894 1737 return walker.checkForward() ;1895 return walker.checkForward() && pathBlock; 1738 1896 }, 1739 1897 1740 1898 /**