source: sandbox/filemanager/tp/fckeditor/editor/_source/classes/fckdomrangeiterator.js @ 1575

Revision 1575, 10.0 KB checked in by amuller, 14 years ago (diff)

Ticket #597 - Implentação, melhorias do modulo gerenciador de arquivos

  • Property svn:executable set to *
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 * This class can be used to interate through nodes inside a range.
22 *
23 * During interation, the provided range can become invalid, due to document
24 * mutations, so CreateBookmark() used to restore it after processing, if
25 * needed.
26 */
27
28var FCKDomRangeIterator = function( range )
29{
30        /**
31         * The FCKDomRange object that marks the interation boundaries.
32         */
33        this.Range = range ;
34
35        /**
36         * Indicates that <br> elements must be used as paragraph boundaries.
37         */
38        this.ForceBrBreak = false ;
39
40        /**
41         * Guarantees that the iterator will always return "real" block elements.
42         * If "false", elements like <li>, <th> and <td> are returned. If "true", a
43         * dedicated block element block element will be created inside those
44         * elements to hold the selected content.
45         */
46        this.EnforceRealBlocks = false ;
47}
48
49FCKDomRangeIterator.CreateFromSelection = function( targetWindow )
50{
51        var range = new FCKDomRange( targetWindow ) ;
52        range.MoveToSelection() ;
53        return new FCKDomRangeIterator( range ) ;
54}
55
56FCKDomRangeIterator.prototype =
57{
58        /**
59         * Get the next paragraph element. It automatically breaks the document
60         * when necessary to generate block elements for the paragraphs.
61         */
62        GetNextParagraph : function()
63        {
64                // The block element to be returned.
65                var block ;
66
67                // The range object used to identify the paragraph contents.
68                var range ;
69
70                // Indicated that the current element in the loop is the last one.
71                var isLast ;
72
73                // Instructs to cleanup remaining BRs.
74                var removePreviousBr ;
75                var removeLastBr ;
76
77                var boundarySet = this.ForceBrBreak ? FCKListsLib.ListBoundaries : FCKListsLib.BlockBoundaries ;
78
79                // This is the first iteration. Let's initialize it.
80                if ( !this._LastNode )
81                {
82                        var range = this.Range.Clone() ;
83                        range.Expand( this.ForceBrBreak ? 'list_contents' : 'block_contents' ) ;
84
85                        this._NextNode = range.GetTouchedStartNode() ;
86                        this._LastNode = range.GetTouchedEndNode() ;
87
88                        // Let's reuse this variable.
89                        range = null ;
90                }
91
92                var currentNode = this._NextNode ;
93                var lastNode = this._LastNode ;
94
95                this._NextNode = null ;
96
97                while ( currentNode )
98                {
99                        // closeRange indicates that a paragraph boundary has been found,
100                        // so the range can be closed.
101                        var closeRange = false ;
102
103                        // includeNode indicates that the current node is good to be part
104                        // of the range. By default, any non-element node is ok for it.
105                        var includeNode = ( currentNode.nodeType != 1 ) ;
106
107                        var continueFromSibling = false ;
108
109                        // If it is an element node, let's check if it can be part of the
110                        // range.
111                        if ( !includeNode )
112                        {
113                                var nodeName = currentNode.nodeName.toLowerCase() ;
114
115                                if ( boundarySet[ nodeName ] && ( !FCKBrowserInfo.IsIE || currentNode.scopeName == 'HTML' ) )
116                                {
117                                        // <br> boundaries must be part of the range. It will
118                                        // happen only if ForceBrBreak.
119                                        if ( nodeName == 'br' )
120                                                includeNode = true ;
121                                        else if ( !range && currentNode.childNodes.length == 0 && nodeName != 'hr' )
122                                        {
123                                                // If we have found an empty block, and haven't started
124                                                // the range yet, it means we must return this block.
125                                                block = currentNode ;
126                                                isLast = currentNode == lastNode ;
127                                                break ;
128                                        }
129
130                                        // The range must finish right before the boundary,
131                                        // including possibly skipped empty spaces. (#1603)
132                                        if ( range )
133                                        {
134                                                range.SetEnd( currentNode, 3, true ) ;
135
136                                                // The found boundary must be set as the next one at this
137                                                // point. (#1717)
138                                                if ( nodeName != 'br' )
139                                                        this._NextNode = FCKDomTools.GetNextSourceNode( currentNode, true, null, lastNode ) || currentNode ;
140                                        }
141
142                                        closeRange = true ;
143                                }
144                                else
145                                {
146                                        // If we have child nodes, let's check them.
147                                        if ( currentNode.firstChild )
148                                        {
149                                                // If we don't have a range yet, let's start it.
150                                                if ( !range )
151                                                {
152                                                        range = new FCKDomRange( this.Range.Window ) ;
153                                                        range.SetStart( currentNode, 3, true ) ;
154                                                }
155
156                                                currentNode = currentNode.firstChild ;
157                                                continue ;
158                                        }
159                                        includeNode = true ;
160                                }
161                        }
162                        else if ( currentNode.nodeType == 3 )
163                        {
164                                // Ignore normal whitespaces (i.e. not including &nbsp; or
165                                // other unicode whitespaces) before/after a block node.
166                                if ( /^[\r\n\t ]+$/.test( currentNode.nodeValue ) )
167                                        includeNode = false ;
168                        }
169
170                        // The current node is good to be part of the range and we are
171                        // starting a new range, initialize it first.
172                        if ( includeNode && !range )
173                        {
174                                range = new FCKDomRange( this.Range.Window ) ;
175                                range.SetStart( currentNode, 3, true ) ;
176                        }
177
178                        // The last node has been found.
179                        isLast = ( ( !closeRange || includeNode ) && currentNode == lastNode ) ;
180//                      isLast = ( currentNode == lastNode && ( currentNode.nodeType != 1 || currentNode.childNodes.length == 0 ) ) ;
181
182                        // If we are in an element boundary, let's check if it is time
183                        // to close the range, otherwise we include the parent within it.
184                        if ( range && !closeRange )
185                        {
186                                while ( !currentNode.nextSibling && !isLast )
187                                {
188                                        var parentNode = currentNode.parentNode ;
189
190                                        if ( boundarySet[ parentNode.nodeName.toLowerCase() ] )
191                                        {
192                                                closeRange = true ;
193                                                isLast = isLast || ( parentNode == lastNode ) ;
194                                                break ;
195                                        }
196
197                                        currentNode = parentNode ;
198                                        includeNode = true ;
199                                        isLast = ( currentNode == lastNode ) ;
200                                        continueFromSibling = true ;
201                                }
202                        }
203
204                        // Now finally include the node.
205                        if ( includeNode )
206                                range.SetEnd( currentNode, 4, true ) ;
207
208                        // We have found a block boundary. Let's close the range and move out of the
209                        // loop.
210                        if ( ( closeRange || isLast ) && range )
211                        {
212                                range._UpdateElementInfo() ;
213
214                                if ( range.StartNode == range.EndNode
215                                                && range.StartNode.parentNode == range.StartBlockLimit
216                                                && range.StartNode.getAttribute && range.StartNode.getAttribute( '_fck_bookmark' ) )
217                                        range = null ;
218                                else
219                                        break ;
220                        }
221
222                        if ( isLast )
223                                break ;
224
225                        currentNode = FCKDomTools.GetNextSourceNode( currentNode, continueFromSibling, null, lastNode ) ;
226                }
227
228                // Now, based on the processed range, look for (or create) the block to be returned.
229                if ( !block )
230                {
231                        // If no range has been found, this is the end.
232                        if ( !range )
233                        {
234                                this._NextNode = null ;
235                                return null ;
236                        }
237
238                        block = range.StartBlock ;
239
240                        if ( !block
241                                && !this.EnforceRealBlocks
242                                && range.StartBlockLimit.nodeName.IEquals( 'DIV', 'TH', 'TD' )
243                                && range.CheckStartOfBlock()
244                                && range.CheckEndOfBlock() )
245                        {
246                                block = range.StartBlockLimit ;
247                        }
248                        else if ( !block || ( this.EnforceRealBlocks && block.nodeName.toLowerCase() == 'li' ) )
249                        {
250                                // Create the fixed block.
251                                block = this.Range.Window.document.createElement( FCKConfig.EnterMode == 'p' ? 'p' : 'div' ) ;
252
253                                // Move the contents of the temporary range to the fixed block.
254                                range.ExtractContents().AppendTo( block ) ;
255                                FCKDomTools.TrimNode( block ) ;
256
257                                // Insert the fixed block into the DOM.
258                                range.InsertNode( block ) ;
259
260                                removePreviousBr = true ;
261                                removeLastBr = true ;
262                        }
263                        else if ( block.nodeName.toLowerCase() != 'li' )
264                        {
265                                // If the range doesn't includes the entire contents of the
266                                // block, we must split it, isolating the range in a dedicated
267                                // block.
268                                if ( !range.CheckStartOfBlock() || !range.CheckEndOfBlock() )
269                                {
270                                        // The resulting block will be a clone of the current one.
271                                        block = block.cloneNode( false ) ;
272
273                                        // Extract the range contents, moving it to the new block.
274                                        range.ExtractContents().AppendTo( block ) ;
275                                        FCKDomTools.TrimNode( block ) ;
276
277                                        // Split the block. At this point, the range will be in the
278                                        // right position for our intents.
279                                        var splitInfo = range.SplitBlock() ;
280
281                                        removePreviousBr = !splitInfo.WasStartOfBlock ;
282                                        removeLastBr = !splitInfo.WasEndOfBlock ;
283
284                                        // Insert the new block into the DOM.
285                                        range.InsertNode( block ) ;
286                                }
287                        }
288                        else if ( !isLast )
289                        {
290                                // LIs are returned as is, with all their children (due to the
291                                // nested lists). But, the next node is the node right after
292                                // the current range, which could be an <li> child (nested
293                                // lists) or the next sibling <li>.
294
295                                this._NextNode = block == lastNode ? null : FCKDomTools.GetNextSourceNode( range.EndNode, true, null, lastNode ) ;
296                                return block ;
297                        }
298                }
299
300                if ( removePreviousBr )
301                {
302                        var previousSibling = block.previousSibling ;
303                        if ( previousSibling && previousSibling.nodeType == 1 )
304                        {
305                                if ( previousSibling.nodeName.toLowerCase() == 'br' )
306                                        previousSibling.parentNode.removeChild( previousSibling ) ;
307                                else if ( previousSibling.lastChild && previousSibling.lastChild.nodeName.IEquals( 'br' ) )
308                                        previousSibling.removeChild( previousSibling.lastChild ) ;
309                        }
310                }
311
312                if ( removeLastBr )
313                {
314                        var lastChild = block.lastChild ;
315                        if ( lastChild && lastChild.nodeType == 1 && lastChild.nodeName.toLowerCase() == 'br' )
316                                block.removeChild( lastChild ) ;
317                }
318
319                // Get a reference for the next element. This is important because the
320                // above block can be removed or changed, so we can rely on it for the
321                // next interation.
322                if ( !this._NextNode )
323                        this._NextNode = ( isLast || block == lastNode ) ? null : FCKDomTools.GetNextSourceNode( block, true, null, lastNode ) ;
324
325                return block ;
326        }
327} ;
Note: See TracBrowser for help on using the repository browser.