From cc90cedc856153358cdc8852f46bc32d83897d04 Mon Sep 17 00:00:00 2001 From: Damyon Wiese Date: Tue, 1 Apr 2014 15:20:59 +0800 Subject: [PATCH] MDL-43856 MathJax: Improvements to the MathJax filter * Remove all traces of mathjax from the atto equation editor - it is filter agnostic * Add a M.core.event module for core events that can be published/subscribed to by plugins (loose coupling) * Add a FILTER_CONTENT_UPDATED event so plugins can tell the filter system when nodes are added to the page * Implement a listener for this event in the MathJax filter * Fire this event from the equation editor and from the glossary filter * Add a nolink tag to the mathjax filter, so equations will not be processed by the other filters * Add a smarter throttle function to the equation editor preview updates (Y.throttle is dumb) --- ...moodle-filter_glossary-autolinker-debug.js | 3 + .../moodle-filter_glossary-autolinker-min.js | 2 +- .../moodle-filter_glossary-autolinker.js | 3 + .../yui/src/autolinker/js/autolinker.js | 2 + .../yui/src/autolinker/meta/autolinker.json | 1 + filter/mathjaxloader/filter.php | 25 ++- .../lang/en/filter_mathjaxloader.php | 14 +- filter/mathjaxloader/settings.php | 19 +- ...oodle-filter_mathjaxloader-loader-debug.js | 20 +- .../moodle-filter_mathjaxloader-loader-min.js | 2 +- .../moodle-filter_mathjaxloader-loader.js | 20 +- .../mathjaxloader/yui/src/loader/js/loader.js | 18 ++ .../yui/src/loader/meta/loader.json | 1 + lib/editor/atto/plugins/equation/lib.php | 6 +- lib/editor/atto/plugins/equation/settings.php | 1 + .../moodle-atto_equation-button-debug.js | 186 +++++++++++------- .../moodle-atto_equation-button-min.js | 3 +- .../moodle-atto_equation-button.js | 186 +++++++++++------- .../equation/yui/src/button/js/button.js | 184 ++++++++++------- .../equation/yui/src/button/meta/button.json | 1 + .../moodle-core-event-debug.js | 63 ++++++ .../moodle-core-event-min.js | 1 + .../moodle-core-event/moodle-core-event.js | 60 ++++++ lib/yui/src/event/build.json | 10 + lib/yui/src/event/js/event.js | 58 ++++++ lib/yui/src/event/meta/event.json | 7 + 26 files changed, 656 insertions(+), 240 deletions(-) create mode 100644 lib/yui/build/moodle-core-event/moodle-core-event-debug.js create mode 100644 lib/yui/build/moodle-core-event/moodle-core-event-min.js create mode 100644 lib/yui/build/moodle-core-event/moodle-core-event.js create mode 100644 lib/yui/src/event/build.json create mode 100644 lib/yui/src/event/js/event.js create mode 100644 lib/yui/src/event/meta/event.json diff --git a/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-debug.js b/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-debug.js index 0a1867900fa..92b7fe50f2c 100644 --- a/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-debug.js +++ b/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-debug.js @@ -72,6 +72,8 @@ Y.extend(AUTOLINKER, Y.Base, { alertpanel = new M.core.alert({title:data.entries[key].concept, message:definition, modal:false, yesLabel: M.util.get_string('ok', 'moodle')}); alertpanel.show(); + Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(alertpanel.get('boundingBox')))}); + Y.Node.one('#id_yuialertconfirm-' + alertpanel.get('COUNT')).focus(); } @@ -141,6 +143,7 @@ M.filter_glossary.init_filter_autolinking = function(config) { "json-parse", "event-delegate", "overlay", + "moodle-core-event", "moodle-core-notification-alert" ] }); diff --git a/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-min.js b/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-min.js index 5d6f83b4b80..a895bd0664e 100644 --- a/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-min.js +++ b/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-min.js @@ -1 +1 @@ -YUI.add("moodle-filter_glossary-autolinker",function(e,t){var n="Glossary filter autolinker",r="width",i="height",s="menubar",o="location",u="scrollbars",a="resizable",f="toolbar",l="status",c="directories",h="fullscreen",p="dependent",d;d=function(){d.superclass.constructor.apply(this,arguments)},e.extend(d,e.Base,{overlay:null,initializer:function(){var t=this;e.delegate("click",function(n){n.preventDefault();var r="",i=e.Node.create('
'),s=new e.Overlay({headerContent:r,bodyContent:i}),o,u;t.overlay=s,s.render(e.one(document.body)),o=this.getAttribute("href").replace("showentry.php","showentry_ajax.php"),u={method:"get",context:t,on:{success:function(e,t){this.display_callback(t.responseText)},failure:function(e,t){var n=t.statusText;M.cfg.developerdebug&&(t.statusText+=" ("+o+")"),this.display_callback("bodyContent",n)}}},e.io(o,u)},e.one(document.body),"a.glossary.autolink.concept")},display_callback:function(t){var n,r,i;try{n=e.JSON.parse(t);if(n.success){this.overlay.hide();for(r in n.entries)definition=n.entries[r].definition+n.entries[r].attachments,i=new M.core.alert({title:n.entries[r].concept,message:definition,modal:!1,yesLabel:M.util.get_string("ok","moodle")}),i.show(),e.Node.one("#id_yuialertconfirm-"+i.get("COUNT")).focus();return!0}n.error&&new M.core.ajaxException(n)}catch(s){new M.core.exception(s)}return!1}},{NAME:n,ATTRS:{url:{validator:e.Lang.isString,value:M.cfg.wwwroot+"/mod/glossary/showentry.php"},name:{validator:e.Lang.isString,value:"glossaryconcept"},options:{getter:function(){return{width:this.get(r),height:this.get(i),menubar:this.get(s),location:this.get(o),scrollbars:this.get(u),resizable:this.get(a),toolbar:this.get(f),status:this.get(l),directories:this.get(c),fullscreen:this.get(h),dependent:this.get(p)}},readOnly:!0},width:{value:600},height:{value:450},menubar:{value:!1},location:{value:!1},scrollbars:{value:!0},resizable:{value:!0},toolbar:{value:!0},status:{value:!0},directories:{value:!1},fullscreen:{value:!1},dependent:{value:!0}}}),M.filter_glossary=M.filter_glossary||{},M.filter_glossary.init_filter_autolinking=function(e){return new d(e)}},"@VERSION@",{requires:["base","node","io-base","json-parse","event-delegate","overlay","moodle-core-notification-alert"]}); +YUI.add("moodle-filter_glossary-autolinker",function(e,t){var n="Glossary filter autolinker",r="width",i="height",s="menubar",o="location",u="scrollbars",a="resizable",f="toolbar",l="status",c="directories",h="fullscreen",p="dependent",d;d=function(){d.superclass.constructor.apply(this,arguments)},e.extend(d,e.Base,{overlay:null,initializer:function(){var t=this;e.delegate("click",function(n){n.preventDefault();var r="",i=e.Node.create('
'),s=new e.Overlay({headerContent:r,bodyContent:i}),o,u;t.overlay=s,s.render(e.one(document.body)),o=this.getAttribute("href").replace("showentry.php","showentry_ajax.php"),u={method:"get",context:t,on:{success:function(e,t){this.display_callback(t.responseText)},failure:function(e,t){var n=t.statusText;M.cfg.developerdebug&&(t.statusText+=" ("+o+")"),this.display_callback("bodyContent",n)}}},e.io(o,u)},e.one(document.body),"a.glossary.autolink.concept")},display_callback:function(t){var n,r,i;try{n=e.JSON.parse(t);if(n.success){this.overlay.hide();for(r in n.entries)definition=n.entries[r].definition+n.entries[r].attachments,i=new M.core.alert({title:n.entries[r].concept,message:definition,modal:!1,yesLabel:M.util.get_string("ok","moodle")}),i.show(),e.fire(M.core.event.FILTER_CONTENT_UPDATED,{nodes:new e.NodeList(i.get("boundingBox"))}),e.Node.one("#id_yuialertconfirm-"+i.get("COUNT")).focus();return!0}n.error&&new M.core.ajaxException(n)}catch(s){new M.core.exception(s)}return!1}},{NAME:n,ATTRS:{url:{validator:e.Lang.isString,value:M.cfg.wwwroot+"/mod/glossary/showentry.php"},name:{validator:e.Lang.isString,value:"glossaryconcept"},options:{getter:function(){return{width:this.get(r),height:this.get(i),menubar:this.get(s),location:this.get(o),scrollbars:this.get(u),resizable:this.get(a),toolbar:this.get(f),status:this.get(l),directories:this.get(c),fullscreen:this.get(h),dependent:this.get(p)}},readOnly:!0},width:{value:600},height:{value:450},menubar:{value:!1},location:{value:!1},scrollbars:{value:!0},resizable:{value:!0},toolbar:{value:!0},status:{value:!0},directories:{value:!1},fullscreen:{value:!1},dependent:{value:!0}}}),M.filter_glossary=M.filter_glossary||{},M.filter_glossary.init_filter_autolinking=function(e){return new d(e)}},"@VERSION@",{requires:["base","node","io-base","json-parse","event-delegate","overlay","moodle-core-event","moodle-core-notification-alert"]}); diff --git a/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker.js b/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker.js index 0a1867900fa..92b7fe50f2c 100644 --- a/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker.js +++ b/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker.js @@ -72,6 +72,8 @@ Y.extend(AUTOLINKER, Y.Base, { alertpanel = new M.core.alert({title:data.entries[key].concept, message:definition, modal:false, yesLabel: M.util.get_string('ok', 'moodle')}); alertpanel.show(); + Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(alertpanel.get('boundingBox')))}); + Y.Node.one('#id_yuialertconfirm-' + alertpanel.get('COUNT')).focus(); } @@ -141,6 +143,7 @@ M.filter_glossary.init_filter_autolinking = function(config) { "json-parse", "event-delegate", "overlay", + "moodle-core-event", "moodle-core-notification-alert" ] }); diff --git a/filter/glossary/yui/src/autolinker/js/autolinker.js b/filter/glossary/yui/src/autolinker/js/autolinker.js index 3217f4a2a10..8879603b88c 100644 --- a/filter/glossary/yui/src/autolinker/js/autolinker.js +++ b/filter/glossary/yui/src/autolinker/js/autolinker.js @@ -70,6 +70,8 @@ Y.extend(AUTOLINKER, Y.Base, { alertpanel = new M.core.alert({title:data.entries[key].concept, message:definition, modal:false, yesLabel: M.util.get_string('ok', 'moodle')}); alertpanel.show(); + Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(alertpanel.get('boundingBox')))}); + Y.Node.one('#id_yuialertconfirm-' + alertpanel.get('COUNT')).focus(); } diff --git a/filter/glossary/yui/src/autolinker/meta/autolinker.json b/filter/glossary/yui/src/autolinker/meta/autolinker.json index ac4042ed378..065cb2eea78 100644 --- a/filter/glossary/yui/src/autolinker/meta/autolinker.json +++ b/filter/glossary/yui/src/autolinker/meta/autolinker.json @@ -7,6 +7,7 @@ "json-parse", "event-delegate", "overlay", + "moodle-core-event", "moodle-core-notification-alert" ] } diff --git a/filter/mathjaxloader/filter.php b/filter/mathjaxloader/filter.php index c0248fe1925..4876429b277 100644 --- a/filter/mathjaxloader/filter.php +++ b/filter/mathjaxloader/filter.php @@ -132,14 +132,29 @@ class filter_mathjaxloader extends moodle_text_filter { * @param array $options The filter options. */ public function filter($text, array $options = array()) { - // This replaces blah syntax with [tex] blah [/tex] syntax - // because MathJax cannot handle html tags as delimiters. + $legacy = get_config('filter_mathjaxloader', 'texfiltercompatibility'); + if ($legacy) { + // This replaces any of the tex filter maths delimiters with the default for inline maths in MathJAX "\( blah \)". + // blah + $text = preg_replace('|<(/?) *tex( [^>]*)?>|u', '[\1tex]', $text); + // [tex.*] blah [/tex] + $text = str_replace('[tex]', '\\(', $text); + $text = str_replace('[/tex]', '\\)', $text); + // $$ blah $$ + $text = preg_replace('|\$\$[\S\s]\$\$|u', '\\(\1\\)', $text); + // \[ blah \] + $text = str_replace('\\[', '\\(', $text); + $text = str_replace('\\]', '\\)', $text); + } - $text = preg_replace('|<(/?) *tex( [^>]*)?>|u', '[\1tex]', $text); - if (strpos($text, '$$') !== false || strpos($text, '\\[') !== false || strpos($text, '[tex]') !== false) { + $hasinline = strpos($text, '\\(') !== false && strpos($text, '\\)') !== false; + $hasdisplay = (strpos($text, '$$') !== false) || + (strpos($text, '\\[') !== false && strpos($text, '\\]') !== false); + + if ($hasinline || $hasdisplay) { // Only call init if there is at least one equation on the page. $this->lazy_init(); - return '' . $text . ''; + return '' . $text . ''; } return $text; } diff --git a/filter/mathjaxloader/lang/en/filter_mathjaxloader.php b/filter/mathjaxloader/lang/en/filter_mathjaxloader.php index 3327778b507..f244356bba6 100644 --- a/filter/mathjaxloader/lang/en/filter_mathjaxloader.php +++ b/filter/mathjaxloader/lang/en/filter_mathjaxloader.php @@ -29,10 +29,18 @@ $string['filtername'] = 'MathJax'; $string['httpurl'] = 'HTTP MathJax URL'; $string['httpurl_help'] = 'Full URL to MathJax library. Used when the page is loaded via http.'; -$string['httpsurl'] = 'HTTP MathJax URL'; +$string['httpsurl'] = 'HTTPS MathJax URL'; $string['httpsurl_help'] = 'Full URL to MathJax library. Used when the page is loaded via https (secure). '; +$string['texfiltercompatibility'] = 'Tex filter compatibility'; +$string['texfiltercompatibility_help'] = 'The MathJax filter can be used as a replacement for the Tex filter. + +To support all the delimiters supported by the Tex filter MathJax will be configured to display all equations "inline" with the tex.'; $string['localinstall'] = 'Local MathJax installation'; -$string['localinstall_help'] = 'The default MathJAX configuration uses the CDN version of MathJAX, but MathJAX can be installed locally if required. Some reasons this might be useful are to save on bandwidth - or because of local proxy restrictions. To use a local installation of MathJAX, first download the full MathJax library from http://www.mathjax.org/. Then install it on a web server. Finally update the MathJax filter settings httpurl and/or httpsurl to point to the local MathJax.js url.'; +$string['localinstall_help'] = 'The default MathJAX configuration uses the CDN version of MathJAX, but MathJAX can be installed locally if required. + +Some reasons this might be useful are to save on bandwidth - or because of local proxy restrictions. + +To use a local installation of MathJAX, first download the full MathJax library from http://www.mathjax.org/. Then install it on a web server. Finally update the MathJax filter settings httpurl and/or httpsurl to point to the local MathJax.js url.'; $string['mathjaxsettings'] = 'MathJax configuration'; -$string['mathjaxsettings_desc'] = 'The default MathJAX configuration should be appropriate for most users, but MathJax is highly configurable and advanced users may want to provide a different configuration. More information on MathJax configuration options is available here: http://docs.mathjax.org/en/latest/options/index.html'; +$string['mathjaxsettings_desc'] = 'The default MathJAX configuration should be appropriate for most users, but MathJax is highly configurable and any of the standard MathJax configuration options can be added here.'; diff --git a/filter/mathjaxloader/settings.php b/filter/mathjaxloader/settings.php index fa9be8da383..2da905a3879 100644 --- a/filter/mathjaxloader/settings.php +++ b/filter/mathjaxloader/settings.php @@ -44,6 +44,12 @@ if ($ADMIN->fulltree) { PARAM_RAW); $settings->add($item); + $item = new admin_setting_configcheckbox('filter_mathjaxloader/texfiltercompatibility', + new lang_string('texfiltercompatibility', 'filter_mathjaxloader'), + new lang_string('texfiltercompatibility_help', 'filter_mathjaxloader'), + 0); + $settings->add($item); + $default = ' MathJax.Hub.Config({ config: ["MMLorHTML.js", "Safe.js"], @@ -58,19 +64,6 @@ MathJax.Hub.Config({ mpMouse: true }, errorSettings: { message: ["!"] }, - tex2jax: { - skipTags: ["script","noscript","style","textarea"], - inlineMath: [ - ["\\\\(","\\\\)"], - ["$$","$$"], - ["\\\\[","\\\\]"] - ], - displayMath: [ - ["[tex]","[/tex]"], - ], - balanceBraces: true, - preview: "TeX" - }, skipStartupTypeset: true, messageStyle: "none" }); diff --git a/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-debug.js b/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-debug.js index 8cea37eca0c..ea088053a12 100644 --- a/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-debug.js +++ b/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-debug.js @@ -38,8 +38,26 @@ M.filter_mathjaxloader = M.filter_mathjaxloader || { MathJax.Hub.Queue(["Typeset",MathJax.Hub,node.getDOMNode()]); }); MathJax.Hub.Configured(); + + // Listen for events triggered when new text is added to a page that needs + // processing by a filter. + + Y.on(M.core.event.FILTER_CONTENT_UPDATED, this.contentUpdated, this); + }, + + /** + * Handle content updated events - typeset the new content. + * @method contentUpdated + * @param Y.Event - Custom event with "nodes" indicating the root of the updated nodes. + */ + contentUpdated: function(event) { + event.nodes.each(function (node) { + node.all('.filter_mathjaxloader_equation').each(function(node) { + MathJax.Hub.Queue(["Typeset",MathJax.Hub,node.getDOMNode()]); + }); + }); } }; -}, '@VERSION@', {"requires": ["mathjax"]}); +}, '@VERSION@', {"requires": ["moodle-core-event", "mathjax"]}); diff --git a/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-min.js b/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-min.js index 1dffab905e5..1cb456a36c3 100644 --- a/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-min.js +++ b/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-min.js @@ -1 +1 @@ -YUI.add("moodle-filter_mathjaxloader-loader",function(e,t){M.filter_mathjaxloader=M.filter_mathjaxloader||{init:function(t){var n=document.createElement("script");n.type="text/x-mathjax-config",n[window.opera?"innerHTML":"text"]=t.mathjaxconfig,document.getElementsByTagName("head")[0].appendChild(n),MathJax.Localization.setLocale(t.lang),e.all(".filter_mathjaxloader_equation").each(function(e){MathJax.Hub.Queue(["Typeset",MathJax.Hub,e.getDOMNode()])}),MathJax.Hub.Configured()}}},"@VERSION@",{requires:["mathjax"]}); +YUI.add("moodle-filter_mathjaxloader-loader",function(e,t){M.filter_mathjaxloader=M.filter_mathjaxloader||{init:function(t){var n=document.createElement("script");n.type="text/x-mathjax-config",n[window.opera?"innerHTML":"text"]=t.mathjaxconfig,document.getElementsByTagName("head")[0].appendChild(n),MathJax.Localization.setLocale(t.lang),e.all(".filter_mathjaxloader_equation").each(function(e){MathJax.Hub.Queue(["Typeset",MathJax.Hub,e.getDOMNode()])}),MathJax.Hub.Configured(),e.on(M.core.event.FILTER_CONTENT_UPDATED,this.contentUpdated,this)},contentUpdated:function(e){e.nodes.each(function(e){e.all(".filter_mathjaxloader_equation").each(function(e){MathJax.Hub.Queue(["Typeset",MathJax.Hub,e.getDOMNode()])})})}}},"@VERSION@",{requires:["moodle-core-event","mathjax"]}); diff --git a/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader.js b/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader.js index 8cea37eca0c..ea088053a12 100644 --- a/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader.js +++ b/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader.js @@ -38,8 +38,26 @@ M.filter_mathjaxloader = M.filter_mathjaxloader || { MathJax.Hub.Queue(["Typeset",MathJax.Hub,node.getDOMNode()]); }); MathJax.Hub.Configured(); + + // Listen for events triggered when new text is added to a page that needs + // processing by a filter. + + Y.on(M.core.event.FILTER_CONTENT_UPDATED, this.contentUpdated, this); + }, + + /** + * Handle content updated events - typeset the new content. + * @method contentUpdated + * @param Y.Event - Custom event with "nodes" indicating the root of the updated nodes. + */ + contentUpdated: function(event) { + event.nodes.each(function (node) { + node.all('.filter_mathjaxloader_equation').each(function(node) { + MathJax.Hub.Queue(["Typeset",MathJax.Hub,node.getDOMNode()]); + }); + }); } }; -}, '@VERSION@', {"requires": ["mathjax"]}); +}, '@VERSION@', {"requires": ["moodle-core-event", "mathjax"]}); diff --git a/filter/mathjaxloader/yui/src/loader/js/loader.js b/filter/mathjaxloader/yui/src/loader/js/loader.js index 92adb06b0b1..6aaf892cae6 100644 --- a/filter/mathjaxloader/yui/src/loader/js/loader.js +++ b/filter/mathjaxloader/yui/src/loader/js/loader.js @@ -36,5 +36,23 @@ M.filter_mathjaxloader = M.filter_mathjaxloader || { MathJax.Hub.Queue(["Typeset",MathJax.Hub,node.getDOMNode()]); }); MathJax.Hub.Configured(); + + // Listen for events triggered when new text is added to a page that needs + // processing by a filter. + + Y.on(M.core.event.FILTER_CONTENT_UPDATED, this.contentUpdated, this); + }, + + /** + * Handle content updated events - typeset the new content. + * @method contentUpdated + * @param Y.Event - Custom event with "nodes" indicating the root of the updated nodes. + */ + contentUpdated: function(event) { + event.nodes.each(function (node) { + node.all('.filter_mathjaxloader_equation').each(function(node) { + MathJax.Hub.Queue(["Typeset",MathJax.Hub,node.getDOMNode()]); + }); + }); } }; diff --git a/filter/mathjaxloader/yui/src/loader/meta/loader.json b/filter/mathjaxloader/yui/src/loader/meta/loader.json index a8ce1960842..20e4640a20f 100644 --- a/filter/mathjaxloader/yui/src/loader/meta/loader.json +++ b/filter/mathjaxloader/yui/src/loader/meta/loader.json @@ -1,6 +1,7 @@ { "moodle-filter_mathjaxloader-loader": { "requires": [ + "moodle-core-event", "mathjax" ] } diff --git a/lib/editor/atto/plugins/equation/lib.php b/lib/editor/atto/plugins/equation/lib.php index 3e2816ed13f..87865f27b99 100644 --- a/lib/editor/atto/plugins/equation/lib.php +++ b/lib/editor/atto/plugins/equation/lib.php @@ -81,6 +81,8 @@ function atto_equation_params_for_js($elementid, $options, $fpoptions) { 'elements' => get_config('atto_equation', 'librarygroup4'), )); - return array('texfilteractive' => $texfilteractive, 'contextid' => $context->id, 'library' => $library, - 'texdocsurl' => get_docs_url('Using_TeX_Notation')); + return array('texfilteractive' => $texfilteractive, + 'contextid' => $context->id, + 'library' => $library, + 'texdocsurl' => get_docs_url('Using_TeX_Notation')); } diff --git a/lib/editor/atto/plugins/equation/settings.php b/lib/editor/atto/plugins/equation/settings.php index 9aec16a2f7c..a0af0245bcd 100644 --- a/lib/editor/atto/plugins/equation/settings.php +++ b/lib/editor/atto/plugins/equation/settings.php @@ -165,4 +165,5 @@ if ($ADMIN->fulltree) { $desc, $default); $settings->add($setting); + } diff --git a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js index c4612f22483..687af4baf95 100644 --- a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js +++ b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js @@ -48,6 +48,10 @@ var COMPONENTNAME = 'atto_equation', SUBMIT: '.' + CSS.SUBMIT, LIBRARY_BUTTON: '.' + CSS.LIBRARY + ' button' }, + DELIMITERS = { + START: '\\(', + END: '\\)' + }, TEMPLATES = { FORM: '' + '
' + @@ -72,7 +76,7 @@ var COMPONENTNAME = 'atto_equation', '{{#each library}}' + '
' + '{{#split "\n" elements}}' + - '' + + '' + '{{/split}}' + '
' + '{{/each}}' + @@ -111,10 +115,18 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. */ _content: null, + /** + * The source equation we are editing in the text. + * + * @property _sourceEquation + * @type String + * @private + */ + _sourceEquation: '', + initializer: function() { - // If there is a tex filter active - or if MathJax is loaded in - // the page - enable this button. - if (this.get('texfilteractive') || (typeof MathJax !== "undefined")) { + // If there is a tex filter active - enable this button. + if (this.get('texfilteractive')) { // Add the button to the toolbar. this.addButton({ icon: 'e/math', @@ -129,7 +141,14 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. this.unHighlightButtons(); } }, this); + + // We need to convert these to a non dom node based format. + this.editor.all('tex').each(function (texNode) { + var replacement = Y.Node.create('' + DELIMITERS.START + ' ' + texNode.get('text') + ' ' + DELIMITERS.END + ''); + texNode.replace(replacement); + }); } + }, /** @@ -162,10 +181,8 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. tabview.render(); dialogue.show(); - // If MathJax is available, get it to render all the library buttons at once. - if (typeof MathJax !== "undefined") { - MathJax.Hub.Queue(["Typeset", MathJax.Hub, library.getDOMNode()]); - } + // Trigger any JS filters to reprocess the new nodes. + Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(dialogue.get('boundingBox')))}); var equation = this._resolveEquation(); if (equation) { @@ -187,7 +204,8 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. // Find the equation in the surrounding text. var selectedNode = this.get('host').getSelectionParentNode(), text, - equation; + equation, + patterns = [], i; // Note this is a document fragment and YUI doesn't like them. if (!selectedNode) { @@ -196,14 +214,28 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. text = Y.one(selectedNode).get('text'); // We use space or not space because . does not match new lines. - pattern = /\$\$[\S\s]*\$\$/; - equation = pattern.exec(text); - if (equation && equation.length) { - equation = equation.pop(); - // Replace the equation. - equation = equation.substring(2, equation.length - 2); - return equation; + // $$ blah $$ + patterns.push(/\$\$([\S\s]*)\$\$/); + // \( blah \) + patterns.push(/\\\(([\S\s]*)\\\)/); + // \[ blah \] + patterns.push(/\\\[([\S\s]*)\\\]/); + // [tex] blah [/tex] + patterns.push(/\[tex\]([\S\s]*)\[\/tex\]/); + + for (i = 0; i < patterns.length; i++) { + pattern = patterns[i]; + equation = pattern.exec(text); + if (equation && equation.length) { + equation.shift(); + // Remember the inner match so we can replace it later. + this.sourceEquation = equation = equation.shift(); + + return equation; + } } + + this.sourceEquation = ''; return false; }, @@ -218,11 +250,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. var input, selectedNode, text, - pattern, - equation, - value; + value, + host; - var host = this.get('host'); + host = this.get('host'); e.preventDefault(); this.getDialogue({ @@ -235,18 +266,16 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. if (value !== '') { host.setSelection(this._currentSelection); - value = '$$ ' + value.trim() + ' $$'; - selectedNode = Y.one(host.getSelectionParentNode()); - text = selectedNode.get('text'); - pattern = /\$\$[\S\s]*\$\$/; - equation = pattern.exec(text); - if (equation && equation.length) { + if (this.sourceEquation.length) { // Replace the equation. - equation = equation.pop(); - text = text.replace(equation, '$$' + value + '$$'); + selectedNode = Y.one(host.getSelectionParentNode()); + text = selectedNode.get('text'); + + text = text.replace(this.sourceEquation, value); selectedNode.set('text', text); } else { // Insert the new equation. + value = DELIMITERS.START + ' ' + value + ' ' + DELIMITERS.END; host.insertContentAtFocusPoint(value); } @@ -255,6 +284,26 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. } }, + /** + * Smart throttle, only call a function every delay milli seconds, + * and always run the last call. + * + * @param {function} fn + * @param {Integer} delay - delay in milliseconds + * @method _throttle + * @private + */ + _throttle: function(fn, delay) { + var timer = null; + return function () { + var context = this, args = arguments; + clearTimeout(timer); + timer = setTimeout(function () { + fn.apply(context, args); + }, delay); + }; + }, + /** * Update the preview div to match the current equation. * @@ -272,7 +321,6 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. cursorLatex = '\\square ', isChar; - if (e) { e.preventDefault(); } @@ -285,7 +333,7 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. while (equation.charAt(currentPos) === '\\' && currentPos > 0) { currentPos -= 1; } - isChar = /[\w\{\}]/; + isChar = /[a-zA-Z\{\}]/; while (isChar.test(equation.charAt(currentPos)) && currentPos < equation.length) { currentPos += 1; } @@ -294,25 +342,21 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. equation = prefix + equation.substring(0, currentPos) + cursorLatex + equation.substring(currentPos); var previewNode = this._content.one(SELECTORS.EQUATION_PREVIEW); - if (typeof MathJax !== "undefined") { - // If MathJax is available, get it to update the preview without an ajax request. - previewNode.setHTML('$$' + equation + '$$'); - MathJax.Hub.Queue(["Typeset", MathJax.Hub, previewNode.getDOMNode()]); - } else { - // Fall back on an ajax request to the filter. - url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: '$$ ' + equation + ' $$' - }; + equation = DELIMITERS.START + ' ' + equation + ' ' + DELIMITERS.END; + // Make an ajax request to the filter. + url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; + params = { + sesskey: M.cfg.sesskey, + contextid: this.get('contextid'), + action: 'filtertext', + text: equation + }; - preview = Y.io(url, { sync: true, - data: params }); - if (preview.status === 200) { - previewNode.setHTML(preview.responseText); - } + preview = Y.io(url, { sync: true, + data: params }); + if (preview.status === 200) { + previewNode.setHTML(preview.responseText); + Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(previewNode))}); } }, @@ -337,9 +381,9 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. })); this._content.one(SELECTORS.SUBMIT).on('click', this._setEquation, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('valuechange', this._updatePreview, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('mouseup', this._updatePreview, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('keyup', this._updatePreview, this); + this._content.one(SELECTORS.EQUATION_TEXT).on('valuechange', this._throttle(this._updatePreview, 500), this); + this._content.one(SELECTORS.EQUATION_TEXT).on('mouseup', this._throttle(this._updatePreview, 500), this); + this._content.one(SELECTORS.EQUATION_TEXT).on('keyup', this._throttle(this._updatePreview, 500), this); this._content.delegate('click', this._selectLibraryItem, SELECTORS.LIBRARY_BUTTON, this); return this._content; @@ -407,7 +451,7 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. out = ''; parts = str.trim().split(delimiter); while (parts.length > 0) { - current = parts.shift(); + current = parts.shift().trim(); out += options.fn(current); } @@ -417,28 +461,26 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. elementid: this.get('host').get('elementid'), component: COMPONENTNAME, library: library, - CSS: CSS + CSS: CSS, + DELIMITERS: DELIMITERS }); - // Only render the library via ajax is MathJax is not available. - if (typeof MathJax === "undefined") { - var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - var params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: content - }; + var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; + var params = { + sesskey: M.cfg.sesskey, + contextid: this.get('contextid'), + action: 'filtertext', + text: content + }; - preview = Y.io(url, { - sync: true, - data: params, - method: 'POST' - }); + preview = Y.io(url, { + sync: true, + data: params, + method: 'POST' + }); - if (preview.status === 200) { - content = preview.responseText; - } + if (preview.status === 200) { + content = preview.responseText; } return content; } @@ -453,6 +495,7 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. texfilteractive: { value: false }, + /** * The contextid to use when generating this preview. * @@ -482,8 +525,9 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. texdocsurl: { value: null } + } }); -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "io", "event-valuechange", "tabview"]}); +}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-core-event", "io", "event-valuechange", "tabview"]}); diff --git a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js index ff118538888..6e87451bb1f 100644 --- a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js +++ b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js @@ -1 +1,2 @@ -YUI.add("moodle-atto_equation-button",function(e,t){var n="atto_equation",r={EQUATION_TEXT:"atto_equation_equation",EQUATION_PREVIEW:"atto_equation_preview",SUBMIT:"atto_equation_submit",LIBRARY:"atto_equation_library",LIBRARY_GROUP_PREFIX:"atto_equation_library"},i={LIBRARY_GROUP_PREFIX:"."+r.LIBRARY_GROUP_PREFIX,EQUATION_TEXT:"."+r.EQUATION_TEXT,EQUATION_PREVIEW:"."+r.EQUATION_PREVIEW,SUBMIT:"."+r.SUBMIT,LIBRARY_BUTTON:"."+r.LIBRARY+" button"},s={FORM:'{{{library}}}

',LIBRARY:'
{{#each library}}
{{#split "\n" elements}}{{/split}}
{{/each}}
'};e.namespace("M.atto_equation").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_lastCursorPos:0,_content:null,initializer:function(){if(this.get("texfilteractive")||typeof MathJax!="undefined")this.addButton({icon:"e/math",callback:this._displayDialogue}),this.get("host").on("atto:selectionchanged",function(){this._resolveEquation()?this.highlightButtons():this.unHighlightButtons()},this)},_displayDialogue:function(){this._currentSelection=this.get("host").getSelection();if(this._currentSelection===!1)return;var t=this.getDialogue({headerContent:M.util.get_string("pluginname",n),focusAfterHide:!0,width:600}),r=this._getDialogueContent();t.set("bodyContent",r);var s=r.one(i.LIBRARY_GROUP_PREFIX),o=new e.TabView({srcNode:s});o.render(),t.show(),typeof MathJax!="undefined"&&MathJax.Hub.Queue(["Typeset",MathJax.Hub,s.getDOMNode()]);var u=this._resolveEquation();u&&r.one(i.EQUATION_TEXT).set("text",u),this._updatePreview(!1)},_resolveEquation:function(){var t=this.get("host").getSelectionParentNode(),n,r;return t?(n=e.one(t).get("text"),pattern=/\$\$[\S\s]*\$\$/,r=pattern.exec(n),r&&r.length?(r=r.pop(),r=r.substring(2,r.length-2),r):!1):!1},_setEquation:function(t){var n,r,i,s,o,u,a=this.get("host");t.preventDefault(),this.getDialogue({focusAfterHide:null}).hide(),n=t.currentTarget.ancestor(".atto_form").one("textarea"),u=n.get("value"),u!==""&&(a.setSelection(this._currentSelection),u="$$ "+u.trim()+" $$",r=e.one(a.getSelectionParentNode()),i=r.get("text"),s=/\$\$[\S\s]*\$\$/,o=s.exec(i),o&&o.length?(o=o.pop(),i=i.replace(o,"$$"+u+"$$"),r.set("text",i)):a.insertContentAtFocusPoint(u),this.markUpdated())},_updatePreview:function(t){var n=this._content.one(i.EQUATION_TEXT),r=n.get("value"),s,o,u=n.get("selectionStart"),a="",f="\\square ",l;t&&t.preventDefault(),u||(u=0);while(r.charAt(u)==="\\"&&u>0)u-=1;l=/[\w\{\}]/;while(l.test(r.charAt(u))&&u0)i=r.shift(),s+=n.fn(i);return s}),o=t({elementid:this.get("host").get("elementid"),component:n,library:i,CSS:r});if(typeof MathJax=="undefined"){var u=M.cfg.wwwroot+"/lib/editor/atto/plugins/equation/ajax.php",a={sesskey:M.cfg.sesskey,contextid:this.get("contextid"),action:"filtertext",text:o};preview=e.io(u,{sync:!0,data:a,method:"POST"}),preview.status===200&&(o=preview.responseText)}return o}},{ATTRS:{texfilteractive:{value:!1},contextid:{value:null},library:{value:{}},texdocsurl:{value:null}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin","io","event-valuechange","tabview"]}); +YUI.add("moodle-atto_equation-button",function(e,t){var n="atto_equation",r={EQUATION_TEXT:"atto_equation_equation",EQUATION_PREVIEW:"atto_equation_preview",SUBMIT:"atto_equation_submit",LIBRARY:"atto_equation_library",LIBRARY_GROUP_PREFIX:"atto_equation_library"},i={LIBRARY_GROUP_PREFIX:"."+r.LIBRARY_GROUP_PREFIX,EQUATION_TEXT:"."+r.EQUATION_TEXT,EQUATION_PREVIEW:"."+r.EQUATION_PREVIEW,SUBMIT:"."+r.SUBMIT,LIBRARY_BUTTON:"."+r.LIBRARY+" button"},s={START:"\\(",END:"\\)"},o={FORM:'
{{{library}}}

',LIBRARY:'
{{#each library}}
{{#split "\n" elements}}{{/split}}
{{/each}}
'};e.namespace("M.atto_equation").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_lastCursorPos:0,_content:null,_sourceEquation:"",initializer:function(){this.get("texfilteractive")&&(this.addButton({icon:"e/math",callback:this._displayDialogue}),this.get("host").on("atto:selectionchanged",function(){this._resolveEquation()?this.highlightButtons():this.unHighlightButtons()},this),this.editor.all("tex").each(function(t){var n=e.Node.create(""+s.START+" "+t.get("text")+" "+s.END+"");t.replace(n)}))},_displayDialogue:function(){this._currentSelection=this.get("host").getSelection();if(this._currentSelection===!1)return;var t=this.getDialogue({headerContent:M.util.get_string("pluginname",n),focusAfterHide:!0,width:600}),r=this._getDialogueContent();t.set("bodyContent",r);var s=r.one(i.LIBRARY_GROUP_PREFIX),o=new e.TabView({srcNode:s});o.render(),t.show(),e.fire(M.core.event.FILTER_CONTENT_UPDATED,{nodes:new e.NodeList(t.get("boundingBox"))});var u=this._resolveEquation();u&&r.one(i.EQUATION_TEXT).set("text",u),this._updatePreview(!1)},_resolveEquation:function(){var t=this.get("host").getSelectionParentNode(),n,r,i=[],s;if(!t)return!1;n=e.one(t).get("text"),i.push(/\$\$([\S\s]*)\$\$/),i.push(/\\\(([\S\s]*)\\\)/),i.push(/\\\[([\S\s]*)\\\]/),i.push(/\[tex\]([\S\s]*)\[\/tex\]/);for(s=0;s0)a-=1;c=/[a-zA-Z\{\}]/;while(c.test(r.charAt(a))&&a0)i=r.shift().trim(),s+=n.fn(i);return s}),u=t({elementid:this.get("host").get("elementid"),component:n,library:i,CSS:r,DELIMITERS:s});var a=M.cfg.wwwroot+"/lib/editor/atto/plugins/equation/ajax.php",f={sesskey +:M.cfg.sesskey,contextid:this.get("contextid"),action:"filtertext",text:u};return preview=e.io(a,{sync:!0,data:f,method:"POST"}),preview.status===200&&(u=preview.responseText),u}},{ATTRS:{texfilteractive:{value:!1},contextid:{value:null},library:{value:{}},texdocsurl:{value:null}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin","moodle-core-event","io","event-valuechange","tabview"]}); diff --git a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button.js b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button.js index d909984cfd4..96744f1f3e1 100644 --- a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button.js +++ b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button.js @@ -48,6 +48,10 @@ var COMPONENTNAME = 'atto_equation', SUBMIT: '.' + CSS.SUBMIT, LIBRARY_BUTTON: '.' + CSS.LIBRARY + ' button' }, + DELIMITERS = { + START: '\\(', + END: '\\)' + }, TEMPLATES = { FORM: '' + '
' + @@ -72,7 +76,7 @@ var COMPONENTNAME = 'atto_equation', '{{#each library}}' + '
' + '{{#split "\n" elements}}' + - '' + + '' + '{{/split}}' + '
' + '{{/each}}' + @@ -111,10 +115,18 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. */ _content: null, + /** + * The source equation we are editing in the text. + * + * @property _sourceEquation + * @type String + * @private + */ + _sourceEquation: '', + initializer: function() { - // If there is a tex filter active - or if MathJax is loaded in - // the page - enable this button. - if (this.get('texfilteractive') || (typeof MathJax !== "undefined")) { + // If there is a tex filter active - enable this button. + if (this.get('texfilteractive')) { // Add the button to the toolbar. this.addButton({ icon: 'e/math', @@ -129,7 +141,14 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. this.unHighlightButtons(); } }, this); + + // We need to convert these to a non dom node based format. + this.editor.all('tex').each(function (texNode) { + var replacement = Y.Node.create('' + DELIMITERS.START + ' ' + texNode.get('text') + ' ' + DELIMITERS.END + ''); + texNode.replace(replacement); + }); } + }, /** @@ -162,10 +181,8 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. tabview.render(); dialogue.show(); - // If MathJax is available, get it to render all the library buttons at once. - if (typeof MathJax !== "undefined") { - MathJax.Hub.Queue(["Typeset", MathJax.Hub, library.getDOMNode()]); - } + // Trigger any JS filters to reprocess the new nodes. + Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(dialogue.get('boundingBox')))}); var equation = this._resolveEquation(); if (equation) { @@ -187,7 +204,8 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. // Find the equation in the surrounding text. var selectedNode = this.get('host').getSelectionParentNode(), text, - equation; + equation, + patterns = [], i; // Note this is a document fragment and YUI doesn't like them. if (!selectedNode) { @@ -196,14 +214,28 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. text = Y.one(selectedNode).get('text'); // We use space or not space because . does not match new lines. - pattern = /\$\$[\S\s]*\$\$/; - equation = pattern.exec(text); - if (equation && equation.length) { - equation = equation.pop(); - // Replace the equation. - equation = equation.substring(2, equation.length - 2); - return equation; + // $$ blah $$ + patterns.push(/\$\$([\S\s]*)\$\$/); + // \( blah \) + patterns.push(/\\\(([\S\s]*)\\\)/); + // \[ blah \] + patterns.push(/\\\[([\S\s]*)\\\]/); + // [tex] blah [/tex] + patterns.push(/\[tex\]([\S\s]*)\[\/tex\]/); + + for (i = 0; i < patterns.length; i++) { + pattern = patterns[i]; + equation = pattern.exec(text); + if (equation && equation.length) { + equation.shift(); + // Remember the inner match so we can replace it later. + this.sourceEquation = equation = equation.shift(); + + return equation; + } } + + this.sourceEquation = ''; return false; }, @@ -218,11 +250,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. var input, selectedNode, text, - pattern, - equation, - value; + value, + host; - var host = this.get('host'); + host = this.get('host'); e.preventDefault(); this.getDialogue({ @@ -235,18 +266,16 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. if (value !== '') { host.setSelection(this._currentSelection); - value = '$$ ' + value.trim() + ' $$'; - selectedNode = Y.one(host.getSelectionParentNode()); - text = selectedNode.get('text'); - pattern = /\$\$[\S\s]*\$\$/; - equation = pattern.exec(text); - if (equation && equation.length) { + if (this.sourceEquation.length) { // Replace the equation. - equation = equation.pop(); - text = text.replace(equation, '$$' + value + '$$'); + selectedNode = Y.one(host.getSelectionParentNode()); + text = selectedNode.get('text'); + + text = text.replace(this.sourceEquation, value); selectedNode.set('text', text); } else { // Insert the new equation. + value = DELIMITERS.START + ' ' + value + ' ' + DELIMITERS.END; host.insertContentAtFocusPoint(value); } @@ -255,6 +284,26 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. } }, + /** + * Smart throttle, only call a function every delay milli seconds, + * and always run the last call. + * + * @param {function} fn + * @param {Integer} delay - delay in milliseconds + * @method _throttle + * @private + */ + _throttle: function(fn, delay) { + var timer = null; + return function () { + var context = this, args = arguments; + clearTimeout(timer); + timer = setTimeout(function () { + fn.apply(context, args); + }, delay); + }; + }, + /** * Update the preview div to match the current equation. * @@ -272,7 +321,6 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. cursorLatex = '\\square ', isChar; - if (e) { e.preventDefault(); } @@ -285,7 +333,7 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. while (equation.charAt(currentPos) === '\\' && currentPos > 0) { currentPos -= 1; } - isChar = /[\w\{\}]/; + isChar = /[a-zA-Z\{\}]/; while (isChar.test(equation.charAt(currentPos)) && currentPos < equation.length) { currentPos += 1; } @@ -294,25 +342,21 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. equation = prefix + equation.substring(0, currentPos) + cursorLatex + equation.substring(currentPos); var previewNode = this._content.one(SELECTORS.EQUATION_PREVIEW); - if (typeof MathJax !== "undefined") { - // If MathJax is available, get it to update the preview without an ajax request. - previewNode.setHTML('$$' + equation + '$$'); - MathJax.Hub.Queue(["Typeset", MathJax.Hub, previewNode.getDOMNode()]); - } else { - // Fall back on an ajax request to the filter. - url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: '$$ ' + equation + ' $$' - }; + equation = DELIMITERS.START + ' ' + equation + ' ' + DELIMITERS.END; + // Make an ajax request to the filter. + url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; + params = { + sesskey: M.cfg.sesskey, + contextid: this.get('contextid'), + action: 'filtertext', + text: equation + }; - preview = Y.io(url, { sync: true, - data: params }); - if (preview.status === 200) { - previewNode.setHTML(preview.responseText); - } + preview = Y.io(url, { sync: true, + data: params }); + if (preview.status === 200) { + previewNode.setHTML(preview.responseText); + Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(previewNode))}); } }, @@ -337,9 +381,9 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. })); this._content.one(SELECTORS.SUBMIT).on('click', this._setEquation, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('valuechange', this._updatePreview, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('mouseup', this._updatePreview, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('keyup', this._updatePreview, this); + this._content.one(SELECTORS.EQUATION_TEXT).on('valuechange', this._throttle(this._updatePreview, 500), this); + this._content.one(SELECTORS.EQUATION_TEXT).on('mouseup', this._throttle(this._updatePreview, 500), this); + this._content.one(SELECTORS.EQUATION_TEXT).on('keyup', this._throttle(this._updatePreview, 500), this); this._content.delegate('click', this._selectLibraryItem, SELECTORS.LIBRARY_BUTTON, this); return this._content; @@ -406,7 +450,7 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. out = ''; parts = str.trim().split(delimiter); while (parts.length > 0) { - current = parts.shift(); + current = parts.shift().trim(); out += options.fn(current); } @@ -416,28 +460,26 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. elementid: this.get('host').get('elementid'), component: COMPONENTNAME, library: library, - CSS: CSS + CSS: CSS, + DELIMITERS: DELIMITERS }); - // Only render the library via ajax is MathJax is not available. - if (typeof MathJax === "undefined") { - var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - var params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: content - }; + var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; + var params = { + sesskey: M.cfg.sesskey, + contextid: this.get('contextid'), + action: 'filtertext', + text: content + }; - preview = Y.io(url, { - sync: true, - data: params, - method: 'POST' - }); + preview = Y.io(url, { + sync: true, + data: params, + method: 'POST' + }); - if (preview.status === 200) { - content = preview.responseText; - } + if (preview.status === 200) { + content = preview.responseText; } return content; } @@ -452,6 +494,7 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. texfilteractive: { value: false }, + /** * The contextid to use when generating this preview. * @@ -481,8 +524,9 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. texdocsurl: { value: null } + } }); -}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "io", "event-valuechange", "tabview"]}); +}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-core-event", "io", "event-valuechange", "tabview"]}); diff --git a/lib/editor/atto/plugins/equation/yui/src/button/js/button.js b/lib/editor/atto/plugins/equation/yui/src/button/js/button.js index 2e30f82b765..92a3f209016 100644 --- a/lib/editor/atto/plugins/equation/yui/src/button/js/button.js +++ b/lib/editor/atto/plugins/equation/yui/src/button/js/button.js @@ -46,6 +46,10 @@ var COMPONENTNAME = 'atto_equation', SUBMIT: '.' + CSS.SUBMIT, LIBRARY_BUTTON: '.' + CSS.LIBRARY + ' button' }, + DELIMITERS = { + START: '\\(', + END: '\\)' + }, TEMPLATES = { FORM: '' + '' + @@ -70,7 +74,7 @@ var COMPONENTNAME = 'atto_equation', '{{#each library}}' + '
' + '{{#split "\n" elements}}' + - '' + + '' + '{{/split}}' + '
' + '{{/each}}' + @@ -109,10 +113,18 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. */ _content: null, + /** + * The source equation we are editing in the text. + * + * @property _sourceEquation + * @type String + * @private + */ + _sourceEquation: '', + initializer: function() { - // If there is a tex filter active - or if MathJax is loaded in - // the page - enable this button. - if (this.get('texfilteractive') || (typeof MathJax !== "undefined")) { + // If there is a tex filter active - enable this button. + if (this.get('texfilteractive')) { // Add the button to the toolbar. this.addButton({ icon: 'e/math', @@ -127,7 +139,14 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. this.unHighlightButtons(); } }, this); + + // We need to convert these to a non dom node based format. + this.editor.all('tex').each(function (texNode) { + var replacement = Y.Node.create('' + DELIMITERS.START + ' ' + texNode.get('text') + ' ' + DELIMITERS.END + ''); + texNode.replace(replacement); + }); } + }, /** @@ -160,10 +179,8 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. tabview.render(); dialogue.show(); - // If MathJax is available, get it to render all the library buttons at once. - if (typeof MathJax !== "undefined") { - MathJax.Hub.Queue(["Typeset", MathJax.Hub, library.getDOMNode()]); - } + // Trigger any JS filters to reprocess the new nodes. + Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(dialogue.get('boundingBox')))}); var equation = this._resolveEquation(); if (equation) { @@ -185,7 +202,8 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. // Find the equation in the surrounding text. var selectedNode = this.get('host').getSelectionParentNode(), text, - equation; + equation, + patterns = [], i; // Note this is a document fragment and YUI doesn't like them. if (!selectedNode) { @@ -194,14 +212,28 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. text = Y.one(selectedNode).get('text'); // We use space or not space because . does not match new lines. - pattern = /\$\$[\S\s]*\$\$/; - equation = pattern.exec(text); - if (equation && equation.length) { - equation = equation.pop(); - // Replace the equation. - equation = equation.substring(2, equation.length - 2); - return equation; + // $$ blah $$ + patterns.push(/\$\$([\S\s]*)\$\$/); + // \( blah \) + patterns.push(/\\\(([\S\s]*)\\\)/); + // \[ blah \] + patterns.push(/\\\[([\S\s]*)\\\]/); + // [tex] blah [/tex] + patterns.push(/\[tex\]([\S\s]*)\[\/tex\]/); + + for (i = 0; i < patterns.length; i++) { + pattern = patterns[i]; + equation = pattern.exec(text); + if (equation && equation.length) { + equation.shift(); + // Remember the inner match so we can replace it later. + this.sourceEquation = equation = equation.shift(); + + return equation; + } } + + this.sourceEquation = ''; return false; }, @@ -216,11 +248,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. var input, selectedNode, text, - pattern, - equation, - value; + value, + host; - var host = this.get('host'); + host = this.get('host'); e.preventDefault(); this.getDialogue({ @@ -233,18 +264,16 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. if (value !== '') { host.setSelection(this._currentSelection); - value = '$$ ' + value.trim() + ' $$'; - selectedNode = Y.one(host.getSelectionParentNode()); - text = selectedNode.get('text'); - pattern = /\$\$[\S\s]*\$\$/; - equation = pattern.exec(text); - if (equation && equation.length) { + if (this.sourceEquation.length) { // Replace the equation. - equation = equation.pop(); - text = text.replace(equation, '$$' + value + '$$'); + selectedNode = Y.one(host.getSelectionParentNode()); + text = selectedNode.get('text'); + + text = text.replace(this.sourceEquation, value); selectedNode.set('text', text); } else { // Insert the new equation. + value = DELIMITERS.START + ' ' + value + ' ' + DELIMITERS.END; host.insertContentAtFocusPoint(value); } @@ -253,6 +282,26 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. } }, + /** + * Smart throttle, only call a function every delay milli seconds, + * and always run the last call. + * + * @param {function} fn + * @param {Integer} delay - delay in milliseconds + * @method _throttle + * @private + */ + _throttle: function(fn, delay) { + var timer = null; + return function () { + var context = this, args = arguments; + clearTimeout(timer); + timer = setTimeout(function () { + fn.apply(context, args); + }, delay); + }; + }, + /** * Update the preview div to match the current equation. * @@ -270,7 +319,6 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. cursorLatex = '\\square ', isChar; - if (e) { e.preventDefault(); } @@ -283,7 +331,7 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. while (equation.charAt(currentPos) === '\\' && currentPos > 0) { currentPos -= 1; } - isChar = /[\w\{\}]/; + isChar = /[a-zA-Z\{\}]/; while (isChar.test(equation.charAt(currentPos)) && currentPos < equation.length) { currentPos += 1; } @@ -292,25 +340,21 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. equation = prefix + equation.substring(0, currentPos) + cursorLatex + equation.substring(currentPos); var previewNode = this._content.one(SELECTORS.EQUATION_PREVIEW); - if (typeof MathJax !== "undefined") { - // If MathJax is available, get it to update the preview without an ajax request. - previewNode.setHTML('$$' + equation + '$$'); - MathJax.Hub.Queue(["Typeset", MathJax.Hub, previewNode.getDOMNode()]); - } else { - // Fall back on an ajax request to the filter. - url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: '$$ ' + equation + ' $$' - }; + equation = DELIMITERS.START + ' ' + equation + ' ' + DELIMITERS.END; + // Make an ajax request to the filter. + url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; + params = { + sesskey: M.cfg.sesskey, + contextid: this.get('contextid'), + action: 'filtertext', + text: equation + }; - preview = Y.io(url, { sync: true, - data: params }); - if (preview.status === 200) { - previewNode.setHTML(preview.responseText); - } + preview = Y.io(url, { sync: true, + data: params }); + if (preview.status === 200) { + previewNode.setHTML(preview.responseText); + Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(previewNode))}); } }, @@ -335,9 +379,9 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. })); this._content.one(SELECTORS.SUBMIT).on('click', this._setEquation, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('valuechange', this._updatePreview, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('mouseup', this._updatePreview, this); - this._content.one(SELECTORS.EQUATION_TEXT).on('keyup', this._updatePreview, this); + this._content.one(SELECTORS.EQUATION_TEXT).on('valuechange', this._throttle(this._updatePreview, 500), this); + this._content.one(SELECTORS.EQUATION_TEXT).on('mouseup', this._throttle(this._updatePreview, 500), this); + this._content.one(SELECTORS.EQUATION_TEXT).on('keyup', this._throttle(this._updatePreview, 500), this); this._content.delegate('click', this._selectLibraryItem, SELECTORS.LIBRARY_BUTTON, this); return this._content; @@ -405,7 +449,7 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. out = ''; parts = str.trim().split(delimiter); while (parts.length > 0) { - current = parts.shift(); + current = parts.shift().trim(); out += options.fn(current); } @@ -415,28 +459,26 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. elementid: this.get('host').get('elementid'), component: COMPONENTNAME, library: library, - CSS: CSS + CSS: CSS, + DELIMITERS: DELIMITERS }); - // Only render the library via ajax is MathJax is not available. - if (typeof MathJax === "undefined") { - var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; - var params = { - sesskey: M.cfg.sesskey, - contextid: this.get('contextid'), - action: 'filtertext', - text: content - }; + var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php'; + var params = { + sesskey: M.cfg.sesskey, + contextid: this.get('contextid'), + action: 'filtertext', + text: content + }; - preview = Y.io(url, { - sync: true, - data: params, - method: 'POST' - }); + preview = Y.io(url, { + sync: true, + data: params, + method: 'POST' + }); - if (preview.status === 200) { - content = preview.responseText; - } + if (preview.status === 200) { + content = preview.responseText; } return content; } @@ -451,6 +493,7 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. texfilteractive: { value: false }, + /** * The contextid to use when generating this preview. * @@ -480,5 +523,6 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto. texdocsurl: { value: null } + } }); diff --git a/lib/editor/atto/plugins/equation/yui/src/button/meta/button.json b/lib/editor/atto/plugins/equation/yui/src/button/meta/button.json index c0d749fae02..6103cb338de 100644 --- a/lib/editor/atto/plugins/equation/yui/src/button/meta/button.json +++ b/lib/editor/atto/plugins/equation/yui/src/button/meta/button.json @@ -2,6 +2,7 @@ "moodle-atto_equation-button": { "requires": [ "moodle-editor_atto-plugin", + "moodle-core-event", "io", "event-valuechange", "tabview" diff --git a/lib/yui/build/moodle-core-event/moodle-core-event-debug.js b/lib/yui/build/moodle-core-event/moodle-core-event-debug.js new file mode 100644 index 00000000000..14c774f25f3 --- /dev/null +++ b/lib/yui/build/moodle-core-event/moodle-core-event-debug.js @@ -0,0 +1,63 @@ +YUI.add('moodle-core-event', function (Y, NAME) { + +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * @module moodle-core-event + */ + +var LOGNAME = 'moodle-core-event'; + +/** + * List of published global JS events in Moodle. This is a collection + * of global events that can be subscribed to, or fired from any plugin. + * + * @namespace M.core.event + */ +M.core = M.core || {}; + +M.core.event = { + // This event is triggered when a page has added dynamic nodes to a page + // that should be processed by the filter system. An example is loading + // user text that could have equations in it. MathJax can typeset the equations + // but only if it is notified that there are new nodes in the page that need processing. + // This event must contain a property "nodes" listing the root of any new nodes in the DOM (as a NodeList). + // To trigger this event use M.core.Event.fire(M.core.Event.FILTER_CONTENT_UPDATED, {nodes: list}); + FILTER_CONTENT_UPDATED: "filter-content-updated" +}; + + +var eventDefaultConfig = { + emitFacade: true, + defaultFn: function(e) { + Y.log('Event fired: ' + e.type, 'debug', LOGNAME); + }, + preventedFn: function(e) { + Y.log('Event prevented: ' + e.type, 'debug', LOGNAME); + }, + stoppedFn: function(e) { + Y.log('Event stopped: ' + e.type, 'debug', LOGNAME); + } +}; + +for (var key in M.core.event) { + Y.publish(M.core.event[key], eventDefaultConfig); +} + + + + +}, '@VERSION@', {"requires": ["event-custom"]}); diff --git a/lib/yui/build/moodle-core-event/moodle-core-event-min.js b/lib/yui/build/moodle-core-event/moodle-core-event-min.js new file mode 100644 index 00000000000..5b0a2653bc8 --- /dev/null +++ b/lib/yui/build/moodle-core-event/moodle-core-event-min.js @@ -0,0 +1 @@ +YUI.add("moodle-core-event",function(e,t){var n="moodle-core-event";M.core=M.core||{},M.core.event={FILTER_CONTENT_UPDATED:"filter-content-updated"};var r={emitFacade:!0,defaultFn:function(e){},preventedFn:function(e){},stoppedFn:function(e){}};for(var i in M.core.event)e.publish(M.core.event[i],r)},"@VERSION@",{requires:["event-custom"]}); diff --git a/lib/yui/build/moodle-core-event/moodle-core-event.js b/lib/yui/build/moodle-core-event/moodle-core-event.js new file mode 100644 index 00000000000..60a6b176925 --- /dev/null +++ b/lib/yui/build/moodle-core-event/moodle-core-event.js @@ -0,0 +1,60 @@ +YUI.add('moodle-core-event', function (Y, NAME) { + +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * @module moodle-core-event + */ + +var LOGNAME = 'moodle-core-event'; + +/** + * List of published global JS events in Moodle. This is a collection + * of global events that can be subscribed to, or fired from any plugin. + * + * @namespace M.core.event + */ +M.core = M.core || {}; + +M.core.event = { + // This event is triggered when a page has added dynamic nodes to a page + // that should be processed by the filter system. An example is loading + // user text that could have equations in it. MathJax can typeset the equations + // but only if it is notified that there are new nodes in the page that need processing. + // This event must contain a property "nodes" listing the root of any new nodes in the DOM (as a NodeList). + // To trigger this event use M.core.Event.fire(M.core.Event.FILTER_CONTENT_UPDATED, {nodes: list}); + FILTER_CONTENT_UPDATED: "filter-content-updated" +}; + + +var eventDefaultConfig = { + emitFacade: true, + defaultFn: function(e) { + }, + preventedFn: function(e) { + }, + stoppedFn: function(e) { + } +}; + +for (var key in M.core.event) { + Y.publish(M.core.event[key], eventDefaultConfig); +} + + + + +}, '@VERSION@', {"requires": ["event-custom"]}); diff --git a/lib/yui/src/event/build.json b/lib/yui/src/event/build.json new file mode 100644 index 00000000000..62712457527 --- /dev/null +++ b/lib/yui/src/event/build.json @@ -0,0 +1,10 @@ +{ + "name": "moodle-core-event", + "builds": { + "moodle-core-event": { + "jsfiles": [ + "event.js" + ] + } + } +} diff --git a/lib/yui/src/event/js/event.js b/lib/yui/src/event/js/event.js new file mode 100644 index 00000000000..7c861869490 --- /dev/null +++ b/lib/yui/src/event/js/event.js @@ -0,0 +1,58 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * @module moodle-core-event + */ + +var LOGNAME = 'moodle-core-event'; + +/** + * List of published global JS events in Moodle. This is a collection + * of global events that can be subscribed to, or fired from any plugin. + * + * @namespace M.core.event + */ +M.core = M.core || {}; + +M.core.event = { + // This event is triggered when a page has added dynamic nodes to a page + // that should be processed by the filter system. An example is loading + // user text that could have equations in it. MathJax can typeset the equations + // but only if it is notified that there are new nodes in the page that need processing. + // This event must contain a property "nodes" listing the root of any new nodes in the DOM (as a NodeList). + // To trigger this event use M.core.Event.fire(M.core.Event.FILTER_CONTENT_UPDATED, {nodes: list}); + FILTER_CONTENT_UPDATED: "filter-content-updated" +}; + + +var eventDefaultConfig = { + emitFacade: true, + defaultFn: function(e) { + Y.log('Event fired: ' + e.type, 'debug', LOGNAME); + }, + preventedFn: function(e) { + Y.log('Event prevented: ' + e.type, 'debug', LOGNAME); + }, + stoppedFn: function(e) { + Y.log('Event stopped: ' + e.type, 'debug', LOGNAME); + } +}; + +for (var key in M.core.event) { + Y.publish(M.core.event[key], eventDefaultConfig); +} + + diff --git a/lib/yui/src/event/meta/event.json b/lib/yui/src/event/meta/event.json new file mode 100644 index 00000000000..89a7d388714 --- /dev/null +++ b/lib/yui/src/event/meta/event.json @@ -0,0 +1,7 @@ +{ + "moodle-core-event": { + "requires": [ + "event-custom" + ] + } +}