~ubuntu-it-wiki/wiki-ubuntu-it/wiki-repo

« back to all changes in this revision

Viewing changes to applets/FCKeditor/editor/_source/classes/fckenterkey.js

  • Committer: Leo Iannacone
  • Date: 2011-06-02 15:05:37 UTC
  • Revision ID: l3on@ubuntu.com-20110602150537-ycrnf58qf67uf593
Added applets for gui editor

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
 
3
 * Copyright (C) 2003-2010 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, tabSpaces )
 
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
                [ CTRL + 8      , 'CtrlBackspace' ],
 
48
                [ 46            , 'Delete' ]
 
49
        ] ) ;
 
50
 
 
51
        this.TabText = '' ;
 
52
 
 
53
        // Safari by default inserts 4 spaces on TAB, while others make the editor
 
54
        // loose focus. So, we need to handle it here to not include those spaces.
 
55
        if ( tabSpaces > 0 || FCKBrowserInfo.IsSafari )
 
56
        {
 
57
                while ( tabSpaces-- )
 
58
                        this.TabText += '\xa0' ;
 
59
 
 
60
                oKeystrokeHandler.SetKeystrokes( [ 9, 'Tab' ] );
 
61
        }
 
62
 
 
63
        oKeystrokeHandler.AttachToElement( targetWindow.document ) ;
 
64
}
 
65
 
 
66
 
 
67
function FCKEnterKey_OnKeystroke(  keyCombination, keystrokeValue )
 
68
{
 
69
        var oEnterKey = this._EnterKey ;
 
70
 
 
71
        try
 
72
        {
 
73
                switch ( keystrokeValue )
 
74
                {
 
75
                        case 'Enter' :
 
76
                                return oEnterKey.DoEnter() ;
 
77
                                break ;
 
78
                        case 'ShiftEnter' :
 
79
                                return oEnterKey.DoShiftEnter() ;
 
80
                                break ;
 
81
                        case 'Backspace' :
 
82
                                return oEnterKey.DoBackspace() ;
 
83
                                break ;
 
84
                        case 'Delete' :
 
85
                                return oEnterKey.DoDelete() ;
 
86
                                break ;
 
87
                        case 'Tab' :
 
88
                                return oEnterKey.DoTab() ;
 
89
                                break ;
 
90
                        case 'CtrlBackspace' :
 
91
                                return oEnterKey.DoCtrlBackspace() ;
 
92
                                break ;
 
93
                }
 
94
        }
 
95
        catch (e)
 
96
        {
 
97
                // If for any reason we are not able to handle it, go
 
98
                // ahead with the browser default behavior.
 
99
        }
 
100
 
 
101
        return false ;
 
102
}
 
103
 
 
104
/*
 
105
 * Executes the <Enter> key behavior.
 
106
 */
 
107
FCKEnterKey.prototype.DoEnter = function( mode, hasShift )
 
108
{
 
109
        // Save an undo snapshot before doing anything
 
110
        FCKUndo.SaveUndoStep() ;
 
111
 
 
112
        this._HasShift = ( hasShift === true ) ;
 
113
 
 
114
        var parentElement = FCKSelection.GetParentElement() ;
 
115
        var parentPath = new FCKElementPath( parentElement ) ;
 
116
        var sMode = mode || this.EnterMode ;
 
117
 
 
118
        if ( sMode == 'br' || parentPath.Block && parentPath.Block.tagName.toLowerCase() == 'pre' )
 
119
                return this._ExecuteEnterBr() ;
 
120
        else
 
121
                return this._ExecuteEnterBlock( sMode ) ;
 
122
}
 
123
 
 
124
/*
 
125
 * Executes the <Shift>+<Enter> key behavior.
 
126
 */
 
127
FCKEnterKey.prototype.DoShiftEnter = function()
 
128
{
 
129
        return this.DoEnter( this.ShiftEnterMode, true ) ;
 
130
}
 
131
 
 
132
/*
 
133
 * Executes the <Backspace> key behavior.
 
134
 */
 
135
FCKEnterKey.prototype.DoBackspace = function()
 
