fckplugin.js 11 KB

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