fckplugin.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*
  2. * Dokeos - elearning and course management software
  3. *
  4. * Copyright (c) 2008-2009 Dokeos SPRL
  5. * Copyright (c) 2008-2009 Ivan Tcholakov <ivantcholakov@gmail.com>
  6. *
  7. * License:
  8. * GNU Lesser General Public License, Version 3, 29 June 2007
  9. * by Free Software Foundation, Inc. (http://www.gnu.org/licenses/lgpl.html)
  10. *
  11. * Contact address: Dokeos, rue du Corbeau, 108, B-1030 Brussels, Belgium
  12. * Mail: info@dokeos.com
  13. */
  14. // Loading the ASCIIMathML.js if it is not present yet.
  15. if ( typeof AMprocessNode != 'function' )
  16. {
  17. LoadScript( FCKConfig.ScriptASCIIMathML ) ;
  18. }
  19. // Suppressing the built-in notification message when the browser is incompatible.
  20. notifyIfNoMathML = false ;
  21. // Suppressing parsing AsciiMath formulas at loading.
  22. translateASCIIMath = false ;
  23. // Small font is used in the dialog.
  24. mathfontsize = "1.1em";
  25. // Registering the related command.
  26. FCKCommands.RegisterCommand( 'asciimath', new FCKDialogCommand( FCKLang['DlgAsciiMath'], FCKLang['DlgAsciiMath'], FCKConfig.PluginsPath + 'asciimath/fck_asciimath.html', 800, 550 ) ) ;
  27. // Create the "asciimath" toolbar button.
  28. var oAsciiMathItem = new FCKToolbarButton( 'asciimath', FCKLang['DlgAsciiMath'] ) ;
  29. oAsciiMathItem.IconPath = FCKConfig.PluginsPath + 'asciimath/asciimath.gif' ;
  30. // 'asciimath' is the name used in the Toolbar config.
  31. FCKToolbarItems.RegisterItem( 'asciimath', oAsciiMathItem ) ;
  32. // Context menu support.
  33. FCK.ContextMenu.RegisterListener( {
  34. AddItems : function( menu, tag, tagName )
  35. {
  36. if ( FCKAsciiMath.FindFormulaContainer( tag ) )
  37. {
  38. menu.AddSeparator() ;
  39. menu.AddItem( 'asciimath', FCKLang['DlgAsciiMath'], oAsciiMathItem.IconPath ) ;
  40. }
  41. }}
  42. );
  43. // Double-click support.
  44. FCK.RegisterDoubleClickHandler(
  45. function ( tag )
  46. {
  47. if ( FCKAsciiMath.FindFormulaContainer( tag ) )
  48. {
  49. FCKCommands.GetCommand( 'asciimath' ).Execute() ;
  50. }
  51. }, null
  52. ) ;
  53. // This object implements some AsciiMath related operations.
  54. var FCKAsciiMath = new Object() ;
  55. FCKAsciiMath.GetSearchElementFromSelection = function()
  56. {
  57. var oSelectedContainer = FCK.Selection.GetSelectedElement() ;
  58. if ( ! oSelectedContainer )
  59. {
  60. oSelectedContainer = FCK.Selection.GetBoundaryParentElement( true ) ;
  61. }
  62. return oSelectedContainer ;
  63. }
  64. FCKAsciiMath.IsFormula = function( node )
  65. {
  66. if ( node && node.nodeName && node.nodeName.IEquals( 'span' ) && node.className && node.className.indexOf( 'AM' ) != -1 )
  67. {
  68. return true ;
  69. }
  70. return false ;
  71. }
  72. FCKAsciiMath.FindFormulaContainer = function( node )
  73. {
  74. var current_node = node ;
  75. while ( current_node )
  76. {
  77. if ( !current_node.nodeName )
  78. {
  79. continue ;
  80. }
  81. if ( current_node.nodeName.IEquals( 'body', 'table' ) )
  82. {
  83. break ;
  84. }
  85. if ( FCKAsciiMath.IsFormula( current_node ) )
  86. {
  87. return current_node ;
  88. }
  89. if ( current_node.parentNode )
  90. {
  91. current_node = current_node.parentNode ;
  92. }
  93. else
  94. {
  95. break ;
  96. }
  97. }
  98. return null ;
  99. }
  100. FCKAsciiMath.IsParsed = function( node )
  101. {
  102. return node.getElementsByTagName( 'math' )[0] ? true : false ;
  103. }
  104. FCKAsciiMath.GetFormula = function( node )
  105. {
  106. var result = '' ;
  107. if ( FCKAsciiMath.IsFormula( node ) )
  108. {
  109. if ( FCKAsciiMath.IsParsed( node ) )
  110. {
  111. if ( node.title )
  112. {
  113. result = node.title ;
  114. }
  115. }
  116. else
  117. {
  118. result = node.innerHTML ;
  119. }
  120. }
  121. return result.replace( /`/g, '' ) ;
  122. }
  123. FCKAsciiMath.Delete = function()
  124. {
  125. var oSpanAM = FCKAsciiMath.FindFormulaContainer( FCKAsciiMath.GetSearchElementFromSelection() ) ;
  126. if ( oSpanAM )
  127. {
  128. FCK.Selection.SelectNode( oSpanAM ) ;
  129. }
  130. else
  131. {
  132. return ;
  133. }
  134. if ( FCKBrowserInfo.IsIE )
  135. {
  136. // For IE: Before deletion, we have to move the selection outside the formula
  137. // in order to prevent "Unspecified error".
  138. var span_target = FCK.EditorDocument.createElement( 'span' ) ;
  139. span_target.innerHTML = '&nbsp;' ;
  140. span_target = oSpanAM.parentNode.insertBefore( span_target, oSpanAM ) ;
  141. FCK.Selection.SelectNode( span_target ) ;
  142. }
  143. FCK.Selection.Delete() ;
  144. if ( FCKBrowserInfo.IsIE )
  145. {
  146. FCKUndo.SaveUndoStep() ;
  147. oSpanAM.parentNode.removeChild( oSpanAM ) ;
  148. }
  149. }
  150. var FCKAsciiMathProcessor = FCKDocumentProcessor.AppendNew() ;
  151. FCKAsciiMathProcessor.ProcessDocument = function( document )
  152. {
  153. var spans = FCK.EditorDocument.getElementsByTagName( 'SPAN' ) ;
  154. var span ;
  155. var i = spans.length - 1 ;
  156. while ( i >= 0 && ( span = spans[i--] ) )
  157. {
  158. if ( FCKAsciiMath.IsFormula( span ) && !FCKAsciiMath.IsParsed ( span ) )
  159. {
  160. var clone = span.cloneNode( true ) ;
  161. clone.title = span.innerHTML ;
  162. AMprocessNode( clone, false ) ;
  163. clone.setAttribute( '_fckfakelement', 'true', 0 ) ;
  164. clone.setAttribute( '_fckrealelement', FCKTempBin.AddElement( span ), 0 ) ;
  165. // To disable resizing.
  166. clone.onresizestart = function()
  167. {
  168. FCK.EditorWindow.event.returnValue = false ;
  169. return false ;
  170. }
  171. span.parentNode.insertBefore( clone, span ) ;
  172. span.parentNode.removeChild( span ) ;
  173. }
  174. }
  175. }
  176. FCKAsciiMath.SetListeners = function()
  177. {
  178. if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
  179. {
  180. return ;
  181. }
  182. if ( !FCKBrowserInfo.IsIE )
  183. {
  184. // On Gecko we must do this trick so the user select all the SPAN when clicking on it.
  185. FCK.EditorDocument.addEventListener( 'click', function( e )
  186. {
  187. var formula_container = FCKAsciiMath.FindFormulaContainer( e.target ) ;
  188. if ( formula_container )
  189. {
  190. FCKSelection.SelectNode( formula_container ) ;
  191. }
  192. }, true
  193. ) ;
  194. // On Gecko-like browsers we have to prevent editing the parsed formula in the editor.
  195. FCK.EditorDocument.addEventListener( 'keypress', function( e )
  196. {
  197. var key = e.keyCode || e.which ;
  198. switch ( key )
  199. {
  200. // Only keys for moving the cursor should be enabled.
  201. case 37: // Left
  202. case 39: // Right
  203. case 38: // Up
  204. case 40: // Down
  205. case 36: // Home
  206. case 35: // End
  207. case 33: // Pg Up
  208. case 34: // Pg Down
  209. break ;
  210. // Deletion.
  211. case 8: // Backspace
  212. case 46: // Del
  213. if ( FCKAsciiMath.FindFormulaContainer( FCKAsciiMath.GetSearchElementFromSelection() ) )
  214. {
  215. FCKAsciiMath.Delete() ;
  216. if ( e.preventDefault ) e.preventDefault() ;
  217. if ( e.stopPropagation ) e.stopPropagation() ;
  218. break ;
  219. }
  220. default:
  221. if ( FCKAsciiMath.FindFormulaContainer( FCKAsciiMath.GetSearchElementFromSelection() ) )
  222. {
  223. // We are inside a formula, block edition.
  224. if ( e.preventDefault ) e.preventDefault() ;
  225. if ( e.stopPropagation ) e.stopPropagation() ;
  226. }
  227. break ;
  228. }
  229. }, true
  230. ) ;
  231. }
  232. else
  233. {
  234. FCKAsciiMath.KeyDownIE = function( e )
  235. {
  236. if ( !e ) e = window.event ;
  237. var key = e.keyCode ;
  238. switch ( key )
  239. {
  240. // Deletion.
  241. case 8: // Backspace
  242. case 46: // Del
  243. if ( FCKAsciiMath.FindFormulaContainer( FCKAsciiMath.GetSearchElementFromSelection() ) )
  244. {
  245. FCKAsciiMath.Delete() ;
  246. e.cancelBubble = true ;
  247. break ;
  248. }
  249. default:
  250. break ;
  251. }
  252. }
  253. FCKTools.AddEventListener( FCK.EditorDocument.body, 'keydown', FCKAsciiMath.KeyDownIE ) ;
  254. }
  255. }
  256. FCK.Events.AttachEvent( 'OnAfterSetHTML', FCKAsciiMath.SetListeners ) ;
  257. // We need to attach the script AsciiMathML.js after editing a full page content.
  258. // There is no appropriate event to be captured, so the following method has been chosen for modification.
  259. FCK.UpdateLinkedField = function()
  260. {
  261. // Added code.
  262. if ( FCKConfig.FullPage )
  263. {
  264. var html = FCK.EditorDocument.getElementsByTagName('html')[0] ;
  265. var head ;
  266. if ( typeof html == 'object' )
  267. {
  268. head = html.getElementsByTagName( 'HEAD' )[0] ;
  269. }
  270. if ( typeof head == 'object' )
  271. {
  272. var has_formula = false ;
  273. var spans = FCK.EditorDocument.getElementsByTagName( 'SPAN' ) ;
  274. var span ;
  275. var i = spans.length - 1 ;
  276. while ( i >= 0 && ( span = spans[i--] ) )
  277. {
  278. if ( FCKAsciiMath.IsFormula( span ) )
  279. {
  280. has_formula = true ;
  281. break ;
  282. }
  283. }
  284. var has_script = false ;
  285. var head_data = FCK.GetData( false ).match( /<head\s?[^>]*>(.*?)<\/head\s*>/i )[1] ;
  286. if ( head_data )
  287. {
  288. if ( head_data.indexOf( 'ASCIIMathML.js' ) != -1 )
  289. {
  290. has_script = true ;
  291. }
  292. }
  293. if ( !has_script )
  294. {
  295. // TODO: This fragment works in WYSIWYG mode only.
  296. script = FCK.EditorDocument.createElement( 'script' ) ;
  297. script.setAttribute( 'src', FCKConfig.ScriptASCIIMathML ) ;
  298. script.setAttribute( 'type', 'text/javascript' ) ;
  299. head.appendChild( script ) ;
  300. }
  301. }
  302. }
  303. // End added code.
  304. var value = FCK.GetData( FCKConfig.FormatOutput ) ;
  305. if ( FCKConfig.HtmlEncodeOutput )
  306. value = FCKTools.HTMLEncode( value ) ;
  307. FCK.LinkedField.value = value ;
  308. FCK.Events.FireEvent( 'OnAfterLinkedFieldUpdate' ) ;
  309. } ;