136
{
 
137
        var bCustom = false ;
 
138
 
 
139
        // Get the current selection.
 
140
        var oRange = new FCKDomRange( this.Window ) ;
 
141
        oRange.MoveToSelection() ;
 
142
 
 
143
        // Kludge for #247
 
144
        if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
 
145
        {
 
146
                this._FixIESelectAllBug( oRange ) ;
 
147
                return true ;
 
148
        }
 
149
 
 
150
        var isCollapsed = oRange.CheckIsCollapsed() ;
 
151
 
 
152
        if ( !isCollapsed )
 
153
        {
 
154
                // Bug #327, Backspace with an img selection would activate the default action in IE.
 
155
                // Let's override that with our logic here.
 
156
                if ( FCKBrowserInfo.IsIE && this.Window.document.selection.type.toLowerCase() == "control" )
 
157
                {
 
158
                        var controls = this.Window.document.selection.createRange() ;
 
159
                        for ( var i = controls.length - 1 ; i >= 0 ; i-- )
 
160
                        {
 
161
                                var el = controls.item( i ) ;
 
162
                                el.parentNode.removeChild( el ) ;
 
163
                        }
 
164
                        return true ;
 
165
                }
 
166
 
 
167
                return false ;
 
168
        }
 
169
 
 
170
        // On IE, it is better for us handle the deletion if the caret is preceeded
 
171
        // by a <br> (#1383).
 
172
        if ( FCKBrowserInfo.IsIE )
 
173
        {
 
174
                var previousElement = FCKDomTools.GetPreviousSourceElement( oRange.StartNode, true ) ;
 
175
 
 
176
                if ( previousElement && previousElement.nodeName.toLowerCase() == 'br' )
 
177
                {
 
178
                        // Create a range that starts after the <br> and ends at the
 
179
                        // current range position.
 
180
                        var testRange = oRange.Clone() ;
 
181
                        testRange.SetStart( previousElement, 4 ) ;
 
182
 
 
183
                        // If that range is empty, we can proceed cleaning that <br> manually.
 
184
                        if ( testRange.CheckIsEmpty() )
 
185
                        {
 
186
                                previousElement.parentNode.removeChild( previousElement ) ;
 
187
                                return true ;
 
188
                        }
 
189
                }
 
190
        }
 
191
 
 
192
        var oStartBlock = oRange.StartBlock ;
 
193
        var oEndBlock = oRange.EndBlock ;
 
194
 
 
195
        // The selection boundaries must be in the same "block limit" element
 
196
        if ( oRange.StartBlockLimit == oRange.EndBlockLimit && oStartBlock && oEndBlock )
 
197
        {
 
198
                if ( !isCollapsed )
 
199
                {
 
200
                        var bEndOfBlock = oRange.CheckEndOfBlock() ;
 
201
 
 
202
                        oRange.DeleteContents() ;
 
203
 
 
204
                        if ( oStartBlock != oEndBlock )
 
205
                        {
 
206
                                oRange.SetStart(oEndBlock,1) ;
 
207
                                oRange.SetEnd(oEndBlock,1) ;
 
208
 
 
209
//                              if ( bEndOfBlock )
 
210
//                                      oEndBlock.parentNode.removeChild( oEndBlock ) ;
 
211
                        }
 
212
 
 
213
                        oRange.Select() ;
 
214
 
 
215
                        bCustom = ( oStartBlock == oEndBlock ) ;
 
216
                }
 
217
 
 
218
                if ( oRange.CheckStartOfBlock() )
 
219
                {
 
220
                        var oCurrentBlock = oRange.StartBlock ;
 
221
 
 
222
                        var ePrevious = FCKDomTools.GetPreviousSourceElement( oCurrentBlock, true, [ 'BODY', oRange.StartBlockLimit.nodeName ], ['UL','OL'] ) ;
 
223
 
 
224
                        bCustom = this._ExecuteBackspace( oRange, ePrevious, oCurrentBlock ) ;
 
225
                }
 
226
                else if ( FCKBrowserInfo.IsGeckoLike )
 
227
                {
 
228
                        // Firefox and Opera (#1095) loose the selection when executing
 
229
                        // CheckStartOfBlock, so we must reselect.
 
230
                        oRange.Select() ;
 
231
                }
 
232
        }
 
233
 
 
234
        oRange.Release() ;
 
235
        return bCustom ;
 
236
}
 
237
 
 
238
FCKEnterKey.prototype.DoCtrlBackspace = function()
 
239
{
 
240
        FCKUndo.SaveUndoStep() ;
 
241
        var oRange = new FCKDomRange( this.Window ) ;
 
242
        oRange.MoveToSelection() ;
 
243
        if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
 
244
        {
 
245
                this._FixIESelectAllBug( oRange ) ;
 
246
                return true ;
 
247
        }
 
248
        return false ;
 
249
}
 
