fckeditingarea.js
上传用户:ah_jiwei
上传日期:2022-07-24
资源大小:54044k
文件大小:11k
源码类别:

数据库编程

开发平台:

Visual C++

  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.  * FCKEditingArea Class: renders an editable area.
  22.  */
  23. /**
  24.  * @constructor
  25.  * @param {String} targetElement The element that will hold the editing area. Any child element present in the target will be deleted.
  26.  */
  27. var FCKEditingArea = function( targetElement )
  28. {
  29. this.TargetElement = targetElement ;
  30. this.Mode = FCK_EDITMODE_WYSIWYG ;
  31. if ( FCK.IECleanup )
  32. FCK.IECleanup.AddItem( this, FCKEditingArea_Cleanup ) ;
  33. }
  34. /**
  35.  * @param {String} html The complete HTML for the page, including DOCTYPE and the <html> tag.
  36.  */
  37. FCKEditingArea.prototype.Start = function( html, secondCall )
  38. {
  39. var eTargetElement = this.TargetElement ;
  40. var oTargetDocument = FCKTools.GetElementDocument( eTargetElement ) ;
  41. // Remove all child nodes from the target.
  42. var oChild ;
  43. while( ( oChild = eTargetElement.firstChild ) ) // Only one "=".
  44. {
  45. // Set innerHTML = '' to avoid memory leak.
  46. if ( oChild.contentWindow )
  47. oChild.contentWindow.document.body.innerHTML = '' ;
  48. eTargetElement.removeChild( oChild ) ;
  49. }
  50. if ( this.Mode == FCK_EDITMODE_WYSIWYG )
  51. {
  52. // Create the editing area IFRAME.
  53. var oIFrame = this.IFrame = oTargetDocument.createElement( 'iframe' ) ;
  54. // Firefox will render the tables inside the body in Quirks mode if the 
  55. // source of the iframe is set to javascript. see #515
  56. if ( !FCKBrowserInfo.IsGecko )
  57. oIFrame.src = 'javascript:void(0)' ;
  58. oIFrame.frameBorder = 0 ;
  59. oIFrame.width = oIFrame.height = '100%' ;
  60. // Append the new IFRAME to the target.
  61. eTargetElement.appendChild( oIFrame ) ;
  62. // IE has a bug with the <base> tag... it must have a </base> closer,
  63. // otherwise the all successive tags will be set as children nodes of the <base>.
  64. if ( FCKBrowserInfo.IsIE )
  65. html = html.replace( /(<base[^>]*?)s*/?>(?!s*</base>)/gi, '$1></base>' ) ;
  66. else if ( !secondCall )
  67. {
  68. // Gecko moves some tags out of the body to the head, so we must use
  69. // innerHTML to set the body contents (SF BUG 1526154).
  70. // Extract the BODY contents from the html.
  71. var oMatchBefore = html.match( FCKRegexLib.BeforeBody ) ;
  72. var oMatchAfter = html.match( FCKRegexLib.AfterBody ) ;
  73. if ( oMatchBefore && oMatchAfter )
  74. {
  75. var sBody = html.substr( oMatchBefore[1].length,
  76.        html.length - oMatchBefore[1].length - oMatchAfter[1].length ) ; // This is the BODY tag contents.
  77. html =
  78. oMatchBefore[1] + // This is the HTML until the <body...> tag, inclusive.
  79. '&nbsp;' +
  80. oMatchAfter[1] ; // This is the HTML from the </body> tag, inclusive.
  81. // If nothing in the body, place a BOGUS tag so the cursor will appear.
  82. if ( FCKBrowserInfo.IsGecko && ( sBody.length == 0 || FCKRegexLib.EmptyParagraph.test( sBody ) ) )
  83. sBody = '<br type="_moz">' ;
  84. this._BodyHTML = sBody ;
  85. }
  86. else
  87. this._BodyHTML = html ; // Invalid HTML input.
  88. }
  89. // Get the window and document objects used to interact with the newly created IFRAME.
  90. this.Window = oIFrame.contentWindow ;
  91. // IE: Avoid JavaScript errors thrown by the editing are source (like tags events).
  92. // TODO: This error handler is not being fired.
  93. // this.Window.onerror = function() { alert( 'Error!' ) ; return true ; }
  94. var oDoc = this.Document = this.Window.document ;
  95. oDoc.open() ;
  96. oDoc.write( html ) ;
  97. oDoc.close() ;
  98. // Firefox 1.0.x is buggy... ohh yes... so let's do it two times and it
  99. // will magically work.
  100. if ( FCKBrowserInfo.IsGecko10 && !secondCall )
  101. {
  102. this.Start( html, true ) ;
  103. return ;
  104. }
  105. this.Window._FCKEditingArea = this ;
  106. // FF 1.0.x is buggy... we must wait a lot to enable editing because
  107. // sometimes the content simply disappears, for example when pasting
  108. // "bla1!<img src='some_url'>!bla2" in the source and then switching
  109. // back to design.
  110. if ( FCKBrowserInfo.IsGecko10 )
  111. this.Window.setTimeout( FCKEditingArea_CompleteStart, 500 ) ;
  112. else
  113. FCKEditingArea_CompleteStart.call( this.Window ) ;
  114. }
  115. else
  116. {
  117. var eTextarea = this.Textarea = oTargetDocument.createElement( 'textarea' ) ;
  118. eTextarea.className = 'SourceField' ;
  119. eTextarea.dir = 'ltr' ;
  120. FCKDomTools.SetElementStyles( eTextarea, 
  121. width : '100%', 
  122. height : '100%', 
  123. border : 'none', 
  124. resize : 'none',
  125. outline : 'none'
  126. } ) ;
  127. eTargetElement.appendChild( eTextarea ) ;
  128. eTextarea.value = html  ;
  129. // Fire the "OnLoad" event.
  130. FCKTools.RunFunction( this.OnLoad ) ;
  131. }
  132. }
  133. // "this" here is FCKEditingArea.Window
  134. function FCKEditingArea_CompleteStart()
  135. {
  136. // On Firefox, the DOM takes a little to become available. So we must wait for it in a loop.
  137. if ( !this.document.body )
  138. {
  139. this.setTimeout( FCKEditingArea_CompleteStart, 50 ) ;
  140. return ;
  141. }
  142. var oEditorArea = this._FCKEditingArea ;
  143. oEditorArea.MakeEditable() ;
  144. // Fire the "OnLoad" event.
  145. FCKTools.RunFunction( oEditorArea.OnLoad ) ;
  146. }
  147. FCKEditingArea.prototype.MakeEditable = function()
  148. {
  149. var oDoc = this.Document ;
  150. if ( FCKBrowserInfo.IsIE )
  151. {
  152. // Kludge for #141 and #523
  153. oDoc.body.disabled = true ;
  154. oDoc.body.contentEditable = true ;
  155. oDoc.body.removeAttribute( "disabled" ) ;
  156. /* The following commands don't throw errors, but have no effect.
  157. oDoc.execCommand( 'AutoDetect', false, false ) ;
  158. oDoc.execCommand( 'KeepSelection', false, true ) ;
  159. */
  160. }
  161. else
  162. {
  163. try
  164. {
  165. // Disable Firefox 2 Spell Checker.
  166. oDoc.body.spellcheck = ( this.FFSpellChecker !== false ) ;
  167. if ( this._BodyHTML )
  168. {
  169. oDoc.body.innerHTML = this._BodyHTML ;
  170. this._BodyHTML = null ;
  171. }
  172. oDoc.designMode = 'on' ;
  173. // Tell Gecko to use or not the <SPAN> tag for the bold, italic and underline.
  174. try
  175. {
  176. oDoc.execCommand( 'styleWithCSS', false, FCKConfig.GeckoUseSPAN ) ;
  177. }
  178. catch (e)
  179. {
  180. // As evidenced here, useCSS is deprecated in favor of styleWithCSS:
  181. // http://www.mozilla.org/editor/midas-spec.html
  182. oDoc.execCommand( 'useCSS', false, !FCKConfig.GeckoUseSPAN ) ;
  183. }
  184. // Analyzing Firefox 1.5 source code, it seams that there is support for a
  185. // "insertBrOnReturn" command. Applying it gives no error, but it doesn't
  186. // gives the same behavior that you have with IE. It works only if you are
  187. // already inside a paragraph and it doesn't render correctly in the first enter.
  188. // oDoc.execCommand( 'insertBrOnReturn', false, false ) ;
  189. // Tell Gecko (Firefox 1.5+) to enable or not live resizing of objects (by Alfonso Martinez)
  190. oDoc.execCommand( 'enableObjectResizing', false, !FCKConfig.DisableObjectResizing ) ;
  191. // Disable the standard table editing features of Firefox.
  192. oDoc.execCommand( 'enableInlineTableEditing', false, !FCKConfig.DisableFFTableHandles ) ;
  193. }
  194. catch (e) 
  195. {
  196. // In Firefox if the iframe is initially hidden it can't be set to designMode and it raises an exception
  197. // So we set up a DOM Mutation event Listener on the HTML, as it will raise several events when the document is  visible again
  198. FCKTools.AddEventListener( this.Window.frameElement, 'DOMAttrModified', FCKEditingArea_Document_AttributeNodeModified ) ;
  199. }
  200. }
  201. }
  202. // This function processes the notifications of the DOM Mutation event on the document
  203. // We use it to know that the document will be ready to be editable again (or we hope so)
  204. function FCKEditingArea_Document_AttributeNodeModified( evt )
  205. {
  206. var editingArea = evt.currentTarget.contentWindow._FCKEditingArea ;
  207. // We want to run our function after the events no longer fire, so we can know that it's a stable situation
  208. if ( editingArea._timer )
  209. window.clearTimeout( editingArea._timer ) ;
  210. editingArea._timer = FCKTools.SetTimeout( FCKEditingArea_MakeEditableByMutation, 1000, editingArea ) ;
  211. }
  212. // This function ideally should be called after the document is visible, it does clean up of the
  213. // mutation tracking and tries again to make the area editable.
  214. function FCKEditingArea_MakeEditableByMutation()
  215. {
  216. // Clean up
  217. delete this._timer ;
  218. // Now we don't want to keep on getting this event
  219. FCKTools.RemoveEventListener( this.Window.frameElement, 'DOMAttrModified', FCKEditingArea_Document_AttributeNodeModified ) ;
  220. // Let's try now to set the editing area editable
  221. // If it fails it will set up the Mutation Listener again automatically
  222. this.MakeEditable() ;
  223. }
  224. FCKEditingArea.prototype.Focus = function()
  225. {
  226. try
  227. {
  228. if ( this.Mode == FCK_EDITMODE_WYSIWYG )
  229. {
  230. // The following check is important to avoid IE entering in a focus loop. Ref:
  231. // http://sourceforge.net/tracker/index.php?func=detail&aid=1567060&group_id=75348&atid=543653
  232. if ( FCKBrowserInfo.IsIE && this.Document.hasFocus() )
  233. this._EnsureFocusIE() ;
  234. if ( FCKBrowserInfo.IsSafari )
  235. this.IFrame.focus() ;
  236. else
  237. {
  238. this.Window.focus() ;
  239. // In IE it can happen that the document is in theory focused but the active element is outside it
  240. if ( FCKBrowserInfo.IsIE )
  241. this._EnsureFocusIE() ;
  242. }
  243. }
  244. else
  245. {
  246. var oDoc = FCKTools.GetElementDocument( this.Textarea ) ;
  247. if ( (!oDoc.hasFocus || oDoc.hasFocus() ) && oDoc.activeElement == this.Textarea )
  248. return ;
  249. this.Textarea.focus() ;
  250. }
  251. }
  252. catch(e) {}
  253. }
  254. FCKEditingArea.prototype._EnsureFocusIE = function()
  255. {
  256. // In IE it can happen that the document is in theory focused but the active element is outside it
  257. this.Document.body.setActive() ;
  258. // Kludge for #141... yet more code to workaround IE bugs
  259. var range = this.Document.selection.createRange() ;
  260. // Only apply the fix when in a block and the block is empty.
  261. var parentNode = range.parentElement() ;
  262. if ( ! ( parentNode.childNodes.length == 0 && ( 
  263. FCKListsLib.BlockElements[parentNode.nodeName.toLowerCase()] || 
  264. FCKListsLib.NonEmptyBlockElements[parentNode.nodeName.toLowerCase()] ) ) )
  265. return ;
  266. var oldLength = range.text.length ;
  267. range.moveEnd( "character", 1 ) ;
  268. range.select() ;
  269. if ( range.text.length > oldLength )
  270. {
  271. range.moveEnd( "character", -1 ) ;
  272. range.select() ;
  273. }
  274. }
  275. function FCKEditingArea_Cleanup()
  276. {
  277. if ( this.Document )
  278. this.Document.body.innerHTML = "" ;
  279. this.TargetElement = null ;
  280. this.IFrame = null ;
  281. this.Document = null ;
  282. this.Textarea = null ;
  283. if ( this.Window )
  284. {
  285. this.Window._FCKEditingArea = null ;
  286. this.Window = null ;
  287. }
  288. }