source: trunk/filemanager/tp/ckeditor/_source/plugins/domiterator/plugin.js @ 2000

Revision 2000, 11.1 KB checked in by amuller, 14 years ago (diff)

Ticket #597 - Implementação do módulo gerenciador de arquivos

Line 
1/*
2Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.html or http://ckeditor.com/license
4*/
5
6/**
7 * @file DOM iterator, which iterates over list items, lines and paragraphs.
8 */
9
10CKEDITOR.plugins.add( 'domiterator' );
11
12(function()
13{
14
15        var iterator = function( range )
16        {
17                if ( arguments.length < 1 )
18                        return;
19
20                this.range = range;
21                this.forceBrBreak = false;
22
23                // Whether include <br>s into the enlarged range.(#3730).
24                this.enlargeBr = true;
25                this.enforceRealBlocks = false;
26
27                this._ || ( this._ = {} );
28        },
29                beginWhitespaceRegex = /^[\r\n\t ]+$/;
30
31
32        iterator.prototype = {
33                getNextParagraph : function( blockTag )
34                {
35                        // The block element to be returned.
36                        var block;
37
38                        // The range object used to identify the paragraph contents.
39                        var range;
40
41                        // Indicats that the current element in the loop is the last one.
42                        var isLast;
43
44                        // Instructs to cleanup remaining BRs.
45                        var removePreviousBr, removeLastBr;
46
47                        // This is the first iteration. Let's initialize it.
48                        if ( !this._.lastNode )
49                        {
50                                range = this.range.clone();
51                                range.enlarge( this.forceBrBreak || !this.enlargeBr ?
52                                                           CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS : CKEDITOR.ENLARGE_BLOCK_CONTENTS );
53
54                                var walker = new CKEDITOR.dom.walker( range ),
55                                        ignoreBookmarkTextEvaluator = CKEDITOR.dom.walker.bookmark( true, true );
56                                // Avoid anchor inside bookmark inner text.
57                                walker.evaluator = ignoreBookmarkTextEvaluator;
58                                this._.nextNode = walker.next();
59                                // TODO: It's better to have walker.reset() used here.
60                                walker = new CKEDITOR.dom.walker( range );
61                                walker.evaluator = ignoreBookmarkTextEvaluator;
62                                var lastNode = walker.previous();
63                                this._.lastNode = lastNode.getNextSourceNode( true );
64
65                                // We may have an empty text node at the end of block due to [3770].
66                                // If that node is the lastNode, it would cause our logic to leak to the
67                                // next block.(#3887)
68                                if ( this._.lastNode &&
69                                                this._.lastNode.type == CKEDITOR.NODE_TEXT &&
70                                                !CKEDITOR.tools.trim( this._.lastNode.getText( ) ) &&
71                                                this._.lastNode.getParent().isBlockBoundary() )
72                                {
73                                        var testRange = new CKEDITOR.dom.range( range.document );
74                                        testRange.moveToPosition( this._.lastNode, CKEDITOR.POSITION_AFTER_END );
75                                        if ( testRange.checkEndOfBlock() )
76                                        {
77                                                var path = new CKEDITOR.dom.elementPath( testRange.endContainer );
78                                                var lastBlock = path.block || path.blockLimit;
79                                                this._.lastNode = lastBlock.getNextSourceNode( true );
80                                        }
81                                }
82
83                                // Probably the document end is reached, we need a marker node.
84                                if ( !this._.lastNode )
85                                {
86                                        this._.lastNode = this._.docEndMarker = range.document.createText( '' );
87                                        this._.lastNode.insertAfter( lastNode );
88                                }
89
90                                // Let's reuse this variable.
91                                range = null;
92                        }
93
94                        var currentNode = this._.nextNode;
95                        lastNode = this._.lastNode;
96
97                        this._.nextNode = null;
98                        while ( currentNode )
99                        {
100                                // closeRange indicates that a paragraph boundary has been found,
101                                // so the range can be closed.
102                                var closeRange = false;
103
104                                // includeNode indicates that the current node is good to be part
105                                // of the range. By default, any non-element node is ok for it.
106                                var includeNode = ( currentNode.type != CKEDITOR.NODE_ELEMENT ),
107                                        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.getName();
114
115                                        if ( currentNode.isBlockBoundary( this.forceBrBreak && { br : 1 } ) )
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.getChildCount() && 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.equals( 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.setEndAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
135
136                                                        // The found boundary must be set as the next one at this
137                                                        // point. (#1717)
138                                                        if ( nodeName != 'br' )
139                                                                this._.nextNode = currentNode;
140                                                }
141
142                                                closeRange = true;
143                                        }
144                                        else
145                                        {
146                                                // If we have child nodes, let's check them.
147                                                if ( currentNode.getFirst() )
148                                                {
149                                                        // If we don't have a range yet, let's start it.
150                                                        if ( !range )
151                                                        {
152                                                                range = new CKEDITOR.dom.range( this.range.document );
153                                                                range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
154                                                        }
155
156                                                        currentNode = currentNode.getFirst();
157                                                        continue;
158                                                }
159                                                includeNode = true;
160                                        }
161                                }
162                                else if ( currentNode.type == CKEDITOR.NODE_TEXT )
163                                {
164                                        // Ignore normal whitespaces (i.e. not including &nbsp; or
165                                        // other unicode whitespaces) before/after a block node.
166                                        if ( beginWhitespaceRegex.test( currentNode.getText() ) )
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 CKEDITOR.dom.range( this.range.document );
175                                        range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
176                                }
177
178                                // The last node has been found.
179                                isLast = ( ( !closeRange || includeNode ) && currentNode.equals( lastNode ) );
180
181                                // If we are in an element boundary, let's check if it is time
182                                // to close the range, otherwise we include the parent within it.
183                                if ( range && !closeRange )
184                                {
185                                        while ( !currentNode.getNext() && !isLast )
186                                        {
187                                                var parentNode = currentNode.getParent();
188
189                                                if ( parentNode.isBlockBoundary( this.forceBrBreak && { br : 1 } ) )
190                                                {
191                                                        closeRange = true;
192                                                        isLast = isLast || ( parentNode.equals( lastNode) );
193                                                        break;
194                                                }
195
196                                                currentNode = parentNode;
197                                                includeNode = true;
198                                                isLast = ( currentNode.equals( lastNode ) );
199                                                continueFromSibling = true;
200                                        }
201                                }
202
203                                // Now finally include the node.
204                                if ( includeNode )
205                                        range.setEndAt( currentNode, CKEDITOR.POSITION_AFTER_END );
206
207                                currentNode = currentNode.getNextSourceNode( continueFromSibling, null, lastNode );
208                                isLast = !currentNode;
209
210                                // We have found a block boundary. Let's close the range and move out of the
211                                // loop.
212                                if ( ( closeRange || isLast ) && range )
213                                {
214                                        var boundaryNodes = range.getBoundaryNodes(),
215                                                startPath = new CKEDITOR.dom.elementPath( range.startContainer ),
216                                                endPath = new CKEDITOR.dom.elementPath( range.endContainer );
217
218                                        // Drop the range if it only contains bookmark nodes.(#4087)
219                                        if ( boundaryNodes.startNode.equals( boundaryNodes.endNode )
220                                                && boundaryNodes.startNode.getParent().equals( startPath.blockLimit )
221                                                && boundaryNodes.startNode.type == CKEDITOR.NODE_ELEMENT
222                                                && boundaryNodes.startNode.getAttribute( '_fck_bookmark' ) )
223                                        {
224                                                range = null;
225                                                this._.nextNode = null;
226                                        }
227                                        else
228                                                break;
229                                }
230
231                                if ( isLast )
232                                        break;
233
234                        }
235
236                        // Now, based on the processed range, look for (or create) the block to be returned.
237                        if ( !block )
238                        {
239                                // If no range has been found, this is the end.
240                                if ( !range )
241                                {
242                                        this._.docEndMarker && this._.docEndMarker.remove();
243                                        this._.nextNode = null;
244                                        return null;
245                                }
246
247                                startPath = new CKEDITOR.dom.elementPath( range.startContainer );
248                                var startBlockLimit = startPath.blockLimit,
249                                        checkLimits = { div : 1, th : 1, td : 1 };
250                                block = startPath.block;
251
252                                if ( !block
253                                                && !this.enforceRealBlocks
254                                                && checkLimits[ startBlockLimit.getName() ]
255                                                && range.checkStartOfBlock()
256                                                && range.checkEndOfBlock() )
257                                        block = startBlockLimit;
258                                else if ( !block || ( this.enforceRealBlocks && block.getName() == 'li' ) )
259                                {
260                                        // Create the fixed block.
261                                        block = this.range.document.createElement( blockTag || 'p' );
262
263                                        // Move the contents of the temporary range to the fixed block.
264                                        range.extractContents().appendTo( block );
265                                        block.trim();
266
267                                        // Insert the fixed block into the DOM.
268                                        range.insertNode( block );
269
270                                        removePreviousBr = removeLastBr = true;
271                                }
272                                else if ( block.getName() != 'li' )
273                                {
274                                        // If the range doesn't includes the entire contents of the
275                                        // block, we must split it, isolating the range in a dedicated
276                                        // block.
277                                        if ( !range.checkStartOfBlock() || !range.checkEndOfBlock() )
278                                        {
279                                                // The resulting block will be a clone of the current one.
280                                                block = block.clone( false );
281
282                                                // Extract the range contents, moving it to the new block.
283                                                range.extractContents().appendTo( block );
284                                                block.trim();
285
286                                                // Split the block. At this point, the range will be in the
287                                                // right position for our intents.
288                                                var splitInfo = range.splitBlock();
289
290                                                removePreviousBr = !splitInfo.wasStartOfBlock;
291                                                removeLastBr = !splitInfo.wasEndOfBlock;
292
293                                                // Insert the new block into the DOM.
294                                                range.insertNode( block );
295                                        }
296                                }
297                                else if ( !isLast )
298                                {
299                                        // LIs are returned as is, with all their children (due to the
300                                        // nested lists). But, the next node is the node right after
301                                        // the current range, which could be an <li> child (nested
302                                        // lists) or the next sibling <li>.
303
304                                        this._.nextNode = ( block.equals( lastNode ) ? null :
305                                                range.getBoundaryNodes().endNode.getNextSourceNode( true, null, lastNode ) );
306                                }
307                        }
308
309                        if ( removePreviousBr )
310                        {
311                                var previousSibling = block.getPrevious();
312                                if ( previousSibling && previousSibling.type == CKEDITOR.NODE_ELEMENT )
313                                {
314                                        if ( previousSibling.getName() == 'br' )
315                                                previousSibling.remove();
316                                        else if ( previousSibling.getLast() && previousSibling.getLast().$.nodeName.toLowerCase() == 'br' )
317                                                previousSibling.getLast().remove();
318                                }
319                        }
320
321                        if ( removeLastBr )
322                        {
323                                // Ignore bookmark nodes.(#3783)
324                                var bookmarkGuard = CKEDITOR.dom.walker.bookmark( false, true );
325
326                                var lastChild = block.getLast();
327                                if ( lastChild && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.getName() == 'br' )
328                                {
329                                        // Take care not to remove the block expanding <br> in non-IE browsers.
330                                        if ( CKEDITOR.env.ie
331                                                 || lastChild.getPrevious( bookmarkGuard )
332                                                 || lastChild.getNext( bookmarkGuard ) )
333                                                lastChild.remove();
334                                }
335                        }
336
337                        // Get a reference for the next element. This is important because the
338                        // above block can be removed or changed, so we can rely on it for the
339                        // next interation.
340                        if ( !this._.nextNode )
341                        {
342                                this._.nextNode = ( isLast || block.equals( lastNode ) ) ? null :
343                                        block.getNextSourceNode( true, null, lastNode );
344                        }
345
346                        return block;
347                }
348        };
349
350        CKEDITOR.dom.range.prototype.createIterator = function()
351        {
352                return new iterator( this );
353        };
354})();
Note: See TracBrowser for help on using the repository browser.