250
 
 
251
FCKEnterKey.prototype._ExecuteBackspace = function( range, previous, currentBlock )
 
252
{
 
253
        var bCustom = false ;
 
254
 
 
255
        // We could be in a nested LI.
 
256
        if ( !previous && currentBlock && currentBlock.nodeName.IEquals( 'LI' ) && currentBlock.parentNode.parentNode.nodeName.IEquals( 'LI' ) )
 
257
        {
 
258
                this._OutdentWithSelection( currentBlock, range ) ;
 
259
                return true ;
 
260
        }
 
261
 
 
262
        if ( previous && previous.nodeName.IEquals( 'LI' ) )
 
263
        {
 
264
                var oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ;
 
265
 
 
266
                while ( oNestedList )
 
267
                {
 
268
                        previous = FCKDomTools.GetLastChild( oNestedList, 'LI' ) ;
 
269
                        oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ;
 
270
                }
 
271
        }
 
272
 
 
273
        if ( previous && currentBlock )
 
274
        {
 
275
                // If we are in a LI, and the previous block is not an LI, we must outdent it.
 
276
                if ( currentBlock.nodeName.IEquals( 'LI' ) && !previous.nodeName.IEquals( 'LI' ) )
 
277
                {
 
278
                        this._OutdentWithSelection( currentBlock, range ) ;
 
279
                        return true ;
 
280
                }
 
281
 
 
282
                // Take a reference to the parent for post processing cleanup.
 
283
                var oCurrentParent = currentBlock.parentNode ;
 
284
 
 
285
                var sPreviousName = previous.nodeName.toLowerCase() ;
 
286
                if ( FCKListsLib.EmptyElements[ sPreviousName ] != null || sPreviousName == 'table' )
 
287
                {
 
288
                        FCKDomTools.RemoveNode( previous ) ;
 
289
                        bCustom = true ;
 
290
                }
 
291
                else
 
292
                {
 
293
                        // Remove the current block.
 
294
                        FCKDomTools.RemoveNode( currentBlock ) ;
 
295
 
 
296
                        // Remove any empty tag left by the block removal.
 
297
                        while ( oCurrentParent.innerHTML.Trim().length == 0 )
 
298
                        {
 
299
                                var oParent = oCurrentParent.parentNode ;
 
300
                                oParent.removeChild( oCurrentParent ) ;
 
301
                                oCurrentParent = oParent ;
 
302
                        }
 
303
 
 
304
                        // Cleanup the previous and the current elements.
 
305
                        FCKDomTools.LTrimNode( currentBlock ) ;
 
306
                        FCKDomTools.RTrimNode( previous ) ;
 
307
 
 
308
                        // Append a space to the previous.
 
309
                        // Maybe it is not always desirable...
 
310
                        // previous.appendChild( this.Window.document.createTextNode( ' ' ) ) ;
 
311
 
 
312
                        // Set the range to the end of the previous element and bookmark it.
 
313
                        range.SetStart( previous, 2, true ) ;
 
314
                        range.Collapse( true ) ;
 
315
                        var oBookmark = range.CreateBookmark( true ) ;
 
316
 
 
317
                        // Move the contents of the block to the previous element and delete it.
 
318
                        // But for some block types (e.g. table), moving the children to the previous block makes no sense.
 
319
                        // So a check is needed. (See #1081)
 
320
                        if ( ! currentBlock.tagName.IEquals( [ 'TABLE' ] ) )
 
321
                                FCKDomTools.MoveChildren( currentBlock, previous ) ;
 
322
 
 
323
                        // Place the selection at the bookmark.
 
324
                        range.SelectBookmark( oBookmark ) ;
 
325
 
 
326
                        bCustom = true ;
 
327
                }
 
328
        }
 
329
 
 
330
        return bCustom ;
 
331
}
 
332
 
 
333
/*
 
334
 * Executes the <Delete> key behavior.
 
335
 */
 
336
FCKEnterKey.prototype.DoDelete = function()
 
