2
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
3
* Copyright (C) 2003-2008 Frederico Caldeira Knabben
7
* Licensed under the terms of any of the following licenses at your
10
* - GNU General Public License Version 2 or later (the "GPL")
11
* http://www.gnu.org/licenses/gpl.html
13
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
14
* http://www.gnu.org/licenses/lgpl.html
16
* - Mozilla Public License Version 1.1 or later (the "MPL")
17
* http://www.mozilla.org/MPL/MPL-1.1.html
21
* FCKBlockQuoteCommand Class: adds or removes blockquote tags.
24
var FCKBlockQuoteCommand = function()
28
FCKBlockQuoteCommand.prototype =
32
FCKUndo.SaveUndoStep() ;
34
var state = this.GetState() ;
36
var range = new FCKDomRange( FCK.EditorWindow ) ;
37
range.MoveToSelection() ;
39
var bookmark = range.CreateBookmark() ;
41
// Kludge for #1592: if the bookmark nodes are in the beginning of
42
// blockquote, then move them to the nearest block element in the
44
if ( FCKBrowserInfo.IsIE )
46
var bStart = range.GetBookmarkNode( bookmark, true ) ;
47
var bEnd = range.GetBookmarkNode( bookmark, false ) ;
52
&& bStart.parentNode.nodeName.IEquals( 'blockquote' )
53
&& !bStart.previousSibling )
56
while ( ( cursor = cursor.nextSibling ) )
58
if ( FCKListsLib.BlockElements[ cursor.nodeName.toLowerCase() ] )
59
FCKDomTools.MoveNode( bStart, cursor, true ) ;
64
&& bEnd.parentNode.nodeName.IEquals( 'blockquote' )
65
&& !bEnd.previousSibling )
68
while ( ( cursor = cursor.nextSibling ) )
70
if ( FCKListsLib.BlockElements[ cursor.nodeName.toLowerCase() ] )
72
if ( cursor.firstChild == bStart )
73
FCKDomTools.InsertAfterNode( bStart, bEnd ) ;
75
FCKDomTools.MoveNode( bEnd, cursor, true ) ;
81
var iterator = new FCKDomRangeIterator( range ) ;
84
if ( state == FCK_TRISTATE_OFF )
86
iterator.EnforceRealBlocks = true ;
88
while ( ( block = iterator.GetNextParagraph() ) )
89
paragraphs.push( block ) ;
91
// If no paragraphs, create one from the current selection position.
92
if ( paragraphs.length < 1 )
94
para = range.Window.document.createElement( FCKConfig.EnterMode.IEquals( 'p' ) ? 'p' : 'div' ) ;
95
range.InsertNode( para ) ;
96
para.appendChild( range.Window.document.createTextNode( '\ufeff' ) ) ;
97
range.MoveToBookmark( bookmark ) ;
98
range.MoveToNodeContents( para ) ;
99
range.Collapse( true ) ;
100
bookmark = range.CreateBookmark() ;
101
paragraphs.push( para ) ;
104
// Make sure all paragraphs have the same parent.
105
var commonParent = paragraphs[0].parentNode ;
107
for ( var i = 0 ; i < paragraphs.length ; i++ )
109
block = paragraphs[i] ;
110
commonParent = FCKDomTools.GetCommonParents( block.parentNode, commonParent ).pop() ;
112
var lastBlock = null ;
113
while ( paragraphs.length > 0 )
115
block = paragraphs.shift() ;
116
while ( block.parentNode != commonParent )
117
block = block.parentNode ;
118
if ( block != lastBlock )
123
// If any of the selected blocks is a blockquote, remove it to prevent nested blockquotes.
124
while ( tmp.length > 0 )
126
block = tmp.shift() ;
127
if ( block.nodeName.IEquals( 'blockquote' ) )
129
var docFrag = FCKTools.GetElementDocument( block ).createDocumentFragment() ;
130
while ( block.firstChild )
132
docFrag.appendChild( block.removeChild( block.firstChild ) ) ;
133
paragraphs.push( docFrag.lastChild ) ;
135
block.parentNode.replaceChild( docFrag, block ) ;
138
paragraphs.push( block ) ;
141
// Now we have all the blocks to be included in a new blockquote node.
142
var bqBlock = range.Window.document.createElement( 'blockquote' ) ;
143
commonParent.insertBefore( bqBlock, paragraphs[0] ) ;
144
while ( paragraphs.length > 0 )
146
block = paragraphs.shift() ;
147
bqBlock.appendChild( block ) ;
150
else if ( state == FCK_TRISTATE_ON )
152
var moveOutNodes = [] ;
153
while ( ( block = iterator.GetNextParagraph() ) )
155
var bqParent = null ;
157
while ( block.parentNode )
159
if ( block.parentNode.nodeName.IEquals( 'blockquote' ) )
161
bqParent = block.parentNode ;
165
block = block.parentNode ;
168
if ( bqParent && bqChild )
169
moveOutNodes.push( bqChild ) ;
172
var movedNodes = [] ;
173
while ( moveOutNodes.length > 0 )
175
var node = moveOutNodes.shift() ;
176
var bqBlock = node.parentNode ;
178
// If the node is located at the beginning or the end, just take it out without splitting.
179
// Otherwise, split the blockquote node and move the paragraph in between the two blockquote nodes.
180
if ( node == node.parentNode.firstChild )
182
bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock ) ;
183
if ( ! bqBlock.firstChild )
184
bqBlock.parentNode.removeChild( bqBlock ) ;
186
else if ( node == node.parentNode.lastChild )
188
bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock.nextSibling ) ;
189
if ( ! bqBlock.firstChild )
190
bqBlock.parentNode.removeChild( bqBlock ) ;
193
FCKDomTools.BreakParent( node, node.parentNode, range ) ;
195
movedNodes.push( node ) ;
198
if ( FCKConfig.EnterMode.IEquals( 'br' ) )
200
while ( movedNodes.length )
202
var node = movedNodes.shift() ;
203
var firstTime = true ;
204
if ( node.nodeName.IEquals( 'div' ) )
206
var docFrag = FCKTools.GetElementDocument( node ).createDocumentFragment() ;
207
var needBeginBr = firstTime && node.previousSibling &&
208
!FCKListsLib.BlockBoundaries[node.previousSibling.nodeName.toLowerCase()] ;
209
if ( firstTime && needBeginBr )
210
docFrag.appendChild( FCKTools.GetElementDocument( node ).createElement( 'br' ) ) ;
211
var needEndBr = node.nextSibling &&
212
!FCKListsLib.BlockBoundaries[node.nextSibling.nodeName.toLowerCase()] ;
213
while ( node.firstChild )
214
docFrag.appendChild( node.removeChild( node.firstChild ) ) ;
216
docFrag.appendChild( FCKTools.GetElementDocument( node ).createElement( 'br' ) ) ;
217
node.parentNode.replaceChild( docFrag, node ) ;
223
range.MoveToBookmark( bookmark ) ;
227
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
230
GetState : function()
232
// Disabled if not WYSIWYG.
233
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )
234
return FCK_TRISTATE_DISABLED ;
236
var path = new FCKElementPath( FCKSelection.GetBoundaryParentElement( true ) ) ;
237
var firstBlock = path.Block || path.BlockLimit ;
239
if ( !firstBlock || firstBlock.nodeName.toLowerCase() == 'body' )
240
return FCK_TRISTATE_OFF ;
242
// See if the first block has a blockquote parent.
243
for ( var i = 0 ; i < path.Elements.length ; i++ )
245
if ( path.Elements[i].nodeName.IEquals( 'blockquote' ) )
246
return FCK_TRISTATE_ON ;
248
return FCK_TRISTATE_OFF ;