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