1 | /** |
---|
2 | * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved. |
---|
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license |
---|
4 | */ |
---|
5 | |
---|
6 | ( function() { |
---|
7 | CKEDITOR.plugins.add( 'enterkey', { |
---|
8 | init: function( editor ) { |
---|
9 | editor.addCommand( 'enter', { |
---|
10 | modes: { wysiwyg: 1 }, |
---|
11 | editorFocus: false, |
---|
12 | exec: function( editor ) { |
---|
13 | enter( editor ); |
---|
14 | } |
---|
15 | } ); |
---|
16 | |
---|
17 | editor.addCommand( 'shiftEnter', { |
---|
18 | modes: { wysiwyg: 1 }, |
---|
19 | editorFocus: false, |
---|
20 | exec: function( editor ) { |
---|
21 | shiftEnter( editor ); |
---|
22 | } |
---|
23 | } ); |
---|
24 | |
---|
25 | editor.setKeystroke( [ |
---|
26 | [ 13, 'enter' ], |
---|
27 | [ CKEDITOR.SHIFT + 13, 'shiftEnter' ] |
---|
28 | ] ); |
---|
29 | } |
---|
30 | } ); |
---|
31 | |
---|
32 | var whitespaces = CKEDITOR.dom.walker.whitespaces(), |
---|
33 | bookmark = CKEDITOR.dom.walker.bookmark(); |
---|
34 | |
---|
35 | CKEDITOR.plugins.enterkey = { |
---|
36 | enterBlock: function( editor, mode, range, forceMode ) { |
---|
37 | // Get the range for the current selection. |
---|
38 | range = range || getRange( editor ); |
---|
39 | |
---|
40 | // We may not have valid ranges to work on, like when inside a |
---|
41 | // contenteditable=false element. |
---|
42 | if ( !range ) |
---|
43 | return; |
---|
44 | |
---|
45 | // When range is in nested editable, we have to replace range with this one, |
---|
46 | // which have root property set to closest editable, to make auto paragraphing work. (#12162) |
---|
47 | range = replaceRangeWithClosestEditableRoot( range ); |
---|
48 | |
---|
49 | var doc = range.document; |
---|
50 | |
---|
51 | var atBlockStart = range.checkStartOfBlock(), |
---|
52 | atBlockEnd = range.checkEndOfBlock(), |
---|
53 | path = editor.elementPath( range.startContainer ), |
---|
54 | block = path.block, |
---|
55 | |
---|
56 | // Determine the block element to be used. |
---|
57 | blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' ), |
---|
58 | |
---|
59 | newBlock; |
---|
60 | |
---|
61 | if ( CKEDITOR.env.gecko) { |
---|
62 | var originalText = block.getText(); |
---|
63 | block.setText(originalText); |
---|
64 | } |
---|
65 | |
---|
66 | // Exit the list when we're inside an empty list item block. (#5376) |
---|
67 | if ( atBlockStart && atBlockEnd ) { |
---|
68 | // Exit the list when we're inside an empty list item block. (#5376) |
---|
69 | if ( block && ( block.is( 'li' ) || block.getParent().is( 'li' ) ) ) { |
---|
70 | // Make sure to point to the li when dealing with empty list item. |
---|
71 | if ( !block.is( 'li' ) ) |
---|
72 | block = block.getParent(); |
---|
73 | |
---|
74 | var blockParent = block.getParent(), |
---|
75 | blockGrandParent = blockParent.getParent(), |
---|
76 | |
---|
77 | firstChild = !block.hasPrevious(), |
---|
78 | lastChild = !block.hasNext(), |
---|
79 | |
---|
80 | selection = editor.getSelection(), |
---|
81 | bookmarks = selection.createBookmarks(), |
---|
82 | |
---|
83 | orgDir = block.getDirection( 1 ), |
---|
84 | className = block.getAttribute( 'class' ), |
---|
85 | style = block.getAttribute( 'style' ), |
---|
86 | dirLoose = blockGrandParent.getDirection( 1 ) != orgDir, |
---|
87 | |
---|
88 | enterMode = editor.enterMode, |
---|
89 | needsBlock = enterMode != CKEDITOR.ENTER_BR || dirLoose || style || className, |
---|
90 | |
---|
91 | child; |
---|
92 | |
---|
93 | if ( blockGrandParent.is( 'li' ) ) { |
---|
94 | |
---|
95 | // If block is the first or the last child of the parent |
---|
96 | // list, degrade it and move to the outer list: |
---|
97 | // before the parent list if block is first child and after |
---|
98 | // the parent list if block is the last child, respectively. |
---|
99 | // |
---|
100 | // <ul> => <ul> |
---|
101 | // <li> => <li> |
---|
102 | // <ul> => <ul> |
---|
103 | // <li>x</li> => <li>x</li> |
---|
104 | // <li>^</li> => </ul> |
---|
105 | // </ul> => </li> |
---|
106 | // </li> => <li>^</li> |
---|
107 | // </ul> => </ul> |
---|
108 | // |
---|
109 | // AND |
---|
110 | // |
---|
111 | // <ul> => <ul> |
---|
112 | // <li> => <li>^</li> |
---|
113 | // <ul> => <li> |
---|
114 | // <li>^</li> => <ul> |
---|
115 | // <li>x</li> => <li>x</li> |
---|
116 | // </ul> => </ul> |
---|
117 | // </li> => </li> |
---|
118 | // </ul> => </ul> |
---|
119 | |
---|
120 | if ( firstChild || lastChild ) { |
---|
121 | |
---|
122 | // If it's only child, we don't want to keep perent ul anymore. |
---|
123 | if ( firstChild && lastChild ) { |
---|
124 | blockParent.remove(); |
---|
125 | } |
---|
126 | |
---|
127 | block[lastChild ? 'insertAfter' : 'insertBefore']( blockGrandParent ); |
---|
128 | |
---|
129 | // If the empty block is neither first nor last child |
---|
130 | // then split the list and the block as an element |
---|
131 | // of outer list. |
---|
132 | // |
---|
133 | // => <ul> |
---|
134 | // => <li> |
---|
135 | // <ul> => <ul> |
---|
136 | // <li> => <li>x</li> |
---|
137 | // <ul> => </ul> |
---|
138 | // <li>x</li> => </li> |
---|
139 | // <li>^</li> => <li>^</li> |
---|
140 | // <li>y</li> => <li> |
---|
141 | // </ul> => <ul> |
---|
142 | // </li> => <li>y</li> |
---|
143 | // </ul> => </ul> |
---|
144 | // => </li> |
---|
145 | // => </ul> |
---|
146 | |
---|
147 | } else { |
---|
148 | block.breakParent( blockGrandParent ); |
---|
149 | } |
---|
150 | } |
---|
151 | |
---|
152 | else if ( !needsBlock ) { |
---|
153 | block.appendBogus( true ); |
---|
154 | |
---|
155 | // If block is the first or last child of the parent |
---|
156 | // list, move all block's children out of the list: |
---|
157 | // before the list if block is first child and after the list |
---|
158 | // if block is the last child, respectively. |
---|
159 | // |
---|
160 | // <ul> => <ul> |
---|
161 | // <li>x</li> => <li>x</li> |
---|
162 | // <li>^</li> => </ul> |
---|
163 | // </ul> => ^ |
---|
164 | // |
---|
165 | // AND |
---|
166 | // |
---|
167 | // <ul> => ^ |
---|
168 | // <li>^</li> => <ul> |
---|
169 | // <li>x</li> => <li>x</li> |
---|
170 | // </ul> => </ul> |
---|
171 | |
---|
172 | if ( firstChild || lastChild ) { |
---|
173 | while ( ( child = block[ firstChild ? 'getFirst' : 'getLast' ]() ) ) |
---|
174 | child[ firstChild ? 'insertBefore' : 'insertAfter' ]( blockParent ); |
---|
175 | } |
---|
176 | |
---|
177 | // If the empty block is neither first nor last child |
---|
178 | // then split the list and put all the block contents |
---|
179 | // between two lists. |
---|
180 | // |
---|
181 | // <ul> => <ul> |
---|
182 | // <li>x</li> => <li>x</li> |
---|
183 | // <li>^</li> => </ul> |
---|
184 | // <li>y</li> => ^ |
---|
185 | // </ul> => <ul> |
---|
186 | // => <li>y</li> |
---|
187 | // => </ul> |
---|
188 | |
---|
189 | else { |
---|
190 | block.breakParent( blockParent ); |
---|
191 | |
---|
192 | while ( ( child = block.getLast() ) ) |
---|
193 | child.insertAfter( blockParent ); |
---|
194 | } |
---|
195 | |
---|
196 | block.remove(); |
---|
197 | } else { |
---|
198 | // Original path block is the list item, create new block for the list item content. |
---|
199 | if ( path.block.is( 'li' ) ) { |
---|
200 | // Use <div> block for ENTER_BR and ENTER_DIV. |
---|
201 | newBlock = doc.createElement( mode == CKEDITOR.ENTER_P ? 'p' : 'div' ); |
---|
202 | |
---|
203 | if ( dirLoose ) |
---|
204 | newBlock.setAttribute( 'dir', orgDir ); |
---|
205 | |
---|
206 | style && newBlock.setAttribute( 'style', style ); |
---|
207 | className && newBlock.setAttribute( 'class', className ); |
---|
208 | |
---|
209 | // Move all the child nodes to the new block. |
---|
210 | block.moveChildren( newBlock ); |
---|
211 | } |
---|
212 | // The original path block is not a list item, just copy the block to out side of the list. |
---|
213 | else { |
---|
214 | newBlock = path.block; |
---|
215 | } |
---|
216 | |
---|
217 | // If block is the first or last child of the parent |
---|
218 | // list, move it out of the list: |
---|
219 | // before the list if block is first child and after the list |
---|
220 | // if block is the last child, respectively. |
---|
221 | // |
---|
222 | // <ul> => <ul> |
---|
223 | // <li>x</li> => <li>x</li> |
---|
224 | // <li>^</li> => </ul> |
---|
225 | // </ul> => <p>^</p> |
---|
226 | // |
---|
227 | // AND |
---|
228 | // |
---|
229 | // <ul> => <p>^</p> |
---|
230 | // <li>^</li> => <ul> |
---|
231 | // <li>x</li> => <li>x</li> |
---|
232 | // </ul> => </ul> |
---|
233 | |
---|
234 | if ( firstChild || lastChild ) |
---|
235 | newBlock[ firstChild ? 'insertBefore' : 'insertAfter' ]( blockParent ); |
---|
236 | |
---|
237 | // If the empty block is neither first nor last child |
---|
238 | // then split the list and put the new block between |
---|
239 | // two lists. |
---|
240 | // |
---|
241 | // => <ul> |
---|
242 | // <ul> => <li>x</li> |
---|
243 | // <li>x</li> => </ul> |
---|
244 | // <li>^</li> => <p>^</p> |
---|
245 | // <li>y</li> => <ul> |
---|
246 | // </ul> => <li>y</li> |
---|
247 | // => </ul> |
---|
248 | |
---|
249 | else { |
---|
250 | block.breakParent( blockParent ); |
---|
251 | newBlock.insertAfter( blockParent ); |
---|
252 | } |
---|
253 | |
---|
254 | block.remove(); |
---|
255 | } |
---|
256 | |
---|
257 | selection.selectBookmarks( bookmarks ); |
---|
258 | |
---|
259 | return; |
---|
260 | } |
---|
261 | |
---|
262 | if ( block && block.getParent().is( 'blockquote' ) ) { |
---|
263 | block.breakParent( block.getParent() ); |
---|
264 | |
---|
265 | // If we were at the start of <blockquote>, there will be an empty element before it now. |
---|
266 | if ( !block.getPrevious().getFirst( CKEDITOR.dom.walker.invisible( 1 ) ) ) |
---|
267 | block.getPrevious().remove(); |
---|
268 | |
---|
269 | // If we were at the end of <blockquote>, there will be an empty element after it now. |
---|
270 | if ( !block.getNext().getFirst( CKEDITOR.dom.walker.invisible( 1 ) ) ) |
---|
271 | block.getNext().remove(); |
---|
272 | |
---|
273 | range.moveToElementEditStart( block ); |
---|
274 | range.select(); |
---|
275 | return; |
---|
276 | } |
---|
277 | } |
---|
278 | // Don't split <pre> if we're in the middle of it, act as shift enter key. |
---|
279 | else if ( block && block.is( 'pre' ) ) { |
---|
280 | if ( !atBlockEnd ) { |
---|
281 | enterBr( editor, mode, range, forceMode ); |
---|
282 | return; |
---|
283 | } |
---|
284 | } |
---|
285 | |
---|
286 | // Split the range. |
---|
287 | var splitInfo = range.splitBlock( blockTag ); |
---|
288 | |
---|
289 | if ( !splitInfo ) |
---|
290 | return; |
---|
291 | |
---|
292 | // Get the current blocks. |
---|
293 | var previousBlock = splitInfo.previousBlock, |
---|
294 | nextBlock = splitInfo.nextBlock; |
---|
295 | |
---|
296 | var isStartOfBlock = splitInfo.wasStartOfBlock, |
---|
297 | isEndOfBlock = splitInfo.wasEndOfBlock; |
---|
298 | |
---|
299 | var node; |
---|
300 | |
---|
301 | // If this is a block under a list item, split it as well. (#1647) |
---|
302 | if ( nextBlock ) { |
---|
303 | node = nextBlock.getParent(); |
---|
304 | if ( node.is( 'li' ) ) { |
---|
305 | nextBlock.breakParent( node ); |
---|
306 | nextBlock.move( nextBlock.getNext(), 1 ); |
---|
307 | } |
---|
308 | } else if ( previousBlock && ( node = previousBlock.getParent() ) && node.is( 'li' ) ) { |
---|
309 | previousBlock.breakParent( node ); |
---|
310 | node = previousBlock.getNext(); |
---|
311 | range.moveToElementEditStart( node ); |
---|
312 | previousBlock.move( previousBlock.getPrevious() ); |
---|
313 | } |
---|
314 | |
---|
315 | // If we have both the previous and next blocks, it means that the |
---|
316 | // boundaries were on separated blocks, or none of them where on the |
---|
317 | // block limits (start/end). |
---|
318 | if ( !isStartOfBlock && !isEndOfBlock ) { |
---|
319 | // If the next block is an <li> with another list tree as the first |
---|
320 | // child, we'll need to append a filler (<br>/NBSP) or the list item |
---|
321 | // wouldn't be editable. (#1420) |
---|
322 | if ( nextBlock.is( 'li' ) ) { |
---|
323 | var walkerRange = range.clone(); |
---|
324 | walkerRange.selectNodeContents( nextBlock ); |
---|
325 | var walker = new CKEDITOR.dom.walker( walkerRange ); |
---|
326 | walker.evaluator = function( node ) { |
---|
327 | return !( bookmark( node ) || whitespaces( node ) || node.type == CKEDITOR.NODE_ELEMENT && node.getName() in CKEDITOR.dtd.$inline && !( node.getName() in CKEDITOR.dtd.$empty ) ); |
---|
328 | }; |
---|
329 | |
---|
330 | node = walker.next(); |
---|
331 | if ( node && node.type == CKEDITOR.NODE_ELEMENT && node.is( 'ul', 'ol' ) ) |
---|
332 | ( CKEDITOR.env.needsBrFiller ? doc.createElement( 'br' ) : doc.createText( '\xa0' ) ).insertBefore( node ); |
---|
333 | } |
---|
334 | |
---|
335 | // Move the selection to the end block. |
---|
336 | if ( nextBlock ) |
---|
337 | range.moveToElementEditStart( nextBlock ); |
---|
338 | } else { |
---|
339 | var newBlockDir; |
---|
340 | |
---|
341 | if ( previousBlock ) { |
---|
342 | // Do not enter this block if it's a header tag, or we are in |
---|
343 | // a Shift+Enter (#77). Create a new block element instead |
---|
344 | // (later in the code). |
---|
345 | if ( previousBlock.is( 'li' ) || !( headerTagRegex.test( previousBlock.getName() ) || previousBlock.is( 'pre' ) ) ) { |
---|
346 | // Otherwise, duplicate the previous block. |
---|
347 | newBlock = previousBlock.clone(); |
---|
348 | } |
---|
349 | } else if ( nextBlock ) { |
---|
350 | newBlock = nextBlock.clone(); |
---|
351 | } |
---|
352 | |
---|
353 | if ( !newBlock ) { |
---|
354 | // We have already created a new list item. (#6849) |
---|
355 | if ( node && node.is( 'li' ) ) |
---|
356 | newBlock = node; |
---|
357 | else { |
---|
358 | newBlock = doc.createElement( blockTag ); |
---|
359 | if ( previousBlock && ( newBlockDir = previousBlock.getDirection() ) ) |
---|
360 | newBlock.setAttribute( 'dir', newBlockDir ); |
---|
361 | } |
---|
362 | } |
---|
363 | // Force the enter block unless we're talking of a list item. |
---|
364 | else if ( forceMode && !newBlock.is( 'li' ) ) { |
---|
365 | newBlock.renameNode( blockTag ); |
---|
366 | } |
---|
367 | |
---|
368 | // Recreate the inline elements tree, which was available |
---|
369 | // before hitting enter, so the same styles will be available in |
---|
370 | // the new block. |
---|
371 | var elementPath = splitInfo.elementPath; |
---|
372 | if ( elementPath ) { |
---|
373 | for ( var i = 0, len = elementPath.elements.length; i < len; i++ ) { |
---|
374 | var element = elementPath.elements[ i ]; |
---|
375 | |
---|
376 | if ( element.equals( elementPath.block ) || element.equals( elementPath.blockLimit ) ) |
---|
377 | break; |
---|
378 | |
---|
379 | if ( CKEDITOR.dtd.$removeEmpty[ element.getName() ] ) { |
---|
380 | element = element.clone(); |
---|
381 | newBlock.moveChildren( element ); |
---|
382 | newBlock.append( element ); |
---|
383 | } |
---|
384 | } |
---|
385 | } |
---|
386 | |
---|
387 | newBlock.appendBogus(); |
---|
388 | |
---|
389 | if ( !newBlock.getParent() ) |
---|
390 | range.insertNode( newBlock ); |
---|
391 | |
---|
392 | // list item start number should not be duplicated (#7330), but we need |
---|
393 | // to remove the attribute after it's onto the DOM tree because of old IEs (#7581). |
---|
394 | newBlock.is( 'li' ) && newBlock.removeAttribute( 'value' ); |
---|
395 | |
---|
396 | // This is tricky, but to make the new block visible correctly |
---|
397 | // we must select it. |
---|
398 | // The previousBlock check has been included because it may be |
---|
399 | // empty if we have fixed a block-less space (like ENTER into an |
---|
400 | // empty table cell). |
---|
401 | if ( CKEDITOR.env.ie && isStartOfBlock && ( !isEndOfBlock || !previousBlock.getChildCount() ) ) { |
---|
402 | // Move the selection to the new block. |
---|
403 | range.moveToElementEditStart( isEndOfBlock ? previousBlock : newBlock ); |
---|
404 | range.select(); |
---|
405 | } |
---|
406 | |
---|
407 | // Move the selection to the new block. |
---|
408 | range.moveToElementEditStart( isStartOfBlock && !isEndOfBlock ? nextBlock : newBlock ); |
---|
409 | } |
---|
410 | |
---|
411 | range.select(); |
---|
412 | range.scrollIntoView(); |
---|
413 | }, |
---|
414 | |
---|
415 | enterBr: function( editor, mode, range, forceMode ) { |
---|
416 | // Get the range for the current selection. |
---|
417 | range = range || getRange( editor ); |
---|
418 | |
---|
419 | // We may not have valid ranges to work on, like when inside a |
---|
420 | // contenteditable=false element. |
---|
421 | if ( !range ) |
---|
422 | return; |
---|
423 | |
---|
424 | var doc = range.document; |
---|
425 | |
---|
426 | var isEndOfBlock = range.checkEndOfBlock(); |
---|
427 | |
---|
428 | var elementPath = new CKEDITOR.dom.elementPath( editor.getSelection().getStartElement() ); |
---|
429 | |
---|
430 | var startBlock = elementPath.block, |
---|
431 | startBlockTag = startBlock && elementPath.block.getName(); |
---|
432 | |
---|
433 | if ( !forceMode && startBlockTag == 'li' ) { |
---|
434 | enterBlock( editor, mode, range, forceMode ); |
---|
435 | return; |
---|
436 | } |
---|
437 | |
---|
438 | // If we are at the end of a header block. |
---|
439 | if ( !forceMode && isEndOfBlock && headerTagRegex.test( startBlockTag ) ) { |
---|
440 | var newBlock, newBlockDir; |
---|
441 | |
---|
442 | if ( ( newBlockDir = startBlock.getDirection() ) ) { |
---|
443 | newBlock = doc.createElement( 'div' ); |
---|
444 | newBlock.setAttribute( 'dir', newBlockDir ); |
---|
445 | newBlock.insertAfter( startBlock ); |
---|
446 | range.setStart( newBlock, 0 ); |
---|
447 | } else { |
---|
448 | // Insert a <br> after the current paragraph. |
---|
449 | doc.createElement( 'br' ).insertAfter( startBlock ); |
---|
450 | |
---|
451 | // A text node is required by Gecko only to make the cursor blink. |
---|
452 | if ( CKEDITOR.env.gecko ) |
---|
453 | doc.createText( '' ).insertAfter( startBlock ); |
---|
454 | |
---|
455 | // IE has different behaviors regarding position. |
---|
456 | range.setStartAt( startBlock.getNext(), CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_START ); |
---|
457 | } |
---|
458 | } else { |
---|
459 | var lineBreak; |
---|
460 | |
---|
461 | // IE<8 prefers text node as line-break inside of <pre> (#4711). |
---|
462 | if ( startBlockTag == 'pre' && CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) |
---|
463 | lineBreak = doc.createText( '\r' ); |
---|
464 | else |
---|
465 | lineBreak = doc.createElement( 'br' ); |
---|
466 | |
---|
467 | range.deleteContents(); |
---|
468 | range.insertNode( lineBreak ); |
---|
469 | |
---|
470 | // Old IEs have different behavior regarding position. |
---|
471 | if ( !CKEDITOR.env.needsBrFiller ) |
---|
472 | range.setStartAt( lineBreak, CKEDITOR.POSITION_AFTER_END ); |
---|
473 | else { |
---|
474 | // A text node is required by Gecko only to make the cursor blink. |
---|
475 | // We need some text inside of it, so the bogus <br> is properly |
---|
476 | // created. |
---|
477 | doc.createText( '\ufeff' ).insertAfter( lineBreak ); |
---|
478 | |
---|
479 | // If we are at the end of a block, we must be sure the bogus node is available in that block. |
---|
480 | if ( isEndOfBlock ) { |
---|
481 | // In most situations we've got an elementPath.block (e.g. <p>), but in a |
---|
482 | // blockless editor or when autoP is false that needs to be a block limit. |
---|
483 | ( startBlock || elementPath.blockLimit ).appendBogus(); |
---|
484 | } |
---|
485 | |
---|
486 | // Now we can remove the text node contents, so the caret doesn't |
---|
487 | // stop on it. |
---|
488 | lineBreak.getNext().$.nodeValue = ''; |
---|
489 | |
---|
490 | range.setStartAt( lineBreak.getNext(), CKEDITOR.POSITION_AFTER_START ); |
---|
491 | |
---|
492 | } |
---|
493 | } |
---|
494 | |
---|
495 | // This collapse guarantees the cursor will be blinking. |
---|
496 | range.collapse( true ); |
---|
497 | |
---|
498 | range.select(); |
---|
499 | range.scrollIntoView(); |
---|
500 | } |
---|
501 | }; |
---|
502 | |
---|
503 | var plugin = CKEDITOR.plugins.enterkey, |
---|
504 | enterBr = plugin.enterBr, |
---|
505 | enterBlock = plugin.enterBlock, |
---|
506 | headerTagRegex = /^h[1-6]$/; |
---|
507 | |
---|
508 | function shiftEnter( editor ) { |
---|
509 | // On SHIFT+ENTER: |
---|
510 | // 1. We want to enforce the mode to be respected, instead |
---|
511 | // of cloning the current block. (#77) |
---|
512 | return enter( editor, editor.activeShiftEnterMode, 1 ); |
---|
513 | } |
---|
514 | |
---|
515 | function enter( editor, mode, forceMode ) { |
---|
516 | forceMode = editor.config.forceEnterMode || forceMode; |
---|
517 | |
---|
518 | // Only effective within document. |
---|
519 | if ( editor.mode != 'wysiwyg' ) |
---|
520 | return; |
---|
521 | |
---|
522 | if ( !mode ) |
---|
523 | mode = editor.activeEnterMode; |
---|
524 | |
---|
525 | // TODO this should be handled by setting editor.activeEnterMode on selection change. |
---|
526 | // Check path block specialities: |
---|
527 | // 1. Cannot be a un-splittable element, e.g. table caption; |
---|
528 | var path = editor.elementPath(); |
---|
529 | if ( !path.isContextFor( 'p' ) ) { |
---|
530 | mode = CKEDITOR.ENTER_BR; |
---|
531 | forceMode = 1; |
---|
532 | } |
---|
533 | |
---|
534 | editor.fire( 'saveSnapshot' ); // Save undo step. |
---|
535 | |
---|
536 | if ( mode == CKEDITOR.ENTER_BR ) |
---|
537 | enterBr( editor, mode, null, forceMode ); |
---|
538 | else |
---|
539 | enterBlock( editor, mode, null, forceMode ); |
---|
540 | |
---|
541 | editor.fire( 'saveSnapshot' ); |
---|
542 | } |
---|
543 | |
---|
544 | function getRange( editor ) { |
---|
545 | // Get the selection ranges. |
---|
546 | var ranges = editor.getSelection().getRanges( true ); |
---|
547 | |
---|
548 | // Delete the contents of all ranges except the first one. |
---|
549 | for ( var i = ranges.length - 1; i > 0; i-- ) { |
---|
550 | ranges[ i ].deleteContents(); |
---|
551 | } |
---|
552 | |
---|
553 | // Return the first range. |
---|
554 | return ranges[ 0 ]; |
---|
555 | } |
---|
556 | |
---|
557 | function replaceRangeWithClosestEditableRoot( range ) { |
---|
558 | var closestEditable = range.startContainer.getAscendant( function( node ) { |
---|
559 | return node.type == CKEDITOR.NODE_ELEMENT && node.getAttribute( 'contenteditable' ) == 'true'; |
---|
560 | }, true ); |
---|
561 | |
---|
562 | if ( range.root.equals( closestEditable ) ) { |
---|
563 | return range; |
---|
564 | } else { |
---|
565 | var newRange = new CKEDITOR.dom.range( closestEditable ); |
---|
566 | |
---|
567 | newRange.moveToRange( range ); |
---|
568 | return newRange; |
---|
569 | } |
---|
570 | } |
---|
571 | } )(); |
---|