PluginProbe
Wp-Insert / 1.2
Wp-Insert v1.2
trunk 1.0 1.1 1.2 1.2.1 1.2.2 1.3.0 1.3.1 1.3.3 1.4 1.5.0 1.5.1 1.5.2 1.5.3 1.6.0 1.6.1 1.6.2 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 2.0 All 63 releases
wp-insert / fckeditor / editor / _source / classes / fckdomrangeiterator.js

fckdomrangeiterator.js in Wp-Insert 1.2, at fckeditor/editor/_source/classes/fckdomrangeiterator.js

655 lines 10.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*
2
3 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
4
5 * Copyright (C) 2003-2009 Frederico Caldeira Knabben
6
7 *
8
9 * == BEGIN LICENSE ==
10
11 *
12
13 * Licensed under the terms of any of the following licenses at your
14
15 * choice:
16
17 *
18
19 * - GNU General Public License Version 2 or later (the "GPL")
20
21 * http://www.gnu.org/licenses/gpl.html
22
23 *
24
25 * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
26
27 * http://www.gnu.org/licenses/lgpl.html
28
29 *
30
31 * - Mozilla Public License Version 1.1 or later (the "MPL")
32
33 * http://www.mozilla.org/MPL/MPL-1.1.html
34
35 *
36
37 * == END LICENSE ==
38
39 *
40
41 * This class can be used to interate through nodes inside a range.
42
43 *
44
45 * During interation, the provided range can become invalid, due to document
46
47 * mutations, so CreateBookmark() used to restore it after processing, if
48
49 * needed.
50
51 */
52
53
54
55 var FCKDomRangeIterator = function( range )
56
57 {
58
59 /**
60
61 * The FCKDomRange object that marks the interation boundaries.
62
63 */
64
65 this.Range = range ;
66
67
68
69 /**
70
71 * Indicates that <br> elements must be used as paragraph boundaries.
72
73 */
74
75 this.ForceBrBreak = false ;
76
77
78
79 /**
80
81 * Guarantees that the iterator will always return "real" block elements.
82
83 * If "false", elements like <li>, <th> and <td> are returned. If "true", a
84
85 * dedicated block element block element will be created inside those
86
87 * elements to hold the selected content.
88
89 */
90
91 this.EnforceRealBlocks = false ;
92
93 }
94
95
96
97 FCKDomRangeIterator.CreateFromSelection = function( targetWindow )
98
99 {
100
101 var range = new FCKDomRange( targetWindow ) ;
102
103 range.MoveToSelection() ;
104
105 return new FCKDomRangeIterator( range ) ;
106
107 }
108
109
110
111 FCKDomRangeIterator.prototype =
112
113 {
114
115 /**
116
117 * Get the next paragraph element. It automatically breaks the document
118
119 * when necessary to generate block elements for the paragraphs.
120
121 */
122
123 GetNextParagraph : function()
124
125 {
126
127 // The block element to be returned.
128
129 var block ;
130
131
132
133 // The range object used to identify the paragraph contents.
134
135 var range ;
136
137
138
139 // Indicated that the current element in the loop is the last one.
140
141 var isLast ;
142
143
144
145 // Instructs to cleanup remaining BRs.
146
147 var removePreviousBr ;
148
149 var removeLastBr ;
150
151
152
153 var boundarySet = this.ForceBrBreak ? FCKListsLib.ListBoundaries : FCKListsLib.BlockBoundaries ;
154
155
156
157 // This is the first iteration. Let's initialize it.
158
159 if ( !this._LastNode )
160
161 {
162
163 var range = this.Range.Clone() ;
164
165 range.Expand( this.ForceBrBreak ? 'list_contents' : 'block_contents' ) ;
166
167
168
169 this._NextNode = range.GetTouchedStartNode() ;
170
171 this._LastNode = range.GetTouchedEndNode() ;
172
173
174
175 // Let's reuse this variable.
176
177 range = null ;
178
179 }
180
181
182
183 var currentNode = this._NextNode ;
184
185 var lastNode = this._LastNode ;
186
187
188
189 this._NextNode = null ;
190
191
192
193 while ( currentNode )
194
195 {
196
197 // closeRange indicates that a paragraph boundary has been found,
198
199 // so the range can be closed.
200
201 var closeRange = false ;
202
203
204
205 // includeNode indicates that the current node is good to be part
206
207 // of the range. By default, any non-element node is ok for it.
208
209 var includeNode = ( currentNode.nodeType != 1 ) ;
210
211
212
213 var continueFromSibling = false ;
214
215
216
217 // If it is an element node, let's check if it can be part of the
218
219 // range.
220
221 if ( !includeNode )
222
223 {
224
225 var nodeName = currentNode.nodeName.toLowerCase() ;
226
227
228
229 if ( boundarySet[ nodeName ] && ( !FCKBrowserInfo.IsIE || currentNode.scopeName == 'HTML' ) )
230
231 {
232
233 // <br> boundaries must be part of the range. It will
234
235 // happen only if ForceBrBreak.
236
237 if ( nodeName == 'br' )
238
239 includeNode = true ;
240
241 else if ( !range && currentNode.childNodes.length == 0 && nodeName != 'hr' )
242
243 {
244
245 // If we have found an empty block, and haven't started
246
247 // the range yet, it means we must return this block.
248
249 block = currentNode ;
250
251 isLast = currentNode == lastNode ;
252
253 break ;
254
255 }
256
257
258
259 // The range must finish right before the boundary,
260
261 // including possibly skipped empty spaces. (#1603)
262
263 if ( range )
264
265 {
266
267 range.SetEnd( currentNode, 3, true ) ;
268
269
270
271 // The found boundary must be set as the next one at this
272
273 // point. (#1717)
274
275 if ( nodeName != 'br' )
276
277 this._NextNode = FCKDomTools.GetNextSourceNode( currentNode, true, null, lastNode ) || currentNode ;
278
279 }
280
281
282
283 closeRange = true ;
284
285 }
286
287 else
288
289 {
290
291 // If we have child nodes, let's check them.
292
293 if ( currentNode.firstChild )
294
295 {
296
297 // If we don't have a range yet, let's start it.
298
299 if ( !range )
300
301 {
302
303 range = new FCKDomRange( this.Range.Window ) ;
304
305 range.SetStart( currentNode, 3, true ) ;
306
307 }
308
309
310
311 currentNode = currentNode.firstChild ;
312
313 continue ;
314
315 }
316
317 includeNode = true ;
318
319 }
320
321 }
322
323 else if ( currentNode.nodeType == 3 )
324
325 {
326
327 // Ignore normal whitespaces (i.e. not including &nbsp; or
328
329 // other unicode whitespaces) before/after a block node.
330
331 if ( /^[\r\n\t ]+$/.test( currentNode.nodeValue ) )
332
333 includeNode = false ;
334
335 }
336
337
338
339 // The current node is good to be part of the range and we are
340
341 // starting a new range, initialize it first.
342
343 if ( includeNode && !range )
344
345 {
346
347 range = new FCKDomRange( this.Range.Window ) ;
348
349 range.SetStart( currentNode, 3, true ) ;
350
351 }
352
353
354
355 // The last node has been found.
356
357 isLast = ( ( !closeRange || includeNode ) && currentNode == lastNode ) ;
358
359 // isLast = ( currentNode == lastNode && ( currentNode.nodeType != 1 || currentNode.childNodes.length == 0 ) ) ;
360
361
362
363 // If we are in an element boundary, let's check if it is time
364
365 // to close the range, otherwise we include the parent within it.
366
367 if ( range && !closeRange )
368
369 {
370
371 while ( !currentNode.nextSibling && !isLast )
372
373 {
374
375 var parentNode = currentNode.parentNode ;
376
377
378
379 if ( boundarySet[ parentNode.nodeName.toLowerCase() ] )
380
381 {
382
383 closeRange = true ;
384
385 isLast = isLast || ( parentNode == lastNode ) ;
386
387 break ;
388
389 }
390
391
392
393 currentNode = parentNode ;
394
395 includeNode = true ;
396
397 isLast = ( currentNode == lastNode ) ;
398
399 continueFromSibling = true ;
400
401 }
402
403 }
404
405
406
407 // Now finally include the node.
408
409 if ( includeNode )
410
411 range.SetEnd( currentNode, 4, true ) ;
412
413
414
415 // We have found a block boundary. Let's close the range and move out of the
416
417 // loop.
418
419 if ( ( closeRange || isLast ) && range )
420
421 {
422
423 range._UpdateElementInfo() ;
424
425
426
427 if ( range.StartNode == range.EndNode
428
429 && range.StartNode.parentNode == range.StartBlockLimit
430
431 && range.StartNode.getAttribute && range.StartNode.getAttribute( '_fck_bookmark' ) )
432
433 range = null ;
434
435 else
436
437 break ;
438
439 }
440
441
442
443 if ( isLast )
444
445 break ;
446
447
448
449 currentNode = FCKDomTools.GetNextSourceNode( currentNode, continueFromSibling, null, lastNode ) ;
450
451 }
452
453
454
455 // Now, based on the processed range, look for (or create) the block to be returned.
456
457 if ( !block )
458
459 {
460
461 // If no range has been found, this is the end.
462
463 if ( !range )
464
465 {
466
467 this._NextNode = null ;
468
469 return null ;
470
471 }
472
473
474
475 block = range.StartBlock ;
476
477
478
479 if ( !block
480
481 && !this.EnforceRealBlocks
482
483 && range.StartBlockLimit.nodeName.IEquals( 'DIV', 'TH', 'TD' )
484
485 && range.CheckStartOfBlock()
486
487 && range.CheckEndOfBlock() )
488
489 {
490
491 block = range.StartBlockLimit ;
492
493 }
494
495 else if ( !block || ( this.EnforceRealBlocks && block.nodeName.toLowerCase() == 'li' ) )
496
497 {
498
499 // Create the fixed block.
500
501 block = this.Range.Window.document.createElement( FCKConfig.EnterMode == 'p' ? 'p' : 'div' ) ;
502
503
504
505 // Move the contents of the temporary range to the fixed block.
506
507 range.ExtractContents().AppendTo( block ) ;
508
509 FCKDomTools.TrimNode( block ) ;
510
511
512
513 // Insert the fixed block into the DOM.
514
515 range.InsertNode( block ) ;
516
517
518
519 removePreviousBr = true ;
520
521 removeLastBr = true ;
522
523 }
524
525 else if ( block.nodeName.toLowerCase() != 'li' )
526
527 {
528
529 // If the range doesn't includes the entire contents of the
530
531 // block, we must split it, isolating the range in a dedicated
532
533 // block.
534
535 if ( !range.CheckStartOfBlock() || !range.CheckEndOfBlock() )
536
537 {
538
539 // The resulting block will be a clone of the current one.
540
541 block = block.cloneNode( false ) ;
542
543
544
545 // Extract the range contents, moving it to the new block.
546
547 range.ExtractContents().AppendTo( block ) ;
548
549 FCKDomTools.TrimNode( block ) ;
550
551
552
553 // Split the block. At this point, the range will be in the
554
555 // right position for our intents.
556
557 var splitInfo = range.SplitBlock() ;
558
559
560
561 removePreviousBr = !splitInfo.WasStartOfBlock ;
562
563 removeLastBr = !splitInfo.WasEndOfBlock ;
564
565
566
567 // Insert the new block into the DOM.
568
569 range.InsertNode( block ) ;
570
571 }
572
573 }
574
575 else if ( !isLast )
576
577 {
578
579 // LIs are returned as is, with all their children (due to the
580
581 // nested lists). But, the next node is the node right after
582
583 // the current range, which could be an <li> child (nested
584
585 // lists) or the next sibling <li>.
586
587
588
589 this._NextNode = block == lastNode ? null : FCKDomTools.GetNextSourceNode( range.EndNode, true, null, lastNode ) ;
590
591 return block ;
592
593 }
594
595 }
596
597
598
599 if ( removePreviousBr )
600
601 {
602
603 var previousSibling = block.previousSibling ;
604
605 if ( previousSibling && previousSibling.nodeType == 1 )
606
607 {
608
609 if ( previousSibling.nodeName.toLowerCase() == 'br' )
610
611 previousSibling.parentNode.removeChild( previousSibling ) ;
612
613 else if ( previousSibling.lastChild && previousSibling.lastChild.nodeName.IEquals( 'br' ) )
614
615 previousSibling.removeChild( previousSibling.lastChild ) ;
616
617 }
618
619 }
620
621
622
623 if ( removeLastBr )
624
625 {
626
627 var lastChild = block.lastChild ;
628
629 if ( lastChild && lastChild.nodeType == 1 && lastChild.nodeName.toLowerCase() == 'br' )
630
631 block.removeChild( lastChild ) ;
632
633 }
634
635
636
637 // Get a reference for the next element. This is important because the
638
639 // above block can be removed or changed, so we can rely on it for the
640
641 // next interation.
642
643 if ( !this._NextNode )
644
645 this._NextNode = ( isLast || block == lastNode ) ? null : FCKDomTools.GetNextSourceNode( block, true, null, lastNode ) ;
646
647
648
649 return block ;
650
651 }
652
653 } ;
654
655