| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 /* 2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 */ 5 6 (function() 7 { 8 CKEDITOR.plugins.add( 'enterkey', 9 { 10 requires : [ 'keystrokes', 'indent' ], 11 12 init : function( editor ) 13 { 14 var specialKeys = editor.specialKeys; 15 specialKeys[ 13 ] = enter; 16 specialKeys[ CKEDITOR.SHIFT + 13 ] = shiftEnter; 17 } 18 }); 19 20 CKEDITOR.plugins.enterkey = 21 { 22 enterBlock : function( editor, mode, range, forceMode ) 23 { 24 // Get the range for the current selection. 25 range = range || getRange( editor ); 26 27 // We may not have valid ranges to work on, like when inside a 28 // contenteditable=false element. 29 if ( !range ) 30 return; 31 32 var doc = range.document; 33 34 // Exit the list when we're inside an empty list item block. (#5376) 35 if ( range.checkStartOfBlock() && range.checkEndOfBlock() ) 36 { 37 var path = new CKEDITOR.dom.elementPath( range.startContainer ), 38 block = path.block; 39 40 if ( block && ( block.is( 'li' ) || block.getParent().is( 'li' ) ) ) 41 { 42 editor.execCommand( 'outdent' ); 43 return; 44 } 45 } 46 47 // Determine the block element to be used. 48 var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' ); 49 50 // Split the range. 51 var splitInfo = range.splitBlock( blockTag ); 52 53 if ( !splitInfo ) 54 return; 55 56 // Get the current blocks. 57 var previousBlock = splitInfo.previousBlock, 58 nextBlock = splitInfo.nextBlock; 59 60 var isStartOfBlock = splitInfo.wasStartOfBlock, 61 isEndOfBlock = splitInfo.wasEndOfBlock; 62 63 var node; 64 65 // If this is a block under a list item, split it as well. (#1647) 66 if ( nextBlock ) 67 { 68 node = nextBlock.getParent(); 69 if ( node.is( 'li' ) ) 70 { 71 nextBlock.breakParent( node ); 72 nextBlock.move( nextBlock.getNext(), true ); 73 } 74 } 75 else if ( previousBlock && ( node = previousBlock.getParent() ) && node.is( 'li' ) ) 76 { 77 previousBlock.breakParent( node ); 78 range.moveToElementEditStart( previousBlock.getNext() ); 79 previousBlock.move( previousBlock.getPrevious() ); 80 } 81 82 // If we have both the previous and next blocks, it means that the 83 // boundaries were on separated blocks, or none of them where on the 84 // block limits (start/end). 85 if ( !isStartOfBlock && !isEndOfBlock ) 86 { 87 // If the next block is an <li> with another list tree as the first 88 // child, we'll need to append a filler (<br>/NBSP) or the list item 89 // wouldn't be editable. (#1420) 90 if ( nextBlock.is( 'li' ) 91 && ( node = nextBlock.getFirst( CKEDITOR.dom.walker.invisible( true ) ) ) 92 && node.is && node.is( 'ul', 'ol' ) ) 93 ( CKEDITOR.env.ie ? doc.createText( '\xa0' ) : doc.createElement( 'br' ) ).insertBefore( node ); 94 95 // Move the selection to the end block. 96 if ( nextBlock ) 97 range.moveToElementEditStart( nextBlock ); 98 } 99 else 100 { 101 var newBlock; 102 103 if ( previousBlock ) 104 { 105 // Do not enter this block if it's a header tag, or we are in 106 // a Shift+Enter (#77). Create a new block element instead 107 // (later in the code). 108 if ( previousBlock.is( 'li' ) || !headerTagRegex.test( previousBlock.getName() ) ) 109 { 110 // Otherwise, duplicate the previous block. 111 newBlock = previousBlock.clone(); 112 } 113 } 114 else if ( nextBlock ) 115 newBlock = nextBlock.clone(); 116 117 if ( !newBlock ) 118 newBlock = doc.createElement( blockTag ); 119 // Force the enter block unless we're talking of a list item. 120 else if ( forceMode && !newBlock.is( 'li' ) ) 121 newBlock.renameNode( blockTag ); 122 123 // Recreate the inline elements tree, which was available 124 // before hitting enter, so the same styles will be available in 125 // the new block. 126 var elementPath = splitInfo.elementPath; 127 if ( elementPath ) 128 { 129 for ( var i = 0, len = elementPath.elements.length ; i < len ; i++ ) 130 { 131 var element = elementPath.elements[ i ]; 132 133 if ( element.equals( elementPath.block ) || element.equals( elementPath.blockLimit ) ) 134 break; 135 136 if ( CKEDITOR.dtd.$removeEmpty[ element.getName() ] ) 137 { 138 element = element.clone(); 139 newBlock.moveChildren( element ); 140 newBlock.append( element ); 141 } 142 } 143 } 144 145 if ( !CKEDITOR.env.ie ) 146 newBlock.appendBogus(); 147 148 range.insertNode( newBlock ); 149 150 // This is tricky, but to make the new block visible correctly 151 // we must select it. 152 // The previousBlock check has been included because it may be 153 // empty if we have fixed a block-less space (like ENTER into an 154 // empty table cell). 155 if ( CKEDITOR.env.ie && isStartOfBlock && ( !isEndOfBlock || !previousBlock.getChildCount() ) ) 156 { 157 // Move the selection to the new block. 158 range.moveToElementEditStart( isEndOfBlock ? previousBlock : newBlock ); 159 range.select(); 160 } 161 162 // Move the selection to the new block. 163 range.moveToElementEditStart( isStartOfBlock && !isEndOfBlock ? nextBlock : newBlock ); 164 } 165 166 if ( !CKEDITOR.env.ie ) 167 { 168 if ( nextBlock ) 169 { 170 // If we have split the block, adds a temporary span at the 171 // range position and scroll relatively to it. 172 var tmpNode = doc.createElement( 'span' ); 173 174 // We need some content for Safari. 175 tmpNode.setHtml( ' ' ); 176 177 range.insertNode( tmpNode ); 178 tmpNode.scrollIntoView(); 179 range.deleteContents(); 180 } 181 else 182 { 183 // We may use the above scroll logic for the new block case 184 // too, but it gives some weird result with Opera. 185 newBlock.scrollIntoView(); 186 } 187 } 188 189 range.select(); 190 }, 191 192 enterBr : function( editor, mode, range, forceMode ) 193 { 194 // Get the range for the current selection. 195 range = range || getRange( editor ); 196 197 // We may not have valid ranges to work on, like when inside a 198 // contenteditable=false element. 199 if ( !range ) 200 return; 201 202 var doc = range.document; 203 204 // Determine the block element to be used. 205 var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' ); 206 207 var isEndOfBlock = range.checkEndOfBlock(); 208 209 var elementPath = new CKEDITOR.dom.elementPath( editor.getSelection().getStartElement() ); 210 211 var startBlock = elementPath.block, 212 startBlockTag = startBlock && elementPath.block.getName(); 213 214 var isPre = false; 215 216 if ( !forceMode && startBlockTag == 'li' ) 217 { 218 enterBlock( editor, mode, range, forceMode ); 219 return; 220 } 221 222 // If we are at the end of a header block. 223 if ( !forceMode && isEndOfBlock && headerTagRegex.test( startBlockTag ) ) 224 { 225 // Insert a <br> after the current paragraph. 226 doc.createElement( 'br' ).insertAfter( startBlock ); 227 228 // A text node is required by Gecko only to make the cursor blink. 229 if ( CKEDITOR.env.gecko ) 230 doc.createText( '' ).insertAfter( startBlock ); 231 232 // IE has different behaviors regarding position. 233 range.setStartAt( startBlock.getNext(), CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_START ); 234 } 235 else 236 { 237 var lineBreak; 238 239 isPre = ( startBlockTag == 'pre' ); 240 241 // Gecko prefers <br> as line-break inside <pre> (#4711). 242 if ( isPre && !CKEDITOR.env.gecko ) 243 lineBreak = doc.createText( CKEDITOR.env.ie ? '\r' : '\n' ); 244 else 245 lineBreak = doc.createElement( 'br' ); 246 247 range.deleteContents(); 248 range.insertNode( lineBreak ); 249 250 // A text node is required by Gecko only to make the cursor blink. 251 // We need some text inside of it, so the bogus <br> is properly 252 // created. 253 if ( !CKEDITOR.env.ie ) 254 doc.createText( '\ufeff' ).insertAfter( lineBreak ); 255 256 // If we are at the end of a block, we must be sure the bogus node is available in that block. 257 if ( isEndOfBlock && !CKEDITOR.env.ie ) 258 lineBreak.getParent().appendBogus(); 259 260 // Now we can remove the text node contents, so the caret doesn't 261 // stop on it. 262 if ( !CKEDITOR.env.ie ) 263 lineBreak.getNext().$.nodeValue = ''; 264 // IE has different behavior regarding position. 265 if ( CKEDITOR.env.ie ) 266 range.setStartAt( lineBreak, CKEDITOR.POSITION_AFTER_END ); 267 else 268 range.setStartAt( lineBreak.getNext(), CKEDITOR.POSITION_AFTER_START ); 269 270 // Scroll into view, for non IE. 271 if ( !CKEDITOR.env.ie ) 272 { 273 var dummy = null; 274 275 // BR is not positioned in Opera and Webkit. 276 if ( !CKEDITOR.env.gecko ) 277 { 278 dummy = doc.createElement( 'span' ); 279 // We need have some contents for Webkit to position it 280 // under parent node. ( #3681) 281 dummy.setHtml(' '); 282 } 283 else 284 dummy = doc.createElement( 'br' ); 285 286 dummy.insertBefore( lineBreak.getNext() ); 287 dummy.scrollIntoView(); 288 dummy.remove(); 289 } 290 } 291 292 // This collapse guarantees the cursor will be blinking. 293 range.collapse( true ); 294 295 range.select( isPre ); 296 } 297 }; 298 299 var plugin = CKEDITOR.plugins.enterkey, 300 enterBr = plugin.enterBr, 301 enterBlock = plugin.enterBlock, 302 headerTagRegex = /^h[1-6]$/; 303 304 function shiftEnter( editor ) 305 { 306 // Only effective within document. 307 if ( editor.mode != 'wysiwyg' ) 308 return false; 309 310 // On SHIFT+ENTER: 311 // 1. We want to enforce the mode to be respected, instead 312 // of cloning the current block. (#77) 313 // 2. Always perform a block break when inside <pre> (#5402). 314 if ( editor.getSelection().getStartElement().hasAscendant( 'pre', true ) ) 315 { 316 setTimeout( function() { enterBlock( editor, editor.config.enterMode, null, true ); }, 0 ); 317 return true; 318 } 319 else 320 return enter( editor, editor.config.shiftEnterMode, true ); 321 } 322 323 function enter( editor, mode, forceMode ) 324 { 325 forceMode = editor.config.forceEnterMode || forceMode; 326 327 // Only effective within document. 328 if ( editor.mode != 'wysiwyg' ) 329 return false; 330 331 if ( !mode ) 332 mode = editor.config.enterMode; 333 334 // Use setTimout so the keys get cancelled immediatelly. 335 setTimeout( function() 336 { 337 editor.fire( 'saveSnapshot' ); // Save undo step. 338 if ( mode == CKEDITOR.ENTER_BR || editor.getSelection().getStartElement().hasAscendant( 'pre', true ) ) 339 enterBr( editor, mode, null, forceMode ); 340 else 341 enterBlock( editor, mode, null, forceMode ); 342 343 }, 0 ); 344 345 return true; 346 } 347 348 349 function getRange( editor ) 350 { 351 // Get the selection ranges. 352 var ranges = editor.getSelection().getRanges( true ); 353 354 // Delete the contents of all ranges except the first one. 355 for ( var i = ranges.length - 1 ; i > 0 ; i-- ) 356 { 357 ranges[ i ].deleteContents(); 358 } 359 360 // Return the first range. 361 return ranges[ 0 ]; 362 } 363 })();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |