source: extensions/FCKEditor/editor/_source/commandclasses/fckblockquotecommand.js @ 3295

Last change on this file since 3295 was 3295, checked in by patdenice, 15 years ago

New extension added:
FCK Editor (2.0.a)

File size: 8.8 KB
Line 
1/*
2 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
3 * Copyright (C) 2003-2009 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 * FCKBlockQuoteCommand Class: adds or removes blockquote tags.
22 */
23
24var FCKBlockQuoteCommand = function()
25{
26}
27
28FCKBlockQuoteCommand.prototype =
29{
30        Execute : function()
31        {
32                FCKUndo.SaveUndoStep() ;
33
34                var state = this.GetState() ;
35
36                var range = new FCKDomRange( FCK.EditorWindow ) ;
37                range.MoveToSelection() ;
38
39                var bookmark = range.CreateBookmark() ;
40
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
43                // blockquote.
44                if ( FCKBrowserInfo.IsIE )
45                {
46                        var bStart      = range.GetBookmarkNode( bookmark, true ) ;
47                        var bEnd        = range.GetBookmarkNode( bookmark, false ) ;
48
49                        var cursor ;
50
51                        if ( bStart
52                                        && bStart.parentNode.nodeName.IEquals( 'blockquote' )
53                                        && !bStart.previousSibling )
54                        {
55                                cursor = bStart ;
56                                while ( ( cursor = cursor.nextSibling ) )
57                                {
58                                        if ( FCKListsLib.BlockElements[ cursor.nodeName.toLowerCase() ] )
59                                                FCKDomTools.MoveNode( bStart, cursor, true ) ;
60                                }
61                        }
62
63                        if ( bEnd
64                                        && bEnd.parentNode.nodeName.IEquals( 'blockquote' )
65                                        && !bEnd.previousSibling )
66                        {
67                                cursor = bEnd ;
68                                while ( ( cursor = cursor.nextSibling ) )
69                                {
70                                        if ( FCKListsLib.BlockElements[ cursor.nodeName.toLowerCase() ] )
71                                        {
72                                                if ( cursor.firstChild == bStart )
73                                                        FCKDomTools.InsertAfterNode( bStart, bEnd ) ;
74                                                else
75                                                        FCKDomTools.MoveNode( bEnd, cursor, true ) ;
76                                        }
77                                }
78                        }
79                }
80
81                var iterator = new FCKDomRangeIterator( range ) ;
82                var block ;
83
84                if ( state == FCK_TRISTATE_OFF )
85                {
86                        var paragraphs = [] ;
87                        while ( ( block = iterator.GetNextParagraph() ) )
88                                paragraphs.push( block ) ;
89
90                        // If no paragraphs, create one from the current selection position.
91                        if ( paragraphs.length < 1 )
92                        {
93                                para = range.Window.document.createElement( FCKConfig.EnterMode.IEquals( 'p' ) ? 'p' : 'div' ) ;
94                                range.InsertNode( para ) ;
95                                para.appendChild( range.Window.document.createTextNode( '\ufeff' ) ) ;
96                                range.MoveToBookmark( bookmark ) ;
97                                range.MoveToNodeContents( para ) ;
98                                range.Collapse( true ) ;
99                                bookmark = range.CreateBookmark() ;
100                                paragraphs.push( para ) ;
101                        }
102
103                        // Make sure all paragraphs have the same parent.
104                        var commonParent = paragraphs[0].parentNode ;
105                        var tmp = [] ;
106                        for ( var i = 0 ; i < paragraphs.length ; i++ )
107                        {
108                                block = paragraphs[i] ;
109                                commonParent = FCKDomTools.GetCommonParents( block.parentNode, commonParent ).pop() ;
110                        }
111
112                        // The common parent must not be the following tags: table, tbody, tr, ol, ul.
113                        while ( commonParent.nodeName.IEquals( 'table', 'tbody', 'tr', 'ol', 'ul' ) )
114                                commonParent = commonParent.parentNode ;
115
116                        // Reconstruct the block list to be processed such that all resulting blocks
117                        // satisfy parentNode == commonParent.
118                        var lastBlock = null ;
119                        while ( paragraphs.length > 0 )
120                        {
121                                block = paragraphs.shift() ;
122                                while ( block.parentNode != commonParent )
123                                        block = block.parentNode ;
124                                if ( block != lastBlock )
125                                        tmp.push( block ) ;
126                                lastBlock = block ;
127                        }
128
129                        // If any of the selected blocks is a blockquote, remove it to prevent nested blockquotes.
130                        while ( tmp.length > 0 )
131                        {
132                                block = tmp.shift() ;
133                                if ( block.nodeName.IEquals( 'blockquote' ) )
134                                {
135                                        var docFrag = FCKTools.GetElementDocument( block ).createDocumentFragment() ;
136                                        while ( block.firstChild )
137                                        {
138                                                docFrag.appendChild( block.removeChild( block.firstChild ) ) ;
139                                                paragraphs.push( docFrag.lastChild ) ;
140                                        }
141                                        block.parentNode.replaceChild( docFrag, block ) ;
142                                }
143                                else
144                                        paragraphs.push( block ) ;
145                        }
146
147                        // Now we have all the blocks to be included in a new blockquote node.
148                        var bqBlock = range.Window.document.createElement( 'blockquote' ) ;
149                        commonParent.insertBefore( bqBlock, paragraphs[0] ) ;
150                        while ( paragraphs.length > 0 )
151                        {
152                                block = paragraphs.shift() ;
153                                bqBlock.appendChild( block ) ;
154                        }
155                }
156                else if ( state == FCK_TRISTATE_ON )
157                {
158                        var moveOutNodes = [] ;
159                        var elementMarkers = {} ;
160                        while ( ( block = iterator.GetNextParagraph() ) )
161                        {
162                                var bqParent = null ;
163                                var bqChild = null ;
164                                while ( block.parentNode )
165                                {
166                                        if ( block.parentNode.nodeName.IEquals( 'blockquote' ) )
167                                        {
168                                                bqParent = block.parentNode ;
169                                                bqChild = block ;
170                                                break ;
171                                        }
172                                        block = block.parentNode ;
173                                }
174
175                                // Remember the blocks that were recorded down in the moveOutNodes array
176                                // to prevent duplicates.
177                                if ( bqParent && bqChild && !bqChild._fckblockquotemoveout )
178                                {
179                                        moveOutNodes.push( bqChild ) ;
180                                        FCKDomTools.SetElementMarker( elementMarkers, bqChild, '_fckblockquotemoveout', true ) ;
181                                }
182                        }
183                        FCKDomTools.ClearAllMarkers( elementMarkers ) ;
184
185                        var movedNodes = [] ;
186                        var processedBlockquoteBlocks = [], elementMarkers = {} ;
187                        var noBlockLeft = function( bqBlock )
188                        {
189                                for ( var i = 0 ; i < bqBlock.childNodes.length ; i++ )
190                                {
191                                        if ( FCKListsLib.BlockElements[ bqBlock.childNodes[i].nodeName.toLowerCase() ] )
192                                                return false ;
193                                }
194                                return true ;
195                        } ;
196                        while ( moveOutNodes.length > 0 )
197                        {
198                                var node = moveOutNodes.shift() ;
199                                var bqBlock = node.parentNode ;
200
201                                // If the node is located at the beginning or the end, just take it out without splitting.
202                                // Otherwise, split the blockquote node and move the paragraph in between the two blockquote nodes.
203                                if ( node == node.parentNode.firstChild )
204                                        bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock ) ;
205                                else if ( node == node.parentNode.lastChild )
206                                        bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock.nextSibling ) ;
207                                else
208                                        FCKDomTools.BreakParent( node, node.parentNode, range ) ;
209
210                                // Remember the blockquote node so we can clear it later (if it becomes empty).
211                                if ( !bqBlock._fckbqprocessed )
212                                {
213                                        processedBlockquoteBlocks.push( bqBlock ) ;
214                                        FCKDomTools.SetElementMarker( elementMarkers, bqBlock, '_fckbqprocessed', true );
215                                }
216
217                                movedNodes.push( node ) ;
218                        }
219
220                        // Clear blockquote nodes that have become empty.
221                        for ( var i = processedBlockquoteBlocks.length - 1 ; i >= 0 ; i-- )
222                        {
223                                var bqBlock = processedBlockquoteBlocks[i] ;
224                                if ( noBlockLeft( bqBlock ) )
225                                        FCKDomTools.RemoveNode( bqBlock ) ;
226                        }
227                        FCKDomTools.ClearAllMarkers( elementMarkers ) ;
228
229                        if ( FCKConfig.EnterMode.IEquals( 'br' ) )
230                        {
231                                while ( movedNodes.length )
232                                {
233                                        var node = movedNodes.shift() ;
234                                        var firstTime = true ;
235                                        if ( node.nodeName.IEquals( 'div' ) )
236                                        {
237                                                var docFrag = FCKTools.GetElementDocument( node ).createDocumentFragment() ;
238                                                var needBeginBr = firstTime && node.previousSibling &&
239                                                        !FCKListsLib.BlockBoundaries[node.previousSibling.nodeName.toLowerCase()] ;
240                                                if ( firstTime && needBeginBr )
241                                                        docFrag.appendChild( FCKTools.GetElementDocument( node ).createElement( 'br' ) ) ;
242                                                var needEndBr = node.nextSibling &&
243                                                        !FCKListsLib.BlockBoundaries[node.nextSibling.nodeName.toLowerCase()] ;
244                                                while ( node.firstChild )
245                                                        docFrag.appendChild( node.removeChild( node.firstChild ) ) ;
246                                                if ( needEndBr )
247                                                        docFrag.appendChild( FCKTools.GetElementDocument( node ).createElement( 'br' ) ) ;
248                                                node.parentNode.replaceChild( docFrag, node ) ;
249                                                firstTime = false ;
250                                        }
251                                }
252                        }
253                }
254                range.MoveToBookmark( bookmark ) ;
255                range.Select() ;
256
257                FCK.Focus() ;
258                FCK.Events.FireEvent( 'OnSelectionChange' ) ;
259        },
260
261        GetState : function()
262        {
263                // Disabled if not WYSIWYG.
264                if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )
265                        return FCK_TRISTATE_DISABLED ;
266
267                var path = new FCKElementPath( FCKSelection.GetBoundaryParentElement( true ) ) ;
268                var firstBlock = path.Block || path.BlockLimit ;
269
270                if ( !firstBlock || firstBlock.nodeName.toLowerCase() == 'body' )
271                        return FCK_TRISTATE_OFF ;
272
273                // See if the first block has a blockquote parent.
274                for ( var i = 0 ; i < path.Elements.length ; i++ )
275                {
276                        if ( path.Elements[i].nodeName.IEquals( 'blockquote' ) )
277                                return FCK_TRISTATE_ON ;
278                }
279                return FCK_TRISTATE_OFF ;
280        }
281} ;
Note: See TracBrowser for help on using the repository browser.