337
{
 
338
        // Save an undo snapshot before doing anything
 
339
        // This is to conform with the behavior seen in MS Word
 
340
        FCKUndo.SaveUndoStep() ;
 
341
 
 
342
        // The <Delete> has the same effect as the <Backspace>, so we have the same
 
343
        // results if we just move to the next block and apply the same <Backspace> logic.
 
344
 
 
345
        var bCustom = false ;
 
346
 
 
347
        // Get the current selection.
 
348
        var oRange = new FCKDomRange( this.Window ) ;
 
349
        oRange.MoveToSelection() ;
 
350
 
 
351
        // Kludge for #247
 
352
        if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
 
353
        {
 
354
                this._FixIESelectAllBug( oRange ) ;
 
355
                return true ;
 
356
        }
 
357
 
 
358
        // There is just one special case for collapsed selections at the end of a block.
 
359
        if ( oRange.CheckIsCollapsed() && oRange.CheckEndOfBlock( FCKBrowserInfo.IsGeckoLike ) )
 
360
        {
 
361
                var oCurrentBlock = oRange.StartBlock ;
 
362
                var eCurrentCell = FCKTools.GetElementAscensor( oCurrentBlock, 'td' );
 
363
 
 
364
                var eNext = FCKDomTools.GetNextSourceElement( oCurrentBlock, true, [ oRange.StartBlockLimit.nodeName ],
 
365
                                ['UL','OL','TR'], true ) ;
 
366
 
 
367
                // Bug #1323 : if we're in a table cell, and the next node belongs to a different cell, then don't
 
368
                // delete anything.
 
369
                if ( eCurrentCell )
 
370
                {
 
371
                        var eNextCell = FCKTools.GetElementAscensor( eNext, 'td' );
 
372
                        if ( eNextCell != eCurrentCell )
 
373
                                return true ;
 
374
                }
 
375
 
 
376
                bCustom = this._ExecuteBackspace( oRange, oCurrentBlock, eNext ) ;
 
377
        }
 
378
 
 
379
        oRange.Release() ;
 
380
        return bCustom ;
 
381
}
 
382
 
 
383
/*
 
384
 * Executes the <Tab> key behavior.
 
385
 */
 
386
FCKEnterKey.prototype.DoTab = function()
 
387
{
 
388
        var oRange = new FCKDomRange( this.Window );
 
389
        oRange.MoveToSelection() ;
 
390
 
 
391
        // If the user pressed <tab> inside a table, we should give him the default behavior ( moving between cells )
 
392
        // instead of giving him more non-breaking spaces. (Bug #973)
 
393
        var node = oRange._Range.startContainer ;
 
394
        while ( node )
 
395
        {
 
396
                if ( node.nodeType == 1 )
 
397
                {
 
398
                        var tagName = node.tagName.toLowerCase() ;
 
399
                        if ( tagName == "tr" || tagName == "td" || tagName == "th" || tagName == "tbody" || tagName == "table" )
 
400
                                return false ;
 
401
                        else
 
402
                                break ;
 
403
                }
 
404
                node = node.parentNode ;
 
405
        }
 
406
 
 
407
        if ( this.TabText )
 
408
        {
 
409
                oRange.DeleteContents() ;
 
410
                oRange.InsertNode( this.Window.document.createTextNode( this.TabText ) ) ;
 
411
                oRange.Collapse( false ) ;
 
412
                oRange.Select() ;
 
413
        }
 
414
        return true ;
 
415
}
 
416
 
 
417
FCKEnterKey.prototype._ExecuteEnterBlock = function( blockTag, range )
 
