1 | /* |
---|
2 | * FCKeditor - The text editor for Internet - http://www.fckeditor.net |
---|
3 | * Copyright (C) 2003-2007 Frederico Caldeira Knabben |
---|
4 | * |
---|
5 | * == BEGIN LICENSE == |
---|
6 | * |
---|
7 | * Licensed under the terms of any of the following licenses at your |
---|
8 | * choice: |
---|
9 | * |
---|
10 | * - GNU General Public License Version 2 or later (the "GPL") |
---|
11 | * http://www.gnu.org/licenses/gpl.html |
---|
12 | * |
---|
13 | * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") |
---|
14 | * http://www.gnu.org/licenses/lgpl.html |
---|
15 | * |
---|
16 | * - Mozilla Public License Version 1.1 or later (the "MPL") |
---|
17 | * http://www.mozilla.org/MPL/MPL-1.1.html |
---|
18 | * |
---|
19 | * == END LICENSE == |
---|
20 | * |
---|
21 | * Controls the [Enter] keystroke behavior in a document. |
---|
22 | */ |
---|
23 | |
---|
24 | /* |
---|
25 | * Constructor. |
---|
26 | * @targetDocument : the target document. |
---|
27 | * @enterMode : the behavior for the <Enter> keystroke. |
---|
28 | * May be "p", "div", "br". Default is "p". |
---|
29 | * @shiftEnterMode : the behavior for the <Shift>+<Enter> keystroke. |
---|
30 | * May be "p", "div", "br". Defaults to "br". |
---|
31 | */ |
---|
32 | var FCKEnterKey = function( targetWindow, enterMode, shiftEnterMode ) |
---|
33 | { |
---|
34 | this.Window = targetWindow ; |
---|
35 | this.EnterMode = enterMode || 'p' ; |
---|
36 | this.ShiftEnterMode = shiftEnterMode || 'br' ; |
---|
37 | |
---|
38 | // Setup the Keystroke Handler. |
---|
39 | var oKeystrokeHandler = new FCKKeystrokeHandler( false ) ; |
---|
40 | oKeystrokeHandler._EnterKey = this ; |
---|
41 | oKeystrokeHandler.OnKeystroke = FCKEnterKey_OnKeystroke ; |
---|
42 | |
---|
43 | oKeystrokeHandler.SetKeystrokes( [ |
---|
44 | [ 13 , 'Enter' ], |
---|
45 | [ SHIFT + 13, 'ShiftEnter' ], |
---|
46 | [ 8 , 'Backspace' ], |
---|
47 | [ 46 , 'Delete' ] |
---|
48 | ] ) ; |
---|
49 | |
---|
50 | oKeystrokeHandler.AttachToElement( targetWindow.document ) ; |
---|
51 | } |
---|
52 | |
---|
53 | |
---|
54 | function FCKEnterKey_OnKeystroke( keyCombination, keystrokeValue ) |
---|
55 | { |
---|
56 | var oEnterKey = this._EnterKey ; |
---|
57 | |
---|
58 | try |
---|
59 | { |
---|
60 | switch ( keystrokeValue ) |
---|
61 | { |
---|
62 | case 'Enter' : |
---|
63 | return oEnterKey.DoEnter() ; |
---|
64 | break ; |
---|
65 | |
---|
66 | case 'ShiftEnter' : |
---|
67 | return oEnterKey.DoShiftEnter() ; |
---|
68 | break ; |
---|
69 | |
---|
70 | case 'Backspace' : |
---|
71 | return oEnterKey.DoBackspace() ; |
---|
72 | break ; |
---|
73 | |
---|
74 | case 'Delete' : |
---|
75 | return oEnterKey.DoDelete() ; |
---|
76 | } |
---|
77 | } |
---|
78 | catch (e) |
---|
79 | { |
---|
80 | // If for any reason we are not able to handle it, go |
---|
81 | // ahead with the browser default behavior. |
---|
82 | } |
---|
83 | |
---|
84 | return false ; |
---|
85 | } |
---|
86 | |
---|
87 | /* |
---|
88 | * Executes the <Enter> key behavior. |
---|
89 | */ |
---|
90 | FCKEnterKey.prototype.DoEnter = function( mode, hasShift ) |
---|
91 | { |
---|
92 | this._HasShift = ( hasShift === true ) ; |
---|
93 | |
---|
94 | var sMode = mode || this.EnterMode ; |
---|
95 | |
---|
96 | if ( sMode == 'br' ) |
---|
97 | return this._ExecuteEnterBr() ; |
---|
98 | else |
---|
99 | return this._ExecuteEnterBlock( sMode ) ; |
---|
100 | } |
---|
101 | |
---|
102 | /* |
---|
103 | * Executes the <Shift>+<Enter> key behavior. |
---|
104 | */ |
---|
105 | FCKEnterKey.prototype.DoShiftEnter = function() |
---|
106 | { |
---|
107 | return this.DoEnter( this.ShiftEnterMode, true ) ; |
---|
108 | } |
---|
109 | |
---|
110 | /* |
---|
111 | * Executes the <Backspace> key behavior. |
---|
112 | */ |
---|
113 | FCKEnterKey.prototype.DoBackspace = function() |
---|
114 | { |
---|
115 | var bCustom = false ; |
---|
116 | |
---|
117 | // Get the current selection. |
---|
118 | var oRange = new FCKDomRange( this.Window ) ; |
---|
119 | oRange.MoveToSelection() ; |
---|
120 | |
---|
121 | if ( !oRange.CheckIsCollapsed() ) |
---|
122 | return false ; |
---|
123 | |
---|
124 | var oStartBlock = oRange.StartBlock ; |
---|
125 | var oEndBlock = oRange.EndBlock ; |
---|
126 | |
---|
127 | // The selection boundaries must be in the same "block limit" element |
---|
128 | if ( oRange.StartBlockLimit == oRange.EndBlockLimit && oStartBlock && oEndBlock ) |
---|
129 | { |
---|
130 | if ( !oRange.CheckIsCollapsed() ) |
---|
131 | { |
---|
132 | var bEndOfBlock = oRange.CheckEndOfBlock() ; |
---|
133 | |
---|
134 | oRange.DeleteContents() ; |
---|
135 | |
---|
136 | if ( oStartBlock != oEndBlock ) |
---|
137 | { |
---|
138 | oRange.SetStart(oEndBlock,1) ; |
---|
139 | oRange.SetEnd(oEndBlock,1) ; |
---|
140 | |
---|
141 | // if ( bEndOfBlock ) |
---|
142 | // oEndBlock.parentNode.removeChild( oEndBlock ) ; |
---|
143 | } |
---|
144 | |
---|
145 | oRange.Select() ; |
---|
146 | |
---|
147 | bCustom = ( oStartBlock == oEndBlock ) ; |
---|
148 | } |
---|
149 | |
---|
150 | if ( oRange.CheckStartOfBlock() ) |
---|
151 | { |
---|
152 | var oCurrentBlock = oRange.StartBlock ; |
---|
153 | |
---|
154 | var ePrevious = FCKDomTools.GetPreviousSourceElement( oCurrentBlock, true, [ 'BODY', oRange.StartBlockLimit.nodeName ], ['UL','OL'] ) ; |
---|
155 | |
---|
156 | bCustom = this._ExecuteBackspace( oRange, ePrevious, oCurrentBlock ) ; |
---|
157 | } |
---|
158 | else if ( FCKBrowserInfo.IsGecko ) |
---|
159 | { |
---|
160 | // Firefox looses the selection when executing CheckStartOfBlock, so we must reselect. |
---|
161 | oRange.Select() ; |
---|
162 | } |
---|
163 | } |
---|
164 | |
---|
165 | oRange.Release() ; |
---|
166 | return bCustom ; |
---|
167 | } |
---|
168 | |
---|
169 | FCKEnterKey.prototype._ExecuteBackspace = function( range, previous, currentBlock ) |
---|
170 | { |
---|
171 | var bCustom = false ; |
---|
172 | |
---|
173 | // We could be in a nested LI. |
---|
174 | if ( !previous && currentBlock.nodeName.IEquals( 'LI' ) && currentBlock.parentNode.parentNode.nodeName.IEquals( 'LI' ) ) |
---|
175 | { |
---|
176 | this._OutdentWithSelection( currentBlock, range ) ; |
---|
177 | return true ; |
---|
178 | } |
---|
179 | |
---|
180 | if ( previous && previous.nodeName.IEquals( 'LI' ) ) |
---|
181 | { |
---|
182 | var oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ; |
---|
183 | |
---|
184 | while ( oNestedList ) |
---|
185 | { |
---|
186 | previous = FCKDomTools.GetLastChild( oNestedList, 'LI' ) ; |
---|
187 | oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ; |
---|
188 | } |
---|
189 | } |
---|
190 | |
---|
191 | if ( previous && currentBlock ) |
---|
192 | { |
---|
193 | // If we are in a LI, and the previous block is not an LI, we must outdent it. |
---|
194 | if ( currentBlock.nodeName.IEquals( 'LI' ) && !previous.nodeName.IEquals( 'LI' ) ) |
---|
195 | { |
---|
196 | this._OutdentWithSelection( currentBlock, range ) ; |
---|
197 | return true ; |
---|
198 | } |
---|
199 | |
---|
200 | // Take a reference to the parent for post processing cleanup. |
---|
201 | var oCurrentParent = currentBlock.parentNode ; |
---|
202 | |
---|
203 | var sPreviousName = previous.nodeName.toLowerCase() ; |
---|
204 | if ( FCKListsLib.EmptyElements[ sPreviousName ] != null || sPreviousName == 'table' ) |
---|
205 | { |
---|
206 | FCKDomTools.RemoveNode( previous ) ; |
---|
207 | bCustom = true ; |
---|
208 | } |
---|
209 | else |
---|
210 | { |
---|
211 | // Remove the current block. |
---|
212 | FCKDomTools.RemoveNode( currentBlock ) ; |
---|
213 | |
---|
214 | // Remove any empty tag left by the block removal. |
---|
215 | while ( oCurrentParent.innerHTML.Trim().length == 0 ) |
---|
216 | { |
---|
217 | var oParent = oCurrentParent.parentNode ; |
---|
218 | oParent.removeChild( oCurrentParent ) ; |
---|
219 | oCurrentParent = oParent ; |
---|
220 | } |
---|
221 | |
---|
222 | // Cleanup the previous and the current elements. |
---|
223 | FCKDomTools.TrimNode( currentBlock ) ; |
---|
224 | FCKDomTools.TrimNode( previous ) ; |
---|
225 | |
---|
226 | // Append a space to the previous. |
---|
227 | // Maybe it is not always desirable... |
---|
228 | // previous.appendChild( this.Window.document.createTextNode( ' ' ) ) ; |
---|
229 | |
---|
230 | // Set the range to the end of the previous element and bookmark it. |
---|
231 | range.SetStart( previous, 2 ) ; |
---|
232 | range.Collapse( true ) ; |
---|
233 | var oBookmark = range.CreateBookmark() ; |
---|
234 | |
---|
235 | // Move the contents of the block to the previous element and delete it. |
---|
236 | FCKDomTools.MoveChildren( currentBlock, previous ) ; |
---|
237 | |
---|
238 | // Place the selection at the bookmark. |
---|
239 | range.MoveToBookmark( oBookmark ) ; |
---|
240 | range.Select() ; |
---|
241 | |
---|
242 | bCustom = true ; |
---|
243 | } |
---|
244 | } |
---|
245 | |
---|
246 | return bCustom ; |
---|
247 | } |
---|
248 | |
---|
249 | /* |
---|
250 | * Executes the <Delete> key behavior. |
---|
251 | */ |
---|
252 | FCKEnterKey.prototype.DoDelete = function() |
---|
253 | { |
---|
254 | // The <Delete> has the same effect as the <Backspace>, so we have the same |
---|
255 | // results if we just move to the next block and apply the same <Backspace> logic. |
---|
256 | |
---|
257 | var bCustom = false ; |
---|
258 | |
---|
259 | // Get the current selection. |
---|
260 | var oRange = new FCKDomRange( this.Window ) ; |
---|
261 | oRange.MoveToSelection() ; |
---|
262 | |
---|
263 | // There is just one special case for collapsed selections at the end of a block. |
---|
264 | if ( oRange.CheckIsCollapsed() && oRange.CheckEndOfBlock( FCKBrowserInfo.IsGecko ) ) |
---|
265 | { |
---|
266 | var oCurrentBlock = oRange.StartBlock ; |
---|
267 | |
---|
268 | var eNext = FCKDomTools.GetNextSourceElement( oCurrentBlock, true, [ oRange.StartBlockLimit.nodeName ], ['UL','OL'] ) ; |
---|
269 | |
---|
270 | bCustom = this._ExecuteBackspace( oRange, oCurrentBlock, eNext ) ; |
---|
271 | } |
---|
272 | |
---|
273 | oRange.Release() ; |
---|
274 | return bCustom ; |
---|
275 | } |
---|
276 | |
---|
277 | FCKEnterKey.prototype._ExecuteEnterBlock = function( blockTag, range ) |
---|
278 | { |
---|
279 | // Get the current selection. |
---|
280 | var oRange = range || new FCKDomRange( this.Window ) ; |
---|
281 | |
---|
282 | // If we don't have a range, move it to the selection. |
---|
283 | if ( !range ) |
---|
284 | oRange.MoveToSelection() ; |
---|
285 | |
---|
286 | // The selection boundaries must be in the same "block limit" element. |
---|
287 | if ( oRange.StartBlockLimit == oRange.EndBlockLimit ) |
---|
288 | { |
---|
289 | // If the StartBlock or EndBlock are not available (for text without a |
---|
290 | // block tag), we must fix them, by moving the text to a block. |
---|
291 | if ( !oRange.StartBlock ) |
---|
292 | this._FixBlock( oRange, true, blockTag ) ; |
---|
293 | |
---|
294 | if ( !oRange.EndBlock ) |
---|
295 | this._FixBlock( oRange, false, blockTag ) ; |
---|
296 | |
---|
297 | // Get the current blocks. |
---|
298 | var eStartBlock = oRange.StartBlock ; |
---|
299 | var eEndBlock = oRange.EndBlock ; |
---|
300 | |
---|
301 | // Delete the current selection. |
---|
302 | if ( !oRange.CheckIsEmpty() ) |
---|
303 | oRange.DeleteContents() ; |
---|
304 | |
---|
305 | // If the selection boundaries are in the same block element |
---|
306 | if ( eStartBlock == eEndBlock ) |
---|
307 | { |
---|
308 | var eNewBlock ; |
---|
309 | |
---|
310 | var bIsStartOfBlock = oRange.CheckStartOfBlock() ; |
---|
311 | var bIsEndOfBlock = oRange.CheckEndOfBlock() ; |
---|
312 | |
---|
313 | if ( bIsStartOfBlock && !bIsEndOfBlock ) |
---|
314 | { |
---|
315 | eNewBlock = eStartBlock.cloneNode(false) ; |
---|
316 | |
---|
317 | if ( FCKBrowserInfo.IsGeckoLike ) |
---|
318 | eNewBlock.innerHTML = GECKO_BOGUS ; |
---|
319 | |
---|
320 | // Place the new block before the current block element. |
---|
321 | eStartBlock.parentNode.insertBefore( eNewBlock, eStartBlock ) ; |
---|
322 | |
---|
323 | // This is tricky, but to make the new block visible correctly |
---|
324 | // we must select it. |
---|
325 | if ( FCKBrowserInfo.IsIE ) |
---|
326 | { |
---|
327 | // Move the selection to the new block. |
---|
328 | oRange.MoveToNodeContents( eNewBlock ) ; |
---|
329 | |
---|
330 | oRange.Select() ; |
---|
331 | } |
---|
332 | |
---|
333 | // Move the selection to the new block. |
---|
334 | oRange.MoveToElementEditStart( eStartBlock ) ; |
---|
335 | } |
---|
336 | else |
---|
337 | { |
---|
338 | // Check if the selection is at the end of the block. |
---|
339 | if ( bIsEndOfBlock ) |
---|
340 | { |
---|
341 | var sStartBlockTag = eStartBlock.tagName.toUpperCase() ; |
---|
342 | |
---|
343 | // If the entire block is selected, and we are in a LI, let's decrease its indentation. |
---|
344 | if ( bIsStartOfBlock && sStartBlockTag == 'LI' ) |
---|
345 | { |
---|
346 | this._OutdentWithSelection( eStartBlock, oRange ) ; |
---|
347 | oRange.Release() ; |
---|
348 | return true ; |
---|
349 | } |
---|
350 | else |
---|
351 | { |
---|
352 | // If is a header tag, or we are in a Shift+Enter (#77), |
---|
353 | // create a new block element. |
---|
354 | if ( (/^H[1-6]$/).test( sStartBlockTag ) || this._HasShift ) |
---|
355 | eNewBlock = this.Window.document.createElement( blockTag ) ; |
---|
356 | // Otherwise, duplicate the current block. |
---|
357 | else |
---|
358 | { |
---|
359 | eNewBlock = eStartBlock.cloneNode(false) ; |
---|
360 | this._RecreateEndingTree( eStartBlock, eNewBlock ) ; |
---|
361 | } |
---|
362 | |
---|
363 | if ( FCKBrowserInfo.IsGeckoLike ) |
---|
364 | { |
---|
365 | eNewBlock.innerHTML = GECKO_BOGUS ; |
---|
366 | |
---|
367 | // If the entire block is selected, let's add a bogus in the start block. |
---|
368 | if ( bIsStartOfBlock ) |
---|
369 | eStartBlock.innerHTML = GECKO_BOGUS ; |
---|
370 | } |
---|
371 | } |
---|
372 | } |
---|
373 | else |
---|
374 | { |
---|
375 | // Extract the contents of the block from the selection point to the end of its contents. |
---|
376 | oRange.SetEnd( eStartBlock, 2 ) ; |
---|
377 | var eDocFrag = oRange.ExtractContents() ; |
---|
378 | |
---|
379 | // Duplicate the block element after it. |
---|
380 | eNewBlock = eStartBlock.cloneNode(false) ; |
---|
381 | |
---|
382 | // It could be that we are in a LI with a child UL/OL. Insert a bogus to give us space to type. |
---|
383 | FCKDomTools.TrimNode( eDocFrag.RootNode ) ; |
---|
384 | if ( eDocFrag.RootNode.firstChild.nodeType == 1 && eDocFrag.RootNode.firstChild.tagName.toUpperCase().Equals( 'UL', 'OL' ) ) |
---|
385 | eNewBlock.innerHTML = GECKO_BOGUS ; |
---|
386 | |
---|
387 | // Place the extracted contents in the duplicated block. |
---|
388 | eDocFrag.AppendTo( eNewBlock ) ; |
---|
389 | |
---|
390 | if ( FCKBrowserInfo.IsGecko ) |
---|
391 | { |
---|
392 | // In Gecko, the last child node must be a bogus <br>. |
---|
393 | this._AppendBogusBr( eStartBlock ) ; |
---|
394 | this._AppendBogusBr( eNewBlock ) ; |
---|
395 | } |
---|
396 | } |
---|
397 | |
---|
398 | if ( eNewBlock ) |
---|
399 | { |
---|
400 | FCKDomTools.InsertAfterNode( eStartBlock, eNewBlock ) ; |
---|
401 | |
---|
402 | // Move the selection to the new block. |
---|
403 | oRange.MoveToElementEditStart( eNewBlock ) ; |
---|
404 | |
---|
405 | if ( FCKBrowserInfo.IsGecko ) |
---|
406 | eNewBlock.scrollIntoView( false ) ; |
---|
407 | } |
---|
408 | } |
---|
409 | } |
---|
410 | else |
---|
411 | { |
---|
412 | // Move the selection to the end block. |
---|
413 | oRange.MoveToElementEditStart( eEndBlock ) ; |
---|
414 | } |
---|
415 | |
---|
416 | oRange.Select() ; |
---|
417 | } |
---|
418 | |
---|
419 | // Release the resources used by the range. |
---|
420 | oRange.Release() ; |
---|
421 | |
---|
422 | return true ; |
---|
423 | } |
---|
424 | |
---|
425 | FCKEnterKey.prototype._ExecuteEnterBr = function( blockTag ) |
---|
426 | { |
---|
427 | // Get the current selection. |
---|
428 | var oRange = new FCKDomRange( this.Window ) ; |
---|
429 | oRange.MoveToSelection() ; |
---|
430 | |
---|
431 | // The selection boundaries must be in the same "block limit" element. |
---|
432 | if ( oRange.StartBlockLimit == oRange.EndBlockLimit ) |
---|
433 | { |
---|
434 | oRange.DeleteContents() ; |
---|
435 | |
---|
436 | // Get the new selection (it is collapsed at this point). |
---|
437 | oRange.MoveToSelection() ; |
---|
438 | |
---|
439 | var bIsStartOfBlock = oRange.CheckStartOfBlock() ; |
---|
440 | var bIsEndOfBlock = oRange.CheckEndOfBlock() ; |
---|
441 | |
---|
442 | var sStartBlockTag = oRange.StartBlock ? oRange.StartBlock.tagName.toUpperCase() : '' ; |
---|
443 | |
---|
444 | var bHasShift = this._HasShift ; |
---|
445 | |
---|
446 | if ( !bHasShift && sStartBlockTag == 'LI' ) |
---|
447 | return this._ExecuteEnterBlock( null, oRange ) ; |
---|
448 | |
---|
449 | // If we are at the end of a header block. |
---|
450 | if ( !bHasShift && bIsEndOfBlock && (/^H[1-6]$/).test( sStartBlockTag ) ) |
---|
451 | { |
---|
452 | FCKDebug.Output( 'BR - Header' ) ; |
---|
453 | |
---|
454 | // Insert a BR after the current paragraph. |
---|
455 | FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createElement( 'br' ) ) ; |
---|
456 | |
---|
457 | // The space is required by Gecko only to make the cursor blink. |
---|
458 | if ( FCKBrowserInfo.IsGecko ) |
---|
459 | FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createTextNode( '' ) ) ; |
---|
460 | |
---|
461 | // IE and Gecko have different behaviors regarding the position. |
---|
462 | oRange.SetStart( oRange.StartBlock.nextSibling, FCKBrowserInfo.IsIE ? 3 : 1 ) ; |
---|
463 | } |
---|
464 | else |
---|
465 | { |
---|
466 | FCKDebug.Output( 'BR - No Header' ) ; |
---|
467 | |
---|
468 | var eBr = this.Window.document.createElement( 'br' ) ; |
---|
469 | |
---|
470 | oRange.InsertNode( eBr ) ; |
---|
471 | |
---|
472 | // The space is required by Gecko only to make the cursor blink. |
---|
473 | if ( FCKBrowserInfo.IsGecko ) |
---|
474 | FCKDomTools.InsertAfterNode( eBr, this.Window.document.createTextNode( '' ) ) ; |
---|
475 | |
---|
476 | // If we are at the end of a block, we must be sure the bogus node is available in that block. |
---|
477 | if ( bIsEndOfBlock && FCKBrowserInfo.IsGecko ) |
---|
478 | this._AppendBogusBr( eBr.parentNode ) ; |
---|
479 | |
---|
480 | if ( FCKBrowserInfo.IsIE ) |
---|
481 | oRange.SetStart( eBr, 4 ) ; |
---|
482 | else |
---|
483 | oRange.SetStart( eBr.nextSibling, 1 ) ; |
---|
484 | |
---|
485 | } |
---|
486 | |
---|
487 | // This collapse guarantees the cursor will be blinking. |
---|
488 | oRange.Collapse( true ) ; |
---|
489 | |
---|
490 | oRange.Select() ; |
---|
491 | } |
---|
492 | |
---|
493 | // Release the resources used by the range. |
---|
494 | oRange.Release() ; |
---|
495 | |
---|
496 | return true ; |
---|
497 | } |
---|
498 | |
---|
499 | // Transform a block without a block tag in a valid block (orphan text in the body or td, usually). |
---|
500 | FCKEnterKey.prototype._FixBlock = function( range, isStart, blockTag ) |
---|
501 | { |
---|
502 | // Bookmark the range so we can restore it later. |
---|
503 | var oBookmark = range.CreateBookmark() ; |
---|
504 | |
---|
505 | // Collapse the range to the requested ending boundary. |
---|
506 | range.Collapse( isStart ) ; |
---|
507 | |
---|
508 | // Expands it to the block contents. |
---|
509 | range.Expand( 'block_contents' ) ; |
---|
510 | |
---|
511 | // Create the fixed block. |
---|
512 | var oFixedBlock = this.Window.document.createElement( blockTag ) ; |
---|
513 | |
---|
514 | // Move the contents of the temporary range to the fixed block. |
---|
515 | range.ExtractContents().AppendTo( oFixedBlock ) ; |
---|
516 | FCKDomTools.TrimNode( oFixedBlock ) ; |
---|
517 | |
---|
518 | // Insert the fixed block into the DOM. |
---|
519 | range.InsertNode( oFixedBlock ) ; |
---|
520 | |
---|
521 | // Move the range back to the bookmarked place. |
---|
522 | range.MoveToBookmark( oBookmark ) ; |
---|
523 | } |
---|
524 | |
---|
525 | // Appends a bogus <br> at the end of the element, if not yet available. |
---|
526 | FCKEnterKey.prototype._AppendBogusBr = function( element ) |
---|
527 | { |
---|
528 | var eLastChild = element.getElementsByTagName('br') ; |
---|
529 | |
---|
530 | if ( eLastChild ) |
---|
531 | eLastChild = eLastChild[ eLastChild.legth - 1 ] ; |
---|
532 | |
---|
533 | if ( !eLastChild || eLastChild.getAttribute( 'type', 2 ) != '_moz' ) |
---|
534 | element.appendChild( FCKTools.CreateBogusBR( this.Window.document ) ) ; |
---|
535 | } |
---|
536 | |
---|
537 | // Recreate the elements tree at the end of the source block, at the beginning |
---|
538 | // of the target block. Eg.: |
---|
539 | // If source = <p><u>Some</u> sample <b><i>text</i></b></p> then target = <p><b><i></i></b></p> |
---|
540 | // If source = <p><u>Some</u> sample text</p> then target = <p></p> |
---|
541 | FCKEnterKey.prototype._RecreateEndingTree = function( source, target ) |
---|
542 | { |
---|
543 | while ( ( source = source.lastChild ) && source.nodeType == 1 && FCKListsLib.InlineChildReqElements[ source.nodeName.toLowerCase() ] != null ) |
---|
544 | target = target.insertBefore( source.cloneNode( false ), target.firstChild ) ; |
---|
545 | } |
---|
546 | |
---|
547 | // Outdents a LI, maintaining the seletion defined on a range. |
---|
548 | FCKEnterKey.prototype._OutdentWithSelection = function( li, range ) |
---|
549 | { |
---|
550 | var oBookmark = range.CreateBookmark() ; |
---|
551 | |
---|
552 | FCKListHandler.OutdentListItem( li ) ; |
---|
553 | |
---|
554 | range.MoveToBookmark( oBookmark ) ; |
---|
555 | range.Select() ; |
---|
556 | } |
---|