PluginProbe
Wp-Insert / 1.2.1
Wp-Insert v1.2.1
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.1, at fckeditor/editor/_source/classes/fckdomrangeiterator.js

328 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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
28 var 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
49 FCKDomRangeIterator.CreateFromSelection = function( targetWindow )
50 {
51 var range = new FCKDomRange( targetWindow ) ;
52 range.MoveToSelection() ;
53 return new FCKDomRangeIterator( range ) ;
54 }
55
56 FCKDomRangeIterator.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 } ;
328