[ Index ] |
|
Code source de FCKeditor 2.4 |
1 /* 2 * FCKeditor - The text editor for Internet - http://www.fckeditor.net 3 * Copyright (C) 2003-2007 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 * File Name: fckxhtml.js 22 * Defines the FCKXHtml object, responsible for the XHTML operations. 23 * 24 * File Authors: 25 * Frederico Caldeira Knabben (www.fckeditor.net) 26 * Alfonso Martinez de Lizarrondo - Uritec (alfonso at uritec dot net) 27 */ 28 29 var FCKXHtml = new Object() ; 30 31 FCKXHtml.CurrentJobNum = 0 ; 32 33 FCKXHtml.GetXHTML = function( node, includeNode, format ) 34 { 35 FCKXHtmlEntities.Initialize() ; 36 37 // Save the current IsDirty state. The XHTML processor may change the 38 // original HTML, dirtying it. 39 var bIsDirty = FCK.IsDirty() ; 40 41 this._CreateNode = FCKConfig.ForceStrongEm ? FCKXHtml_CreateNode_StrongEm : FCKXHtml_CreateNode_Normal ; 42 43 // Special blocks are blocks of content that remain untouched during the 44 // process. It is used for SCRIPTs and STYLEs. 45 FCKXHtml.SpecialBlocks = new Array() ; 46 47 // Create the XML DOMDocument object. 48 this.XML = FCKTools.CreateXmlObject( 'DOMDocument' ) ; 49 50 // Add a root element that holds all child nodes. 51 this.MainNode = this.XML.appendChild( this.XML.createElement( 'xhtml' ) ) ; 52 53 FCKXHtml.CurrentJobNum++ ; 54 55 if ( includeNode ) 56 this._AppendNode( this.MainNode, node ) ; 57 else 58 this._AppendChildNodes( this.MainNode, node, false ) ; 59 60 // Get the resulting XHTML as a string. 61 var sXHTML = this._GetMainXmlString() ; 62 63 this.XML = null ; 64 65 // Strip the "XHTML" root node. 66 sXHTML = sXHTML.substr( 7, sXHTML.length - 15 ).Trim() ; 67 68 // Remove the trailing <br> added by Gecko. 69 // REMOVE: Maybe the following is not anymore necessary because a similar 70 // check is made on _AppendNode 71 if ( FCKBrowserInfo.IsGecko ) 72 sXHTML = sXHTML.replace( /<br\/>$/, '' ) ; 73 74 // Add a space in the tags with no closing tags, like <br/> -> <br /> 75 sXHTML = sXHTML.replace( FCKRegexLib.SpaceNoClose, ' />'); 76 77 if ( FCKConfig.ForceSimpleAmpersand ) 78 sXHTML = sXHTML.replace( FCKRegexLib.ForceSimpleAmpersand, '&' ) ; 79 80 if ( format ) 81 sXHTML = FCKCodeFormatter.Format( sXHTML ) ; 82 83 // Now we put back the SpecialBlocks contents. 84 for ( var i = 0 ; i < FCKXHtml.SpecialBlocks.length ; i++ ) 85 { 86 var oRegex = new RegExp( '___FCKsi___' + i ) ; 87 sXHTML = sXHTML.replace( oRegex, FCKXHtml.SpecialBlocks[i] ) ; 88 } 89 90 // Replace entities marker with the ampersand. 91 sXHTML = sXHTML.replace( FCKRegexLib.GeckoEntitiesMarker, '&' ) ; 92 93 // Restore the IsDirty state if it was not dirty. 94 if ( !bIsDirty ) 95 FCK.ResetIsDirty() ; 96 97 return sXHTML ; 98 } 99 100 FCKXHtml._AppendAttribute = function( xmlNode, attributeName, attributeValue ) 101 { 102 try 103 { 104 if ( attributeValue == undefined || attributeValue == null ) 105 attributeValue = '' ; 106 else if ( attributeValue.replace ) 107 { 108 if ( FCKConfig.ForceSimpleAmpersand ) 109 attributeValue = attributeValue.replace( /&/g, '___FCKAmp___' ) ; 110 111 // Entities must be replaced in the attribute values. 112 attributeValue = attributeValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ; 113 } 114 115 // Create the attribute. 116 var oXmlAtt = this.XML.createAttribute( attributeName ) ; 117 oXmlAtt.value = attributeValue ; 118 119 // Set the attribute in the node. 120 xmlNode.attributes.setNamedItem( oXmlAtt ) ; 121 } 122 catch (e) 123 {} 124 } 125 126 FCKXHtml._AppendChildNodes = function( xmlNode, htmlNode, isBlockElement ) 127 { 128 // Trim block elements. This is also needed to avoid Firefox leaving extra 129 // BRs at the end of them (check made inside _AppendNode). 130 if ( isBlockElement ) 131 FCKDomTools.TrimNode( htmlNode ) ; 132 133 var iCount = 0 ; 134 135 var oNode = htmlNode.firstChild ; 136 137 while ( oNode ) 138 { 139 if ( this._AppendNode( xmlNode, oNode ) ) 140 iCount++ ; 141 142 oNode = oNode.nextSibling ; 143 } 144 145 if ( iCount == 0 ) 146 { 147 if ( isBlockElement && FCKConfig.FillEmptyBlocks ) 148 { 149 this._AppendEntity( xmlNode, 'nbsp' ) ; 150 return xmlNode ; 151 } 152 153 var sNodeName = xmlNode.nodeName ; 154 155 // Some inline elements are required to have something inside (span, strong, etc...). 156 if ( FCKListsLib.InlineChildReqElements[ sNodeName ] ) 157 return null ; 158 159 // We can't use short representation of empty elements that are not marked 160 // as empty in th XHTML DTD. 161 if ( !FCKListsLib.EmptyElements[ sNodeName ] ) 162 xmlNode.appendChild( this.XML.createTextNode('') ) ; 163 } 164 165 return xmlNode ; 166 } 167 168 FCKXHtml._AppendNode = function( xmlNode, htmlNode ) 169 { 170 if ( !htmlNode ) 171 return false ; 172 173 switch ( htmlNode.nodeType ) 174 { 175 // Element Node. 176 case 1 : 177 178 // Here we found an element that is not the real element, but a 179 // fake one (like the Flash placeholder image), so we must get the real one. 180 if ( htmlNode.getAttribute('_fckfakelement') ) 181 return FCKXHtml._AppendNode( xmlNode, FCK.GetRealElement( htmlNode ) ) ; 182 183 // Mozilla insert custom nodes in the DOM. 184 if ( FCKBrowserInfo.IsGecko && htmlNode.hasAttribute('_moz_editor_bogus_node') ) 185 return false ; 186 187 // This is for elements that are instrumental to FCKeditor and 188 // must be removed from the final HTML. 189 if ( htmlNode.getAttribute('_fcktemp') ) 190 return false ; 191 192 // Get the element name. 193 var sNodeName = htmlNode.tagName.toLowerCase() ; 194 195 if ( FCKBrowserInfo.IsIE ) 196 { 197 // IE doens't include the scope name in the nodeName. So, add the namespace. 198 if ( htmlNode.scopeName && htmlNode.scopeName != 'HTML' && htmlNode.scopeName != 'FCK' ) 199 sNodeName = htmlNode.scopeName.toLowerCase() + ':' + sNodeName ; 200 } 201 else 202 { 203 if ( sNodeName.StartsWith( 'fck:' ) ) 204 sNodeName = sNodeName.Remove( 0,4 ) ; 205 } 206 207 // Check if the node name is valid, otherwise ignore this tag. 208 // If the nodeName starts with a slash, it is a orphan closing tag. 209 // On some strange cases, the nodeName is empty, even if the node exists. 210 if ( !FCKRegexLib.ElementName.test( sNodeName ) ) 211 return false ; 212 213 // Remove the <br> if it is a bogus node or is the last child. 214 if ( sNodeName == 'br' && ( htmlNode.getAttribute( 'type', 2 ) == '_moz' || !htmlNode.nextSibling ) ) 215 return false ; 216 217 // The already processed nodes must be marked to avoid then to be duplicated (bad formatted HTML). 218 // So here, the "mark" is checked... if the element is Ok, then mark it. 219 if ( htmlNode._fckxhtmljob && htmlNode._fckxhtmljob == FCKXHtml.CurrentJobNum ) 220 return false ; 221 222 var oNode = this._CreateNode( sNodeName ) ; 223 224 // Add all attributes. 225 FCKXHtml._AppendAttributes( xmlNode, htmlNode, oNode, sNodeName ) ; 226 227 htmlNode._fckxhtmljob = FCKXHtml.CurrentJobNum ; 228 229 // Tag specific processing. 230 var oTagProcessor = FCKXHtml.TagProcessors[ sNodeName ] ; 231 232 if ( oTagProcessor ) 233 oNode = oTagProcessor( oNode, htmlNode, xmlNode ) ; 234 else 235 oNode = this._AppendChildNodes( oNode, htmlNode, Boolean( FCKListsLib.NonEmptyBlockElements[ sNodeName ] ) ) ; 236 237 if ( !oNode ) 238 break ; 239 240 xmlNode.appendChild( oNode ) ; 241 242 break ; 243 244 // Text Node. 245 case 3 : 246 return this._AppendTextNode( xmlNode, htmlNode.nodeValue.ReplaceNewLineChars(' ') ) ; 247 248 // Comment 249 case 8 : 250 // IE catches the <!DOTYPE ... > as a comment, but it has no 251 // innerHTML, so we can catch it, and ignore it. 252 if ( FCKBrowserInfo.IsIE && !htmlNode.innerHTML ) 253 break ; 254 255 try { xmlNode.appendChild( this.XML.createComment( htmlNode.nodeValue ) ) ; } 256 catch (e) { /* Do nothing... probably this is a wrong format comment. */ } 257 break ; 258 259 // Unknown Node type. 260 default : 261 xmlNode.appendChild( this.XML.createComment( "Element not supported - Type: " + htmlNode.nodeType + " Name: " + htmlNode.nodeName ) ) ; 262 break ; 263 } 264 return true ; 265 } 266 267 function FCKXHtml_CreateNode_StrongEm( nodeName ) 268 { 269 switch ( nodeName ) 270 { 271 case 'b' : 272 nodeName = 'strong' ; 273 break ; 274 case 'i' : 275 nodeName = 'em' ; 276 break ; 277 } 278 return this.XML.createElement( nodeName ) ; 279 } 280 281 function FCKXHtml_CreateNode_Normal( nodeName ) 282 { 283 return this.XML.createElement( nodeName ) ; 284 } 285 286 // Append an item to the SpecialBlocks array and returns the tag to be used. 287 FCKXHtml._AppendSpecialItem = function( item ) 288 { 289 return '___FCKsi___' + FCKXHtml.SpecialBlocks.AddItem( item ) ; 290 } 291 292 FCKXHtml._AppendEntity = function( xmlNode, entity ) 293 { 294 xmlNode.appendChild( this.XML.createTextNode( '#?-:' + entity + ';' ) ) ; 295 } 296 297 FCKXHtml._AppendTextNode = function( targetNode, textValue ) 298 { 299 var bHadText = textValue.length > 0 ; 300 if ( bHadText ) 301 targetNode.appendChild( this.XML.createTextNode( textValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ) ) ; 302 return bHadText ; 303 } 304 305 // Retrieves a entity (internal format) for a given character. 306 function FCKXHtml_GetEntity( character ) 307 { 308 // We cannot simply place the entities in the text, because the XML parser 309 // will translate & to &. So we use a temporary marker which is replaced 310 // in the end of the processing. 311 var sEntity = FCKXHtmlEntities.Entities[ character ] || ( '#' + character.charCodeAt(0) ) ; 312 return '#?-:' + sEntity + ';' ; 313 } 314 315 // Remove part of an attribute from a node according to a regExp 316 FCKXHtml._RemoveAttribute = function( xmlNode, regX, sAttribute ) 317 { 318 var oAtt = xmlNode.attributes.getNamedItem( sAttribute ) ; 319 320 if ( oAtt && regX.test( oAtt.nodeValue ) ) 321 { 322 var sValue = oAtt.nodeValue.replace( regX, '' ) ; 323 324 if ( sValue.length == 0 ) 325 xmlNode.attributes.removeNamedItem( sAttribute ) ; 326 else 327 oAtt.nodeValue = sValue ; 328 } 329 } 330 331 // An object that hold tag specific operations. 332 FCKXHtml.TagProcessors = 333 { 334 img : function( node, htmlNode ) 335 { 336 // The "ALT" attribute is required in XHTML. 337 if ( ! node.attributes.getNamedItem( 'alt' ) ) 338 FCKXHtml._AppendAttribute( node, 'alt', '' ) ; 339 340 var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ; 341 if ( sSavedUrl != null ) 342 FCKXHtml._AppendAttribute( node, 'src', sSavedUrl ) ; 343 344 return node ; 345 }, 346 347 a : function( node, htmlNode ) 348 { 349 // Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1556878). 350 if ( htmlNode.innerHTML.Trim().length == 0 && !htmlNode.name ) 351 return false ; 352 353 var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ; 354 if ( sSavedUrl != null ) 355 FCKXHtml._AppendAttribute( node, 'href', sSavedUrl ) ; 356 357 358 // Anchors with content has been marked with an additional class, now we must remove it. 359 if ( FCKBrowserInfo.IsIE ) 360 { 361 FCKXHtml._RemoveAttribute( node, FCKRegexLib.FCK_Class, 'class' ) ; 362 363 // Buggy IE, doesn't copy the name of changed anchors. 364 if ( htmlNode.name ) 365 FCKXHtml._AppendAttribute( node, 'name', htmlNode.name ) ; 366 } 367 368 FCKXHtml._AppendChildNodes( node, htmlNode, false ) ; 369 370 return node ; 371 }, 372 373 script : function( node, htmlNode ) 374 { 375 // The "TYPE" attribute is required in XHTML. 376 if ( ! node.attributes.getNamedItem( 'type' ) ) 377 FCKXHtml._AppendAttribute( node, 'type', 'text/javascript' ) ; 378 379 node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.text ) ) ) ; 380 381 return node ; 382 }, 383 384 style : function( node, htmlNode ) 385 { 386 // The "TYPE" attribute is required in XHTML. 387 if ( ! node.attributes.getNamedItem( 'type' ) ) 388 FCKXHtml._AppendAttribute( node, 'type', 'text/css' ) ; 389 390 node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.innerHTML ) ) ) ; 391 392 return node ; 393 }, 394 395 title : function( node, htmlNode ) 396 { 397 node.appendChild( FCKXHtml.XML.createTextNode( FCK.EditorDocument.title ) ) ; 398 399 return node ; 400 }, 401 402 table : function( node, htmlNode ) 403 { 404 // There is a trick to show table borders when border=0. We add to the 405 // table class the FCK__ShowTableBorders rule. So now we must remove it. 406 407 if ( FCKBrowserInfo.IsIE ) 408 FCKXHtml._RemoveAttribute( node, FCKRegexLib.FCK_Class, 'class' ) ; 409 410 FCKXHtml._AppendChildNodes( node, htmlNode, false ) ; 411 412 return node ; 413 }, 414 415 // Fix nested <ul> and <ol>. 416 ol : function( node, htmlNode, targetNode ) 417 { 418 if ( htmlNode.innerHTML.Trim().length == 0 ) 419 return false ; 420 421 var ePSibling = targetNode.lastChild ; 422 423 if ( ePSibling && ePSibling.nodeType == 3 ) 424 ePSibling = ePSibling.previousSibling ; 425 426 if ( ePSibling && ePSibling.nodeName.toUpperCase() == 'LI' ) 427 { 428 htmlNode._fckxhtmljob = null ; 429 FCKXHtml._AppendNode( ePSibling, htmlNode ) ; 430 return false ; 431 } 432 433 FCKXHtml._AppendChildNodes( node, htmlNode ) ; 434 435 return node ; 436 }, 437 438 span : function( node, htmlNode ) 439 { 440 // Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1084404). 441 if ( htmlNode.innerHTML.length == 0 ) 442 return false ; 443 444 FCKXHtml._AppendChildNodes( node, htmlNode, false ) ; 445 446 return node ; 447 } 448 } ; 449 450 FCKXHtml.TagProcessors.ul = FCKXHtml.TagProcessors.ol ;
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 15:28:05 2007 | par Balluche grâce à PHPXref 0.7 |