source: sandbox/3.0/phpgwapi/js/ckeditor/_source/plugins/domiterator/plugin.js @ 2862

Revision 2862, 11.1 KB checked in by rodsouza, 14 years ago (diff)

Ticket #663 - Atualizando e centralizando o CKEditor (v. 3.2.1)

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