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 | * Defines the FCKXHtml object, responsible for the XHTML operations.
|
---|
22 | */
|
---|
23 |
|
---|
24 | var FCKXHtml = new Object() ;
|
---|
25 |
|
---|
26 | FCKXHtml.CurrentJobNum = 0 ;
|
---|
27 |
|
---|
28 | FCKXHtml.GetXHTML = function( node, includeNode, format )
|
---|
29 | {
|
---|
30 | FCKDomTools.CheckAndRemovePaddingNode( FCKTools.GetElementDocument( node ), FCKConfig.EnterMode ) ;
|
---|
31 | FCKXHtmlEntities.Initialize() ;
|
---|
32 |
|
---|
33 | // Set the correct entity to use for empty blocks.
|
---|
34 | this._NbspEntity = ( FCKConfig.ProcessHTMLEntities? 'nbsp' : '#160' ) ;
|
---|
35 |
|
---|
36 | // Save the current IsDirty state. The XHTML processor may change the
|
---|
37 | // original HTML, dirtying it.
|
---|
38 | var bIsDirty = FCK.IsDirty() ;
|
---|
39 |
|
---|
40 | // Special blocks are blocks of content that remain untouched during the
|
---|
41 | // process. It is used for SCRIPTs and STYLEs.
|
---|
42 | FCKXHtml.SpecialBlocks = new Array() ;
|
---|
43 |
|
---|
44 | // Create the XML DOMDocument object.
|
---|
45 | this.XML = FCKTools.CreateXmlObject( 'DOMDocument' ) ;
|
---|
46 |
|
---|
47 | // Add a root element that holds all child nodes.
|
---|
48 | this.MainNode = this.XML.appendChild( this.XML.createElement( 'xhtml' ) ) ;
|
---|
49 |
|
---|
50 | FCKXHtml.CurrentJobNum++ ;
|
---|
51 |
|
---|
52 | // var dTimer = new Date() ;
|
---|
53 |
|
---|
54 | if ( includeNode )
|
---|
55 | this._AppendNode( this.MainNode, node ) ;
|
---|
56 | else
|
---|
57 | this._AppendChildNodes( this.MainNode, node, false ) ;
|
---|
58 |
|
---|
59 | /**
|
---|
60 | * FCKXHtml._AppendNode() marks DOM element objects it has
|
---|
61 | * processed by adding a property called _fckxhtmljob,
|
---|
62 | * setting it equal to the value of FCKXHtml.CurrentJobNum.
|
---|
63 | * On Internet Explorer, if an element object has such a
|
---|
64 | * property, it will show up in the object's attributes
|
---|
65 | * NamedNodeMap, and the corresponding Attr object in
|
---|
66 | * that collection will have is specified property set
|
---|
67 | * to true. This trips up code elsewhere that checks to
|
---|
68 | * see if an element is free of attributes before proceeding
|
---|
69 | * with an edit operation (c.f. FCK.Style.RemoveFromRange())
|
---|
70 | *
|
---|
71 | * refs #2156 and #2834
|
---|
72 | */
|
---|
73 | if ( FCKBrowserInfo.IsIE )
|
---|
74 | FCKXHtml._RemoveXHtmlJobProperties( node ) ;
|
---|
75 |
|
---|
76 | // Get the resulting XHTML as a string.
|
---|
77 | var sXHTML = this._GetMainXmlString() ;
|
---|
78 |
|
---|
79 | // alert( 'Time: ' + ( ( ( new Date() ) - dTimer ) ) + ' ms' ) ;
|
---|
80 |
|
---|
81 | this.XML = null ;
|
---|
82 |
|
---|
83 | // Safari adds xmlns="http://www.w3.org/1999/xhtml" to the root node (#963)
|
---|
84 | if ( FCKBrowserInfo.IsSafari )
|
---|
85 | sXHTML = sXHTML.replace( /^<xhtml.*?>/, '<xhtml>' ) ;
|
---|
86 |
|
---|
87 | // Strip the "XHTML" root node.
|
---|
88 | sXHTML = sXHTML.substr( 7, sXHTML.length - 15 ).Trim() ;
|
---|
89 |
|
---|
90 | // According to the doctype set the proper end for self-closing tags
|
---|
91 | // HTML: <br>
|
---|
92 | // XHTML: Add a space, like <br/> -> <br />
|
---|
93 | if (FCKConfig.DocType.length > 0 && FCKRegexLib.HtmlDocType.test( FCKConfig.DocType ) )
|
---|
94 | sXHTML = sXHTML.replace( FCKRegexLib.SpaceNoClose, '>');
|
---|
95 | else
|
---|
96 | sXHTML = sXHTML.replace( FCKRegexLib.SpaceNoClose, ' />');
|
---|
97 |
|
---|
98 | if ( FCKConfig.ForceSimpleAmpersand )
|
---|
99 | sXHTML = sXHTML.replace( FCKRegexLib.ForceSimpleAmpersand, '&' ) ;
|
---|
100 |
|
---|
101 | if ( format )
|
---|
102 | sXHTML = FCKCodeFormatter.Format( sXHTML ) ;
|
---|
103 |
|
---|
104 | // Now we put back the SpecialBlocks contents.
|
---|
105 | for ( var i = 0 ; i < FCKXHtml.SpecialBlocks.length ; i++ )
|
---|
106 | {
|
---|
107 | var oRegex = new RegExp( '___FCKsi___' + i ) ;
|
---|
108 | sXHTML = sXHTML.replace( oRegex, FCKXHtml.SpecialBlocks[i] ) ;
|
---|
109 | }
|
---|
110 |
|
---|
111 | // Replace entities marker with the ampersand.
|
---|
112 | sXHTML = sXHTML.replace( FCKRegexLib.GeckoEntitiesMarker, '&' ) ;
|
---|
113 |
|
---|
114 | // Restore the IsDirty state if it was not dirty.
|
---|
115 | if ( !bIsDirty )
|
---|
116 | FCK.ResetIsDirty() ;
|
---|
117 |
|
---|
118 | FCKDomTools.EnforcePaddingNode( FCKTools.GetElementDocument( node ), FCKConfig.EnterMode ) ;
|
---|
119 | return sXHTML ;
|
---|
120 | }
|
---|
121 |
|
---|
122 | FCKXHtml._AppendAttribute = function( xmlNode, attributeName, attributeValue )
|
---|
123 | {
|
---|
124 | try
|
---|
125 | {
|
---|
126 | if ( attributeValue == undefined || attributeValue == null )
|
---|
127 | attributeValue = '' ;
|
---|
128 | else if ( attributeValue.replace )
|
---|
129 | {
|
---|
130 | if ( FCKConfig.ForceSimpleAmpersand )
|
---|
131 | attributeValue = attributeValue.replace( /&/g, '___FCKAmp___' ) ;
|
---|
132 |
|
---|
133 | // Entities must be replaced in the attribute values.
|
---|
134 | attributeValue = attributeValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ;
|
---|
135 | }
|
---|
136 |
|
---|
137 | // Create the attribute.
|
---|
138 | var oXmlAtt = this.XML.createAttribute( attributeName ) ;
|
---|
139 | oXmlAtt.value = attributeValue ;
|
---|
140 |
|
---|
141 | // Set the attribute in the node.
|
---|
142 | xmlNode.attributes.setNamedItem( oXmlAtt ) ;
|
---|
143 | }
|
---|
144 | catch (e)
|
---|
145 | {}
|
---|
146 | }
|
---|
147 |
|
---|
148 | FCKXHtml._AppendChildNodes = function( xmlNode, htmlNode, isBlockElement )
|
---|
149 | {
|
---|
150 | var oNode = htmlNode.firstChild ;
|
---|
151 |
|
---|
152 | while ( oNode )
|
---|
153 | {
|
---|
154 | this._AppendNode( xmlNode, oNode ) ;
|
---|
155 | oNode = oNode.nextSibling ;
|
---|
156 | }
|
---|
157 |
|
---|
158 | // Trim block elements. This is also needed to avoid Firefox leaving extra
|
---|
159 | // BRs at the end of them.
|
---|
160 | if ( isBlockElement && htmlNode.tagName && htmlNode.tagName.toLowerCase() != 'pre' )
|
---|
161 | {
|
---|
162 | FCKDomTools.TrimNode( xmlNode ) ;
|
---|
163 |
|
---|
164 | if ( FCKConfig.FillEmptyBlocks )
|
---|
165 | {
|
---|
166 | var lastChild = xmlNode.lastChild ;
|
---|
167 | if ( lastChild && lastChild.nodeType == 1 && lastChild.nodeName == 'br' )
|
---|
168 | this._AppendEntity( xmlNode, this._NbspEntity ) ;
|
---|
169 | }
|
---|
170 | }
|
---|
171 |
|
---|
172 | // If the resulting node is empty.
|
---|
173 | if ( xmlNode.childNodes.length == 0 )
|
---|
174 | {
|
---|
175 | if ( isBlockElement && FCKConfig.FillEmptyBlocks )
|
---|
176 | {
|
---|
177 | this._AppendEntity( xmlNode, this._NbspEntity ) ;
|
---|
178 | return xmlNode ;
|
---|
179 | }
|
---|
180 |
|
---|
181 | var sNodeName = xmlNode.nodeName ;
|
---|
182 |
|
---|
183 | // Some inline elements are required to have something inside (span, strong, etc...).
|
---|
184 | if ( FCKListsLib.InlineChildReqElements[ sNodeName ] )
|
---|
185 | return null ;
|
---|
186 |
|
---|
187 | // We can't use short representation of empty elements that are not marked
|
---|
188 | // as empty in th XHTML DTD.
|
---|
189 | if ( !FCKListsLib.EmptyElements[ sNodeName ] )
|
---|
190 | xmlNode.appendChild( this.XML.createTextNode('') ) ;
|
---|
191 | }
|
---|
192 |
|
---|
193 | return xmlNode ;
|
---|
194 | }
|
---|
195 |
|
---|
196 | FCKXHtml._AppendNode = function( xmlNode, htmlNode )
|
---|
197 | {
|
---|
198 | if ( !htmlNode )
|
---|
199 | return false ;
|
---|
200 |
|
---|
201 | switch ( htmlNode.nodeType )
|
---|
202 | {
|
---|
203 | // Element Node.
|
---|
204 | case 1 :
|
---|
205 | // If we detect a <br> inside a <pre> in Gecko, turn it into a line break instead.
|
---|
206 | // This is a workaround for the Gecko bug here: https://bugzilla.mozilla.org/show_bug.cgi?id=92921
|
---|
207 | if ( FCKBrowserInfo.IsGecko
|
---|
208 | && htmlNode.tagName.toLowerCase() == 'br'
|
---|
209 | && htmlNode.parentNode.tagName.toLowerCase() == 'pre' )
|
---|
210 | {
|
---|
211 | var val = '\r' ;
|
---|
212 | if ( htmlNode == htmlNode.parentNode.firstChild )
|
---|
213 | val += '\r' ;
|
---|
214 | return FCKXHtml._AppendNode( xmlNode, this.XML.createTextNode( val ) ) ;
|
---|
215 | }
|
---|
216 |
|
---|
217 | // Here we found an element that is not the real element, but a
|
---|
218 | // fake one (like the Flash placeholder image), so we must get the real one.
|
---|
219 | if ( htmlNode.getAttribute('_fckfakelement') )
|
---|
220 | return FCKXHtml._AppendNode( xmlNode, FCK.GetRealElement( htmlNode ) ) ;
|
---|
221 |
|
---|
222 | // Ignore bogus BR nodes in the DOM.
|
---|
223 | if ( FCKBrowserInfo.IsGecko &&
|
---|
224 | ( htmlNode.hasAttribute('_moz_editor_bogus_node') || htmlNode.getAttribute( 'type' ) == '_moz' ) )
|
---|
225 | {
|
---|
226 | if ( htmlNode.nextSibling )
|
---|
227 | return false ;
|
---|
228 | else
|
---|
229 | {
|
---|
230 | htmlNode.removeAttribute( '_moz_editor_bogus_node' ) ;
|
---|
231 | htmlNode.removeAttribute( 'type' ) ;
|
---|
232 | }
|
---|
233 | }
|
---|
234 |
|
---|
235 | // This is for elements that are instrumental to FCKeditor and
|
---|
236 | // must be removed from the final HTML.
|
---|
237 | if ( htmlNode.getAttribute('_fcktemp') )
|
---|
238 | return false ;
|
---|
239 |
|
---|
240 | // Get the element name.
|
---|
241 | var sNodeName = htmlNode.tagName.toLowerCase() ;
|
---|
242 |
|
---|
243 | if ( FCKBrowserInfo.IsIE )
|
---|
244 | {
|
---|
245 | // IE doens't include the scope name in the nodeName. So, add the namespace.
|
---|
246 | if ( htmlNode.scopeName && htmlNode.scopeName != 'HTML' && htmlNode.scopeName != 'FCK' )
|
---|
247 | sNodeName = htmlNode.scopeName.toLowerCase() + ':' + sNodeName ;
|
---|
248 | }
|
---|
249 | else
|
---|
250 | {
|
---|
251 | if ( sNodeName.StartsWith( 'fck:' ) )
|
---|
252 | sNodeName = sNodeName.Remove( 0,4 ) ;
|
---|
253 | }
|
---|
254 |
|
---|
255 | // Check if the node name is valid, otherwise ignore this tag.
|
---|
256 | // If the nodeName starts with a slash, it is a orphan closing tag.
|
---|
257 | // On some strange cases, the nodeName is empty, even if the node exists.
|
---|
258 | if ( !FCKRegexLib.ElementName.test( sNodeName ) )
|
---|
259 | return false ;
|
---|
260 |
|
---|
261 | // The already processed nodes must be marked to avoid then to be duplicated (bad formatted HTML).
|
---|
262 | // So here, the "mark" is checked... if the element is Ok, then mark it.
|
---|
263 | if ( htmlNode._fckxhtmljob && htmlNode._fckxhtmljob == FCKXHtml.CurrentJobNum )
|
---|
264 | return false ;
|
---|
265 |
|
---|
266 | var oNode = this.XML.createElement( sNodeName ) ;
|
---|
267 |
|
---|
268 | // Add all attributes.
|
---|
269 | FCKXHtml._AppendAttributes( xmlNode, htmlNode, oNode, sNodeName ) ;
|
---|
270 |
|
---|
271 | htmlNode._fckxhtmljob = FCKXHtml.CurrentJobNum ;
|
---|
272 |
|
---|
273 | // Tag specific processing.
|
---|
274 | var oTagProcessor = FCKXHtml.TagProcessors[ sNodeName ] ;
|
---|
275 |
|
---|
276 | if ( oTagProcessor )
|
---|
277 | oNode = oTagProcessor( oNode, htmlNode, xmlNode ) ;
|
---|
278 | else
|
---|
279 | oNode = this._AppendChildNodes( oNode, htmlNode, Boolean( FCKListsLib.NonEmptyBlockElements[ sNodeName ] ) ) ;
|
---|
280 |
|
---|
281 | if ( !oNode )
|
---|
282 | return false ;
|
---|
283 |
|
---|
284 | xmlNode.appendChild( oNode ) ;
|
---|
285 |
|
---|
286 | break ;
|
---|
287 |
|
---|
288 | // Text Node.
|
---|
289 | case 3 :
|
---|
290 | if ( htmlNode.parentNode && htmlNode.parentNode.nodeName.IEquals( 'pre' ) )
|
---|
291 | return this._AppendTextNode( xmlNode, htmlNode.nodeValue ) ;
|
---|
292 | return this._AppendTextNode( xmlNode, htmlNode.nodeValue.ReplaceNewLineChars(' ') ) ;
|
---|
293 |
|
---|
294 | // Comment
|
---|
295 | case 8 :
|
---|
296 | // IE catches the <!DOTYPE ... > as a comment, but it has no
|
---|
297 | // innerHTML, so we can catch it, and ignore it.
|
---|
298 | if ( FCKBrowserInfo.IsIE && !htmlNode.innerHTML )
|
---|
299 | break ;
|
---|
300 |
|
---|
301 | try { xmlNode.appendChild( this.XML.createComment( htmlNode.nodeValue ) ) ; }
|
---|
302 | catch (e) { /* Do nothing... probably this is a wrong format comment. */ }
|
---|
303 | break ;
|
---|
304 |
|
---|
305 | // Unknown Node type.
|
---|
306 | default :
|
---|
307 | xmlNode.appendChild( this.XML.createComment( "Element not supported - Type: " + htmlNode.nodeType + " Name: " + htmlNode.nodeName ) ) ;
|
---|
308 | break ;
|
---|
309 | }
|
---|
310 | return true ;
|
---|
311 | }
|
---|
312 |
|
---|
313 | // Append an item to the SpecialBlocks array and returns the tag to be used.
|
---|
314 | FCKXHtml._AppendSpecialItem = function( item )
|
---|
315 | {
|
---|
316 | return '___FCKsi___' + ( FCKXHtml.SpecialBlocks.push( item ) - 1 ) ;
|
---|
317 | }
|
---|
318 |
|
---|
319 | FCKXHtml._AppendEntity = function( xmlNode, entity )
|
---|
320 | {
|
---|
321 | xmlNode.appendChild( this.XML.createTextNode( '#?-:' + entity + ';' ) ) ;
|
---|
322 | }
|
---|
323 |
|
---|
324 | FCKXHtml._AppendTextNode = function( targetNode, textValue )
|
---|
325 | {
|
---|
326 | var bHadText = textValue.length > 0 ;
|
---|
327 | if ( bHadText )
|
---|
328 | targetNode.appendChild( this.XML.createTextNode( textValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ) ) ;
|
---|
329 | return bHadText ;
|
---|
330 | }
|
---|
331 |
|
---|
332 | // Retrieves a entity (internal format) for a given character.
|
---|
333 | function FCKXHtml_GetEntity( character )
|
---|
334 | {
|
---|
335 | // We cannot simply place the entities in the text, because the XML parser
|
---|
336 | // will translate & to &. So we use a temporary marker which is replaced
|
---|
337 | // in the end of the processing.
|
---|
338 | var sEntity = FCKXHtmlEntities.Entities[ character ] || ( '#' + character.charCodeAt(0) ) ;
|
---|
339 | return '#?-:' + sEntity + ';' ;
|
---|
340 | }
|
---|
341 |
|
---|
342 | // An object that hold tag specific operations.
|
---|
343 | FCKXHtml.TagProcessors =
|
---|
344 | {
|
---|
345 | a : function( node, htmlNode )
|
---|
346 | {
|
---|
347 | // Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1556878).
|
---|
348 | if ( htmlNode.innerHTML.Trim().length == 0 && !htmlNode.name )
|
---|
349 | return false ;
|
---|
350 |
|
---|
351 | var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
|
---|
352 | if ( sSavedUrl != null )
|
---|
353 | FCKXHtml._AppendAttribute( node, 'href', sSavedUrl ) ;
|
---|
354 |
|
---|
355 |
|
---|
356 | // Anchors with content has been marked with an additional class, now we must remove it.
|
---|
357 | if ( FCKBrowserInfo.IsIE )
|
---|
358 | {
|
---|
359 | // Buggy IE, doesn't copy the name of changed anchors.
|
---|
360 | if ( htmlNode.name )
|
---|
361 | FCKXHtml._AppendAttribute( node, 'name', htmlNode.name ) ;
|
---|
362 | }
|
---|
363 |
|
---|
364 | node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
|
---|
365 |
|
---|
366 | return node ;
|
---|
367 | },
|
---|
368 |
|
---|
369 | area : function( node, htmlNode )
|
---|
370 | {
|
---|
371 | var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
|
---|
372 | if ( sSavedUrl != null )
|
---|
373 | FCKXHtml._AppendAttribute( node, 'href', sSavedUrl ) ;
|
---|
374 |
|
---|
375 | // IE ignores the "COORDS" and "SHAPE" attribute so we must add it manually.
|
---|
376 | if ( FCKBrowserInfo.IsIE )
|
---|
377 | {
|
---|
378 | if ( ! node.attributes.getNamedItem( 'coords' ) )
|
---|
379 | {
|
---|
380 | var sCoords = htmlNode.getAttribute( 'coords', 2 ) ;
|
---|
381 | if ( sCoords && sCoords != '0,0,0' )
|
---|
382 | FCKXHtml._AppendAttribute( node, 'coords', sCoords ) ;
|
---|
383 | }
|
---|
384 |
|
---|
385 | if ( ! node.attributes.getNamedItem( 'shape' ) )
|
---|
386 | {
|
---|
387 | var sShape = htmlNode.getAttribute( 'shape', 2 ) ;
|
---|
388 | if ( sShape && sShape.length > 0 )
|
---|
389 | FCKXHtml._AppendAttribute( node, 'shape', sShape.toLowerCase() ) ;
|
---|
390 | }
|
---|
391 | }
|
---|
392 |
|
---|
393 | return node ;
|
---|
394 | },
|
---|
395 |
|
---|
396 | body : function( node, htmlNode )
|
---|
397 | {
|
---|
398 | node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
|
---|
399 | // Remove spellchecker attributes added for Firefox when converting to HTML code (Bug #1351).
|
---|
400 | node.removeAttribute( 'spellcheck' ) ;
|
---|
401 | return node ;
|
---|
402 | },
|
---|
403 |
|
---|
404 | // IE loses contents of iframes, and Gecko does give it back HtmlEncoded
|
---|
405 | // Note: Opera does lose the content and doesn't provide it in the innerHTML string
|
---|
406 | iframe : function( node, htmlNode )
|
---|
407 | {
|
---|
408 | var sHtml = htmlNode.innerHTML ;
|
---|
409 |
|
---|
410 | // Gecko does give back the encoded html
|
---|
411 | if ( FCKBrowserInfo.IsGecko )
|
---|
412 | sHtml = FCKTools.HTMLDecode( sHtml );
|
---|
413 |
|
---|
414 | // Remove the saved urls here as the data won't be processed as nodes
|
---|
415 | sHtml = sHtml.replace( /\s_fcksavedurl="[^"]*"/g, '' ) ;
|
---|
416 |
|
---|
417 | node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( sHtml ) ) ) ;
|
---|
418 |
|
---|
419 | return node ;
|
---|
420 | },
|
---|
421 |
|
---|
422 | img : function( node, htmlNode )
|
---|
423 | {
|
---|
424 | // The "ALT" attribute is required in XHTML.
|
---|
425 | if ( ! node.attributes.getNamedItem( 'alt' ) )
|
---|
426 | FCKXHtml._AppendAttribute( node, 'alt', '' ) ;
|
---|
427 |
|
---|
428 | var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
|
---|
429 | if ( sSavedUrl != null )
|
---|
430 | FCKXHtml._AppendAttribute( node, 'src', sSavedUrl ) ;
|
---|
431 |
|
---|
432 | // Bug #768 : If the width and height are defined inline CSS,
|
---|
433 | // don't define it again in the HTML attributes.
|
---|
434 | if ( htmlNode.style.width )
|
---|
435 | node.removeAttribute( 'width' ) ;
|
---|
436 | if ( htmlNode.style.height )
|
---|
437 | node.removeAttribute( 'height' ) ;
|
---|
438 |
|
---|
439 | return node ;
|
---|
440 | },
|
---|
441 |
|
---|
442 | // Fix orphaned <li> nodes (Bug #503).
|
---|
443 | li : function( node, htmlNode, targetNode )
|
---|
444 | {
|
---|
445 | // If the XML parent node is already a <ul> or <ol>, then add the <li> as usual.
|
---|
446 | if ( targetNode.nodeName.IEquals( ['ul', 'ol'] ) )
|
---|
447 | return FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
|
---|
448 |
|
---|
449 | var newTarget = FCKXHtml.XML.createElement( 'ul' ) ;
|
---|
450 |
|
---|
451 | // Reset the _fckxhtmljob so the HTML node is processed again.
|
---|
452 | htmlNode._fckxhtmljob = null ;
|
---|
453 |
|
---|
454 | // Loop through all sibling LIs, adding them to the <ul>.
|
---|
455 | do
|
---|
456 | {
|
---|
457 | FCKXHtml._AppendNode( newTarget, htmlNode ) ;
|
---|
458 |
|
---|
459 | // Look for the next element following this <li>.
|
---|
460 | do
|
---|
461 | {
|
---|
462 | htmlNode = FCKDomTools.GetNextSibling( htmlNode ) ;
|
---|
463 |
|
---|
464 | } while ( htmlNode && htmlNode.nodeType == 3 && htmlNode.nodeValue.Trim().length == 0 )
|
---|
465 |
|
---|
466 | } while ( htmlNode && htmlNode.nodeName.toLowerCase() == 'li' )
|
---|
467 |
|
---|
468 | return newTarget ;
|
---|
469 | },
|
---|
470 |
|
---|
471 | // Fix nested <ul> and <ol>.
|
---|
472 | ol : function( node, htmlNode, targetNode )
|
---|
473 | {
|
---|
474 | if ( htmlNode.innerHTML.Trim().length == 0 )
|
---|
475 | return false ;
|
---|
476 |
|
---|
477 | var ePSibling = targetNode.lastChild ;
|
---|
478 |
|
---|
479 | if ( ePSibling && ePSibling.nodeType == 3 )
|
---|
480 | ePSibling = ePSibling.previousSibling ;
|
---|
481 |
|
---|
482 | if ( ePSibling && ePSibling.nodeName.toUpperCase() == 'LI' )
|
---|
483 | {
|
---|
484 | htmlNode._fckxhtmljob = null ;
|
---|
485 | FCKXHtml._AppendNode( ePSibling, htmlNode ) ;
|
---|
486 | return false ;
|
---|
487 | }
|
---|
488 |
|
---|
489 | node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
|
---|
490 |
|
---|
491 | return node ;
|
---|
492 | },
|
---|
493 |
|
---|
494 | pre : function ( node, htmlNode )
|
---|
495 | {
|
---|
496 | var firstChild = htmlNode.firstChild ;
|
---|
497 |
|
---|
498 | if ( firstChild && firstChild.nodeType == 3 )
|
---|
499 | node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( '\r\n' ) ) ) ;
|
---|
500 |
|
---|
501 | FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
|
---|
502 |
|
---|
503 | return node ;
|
---|
504 | },
|
---|
505 |
|
---|
506 | script : function( node, htmlNode )
|
---|
507 | {
|
---|
508 | // The "TYPE" attribute is required in XHTML.
|
---|
509 | if ( ! node.attributes.getNamedItem( 'type' ) )
|
---|
510 | FCKXHtml._AppendAttribute( node, 'type', 'text/javascript' ) ;
|
---|
511 |
|
---|
512 | node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.text ) ) ) ;
|
---|
513 |
|
---|
514 | return node ;
|
---|
515 | },
|
---|
516 |
|
---|
517 | span : function( node, htmlNode )
|
---|
518 | {
|
---|
519 | // Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1084404).
|
---|
520 | if ( htmlNode.innerHTML.length == 0 )
|
---|
521 | return false ;
|
---|
522 |
|
---|
523 | node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
|
---|
524 |
|
---|
525 | return node ;
|
---|
526 | },
|
---|
527 |
|
---|
528 | style : function( node, htmlNode )
|
---|
529 | {
|
---|
530 | // The "TYPE" attribute is required in XHTML.
|
---|
531 | if ( ! node.attributes.getNamedItem( 'type' ) )
|
---|
532 | FCKXHtml._AppendAttribute( node, 'type', 'text/css' ) ;
|
---|
533 |
|
---|
534 | var cssText = htmlNode.innerHTML ;
|
---|
535 | if ( FCKBrowserInfo.IsIE ) // Bug #403 : IE always appends a \r\n to the beginning of StyleNode.innerHTML
|
---|
536 | cssText = cssText.replace( /^(\r\n|\n|\r)/, '' ) ;
|
---|
537 |
|
---|
538 | node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( cssText ) ) ) ;
|
---|
539 |
|
---|
540 | return node ;
|
---|
541 | },
|
---|
542 |
|
---|
543 | title : function( node, htmlNode )
|
---|
544 | {
|
---|
545 | node.appendChild( FCKXHtml.XML.createTextNode( FCK.EditorDocument.title ) ) ;
|
---|
546 |
|
---|
547 | return node ;
|
---|
548 | }
|
---|
549 | } ;
|
---|
550 |
|
---|
551 | FCKXHtml.TagProcessors.ul = FCKXHtml.TagProcessors.ol ;
|
---|