418
{
 
419
        // Get the current selection.
 
420
        var oRange = range || new FCKDomRange( this.Window ) ;
 
421
 
 
422
        var oSplitInfo = oRange.SplitBlock( blockTag ) ;
 
423
 
 
424
        if ( oSplitInfo )
 
425
        {
 
426
                // Get the current blocks.
 
427
                var ePreviousBlock      = oSplitInfo.PreviousBlock ;
 
428
                var eNextBlock          = oSplitInfo.NextBlock ;
 
429
 
 
430
                var bIsStartOfBlock     = oSplitInfo.WasStartOfBlock ;
 
431
                var bIsEndOfBlock       = oSplitInfo.WasEndOfBlock ;
 
432
 
 
433
                // If there is one block under a list item, modify the split so that the list item gets split as well. (Bug #1647)
 
434
                if ( eNextBlock )
 
435
                {
 
436
                        if ( eNextBlock.parentNode.nodeName.IEquals( 'li' ) )
 
437
                        {
 
438
                                FCKDomTools.BreakParent( eNextBlock, eNextBlock.parentNode ) ;
 
439
                                FCKDomTools.MoveNode( eNextBlock, eNextBlock.nextSibling, true ) ;
 
440
                        }
 
441
                }
 
442
                else if ( ePreviousBlock && ePreviousBlock.parentNode.nodeName.IEquals( 'li' ) )
 
443
                {
 
444
                        FCKDomTools.BreakParent( ePreviousBlock, ePreviousBlock.parentNode ) ;
 
445
                        oRange.MoveToElementEditStart( ePreviousBlock.nextSibling );
 
446
                        FCKDomTools.MoveNode( ePreviousBlock, ePreviousBlock.previousSibling ) ;
 
447
                }
 
448
 
 
449
                // If we have both the previous and next blocks, it means that the
 
450
                // boundaries were on separated blocks, or none of them where on the
 
451
                // block limits (start/end).
 
452
                if ( !bIsStartOfBlock && !bIsEndOfBlock )
 
453
                {
 
454
                        // If the next block is an <li> with another list tree as the first child
 
455
                        // We'll need to append a placeholder or the list item wouldn't be editable. (Bug #1420)
 
456
                        if ( eNextBlock.nodeName.IEquals( 'li' ) && eNextBlock.firstChild
 
457
                                        && eNextBlock.firstChild.nodeName.IEquals( ['ul', 'ol'] ) )
 
458
                                eNextBlock.insertBefore( FCKTools.GetElementDocument( eNextBlock ).createTextNode( '\xa0' ), eNextBlock.firstChild ) ;
 
459
                        // Move the selection to the end block.
 
460
                        if ( eNextBlock )
 
461
                                oRange.MoveToElementEditStart( eNextBlock ) ;
 
462
                }
 
463
                else
 
464
                {
 
465
                        if ( bIsStartOfBlock && bIsEndOfBlock && ePreviousBlock.tagName.toUpperCase() == 'LI' )
 
466
                        {
 
467
                                oRange.MoveToElementStart( ePreviousBlock ) ;
 
468
                                this._OutdentWithSelection( ePreviousBlock, oRange ) ;
 
469
                                oRange.Release() ;
 
470
                                return true ;
 
471
                        }
 
472
 
 
473
                        var eNewBlock ;
 
474
 
 
475
                        if ( ePreviousBlock )
 
476
                        {
 
477
                                var sPreviousBlockTag = ePreviousBlock.tagName.toUpperCase() ;
 
478
 
 
479
                                // If is a header tag, or we are in a Shift+Enter (#77),
 
480
                                // create a new block element (later in the code).
 
481
                                if ( !this._HasShift && !(/^H[1-6]$/).test( sPreviousBlockTag ) )
 
482
                                {
 
483
                                        // Otherwise, duplicate the previous block.
 
484
                                        eNewBlock = FCKDomTools.CloneElement( ePreviousBlock ) ;
 
485
                                }
 
486
                        }
 
487
                        else if ( eNextBlock )
 
488
                                eNewBlock = FCKDomTools.CloneElement( eNextBlock ) ;
 
489
 
 
490
                        if ( !eNewBlock )
 
491
                                eNewBlock = this.Window.document.createElement( blockTag ) ;
 
492
 
 
493
                        // Recreate the inline elements tree, which was available
 
494
                        // before the hitting enter, so the same styles will be
 
495
                        // available in the new block.
 
496
                        var elementPath = oSplitInfo.ElementPath ;
 
497
                        if ( elementPath )
 
498
                        {
 
499
                                for ( var i = 0, len = elementPath.Elements.length ; i < len ; i++ )
 
500
                                {
 
501
                                        var element = elementPath.Elements[i] ;
 
502
 
 
503
                                        if ( element == elementPath.Block || element == elementPath.BlockLimit )
 
504
                                                break ;
 
505
 
 
506
                                        if ( FCKListsLib.InlineChildReqElements[ element.nodeName.toLowerCase() ] )
 
507
                                        {
 
508
                                                element = FCKDomTools.CloneElement( element ) ;
 
509
                                                FCKDomTools.MoveChildren( eNewBlock, element ) ;
 
510
                                                eNewBlock.appendChild( element ) ;
 
511
                                        }
 
512
                                }
 
513
                        }
 
514
 
 
515
                        if ( FCKBrowserInfo.IsGeckoLike )
 
516
                                FCKTools.AppendBogusBr( eNewBlock ) ;
 
517
 
 
518
                        oRange.InsertNode( eNewBlock ) ;
 
519
 
 
520
                        // This is tricky, but to make the new block visible correctly
 
521
                        // we must select it.
 
522
                        if ( FCKBrowserInfo.IsIE )
 
523
                        {
 
524
                                // Move the selection to the new block.
 
525
                                oRange.MoveToElementEditStart( eNewBlock ) ;
 
526
                                oRange.Select() ;
 
527
                        }
 
528
 
 
529
                        // Move the selection to the new block.
 
530
                        oRange.MoveToElementEditStart( bIsStartOfBlock && !bIsEndOfBlock ? eNextBlock : eNewBlock ) ;
 
531
                }
 
532
 
 
533
                if ( FCKBrowserInfo.IsGeckoLike )
 
534
                {
 
535
                        if ( eNextBlock )
 
536
                        {
 
537
                                // If we have split the block, adds a temporary span at the
 
538
                                // range position and scroll relatively to it.
 
539
                                var tmpNode = this.Window.document.createElement( 'span' ) ;
 
540
 
 
541
                                // We need some content for Safari.
 
542
                                tmpNode.innerHTML = '&nbsp;';
 
543
 
 
544
                                oRange.InsertNode( tmpNode ) ;
 
545
                                FCKDomTools.ScrollIntoView( tmpNode, false ) ;
 
546
                                oRange.DeleteContents() ;
 
547
                        }
 
548
                        else
 
549
                        {
 
550
                                // We may use the above scroll logic for the new block case
 
551
                                // too, but it gives some weird result with Opera.
 
552
                                FCKDomTools.ScrollIntoView( eNextBlock || eNewBlock, false ) ;
 
553
                        }
 
554
                }
 
555
 
 
556
                oRange.Select() ;
 
557
        }
 
558
 
 
559
        // Release the resources used by the range.
 
560
        oRange.Release() ;
 
561
 
 
562
        return true ;
 
563
}
 
