Ticket #4508: 4508.patch
File 4508.patch, 20.0 KB (added by , 14 years ago) |
---|
-
_source/plugins/enterkey/plugin.js
5 5 6 6 (function() 7 7 { 8 CKEDITOR.plugins. add( 'enterkey',8 CKEDITOR.plugins.enterkey = 9 9 { 10 requires : [ 'keystrokes', 'indent' ], 11 12 init : function( editor ) 10 enterBlock : function( editor, mode, range ) 13 11 { 14 var specialKeys = editor.specialKeys; 15 specialKeys[ 13 ] = enter; 16 specialKeys[ CKEDITOR.SHIFT + 13 ] = shiftEnter; 17 } 18 }); 19 20 var forceMode, 21 headerTagRegex = /^h[1-6]$/; 22 23 function shiftEnter( editor ) 24 { 25 // On SHIFT+ENTER we want to enforce the mode to be respected, instead 26 // of cloning the current block. (#77) 27 forceMode = 1; 28 29 return enter( editor, editor.config.shiftEnterMode ); 30 } 31 32 function enter( editor, mode ) 33 { 34 // Only effective within document. 35 if ( editor.mode != 'wysiwyg' ) 36 return false; 37 38 if ( !mode ) 39 mode = editor.config.enterMode; 40 41 // Use setTimout so the keys get cancelled immediatelly. 42 setTimeout( function() 43 { 44 editor.fire( 'saveSnapshot' ); // Save undo step. 45 if ( mode == CKEDITOR.ENTER_BR || editor.getSelection().getStartElement().hasAscendant( 'pre', true ) ) 46 enterBr( editor, mode ); 47 else 48 enterBlock( editor, mode ); 49 50 forceMode = 0; 51 }, 0 ); 52 53 return true; 54 } 55 56 function enterBlock( editor, mode, range ) 57 { 58 // Get the range for the current selection. 59 range = range || getRange( editor ); 12 // Get the range for the current selection. 13 range = range || getRange( editor ); 60 14 61 var doc = range.document;15 var doc = range.document; 62 16 63 // Determine the block element to be used.64 var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );17 // Determine the block element to be used. 18 var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' ); 65 19 66 // Split the range.67 var splitInfo = range.splitBlock( blockTag );20 // Split the range. 21 var splitInfo = range.splitBlock( blockTag ); 68 22 69 if ( !splitInfo )70 return;23 if ( !splitInfo ) 24 return; 71 25 72 // Get the current blocks.73 var previousBlock = splitInfo.previousBlock,74 nextBlock = splitInfo.nextBlock;26 // Get the current blocks. 27 var previousBlock = splitInfo.previousBlock, 28 nextBlock = splitInfo.nextBlock; 75 29 76 var isStartOfBlock = splitInfo.wasStartOfBlock,77 isEndOfBlock = splitInfo.wasEndOfBlock;30 var isStartOfBlock = splitInfo.wasStartOfBlock, 31 isEndOfBlock = splitInfo.wasEndOfBlock; 78 32 79 var node;33 var node; 80 34 81 // If this is a block under a list item, split it as well. (#1647)82 if ( nextBlock )83 {84 node = nextBlock.getParent();85 if ( node.is( 'li' ) )86 {87 nextBlock.breakParent( node );88 nextBlock.move( nextBlock.getNext(), true );89 }90 }91 else if ( previousBlock && ( node = previousBlock.getParent() ) && node.is( 'li' ) )92 {93 previousBlock.breakParent( node );94 range.moveToElementEditStart( previousBlock.getNext() );95 previousBlock.move( previousBlock.getPrevious() );96 }35 // If this is a block under a list item, split it as well. (#1647) 36 if ( nextBlock ) 37 { 38 node = nextBlock.getParent(); 39 if ( node.is( 'li' ) ) 40 { 41 nextBlock.breakParent( node ); 42 nextBlock.move( nextBlock.getNext(), true ); 43 } 44 } 45 else if ( previousBlock && ( node = previousBlock.getParent() ) && node.is( 'li' ) ) 46 { 47 previousBlock.breakParent( node ); 48 range.moveToElementEditStart( previousBlock.getNext() ); 49 previousBlock.move( previousBlock.getPrevious() ); 50 } 97 51 98 // If we have both the previous and next blocks, it means that the99 // boundaries were on separated blocks, or none of them where on the100 // block limits (start/end).101 if ( !isStartOfBlock && !isEndOfBlock )102 {103 // If the next block is an <li> with another list tree as the first104 // child, we'll need to append a placeholder or the list item105 // wouldn't be editable. (#1420)106 if ( nextBlock.is( 'li' ) && ( node = nextBlock.getFirst() )107 && node.is && node.is( 'ul', 'ol') )108 nextBlock.insertBefore( doc.createText( '\xa0' ), node );52 // If we have both the previous and next blocks, it means that the 53 // boundaries were on separated blocks, or none of them where on the 54 // block limits (start/end). 55 if ( !isStartOfBlock && !isEndOfBlock ) 56 { 57 // If the next block is an <li> with another list tree as the first 58 // child, we'll need to append a placeholder or the list item 59 // wouldn't be editable. (#1420) 60 if ( nextBlock.is( 'li' ) && ( node = nextBlock.getFirst() ) 61 && node.is && node.is( 'ul', 'ol') ) 62 nextBlock.insertBefore( doc.createText( '\xa0' ), node ); 109 63 110 // Move the selection to the end block.111 if ( nextBlock )112 range.moveToElementEditStart( nextBlock );113 }114 else115 {64 // Move the selection to the end block. 65 if ( nextBlock ) 66 range.moveToElementEditStart( nextBlock ); 67 } 68 else 69 { 116 70 117 if ( isStartOfBlock && isEndOfBlock && previousBlock.is( 'li' ) )118 {119 editor.execCommand( 'outdent' );120 return;121 }71 if ( isStartOfBlock && isEndOfBlock && previousBlock.is( 'li' ) ) 72 { 73 editor.execCommand( 'outdent' ); 74 return; 75 } 122 76 123 var newBlock;77 var newBlock; 124 78 125 if ( previousBlock )126 {127 // Do not enter this block if it's a header tag, or we are in128 // a Shift+Enter (#77). Create a new block element instead129 // (later in the code).130 if ( !forceMode && !headerTagRegex.test( previousBlock.getName() ) )131 {132 // Otherwise, duplicate the previous block.133 newBlock = previousBlock.clone();134 }135 }136 else if ( nextBlock )137 newBlock = nextBlock.clone();79 if ( previousBlock ) 80 { 81 // Do not enter this block if it's a header tag, or we are in 82 // a Shift+Enter (#77). Create a new block element instead 83 // (later in the code). 84 if ( !forceMode && !headerTagRegex.test( previousBlock.getName() ) ) 85 { 86 // Otherwise, duplicate the previous block. 87 newBlock = previousBlock.clone(); 88 } 89 } 90 else if ( nextBlock ) 91 newBlock = nextBlock.clone(); 138 92 139 if ( !newBlock )140 newBlock = doc.createElement( blockTag );93 if ( !newBlock ) 94 newBlock = doc.createElement( blockTag ); 141 95 142 // Recreate the inline elements tree, which was available143 // before hitting enter, so the same styles will be available in144 // the new block.145 var elementPath = splitInfo.elementPath;146 if ( elementPath )147 {148 for ( var i = 0, len = elementPath.elements.length ; i < len ; i++ )149 {150 var element = elementPath.elements[ i ];96 // Recreate the inline elements tree, which was available 97 // before hitting enter, so the same styles will be available in 98 // the new block. 99 var elementPath = splitInfo.elementPath; 100 if ( elementPath ) 101 { 102 for ( var i = 0, len = elementPath.elements.length ; i < len ; i++ ) 103 { 104 var element = elementPath.elements[ i ]; 151 105 152 if ( element.equals( elementPath.block ) || element.equals( elementPath.blockLimit ) )153 break;106 if ( element.equals( elementPath.block ) || element.equals( elementPath.blockLimit ) ) 107 break; 154 108 155 if ( CKEDITOR.dtd.$removeEmpty[ element.getName() ] )156 {157 element = element.clone();158 newBlock.moveChildren( element );159 newBlock.append( element );160 }161 }162 }109 if ( CKEDITOR.dtd.$removeEmpty[ element.getName() ] ) 110 { 111 element = element.clone(); 112 newBlock.moveChildren( element ); 113 newBlock.append( element ); 114 } 115 } 116 } 163 117 164 if ( !CKEDITOR.env.ie )165 newBlock.appendBogus();118 if ( !CKEDITOR.env.ie ) 119 newBlock.appendBogus(); 166 120 167 range.insertNode( newBlock );121 range.insertNode( newBlock ); 168 122 169 // This is tricky, but to make the new block visible correctly170 // we must select it.171 // The previousBlock check has been included because it may be172 // empty if we have fixed a block-less space (like ENTER into an173 // empty table cell).174 if ( CKEDITOR.env.ie && isStartOfBlock && ( !isEndOfBlock || !previousBlock.getChildCount() ) )175 {176 // Move the selection to the new block.177 range.moveToElementEditStart( isEndOfBlock ? previousBlock : newBlock );178 range.select();179 }123 // This is tricky, but to make the new block visible correctly 124 // we must select it. 125 // The previousBlock check has been included because it may be 126 // empty if we have fixed a block-less space (like ENTER into an 127 // empty table cell). 128 if ( CKEDITOR.env.ie && isStartOfBlock && ( !isEndOfBlock || !previousBlock.getChildCount() ) ) 129 { 130 // Move the selection to the new block. 131 range.moveToElementEditStart( isEndOfBlock ? previousBlock : newBlock ); 132 range.select(); 133 } 180 134 181 // Move the selection to the new block.182 range.moveToElementEditStart( isStartOfBlock && !isEndOfBlock ? nextBlock : newBlock );183 }135 // Move the selection to the new block. 136 range.moveToElementEditStart( isStartOfBlock && !isEndOfBlock ? nextBlock : newBlock ); 137 } 184 138 185 if ( !CKEDITOR.env.ie )186 {187 if ( nextBlock )188 {189 // If we have split the block, adds a temporary span at the190 // range position and scroll relatively to it.191 var tmpNode = doc.createElement( 'span' );139 if ( !CKEDITOR.env.ie ) 140 { 141 if ( nextBlock ) 142 { 143 // If we have split the block, adds a temporary span at the 144 // range position and scroll relatively to it. 145 var tmpNode = doc.createElement( 'span' ); 192 146 193 // We need some content for Safari.194 tmpNode.setHtml( ' ' );147 // We need some content for Safari. 148 tmpNode.setHtml( ' ' ); 195 149 196 range.insertNode( tmpNode );197 tmpNode.scrollIntoView();198 range.deleteContents();199 }200 else201 {202 // We may use the above scroll logic for the new block case203 // too, but it gives some weird result with Opera.204 newBlock.scrollIntoView();205 }206 }150 range.insertNode( tmpNode ); 151 tmpNode.scrollIntoView(); 152 range.deleteContents(); 153 } 154 else 155 { 156 // We may use the above scroll logic for the new block case 157 // too, but it gives some weird result with Opera. 158 newBlock.scrollIntoView(); 159 } 160 } 207 161 208 range.select();209 }162 range.select(); 163 }, 210 164 211 function enterBr( editor, mode )212 {213 // Get the range for the current selection.214 var range = getRange( editor ),215 doc = range.document;165 enterBr : function( editor, mode ) 166 { 167 // Get the range for the current selection. 168 var range = getRange( editor ), 169 doc = range.document; 216 170 217 // Determine the block element to be used.218 var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );171 // Determine the block element to be used. 172 var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' ); 219 173 220 var isEndOfBlock = range.checkEndOfBlock();174 var isEndOfBlock = range.checkEndOfBlock(); 221 175 222 var elementPath = new CKEDITOR.dom.elementPath( editor.getSelection().getStartElement() );176 var elementPath = new CKEDITOR.dom.elementPath( editor.getSelection().getStartElement() ); 223 177 224 var startBlock = elementPath.block,225 startBlockTag = startBlock && elementPath.block.getName();178 var startBlock = elementPath.block, 179 startBlockTag = startBlock && elementPath.block.getName(); 226 180 227 var isPre = false;181 var isPre = false; 228 182 229 if ( !forceMode && startBlockTag == 'li' )230 {231 enterBlock( editor, mode, range );232 return;233 }183 if ( !forceMode && startBlockTag == 'li' ) 184 { 185 enterBlock( editor, mode, range ); 186 return; 187 } 234 188 235 // If we are at the end of a header block.236 if ( !forceMode && isEndOfBlock && headerTagRegex.test( startBlockTag ) )237 {238 // Insert a <br> after the current paragraph.239 doc.createElement( 'br' ).insertAfter( startBlock );189 // If we are at the end of a header block. 190 if ( !forceMode && isEndOfBlock && headerTagRegex.test( startBlockTag ) ) 191 { 192 // Insert a <br> after the current paragraph. 193 doc.createElement( 'br' ).insertAfter( startBlock ); 240 194 241 // A text node is required by Gecko only to make the cursor blink.242 if ( CKEDITOR.env.gecko )243 doc.createText( '' ).insertAfter( startBlock );195 // A text node is required by Gecko only to make the cursor blink. 196 if ( CKEDITOR.env.gecko ) 197 doc.createText( '' ).insertAfter( startBlock ); 244 198 245 // IE has different behaviors regarding position.246 range.setStartAt( startBlock.getNext(), CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_START );247 }248 else249 {250 var lineBreak;199 // IE has different behaviors regarding position. 200 range.setStartAt( startBlock.getNext(), CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_START ); 201 } 202 else 203 { 204 var lineBreak; 251 205 252 isPre = ( startBlockTag == 'pre' );206 isPre = ( startBlockTag == 'pre' ); 253 207 254 if ( isPre )255 lineBreak = doc.createText( CKEDITOR.env.ie ? '\r' : '\n' );256 else257 lineBreak = doc.createElement( 'br' );208 if ( isPre ) 209 lineBreak = doc.createText( CKEDITOR.env.ie ? '\r' : '\n' ); 210 else 211 lineBreak = doc.createElement( 'br' ); 258 212 259 range.deleteContents();260 range.insertNode( lineBreak );213 range.deleteContents(); 214 range.insertNode( lineBreak ); 261 215 262 // A text node is required by Gecko only to make the cursor blink.263 // We need some text inside of it, so the bogus <br> is properly264 // created.265 if ( !CKEDITOR.env.ie )266 doc.createText( '\ufeff' ).insertAfter( lineBreak );216 // A text node is required by Gecko only to make the cursor blink. 217 // We need some text inside of it, so the bogus <br> is properly 218 // created. 219 if ( !CKEDITOR.env.ie ) 220 doc.createText( '\ufeff' ).insertAfter( lineBreak ); 267 221 268 // If we are at the end of a block, we must be sure the bogus node is available in that block.269 if ( isEndOfBlock && !CKEDITOR.env.ie )270 lineBreak.getParent().appendBogus();222 // If we are at the end of a block, we must be sure the bogus node is available in that block. 223 if ( isEndOfBlock && !CKEDITOR.env.ie ) 224 lineBreak.getParent().appendBogus(); 271 225 272 // Now we can remove the text node contents, so the caret doesn't273 // stop on it.274 if ( !CKEDITOR.env.ie )275 lineBreak.getNext().$.nodeValue = '';276 // IE has different behavior regarding position.277 if ( CKEDITOR.env.ie )278 range.setStartAt( lineBreak, CKEDITOR.POSITION_AFTER_END );279 else280 range.setStartAt( lineBreak.getNext(), CKEDITOR.POSITION_AFTER_START );226 // Now we can remove the text node contents, so the caret doesn't 227 // stop on it. 228 if ( !CKEDITOR.env.ie ) 229 lineBreak.getNext().$.nodeValue = ''; 230 // IE has different behavior regarding position. 231 if ( CKEDITOR.env.ie ) 232 range.setStartAt( lineBreak, CKEDITOR.POSITION_AFTER_END ); 233 else 234 range.setStartAt( lineBreak.getNext(), CKEDITOR.POSITION_AFTER_START ); 281 235 282 // Scroll into view, for non IE.283 if ( !CKEDITOR.env.ie )284 {285 var dummy = null;236 // Scroll into view, for non IE. 237 if ( !CKEDITOR.env.ie ) 238 { 239 var dummy = null; 286 240 287 // BR is not positioned in Opera and Webkit.288 if ( !CKEDITOR.env.gecko )289 {290 dummy = doc.createElement( 'span' );291 // We need have some contents for Webkit to position it292 // under parent node. ( #3681)293 dummy.setHtml(' ');294 }295 else296 dummy = doc.createElement( 'br' );241 // BR is not positioned in Opera and Webkit. 242 if ( !CKEDITOR.env.gecko ) 243 { 244 dummy = doc.createElement( 'span' ); 245 // We need have some contents for Webkit to position it 246 // under parent node. ( #3681) 247 dummy.setHtml(' '); 248 } 249 else 250 dummy = doc.createElement( 'br' ); 297 251 298 dummy.insertBefore( lineBreak.getNext() );299 dummy.scrollIntoView();300 dummy.remove();301 }302 }252 dummy.insertBefore( lineBreak.getNext() ); 253 dummy.scrollIntoView(); 254 dummy.remove(); 255 } 256 } 303 257 304 // This collapse guarantees the cursor will be blinking.305 range.collapse( true );258 // This collapse guarantees the cursor will be blinking. 259 range.collapse( true ); 306 260 307 range.select( isPre ); 308 } 261 range.select( isPre ); 262 } 263 }; 309 264 265 var plugin = CKEDITOR.plugins.enterkey, 266 enterBr = plugin.enterBr, 267 enterBlock = plugin.enterBlock; 268 269 CKEDITOR.plugins.add( 'enterkey', 270 { 271 requires : [ 'keystrokes', 'indent' ], 272 273 init : function( editor ) 274 { 275 var specialKeys = editor.specialKeys; 276 specialKeys[ 13 ] = enter; 277 specialKeys[ CKEDITOR.SHIFT + 13 ] = shiftEnter; 278 } 279 }); 280 281 var forceMode, 282 headerTagRegex = /^h[1-6]$/; 283 284 function shiftEnter( editor ) 285 { 286 // On SHIFT+ENTER we want to enforce the mode to be respected, instead 287 // of cloning the current block. (#77) 288 forceMode = 1; 289 290 return enter( editor, editor.config.shiftEnterMode ); 291 } 292 293 function enter( editor, mode ) 294 { 295 // Only effective within document. 296 if ( editor.mode != 'wysiwyg' ) 297 return false; 298 299 if ( !mode ) 300 mode = editor.config.enterMode; 301 302 // Use setTimout so the keys get cancelled immediatelly. 303 setTimeout( function() 304 { 305 editor.fire( 'saveSnapshot' ); // Save undo step. 306 if ( mode == CKEDITOR.ENTER_BR || editor.getSelection().getStartElement().hasAscendant( 'pre', true ) ) 307 enterBr( editor, mode ); 308 else 309 enterBlock( editor, mode ); 310 311 forceMode = 0; 312 }, 0 ); 313 314 return true; 315 } 316 310 317 function getRange( editor ) 311 318 { 312 319 // Get the selection ranges. -
_source/plugins/pastetext/plugin.js
83 83 }, 84 84 requires : [ 'clipboard' ] 85 85 }); 86 })();87 86 88 CKEDITOR.editor.prototype.insertText = function( text ) 89 { 90 text = CKEDITOR.tools.htmlEncode( text ); 87 var enterKeyPlugin = CKEDITOR.plugins.enterkey; 88 89 function doInsertText( doc, text ) 90 { 91 // Native text insertion. 92 if( CKEDITOR.env.ie ) 93 { 94 var selection = doc.selection; 95 if ( selection.type == 'Control' ) 96 selection.clear(); 97 selection.createRange().pasteHTML( text ); 98 } 99 else 100 doc.execCommand( 'inserthtml', false, text ); 101 } 102 103 function doEnter( editor, mode ) 104 { 105 enterKeyPlugin[ mode == CKEDITOR.ENTER_BR ? 'enterBr' : 'enterBlock' ]( editor, mode ); 106 } 107 108 CKEDITOR.editor.prototype.insertText = function( text ) 109 { 110 var mode = this.getSelection().getStartElement().hasAscendant( 'pre', true ) ? CKEDITOR.ENTER_BR : this.config.enterMode, 111 doc = this.document.$, 112 self = this, 113 line; 114 115 text = CKEDITOR.tools.htmlEncode( text ); 91 116 92 // TODO: Replace the following with fill line break processing (see V2). 93 text = text.replace( /(?:\r\n)|\n|\r/g, '<br>' ); 117 var startIndex = 0; 118 text.replace( /(?:\r\n)|\n|\r/g, function( match, lastIndex ) 119 { 120 line = text.substring( startIndex, lastIndex ); 121 startIndex = lastIndex + match.length; 122 line.length && doInsertText( doc, line ); 123 // Line-break as an editor enter key result. 124 doEnter( self, mode ); 125 } ); 94 126 95 this.insertHtml( text ); 96 }; 127 line = text.substring( startIndex, text.length ); 128 line.length && doInsertText( doc, line ); 129 }; 97 130 131 })(); 132 133 98 134 /** 99 135 * Whether to force all pasting operations to insert on plain text into the 100 136 * editor, loosing any formatting information possibly available in the source