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)
This commit is contained in:
+3
@@ -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"
|
||||
]
|
||||
});
|
||||
|
||||
filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-min.js
Vendored
+1
-1
@@ -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('<div id="glossaryfilteroverlayprogress"><img src="'+M.cfg.loadingicon+'" class="spinner" /></div>'),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('<div id="glossaryfilteroverlayprogress"><img src="'+M.cfg.loadingicon+'" class="spinner" /></div>'),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"]});
|
||||
|
||||
Vendored
+3
@@ -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"
|
||||
]
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"json-parse",
|
||||
"event-delegate",
|
||||
"overlay",
|
||||
"moodle-core-event",
|
||||
"moodle-core-notification-alert"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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 <tex> blah </tex> 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 \)".
|
||||
// <tex.*> blah </tex>
|
||||
$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 '<span class="filter_mathjaxloader_equation">' . $text . '</span>';
|
||||
return '<span class="nolink"><span class="filter_mathjaxloader_equation">' . $text . '</span></span>';
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
@@ -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.';
|
||||
|
||||
|
||||
@@ -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"
|
||||
});
|
||||
|
||||
+19
-1
@@ -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"]});
|
||||
|
||||
+1
-1
@@ -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"]});
|
||||
|
||||
+19
-1
@@ -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"]});
|
||||
|
||||
@@ -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()]);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"moodle-filter_mathjaxloader-loader": {
|
||||
"requires": [
|
||||
"moodle-core-event",
|
||||
"mathjax"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
@@ -165,4 +165,5 @@ if ($ADMIN->fulltree) {
|
||||
$desc,
|
||||
$default);
|
||||
$settings->add($setting);
|
||||
|
||||
}
|
||||
|
||||
+115
-71
@@ -48,6 +48,10 @@ var COMPONENTNAME = 'atto_equation',
|
||||
SUBMIT: '.' + CSS.SUBMIT,
|
||||
LIBRARY_BUTTON: '.' + CSS.LIBRARY + ' button'
|
||||
},
|
||||
DELIMITERS = {
|
||||
START: '\\(',
|
||||
END: '\\)'
|
||||
},
|
||||
TEMPLATES = {
|
||||
FORM: '' +
|
||||
'<form class="atto_form">' +
|
||||
@@ -72,7 +76,7 @@ var COMPONENTNAME = 'atto_equation',
|
||||
'{{#each library}}' +
|
||||
'<div id="{{elementid}}_{{../CSS.LIBRARY_GROUP_PREFIX}}{{@key}}">' +
|
||||
'{{#split "\n" elements}}' +
|
||||
'<button data-tex="{{this}}" title="{{this}}">$${{this}}$$</button>' +
|
||||
'<button data-tex="{{this}}" title="{{this}}">{{../../DELIMITERS.START}}{{this}}{{../../DELIMITERS.END}}</button>' +
|
||||
'{{/split}}' +
|
||||
'</div>' +
|
||||
'{{/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('<span>' + DELIMITERS.START + ' ' + texNode.get('text') + ' ' + DELIMITERS.END + '</span>');
|
||||
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"]});
|
||||
|
||||
+2
-1
File diff suppressed because one or more lines are too long
+115
-71
@@ -48,6 +48,10 @@ var COMPONENTNAME = 'atto_equation',
|
||||
SUBMIT: '.' + CSS.SUBMIT,
|
||||
LIBRARY_BUTTON: '.' + CSS.LIBRARY + ' button'
|
||||
},
|
||||
DELIMITERS = {
|
||||
START: '\\(',
|
||||
END: '\\)'
|
||||
},
|
||||
TEMPLATES = {
|
||||
FORM: '' +
|
||||
'<form class="atto_form">' +
|
||||
@@ -72,7 +76,7 @@ var COMPONENTNAME = 'atto_equation',
|
||||
'{{#each library}}' +
|
||||
'<div id="{{elementid}}_{{../CSS.LIBRARY_GROUP_PREFIX}}{{@key}}">' +
|
||||
'{{#split "\n" elements}}' +
|
||||
'<button data-tex="{{this}}" title="{{this}}">$${{this}}$$</button>' +
|
||||
'<button data-tex="{{this}}" title="{{this}}">{{../../DELIMITERS.START}}{{this}}{{../../DELIMITERS.END}}</button>' +
|
||||
'{{/split}}' +
|
||||
'</div>' +
|
||||
'{{/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('<span>' + DELIMITERS.START + ' ' + texNode.get('text') + ' ' + DELIMITERS.END + '</span>');
|
||||
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"]});
|
||||
|
||||
+114
-70
@@ -46,6 +46,10 @@ var COMPONENTNAME = 'atto_equation',
|
||||
SUBMIT: '.' + CSS.SUBMIT,
|
||||
LIBRARY_BUTTON: '.' + CSS.LIBRARY + ' button'
|
||||
},
|
||||
DELIMITERS = {
|
||||
START: '\\(',
|
||||
END: '\\)'
|
||||
},
|
||||
TEMPLATES = {
|
||||
FORM: '' +
|
||||
'<form class="atto_form">' +
|
||||
@@ -70,7 +74,7 @@ var COMPONENTNAME = 'atto_equation',
|
||||
'{{#each library}}' +
|
||||
'<div id="{{elementid}}_{{../CSS.LIBRARY_GROUP_PREFIX}}{{@key}}">' +
|
||||
'{{#split "\n" elements}}' +
|
||||
'<button data-tex="{{this}}" title="{{this}}">$${{this}}$$</button>' +
|
||||
'<button data-tex="{{this}}" title="{{this}}">{{../../DELIMITERS.START}}{{this}}{{../../DELIMITERS.END}}</button>' +
|
||||
'{{/split}}' +
|
||||
'</div>' +
|
||||
'{{/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('<span>' + DELIMITERS.START + ' ' + texNode.get('text') + ' ' + DELIMITERS.END + '</span>');
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"moodle-atto_equation-button": {
|
||||
"requires": [
|
||||
"moodle-editor_atto-plugin",
|
||||
"moodle-core-event",
|
||||
"io",
|
||||
"event-valuechange",
|
||||
"tabview"
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* @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"]});
|
||||
@@ -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"]});
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* @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"]});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "moodle-core-event",
|
||||
"builds": {
|
||||
"moodle-core-event": {
|
||||
"jsfiles": [
|
||||
"event.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+58
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"moodle-core-event": {
|
||||
"requires": [
|
||||
"event-custom"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user