564
 
 
565
FCKEnterKey.prototype._ExecuteEnterBr = function( blockTag )
 
566
{
 
567
        // Get the current selection.
 
568
        var oRange = new FCKDomRange( this.Window ) ;
 
569
        oRange.MoveToSelection() ;
 
570
 
 
571
        // The selection boundaries must be in the same "block limit" element.
 
572
        if ( oRange.StartBlockLimit == oRange.EndBlockLimit )
 
573
        {
 
574
                oRange.DeleteContents() ;
 
575
 
 
576
                // Get the new selection (it is collapsed at this point).
 
577
                oRange.MoveToSelection() ;
 
578
 
 
579
                var bIsStartOfBlock     = oRange.CheckStartOfBlock() ;
 
580
                var bIsEndOfBlock       = oRange.CheckEndOfBlock() ;
 
581
 
 
582
                var sStartBlockTag = oRange.StartBlock ? oRange.StartBlock.tagName.toUpperCase() : '' ;
 
583
 
 
584
                var bHasShift = this._HasShift ;
 
585
                var bIsPre = false ;
 
586
 
 
587
                if ( !bHasShift && sStartBlockTag == 'LI' )
 
588
                        return this._ExecuteEnterBlock( null, oRange ) ;
 
589
 
 
590
                // If we are at the end of a header block.
 
591
                if ( !bHasShift && bIsEndOfBlock && (/^H[1-6]$/).test( sStartBlockTag ) )
 
592
                {
 
593
                        // Insert a BR after the current paragraph.
 
594
                        FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createElement( 'br' ) ) ;
 
595
 
 
596
                        // The space is required by Gecko only to make the cursor blink.
 
597
                        if ( FCKBrowserInfo.IsGecko )
 
598
                                FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createTextNode( '' ) ) ;
 
599
 
 
600
                        // IE and Gecko have different behaviors regarding the position.
 
601
                        oRange.SetStart( oRange.StartBlock.nextSibling, FCKBrowserInfo.IsIE ? 3 : 1 ) ;
 
602
                }
 
603
                else
 
