fckxhtml.js
上传用户:li2971742
上传日期:2021-11-18
资源大小:39096k
文件大小:11k
源码类别:

OA系统

开发平台:

C#

  1. /*
  2.  * FCKeditor - The text editor for internet
  3.  * Copyright (C) 2003-2006 Frederico Caldeira Knabben
  4.  * 
  5.  * Licensed under the terms of the GNU Lesser General Public License:
  6.  *  http://www.opensource.org/licenses/lgpl-license.php
  7.  * 
  8.  * For further information visit:
  9.  *  http://www.fckeditor.net/
  10.  * 
  11.  * "Support Open Source software. What about a donation today?"
  12.  * 
  13.  * File Name: fckxhtml.js
  14.  *  Defines the FCKXHtml object, responsible for the XHTML operations.
  15.  * 
  16.  * File Authors:
  17.  *  Frederico Caldeira Knabben (fredck@fckeditor.net)
  18.  */
  19. var FCKXHtml = new Object() ;
  20. FCKXHtml.CurrentJobNum = 0 ;
  21. FCKXHtml.GetXHTML = function( node, includeNode, format )
  22. {
  23. FCKXHtmlEntities.Initialize() ;
  24. // Save the current IsDirty state. The XHTML processor may change the
  25. // original HTML, dirtying it.
  26. var bIsDirty = FCK.IsDirty() ;
  27. this._CreateNode = FCKConfig.ForceStrongEm ? FCKXHtml_CreateNode_StrongEm : FCKXHtml_CreateNode_Normal ;
  28. // Special blocks are blocks of content that remain untouched during the
  29. // process. It is used for SCRIPTs and STYLEs.
  30. FCKXHtml.SpecialBlocks = new Array() ;
  31. // Create the XML DOMDocument object.
  32. this.XML = FCKTools.CreateXmlObject( 'DOMDocument' ) ;
  33. // Add a root element that holds all child nodes.
  34. this.MainNode = this.XML.appendChild( this.XML.createElement( 'xhtml' ) ) ;
  35. FCKXHtml.CurrentJobNum++ ;
  36. if ( includeNode )
  37. this._AppendNode( this.MainNode, node ) ;
  38. else
  39. this._AppendChildNodes( this.MainNode, node, false ) ;
  40. // Get the resulting XHTML as a string.
  41. var sXHTML = this._GetMainXmlString() ;
  42. this.XML = null ;
  43. // Strip the "XHTML" root node.
  44. sXHTML = sXHTML.substr( 7, sXHTML.length - 15 ).trim() ;
  45. // Remove the trailing <br> added by Gecko.
  46. if ( FCKBrowserInfo.IsGecko )
  47. sXHTML = sXHTML.replace( /<br/>$/, '' ) ;
  48. // Add a space in the tags with no closing tags, like <br/> -> <br />
  49. sXHTML = sXHTML.replace( FCKRegexLib.SpaceNoClose, ' />');
  50. if ( FCKConfig.ForceSimpleAmpersand )
  51. sXHTML = sXHTML.replace( FCKRegexLib.ForceSimpleAmpersand, '&' ) ;
  52. if ( format )
  53. sXHTML = FCKCodeFormatter.Format( sXHTML ) ;
  54. // Now we put back the SpecialBlocks contents.
  55. for ( var i = 0 ; i < FCKXHtml.SpecialBlocks.length ; i++ )
  56. {
  57. var oRegex = new RegExp( '___FCKsi___' + i ) ;
  58. sXHTML = sXHTML.replace( oRegex, FCKXHtml.SpecialBlocks[i] ) ;
  59. }
  60. // Replace entities marker with the ampersand.
  61. sXHTML = sXHTML.replace( FCKRegexLib.GeckoEntitiesMarker, '&' ) ;
  62. // Restore the IsDirty state if it was not dirty.
  63. if ( !bIsDirty )
  64. FCK.ResetIsDirty() ;
  65. return sXHTML
  66. }
  67. FCKXHtml._AppendAttribute = function( xmlNode, attributeName, attributeValue )
  68. {
  69. if ( FCKConfig.ForceSimpleAmpersand && attributeValue.replace )
  70. attributeValue = attributeValue.replace( /&/g, '___FCKAmp___' ) ;
  71. try
  72. {
  73. // Create the attribute.
  74. var oXmlAtt = this.XML.createAttribute( attributeName ) ;
  75. oXmlAtt.value = attributeValue ? attributeValue : '' ;
  76. // Set the attribute in the node.
  77. xmlNode.attributes.setNamedItem( oXmlAtt ) ;
  78. }
  79. catch (e)
  80. {}
  81. }
  82. FCKXHtml._AppendChildNodes = function( xmlNode, htmlNode, isBlockElement )
  83. {
  84. var iCount = 0 ;
  85. var oNode = htmlNode.firstChild ;
  86. while ( oNode )
  87. {
  88. if ( this._AppendNode( xmlNode, oNode ) )
  89. iCount++ ;
  90. oNode = oNode.nextSibling ;
  91. }
  92. if ( iCount == 0 )
  93. {
  94. if ( isBlockElement && FCKConfig.FillEmptyBlocks )
  95. {
  96. this._AppendEntity( xmlNode, 'nbsp' ) ;
  97. return ;
  98. }
  99. // We can't use short representation of empty elements that are not marked
  100. // as empty in th XHTML DTD.
  101. if ( !FCKRegexLib.EmptyElements.test( htmlNode.nodeName ) )
  102. xmlNode.appendChild( this.XML.createTextNode('') ) ;
  103. }
  104. }
  105. FCKXHtml._AppendNode = function( xmlNode, htmlNode )
  106. {
  107. if ( !htmlNode )
  108. return ;
  109. switch ( htmlNode.nodeType )
  110. {
  111. // Element Node.
  112. case 1 :
  113. // Here we found an element that is not the real element, but a 
  114. // fake one (like the Flash placeholder image), so we must get the real one.
  115. if ( htmlNode.getAttribute('_fckfakelement') )
  116. return FCKXHtml._AppendNode( xmlNode, FCK.GetRealElement( htmlNode ) ) ;
  117. // Mozilla insert custom nodes in the DOM.
  118. if ( FCKBrowserInfo.IsGecko && htmlNode.hasAttribute('_moz_editor_bogus_node') )
  119. return false ;
  120. // This is for elements that are instrumental to FCKeditor and 
  121. // must be removed from the final HTML.
  122. if ( htmlNode.getAttribute('_fcktemp') )
  123. return false ;
  124. // Get the element name.
  125. var sNodeName = htmlNode.nodeName ;
  126. //Add namespace:
  127. if ( FCKBrowserInfo.IsIE && htmlNode.scopeName && htmlNode.scopeName != 'HTML' && htmlNode.scopeName != 'FCK' )
  128. sNodeName = htmlNode.scopeName + ':' + sNodeName ;
  129. // Check if the node name is valid, otherwise ignore this tag.
  130. // If the nodeName starts with a slash, it is a orphan closing tag.
  131. // On some strange cases, the nodeName is empty, even if the node exists.
  132. if ( !FCKRegexLib.ElementName.test( sNodeName ) )
  133. return false ;
  134. sNodeName = sNodeName.toLowerCase() ;
  135. if ( FCKBrowserInfo.IsGecko && sNodeName == 'br' && htmlNode.hasAttribute('type') && htmlNode.getAttribute( 'type', 2 ) == '_moz' )
  136. return false ;
  137. // The already processed nodes must be marked to avoid then to be duplicated (bad formatted HTML).
  138. // So here, the "mark" is checked... if the element is Ok, then mark it.
  139. if ( htmlNode._fckxhtmljob && htmlNode._fckxhtmljob == FCKXHtml.CurrentJobNum )
  140. return false ;
  141. var oNode = this._CreateNode( sNodeName ) ;
  142. // Add all attributes.
  143. FCKXHtml._AppendAttributes( xmlNode, htmlNode, oNode, sNodeName ) ;
  144. htmlNode._fckxhtmljob = FCKXHtml.CurrentJobNum ;
  145. // Tag specific processing.
  146. var oTagProcessor = FCKXHtml.TagProcessors[ sNodeName ] ;
  147. if ( oTagProcessor )
  148. {
  149. oNode = oTagProcessor( oNode, htmlNode, xmlNode ) ;
  150. if ( !oNode ) break ;
  151. }
  152. else
  153. this._AppendChildNodes( oNode, htmlNode, FCKRegexLib.BlockElements.test( sNodeName ) ) ;
  154. xmlNode.appendChild( oNode ) ;
  155. break ;
  156. // Text Node.
  157. case 3 :
  158. this._AppendTextNode( xmlNode, htmlNode.nodeValue.replaceNewLineChars(' ') ) ;
  159. break ;
  160. // Comment
  161. case 8 :
  162. // IE catches the <!DOTYPE ... > as a comment, but it has no
  163. // innerHTML, so we can catch it, and ignore it.
  164. if ( FCKBrowserInfo.IsIE && !htmlNode.innerHTML )
  165. break ;
  166. try { xmlNode.appendChild( this.XML.createComment( htmlNode.nodeValue ) ) ; }
  167. catch (e) { /* Do nothing... probably this is a wrong format comment. */ }
  168. break ;
  169. // Unknown Node type.
  170. default :
  171. xmlNode.appendChild( this.XML.createComment( "Element not supported - Type: " + htmlNode.nodeType + " Name: " + htmlNode.nodeName ) ) ;
  172. break ;
  173. }
  174. return true ;
  175. }
  176. function FCKXHtml_CreateNode_StrongEm( nodeName )
  177. {
  178. switch ( nodeName )
  179. {
  180. case 'b' :
  181. nodeName = 'strong' ;
  182. break ;
  183. case 'i' :
  184. nodeName = 'em' ;
  185. break ;
  186. }
  187. return this.XML.createElement( nodeName ) ;
  188. }
  189. function FCKXHtml_CreateNode_Normal( nodeName )
  190. {
  191. return this.XML.createElement( nodeName ) ;
  192. }
  193. // Append an item to the SpecialBlocks array and returns the tag to be used.
  194. FCKXHtml._AppendSpecialItem = function( item )
  195. {
  196. return '___FCKsi___' + FCKXHtml.SpecialBlocks.AddItem( item ) ;
  197. }
  198. FCKXHtml._AppendEntity = function( xmlNode, entity )
  199. {
  200. xmlNode.appendChild( this.XML.createTextNode( '#?-:' + entity + ';' ) ) ;
  201. }
  202. FCKXHtml._AppendTextNode = function( targetNode, textValue )
  203. {
  204. targetNode.appendChild( this.XML.createTextNode( textValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ) ) ;
  205. return ;
  206. }
  207. // Retrieves a entity (internal format) for a given character.
  208. function FCKXHtml_GetEntity( character )
  209. {
  210. // We cannot simply place the entities in the text, because the XML parser
  211. // will translate & to &amp;. So we use a temporary marker which is replaced
  212. // in the end of the processing.
  213. var sEntity = FCKXHtmlEntities.Entities[ character ] || ( '#' + character.charCodeAt(0) ) ;
  214. return '#?-:' + sEntity + ';' ;
  215. }
  216. // An object that hold tag specific operations.
  217. FCKXHtml.TagProcessors = new Object() ;
  218. FCKXHtml.TagProcessors['img'] = function( node, htmlNode )
  219. {
  220. // The "ALT" attribute is required in XHTML.
  221. if ( ! node.attributes.getNamedItem( 'alt' ) )
  222. FCKXHtml._AppendAttribute( node, 'alt', '' ) ;
  223. var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
  224. if ( sSavedUrl != null )
  225. FCKXHtml._AppendAttribute( node, 'src', sSavedUrl ) ;
  226. return node ;
  227. }
  228. FCKXHtml.TagProcessors['a'] = function( node, htmlNode )
  229. {
  230. var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
  231. if ( sSavedUrl != null )
  232. FCKXHtml._AppendAttribute( node, 'href', sSavedUrl ) ;
  233. FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
  234. // Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1556878).
  235. if ( node.childNodes.length == 0 && !node.getAttribute( 'name' ) )
  236. return false ;
  237. return node ;
  238. }
  239. FCKXHtml.TagProcessors['script'] = function( node, htmlNode )
  240. {
  241. // The "TYPE" attribute is required in XHTML.
  242. if ( ! node.attributes.getNamedItem( 'type' ) )
  243. FCKXHtml._AppendAttribute( node, 'type', 'text/javascript' ) ;
  244. node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.text ) ) ) ;
  245. return node ;
  246. }
  247. FCKXHtml.TagProcessors['style'] = function( node, htmlNode )
  248. {
  249. // The "TYPE" attribute is required in XHTML.
  250. if ( ! node.attributes.getNamedItem( 'type' ) )
  251. FCKXHtml._AppendAttribute( node, 'type', 'text/css' ) ;
  252. node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.innerHTML ) ) ) ;
  253. return node ;
  254. }
  255. FCKXHtml.TagProcessors['title'] = function( node, htmlNode )
  256. {
  257. node.appendChild( FCKXHtml.XML.createTextNode( FCK.EditorDocument.title ) ) ;
  258. return node ;
  259. }
  260. FCKXHtml.TagProcessors['table'] = function( node, htmlNode )
  261. {
  262. // There is a trick to show table borders when border=0. We add to the
  263. // table class the FCK__ShowTableBorders rule. So now we must remove it.
  264. var oClassAtt = node.attributes.getNamedItem( 'class' ) ;
  265. if ( oClassAtt && FCKRegexLib.TableBorderClass.test( oClassAtt.nodeValue ) )
  266. {
  267. var sClass = oClassAtt.nodeValue.replace( FCKRegexLib.TableBorderClass, '' ) ;
  268. if ( sClass.length == 0 )
  269. node.attributes.removeNamedItem( 'class' ) ;
  270. else
  271. FCKXHtml._AppendAttribute( node, 'class', sClass ) ;
  272. }
  273. FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
  274. return node ;
  275. }
  276. // Fix nested <ul> and <ol>.
  277. FCKXHtml.TagProcessors['ol'] = FCKXHtml.TagProcessors['ul'] = function( node, htmlNode, targetNode )
  278. {
  279. if ( htmlNode.innerHTML.trim().length == 0 )
  280. return ;
  281. var ePSibling = targetNode.lastChild ;
  282. if ( ePSibling && ePSibling.nodeType == 3 )
  283. ePSibling = ePSibling.previousSibling ;
  284. if ( ePSibling && ePSibling.nodeName.toUpperCase() == 'LI' )
  285. {
  286. htmlNode._fckxhtmljob = null ;
  287. FCKXHtml._AppendNode( ePSibling, htmlNode ) ;
  288. return ;
  289. }
  290. FCKXHtml._AppendChildNodes( node, htmlNode ) ;
  291. return node ;
  292. }
  293. FCKXHtml.TagProcessors['span'] = function( node, htmlNode )
  294. {
  295. // Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1084404).
  296. if ( htmlNode.innerHTML.length == 0 )
  297. return false ;
  298. FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
  299. return node ;
  300. }