ext-mathjax.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*globals MathJax, svgEditor, svgCanvas, $*/
  2. /*jslint es5: true, todo: true, vars: true*/
  3. /*
  4. * ext-mathjax.js
  5. *
  6. * Licensed under the Apache License
  7. *
  8. * Copyright(c) 2013 Jo Segaert
  9. *
  10. */
  11. svgEditor.addExtension("mathjax", function() {'use strict';
  12. // Configuration of the MathJax extention.
  13. // This will be added to the head tag before MathJax is loaded.
  14. var /*mathjaxConfiguration = '<script type="text/x-mathjax-config">\
  15. MathJax.Hub.Config({\
  16. extensions: ["tex2jax.js"],\
  17. jax: ["input/TeX","output/SVG"],\
  18. showProcessingMessages: true,\
  19. showMathMenu: false,\
  20. showMathMenuMSIE: false,\
  21. errorSettings: {\
  22. message: ["[Math Processing Error]"],\
  23. style: {color: "#CC0000", "font-style":"italic"}\
  24. },\
  25. elements: [],\
  26. tex2jax: {\
  27. ignoreClass: "tex2jax_ignore2", processClass: "tex2jax_process2",\
  28. },\
  29. TeX: {\
  30. extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]\
  31. },\
  32. "SVG": {\
  33. }\
  34. });\
  35. </script>',*/
  36. // mathjaxSrc = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js',
  37. mathjaxSrcSecure = 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG.js',
  38. math,
  39. locationX,
  40. locationY,
  41. mathjaxLoaded = false,
  42. uiStrings = svgEditor.uiStrings;
  43. // TODO: Implement language support. Move these uiStrings to the locale files and the code to the langReady callback.
  44. $.extend(uiStrings, {
  45. mathjax: {
  46. embed_svg: 'Save as mathematics',
  47. embed_mathml: 'Save as figure',
  48. svg_save_warning: 'The math will be transformed into a figure is manipulatable like everything else. You will not be able to manipulate the TeX-code anymore. ',
  49. mathml_save_warning: 'Advised. The math will be saved as a figure.',
  50. title: 'Mathematics code editor'
  51. }
  52. });
  53. function saveMath() {
  54. var code = $('#mathjax_code_textarea').val();
  55. // displaystyle to force MathJax NOT to use the inline style. Because it is
  56. // less fancy!
  57. MathJax.Hub.queue.Push(['Text', math, '\\displaystyle{' + code + '}']);
  58. /*
  59. * The MathJax library doesn't want to bloat your webpage so it creates
  60. * every symbol (glymph) you need only once. These are saved in a <svg> on
  61. * the top of your html document, just under the body tag. Each glymph has
  62. * its unique id and is saved as a <path> in the <defs> tag of the <svg>
  63. *
  64. * Then when the symbols are needed in the rest of your html document they
  65. * are refferd to by a <use> tag.
  66. * Because of bug 1076 we can't just grab the defs tag on the top and add it
  67. * to your formula's <svg> and copy the lot. So we have to replace each
  68. * <use> tag by it's <path>.
  69. */
  70. MathJax.Hub.queue.Push(
  71. function() {
  72. var mathjaxMath = $('.MathJax_SVG');
  73. var svg = $(mathjaxMath.html());
  74. svg.find('use').each(function() {
  75. var x, y, id, transform;
  76. // TODO: find a less pragmatic and more elegant solution to this.
  77. if ($(this).attr('href')) {
  78. id = $(this).attr('href').slice(1); // Works in Chrome.
  79. } else {
  80. id = $(this).attr('xlink:href').slice(1); // Works in Firefox.
  81. }
  82. var glymph = $('#' + id).clone().removeAttr('id');
  83. x = $(this).attr('x');
  84. y = $(this).attr('y');
  85. transform = $(this).attr('transform');
  86. if (transform && ( x || y )) {
  87. glymph.attr('transform', transform + ' translate(' + x + ',' + y + ')');
  88. }
  89. else if (transform) {
  90. glymph.attr('transform', transform);
  91. }
  92. else if (x || y) {
  93. glymph.attr('transform', 'translate(' + x + ',' + y + ')');
  94. }
  95. $(this).replaceWith(glymph);
  96. });
  97. // Remove the style tag because it interferes with SVG-Edit.
  98. svg.removeAttr('style');
  99. svg.attr('xmlns', 'http://www.w3.org/2000/svg');
  100. svgCanvas.importSvgString($('<div>').append(svg.clone()).html(), true);
  101. svgCanvas.ungroupSelectedElement();
  102. // TODO: To undo the adding of the Formula you now have to undo twice.
  103. // This should only be once!
  104. svgCanvas.moveSelectedElements(locationX, locationY, true);
  105. }
  106. );
  107. }
  108. return {
  109. name: "MathJax",
  110. svgicons: svgEditor.curConfig.extPath + "mathjax-icons.xml",
  111. buttons: [{
  112. id: "tool_mathjax",
  113. type: "mode",
  114. title: "Add Mathematics",
  115. events: {
  116. click: function() {
  117. // Only load Mathjax when needed, we don't want to strain Svg-Edit any more.
  118. // From this point on it is very probable that it will be needed, so load it.
  119. if (mathjaxLoaded === false) {
  120. $('<div id="mathjax">\
  121. <!-- Here is where MathJax creates the math -->\
  122. <div id="mathjax_creator" class="tex2jax_process" style="display:none">\
  123. $${}$$\
  124. </div>\
  125. <div id="mathjax_overlay"></div>\
  126. <div id="mathjax_container">\
  127. <div id="tool_mathjax_back" class="toolbar_button">\
  128. <button id="tool_mathjax_save">OK</button>\
  129. <button id="tool_mathjax_cancel">Cancel</button>\
  130. </div>\
  131. <fieldset>\
  132. <legend id="mathjax_legend">Mathematics Editor</legend>\
  133. <label>\
  134. <span id="mathjax_explication">Please type your mathematics in \
  135. <a href="http://en.wikipedia.org/wiki/Help:Displaying_a_formula" target="_blank">TeX</a> code.</span></label>\
  136. <textarea id="mathjax_code_textarea" spellcheck="false"></textarea>\
  137. </fieldset>\
  138. </div>\
  139. </div>'
  140. ).insertAfter('#svg_prefs').hide();
  141. // Make the MathEditor draggable.
  142. $('#mathjax_container').draggable({cancel: 'button,fieldset', containment: 'window'});
  143. // Add functionality and picture to cancel button.
  144. $('#tool_mathjax_cancel').prepend($.getSvgIcon('cancel', true))
  145. .on("click touched", function() {
  146. $('#mathjax').hide();
  147. });
  148. // Add functionality and picture to the save button.
  149. $('#tool_mathjax_save').prepend($.getSvgIcon('ok', true))
  150. .on("click touched", function() {
  151. saveMath();
  152. $('#mathjax').hide();
  153. });
  154. // MathJax preprocessing has to ignore most of the page.
  155. $('body').addClass('tex2jax_ignore');
  156. // Now get (and run) the MathJax Library.
  157. $.getScript(mathjaxSrcSecure)
  158. .done(function(script, textStatus) {
  159. // When MathJax is loaded get the div where the math will be rendered.
  160. MathJax.Hub.queue.Push(function() {
  161. math = MathJax.Hub.getAllJax('#mathjax_creator')[0];
  162. console.log(math);
  163. mathjaxLoaded = true;
  164. console.log('MathJax Loaded');
  165. });
  166. })
  167. // If it fails.
  168. .fail(function() {
  169. console.log("Failed loadeing MathJax.");
  170. $.alert("Failed loading MathJax. You will not be able to change the mathematics.");
  171. });
  172. }
  173. // Set the mode.
  174. svgCanvas.setMode("mathjax");
  175. }
  176. }
  177. }],
  178. mouseDown: function() {
  179. if (svgCanvas.getMode() === "mathjax") {
  180. return {started: true};
  181. }
  182. },
  183. mouseUp: function(opts) {
  184. if (svgCanvas.getMode() === "mathjax") {
  185. // Get the coordinates from your mouse.
  186. var zoom = svgCanvas.getZoom();
  187. // Get the actual coordinate by dividing by the zoom value
  188. locationX = opts.mouse_x / zoom;
  189. locationY = opts.mouse_y / zoom;
  190. $('#mathjax').show();
  191. return {started: false}; // Otherwise the last selected object dissapears.
  192. }
  193. },
  194. callback: function() {
  195. $('<style>').text('\
  196. #mathjax fieldset{\
  197. padding: 5px;\
  198. margin: 5px;\
  199. border: 1px solid #DDD;\
  200. }\
  201. #mathjax label{\
  202. display: block;\
  203. margin: .5em;\
  204. }\
  205. #mathjax legend {\
  206. max-width:195px;\
  207. }\
  208. #mathjax_overlay {\
  209. position: absolute;\
  210. top: 0;\
  211. left: 0;\
  212. right: 0;\
  213. bottom: 0;\
  214. background-color: black;\
  215. opacity: 0.6;\
  216. z-index: 20000;\
  217. }\
  218. \
  219. #mathjax_container {\
  220. position: absolute;\
  221. top: 50px;\
  222. padding: 10px;\
  223. background-color: #B0B0B0;\
  224. border: 1px outset #777;\
  225. opacity: 1.0;\
  226. font-family: Verdana, Helvetica, sans-serif;\
  227. font-size: .8em;\
  228. z-index: 20001;\
  229. }\
  230. \
  231. #tool_mathjax_back {\
  232. margin-left: 1em;\
  233. overflow: auto;\
  234. }\
  235. \
  236. #mathjax_legend{\
  237. font-weight: bold;\
  238. font-size:1.1em;\
  239. }\
  240. \
  241. #mathjax_code_textarea {\\n\
  242. margin: 5px .7em;\
  243. overflow: hidden;\
  244. width: 416px;\
  245. display: block;\
  246. height: 100px;\
  247. }\
  248. ').appendTo('head');
  249. // Add the MathJax configuration.
  250. //$(mathjaxConfiguration).appendTo('head');
  251. }
  252. };
  253. });