604
                {
 
605
                        var eLineBreak ;
 
606
                        bIsPre = sStartBlockTag.IEquals( 'pre' ) ;
 
607
                        if ( bIsPre )
 
608
                                eLineBreak = this.Window.document.createTextNode( FCKBrowserInfo.IsIE ? '\r' : '\n' ) ;
 
609
                        else
 
610
                                eLineBreak = this.Window.document.createElement( 'br' ) ;
 
611
 
 
612
                        oRange.InsertNode( eLineBreak ) ;
 
613
 
 
614
                        // The space is required by Gecko only to make the cursor blink.
 
615
                        if ( FCKBrowserInfo.IsGecko )
 
616
                                FCKDomTools.InsertAfterNode( eLineBreak, this.Window.document.createTextNode( '' ) ) ;
 
617
 
 
618
                        // If we are at the end of a block, we must be sure the bogus node is available in that block.
 
619
                        if ( bIsEndOfBlock && FCKBrowserInfo.IsGeckoLike )
 
620
                                FCKTools.AppendBogusBr( eLineBreak.parentNode ) ;
 
621
 
 
622
                        if ( FCKBrowserInfo.IsIE )
 
623
                                oRange.SetStart( eLineBreak, 4 ) ;
 
624
                        else
 
625
                                oRange.SetStart( eLineBreak.nextSibling, 1 ) ;
 
626
 
 
627
                        if ( ! FCKBrowserInfo.IsIE )
 
628
                        {
 
629
                                var dummy = null ;
 
630
                                if ( FCKBrowserInfo.IsOpera )
 
631
                                        dummy = this.Window.document.createElement( 'span' ) ;
 
632
                                else
 
633
                                        dummy = this.Window.document.createElement( 'br' ) ;
 
634
 
 
635
                                eLineBreak.parentNode.insertBefore( dummy, eLineBreak.nextSibling ) ;
 
636
 
 
637
                                FCKDomTools.ScrollIntoView( dummy, false ) ;
 
638
 
 
639
                                dummy.parentNode.removeChild( dummy ) ;
 
640
                        }
 
641
                }
 
642
 
 
643
                // This collapse guarantees the cursor will be blinking.
 
644
                oRange.Collapse( true ) ;
 
645
 
 
646
                oRange.Select( bIsPre ) ;
 
647
        }
 
648
 
 
649
        // Release the resources used by the range.
 
650
        oRange.Release() ;
 
651
 
 
652
        return true ;
 
653
}
 
654
 
 
655
// Outdents a LI, maintaining the selection defined on a range.
 
656
FCKEnterKey.prototype._OutdentWithSelection = function( li, range )
 
657
{
 
658
        var oBookmark = range.CreateBookmark() ;
 
659
 
 
660
        FCKListHandler.OutdentListItem( li ) ;
 
661
 
 
662
        range.MoveToBookmark( oBookmark ) ;
 
663
        range.Select() ;
 
664
}
 
665
 
 
666
// Is all the contents under a node included by a range?
 
667
FCKEnterKey.prototype._CheckIsAllContentsIncluded = function( range, node )
 
668
{
 
669
        var startOk = false ;
 
670
        var endOk = false ;
 
671
 
 
672
        /*
 
673
        FCKDebug.Output( 'sc='+range.StartContainer.nodeName+
 
674
                        ',so='+range._Range.startOffset+
 
675
                        ',ec='+range.EndContainer.nodeName+
 
676
                        ',eo='+range._Range.endOffset ) ;
 
677
        */
 
678
        if ( range.StartContainer == node || range.StartContainer == node.firstChild )
 
679
                startOk = ( range._Range.startOffset == 0 ) ;
 
680
 
 
681
        if ( range.EndContainer == node || range.EndContainer == node.lastChild )
 
682
        {
 
683
                var nodeLength = range.EndContainer.nodeType == 3 ? range.EndContainer.length : range.EndContainer.childNodes.length ;
 
684
                endOk = ( range._Range.endOffset == nodeLength ) ;
 
685
        }
 
686
 
 
687
        return startOk && endOk ;
 
688
}
 
689
 
 
690
// Kludge for #247
 
691
FCKEnterKey.prototype._FixIESelectAllBug = function( range )
 
692
{
 
693
        var doc = this.Window.document ;
 
694
        doc.body.innerHTML = '' ;
 
695
        var editBlock ;
 
696
        if ( FCKConfig.EnterMode.IEquals( ['div', 'p'] ) )
 
697
        {
 
698
                editBlock = doc.createElement( FCKConfig.EnterMode ) ;
 
699
                doc.body.appendChild( editBlock ) ;
 
700
        }
 
701
        else
 
702
                editBlock = doc.body ;
 
703
 
 
704
        range.MoveToNodeContents( editBlock ) ;
 
705
        range.Collapse( true ) ;
 
706
        range.Select() ;
 
707
        range.Release() ;
 
708
}