PluginProbe
Wp-Insert / 1.7.2
Wp-Insert v1.7.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 / internals / fckxhtml.js

fckxhtml.js in Wp-Insert 1.7.2, at fckeditor/editor/_source/internals/fckxhtml.js

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