MDL-51222 Javascript: Trigger events for filters on DOM insertion

When nodes are added to the dom, they may need to be re-processed by a JS based
filter. To do this we need to trigger the legacy YUI event filter-content-updated.

To make this easier I added some wrappers to template that will insert the node, run any
JS and trigger the event.

I also changed existing yui code to call the amd function to trigger the event. This way
all jquery and yui listeners will always be notified.
This commit is contained in:
Damyon Wiese 2015-08-27 17:15:17 +08:00
parent 74ede2d89a
commit 28de777199
17 changed files with 284 additions and 135 deletions

View File

@ -35,7 +35,8 @@
"plusplus": false,
"predef": [
"M",
"define"
"define",
"require"
],
"proto": false,
"regexdash": false,

View File

@ -1 +1 @@
define(["jquery","core/ajax","core/log","core/notification","core/templates","core/config","core/str"],function(a,b,c,d,e,f,g){var h=function(a,b){var c="@template "+b,d=0,e=[];if(e=a.match(/{{!([\s\S]*?)}}/g),null!==e)for(d=0;d<e.length;d++){var f=e[d],g=f.indexOf(c);if(-1!==g){var h=g+c.length+1;return f=f.substr(h,f.length-2-h)}}return!1},i=function(b,f,i){g.get_string("templateselected","tool_templatelibrary",b).done(function(b){a('[data-region="displaytemplateheader"]').text(b)}).fail(d.exception);var j=h(f,b);j===!1&&(j=h(i,b)),j&&(f=j),a('[data-region="displaytemplatesource"]').text(f);var k=f.match(/Example context \(json\):([\s\S]*)/),l=!1;if(k){var m=k[1].trim();try{l=a.parseJSON(m)}catch(n){c.debug("Could not parse json example context for template."),c.debug(n)}}l?e.render(b,l).done(function(b,c){a('[data-region="displaytemplateexample"]').empty(),a('[data-region="displaytemplateexample"]').append(b),e.runTemplateJS(c)}).fail(d.exception):g.get_string("templatehasnoexample","tool_templatelibrary").done(function(b){a('[data-region="displaytemplateexample"]').text(b)}).fail(d.exception)},j=function(c){var e=c.split("/"),g=e.shift(),h=e.shift(),j=b.call([{methodname:"core_output_load_template",args:{component:g,template:h,themename:f.theme}},{methodname:"tool_templatelibrary_load_canonical_template",args:{component:g,template:h}}],!0,!1);a.when.apply(a,j).done(function(a,b){i(c,a,b)}).fail(d.exception)};return a('[data-region="list-templates"]').on("click","[data-templatename]",function(){var b=a(this).data("templatename");j(b)}),{}});
define(["jquery","core/ajax","core/log","core/notification","core/templates","core/config","core/str"],function(a,b,c,d,e,f,g){var h=function(a,b){var c="@template "+b,d=0,e=[];if(e=a.match(/{{!([\s\S]*?)}}/g),null!==e)for(d=0;d<e.length;d++){var f=e[d],g=f.indexOf(c);if(-1!==g){var h=g+c.length+1;return f=f.substr(h,f.length-2-h)}}return!1},i=function(b,f,i){g.get_string("templateselected","tool_templatelibrary",b).done(function(b){a('[data-region="displaytemplateheader"]').text(b)}).fail(d.exception);var j=h(f,b);j===!1&&(j=h(i,b)),j&&(f=j),a('[data-region="displaytemplatesource"]').text(f);var k=f.match(/Example context \(json\):([\s\S]*)/),l=!1;if(k){var m=k[1].trim();try{l=a.parseJSON(m)}catch(n){c.debug("Could not parse json example context for template."),c.debug(n)}}l?e.render(b,l).done(function(b,c){e.replaceNodeContents(a('[data-region="displaytemplateexample"]'),b,c)}).fail(d.exception):g.get_string("templatehasnoexample","tool_templatelibrary").done(function(b){a('[data-region="displaytemplateexample"]').text(b)}).fail(d.exception)},j=function(c){var e=c.split("/"),g=e.shift(),h=e.shift(),j=b.call([{methodname:"core_output_load_template",args:{component:g,template:h,themename:f.theme}},{methodname:"tool_templatelibrary_load_canonical_template",args:{component:g,template:h}}],!0,!1);a.when.apply(a,j).done(function(a,b){i(c,a,b)}).fail(d.exception)};return a('[data-region="list-templates"]').on("click","[data-templatename]",function(){var b=a(this).data("templatename");j(b)}),{}});

View File

@ -1 +1 @@
define(["jquery","core/ajax","core/log","core/notification","core/templates"],function(a,b,c,d,e){var f=function(b){e.render("tool_templatelibrary/search_results",{templates:b}).done(function(b){a('[data-region="searchresults"]').replaceWith(b)}).fail(d.exception)},g=function(){var c=a('[data-field="component"]').val(),e=a('[data-field="search"]').val();b.call([{methodname:"tool_templatelibrary_list_templates",args:{component:c,search:e},done:f,fail:d.exception}],!0,!1)},h=null,i=function(a,b){null!==h&&window.clearTimeout(h),h=window.setTimeout(function(){a(),h=null},b)},j=function(){i(g,400)};return a('[data-region="list-templates"]').on("change",'[data-field="component"]',j),a('[data-region="list-templates"]').on("input",'[data-field="search"]',j),g(),{}});
define(["jquery","core/ajax","core/log","core/notification","core/templates"],function(a,b,c,d,e){var f=function(b){e.render("tool_templatelibrary/search_results",{templates:b}).done(function(b,c){e.replaceNode(a('[data-region="searchresults"]'),b,c)}).fail(d.exception)},g=function(){var c=a('[data-field="component"]').val(),e=a('[data-field="search"]').val();b.call([{methodname:"tool_templatelibrary_list_templates",args:{component:c,search:e},done:f,fail:d.exception}],!0,!1)},h=null,i=function(a,b){null!==h&&window.clearTimeout(h),h=window.setTimeout(function(){a(),h=null},b)},j=function(){i(g,400)};return a('[data-region="list-templates"]').on("change",'[data-field="component"]',j),a('[data-region="list-templates"]').on("input",'[data-field="search"]',j),g(),{}});

View File

@ -99,9 +99,7 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
}
if (context) {
templates.render(templateName, context).done(function(html, js) {
$('[data-region="displaytemplateexample"]').empty();
$('[data-region="displaytemplateexample"]').append(html);
templates.runTemplateJS(js);
templates.replaceNodeContents($('[data-region="displaytemplateexample"]'), html, js);
}).fail(notification.exception);
} else {
str.get_string('templatehasnoexample', 'tool_templatelibrary').done(function(s) {

View File

@ -32,8 +32,8 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
*/
var reloadListTemplate = function(templateList) {
templates.render('tool_templatelibrary/search_results', { templates: templateList })
.done(function (result) {
$('[data-region="searchresults"]').replaceWith(result);
.done(function (result, js) {
templates.replaceNode($('[data-region="searchresults"]'), result, js);
}).fail(notification.exception);
};

View File

@ -22,46 +22,53 @@ Y.extend(AUTOLINKER, Y.Base, {
alertpanels: {},
initializer : function() {
var self = this;
Y.delegate('click', function(e){
e.preventDefault();
require(['core/event'], function(event) {
Y.delegate('click', function(e){
e.preventDefault();
//display a progress indicator
var title = '',
content = Y.Node.create('<div id="glossaryfilteroverlayprogress">' +
'<img src="' + M.cfg.loadingicon + '" class="spinner" />' +
'</div>'),
o = new Y.Overlay({
headerContent : title,
bodyContent : content
}),
fullurl,
cfg;
self.overlay = o;
o.render(Y.one(document.body));
//display a progress indicator
var title = '',
content = Y.Node.create('<div id="glossaryfilteroverlayprogress">' +
'<img src="' + M.cfg.loadingicon + '" class="spinner" />' +
'</div>'),
o = new Y.Overlay({
headerContent : title,
bodyContent : content
}),
fullurl,
cfg;
self.overlay = o;
o.render(Y.one(document.body));
//Switch over to the ajax url and fetch the glossary item
fullurl = this.getAttribute('href').replace('showentry.php','showentry_ajax.php');
cfg = {
method: 'get',
context : self,
on: {
success: function(id, o) {
this.display_callback(o.responseText);
},
failure: function(id, o) {
var debuginfo = o.statusText;
if (M.cfg.developerdebug) {
o.statusText += ' (' + fullurl + ')';
//Switch over to the ajax url and fetch the glossary item
fullurl = this.getAttribute('href').replace('showentry.php','showentry_ajax.php');
cfg = {
method: 'get',
context : self,
on: {
success: function(id, o) {
this.display_callback(o.responseText, event);
},
failure: function(id, o) {
var debuginfo = o.statusText;
if (M.cfg.developerdebug) {
o.statusText += ' (' + fullurl + ')';
}
new M.core.exception({ message: debuginfo });
}
this.display_callback('bodyContent',debuginfo);
}
}
};
Y.io(fullurl, cfg);
};
Y.io(fullurl, cfg);
}, Y.one(document.body), 'a.glossary.autolink.concept');
}, Y.one(document.body), 'a.glossary.autolink.concept');
});
},
display_callback : function(content) {
/**
* @method display_callback
* @param {String} content - Content to display
* @param {Object} event The amd event module used to fire events for jquery and yui.
*/
display_callback : function(content, event) {
var data,
key,
alertpanel,
@ -78,7 +85,8 @@ Y.extend(AUTOLINKER, Y.Base, {
definition = data.entries[key].definition + data.entries[key].attachments;
alertpanel = new M.core.alert({title:data.entries[key].concept, draggable: true,
message:definition, modal:false, yesLabel: M.util.get_string('ok', 'moodle')});
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(alertpanel.get('boundingBox')))});
// Notify the filters about the modified nodes.
event.notifyFilterContentUpdated(alertpanel.get('boundingBox').getDOMNode());
Y.Node.one('#id_yuialertconfirm-' + alertpanel.get('COUNT')).focus();
// Register alertpanel for stacking.

View File

@ -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,alertpanels:{},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,s,o,u,a=this;try{n=e.JSON.parse(t);if(n.success){this.overlay.hide();for(r in n.entries)o=n.entries[r].definition+n.entries[r].attachments,i=new M.core.alert({title:n.entries[r].concept,draggable:!0,message:o,modal:!1,yesLabel:M.util.get_string("ok","moodle")}),e.fire(M.core.event.FILTER_CONTENT_UPDATED,{nodes:new e.NodeList(i.get("boundingBox"))}),e.Node.one("#id_yuialertconfirm-"+i.get("COUNT")).focus(),s="#moodle-dialogue-"+i.get("COUNT"),i.on("complete",this._deletealertpanel(a.alertpanels,s)),e.Object.isEmpty(this.alertpanels)||(u=this._getLatestWindowPosition(),e.Node.one(s).setXY([u[0]+10,u[1]+10])),this.alertpanels[s]=e.Node.one(s).getXY();return!0}n.error&&new M.core.ajaxException(n)}catch(f){new M.core.exception(f)}return!1},_getLatestWindowPosition:function(){var t=[0,0];return e.Object.each(this.alertpanels,function(e){e[0]>t[0]&&(t=e)}),t},_deletealertpanel:function(e,t){delete e[t]}},{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","moodle-core-notification-exception","moodle-core-notification-ajaxexception"]});
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,alertpanels:{},initializer:function(){var t=this;require(["core/event"],function(n){e.delegate("click",function(r){r.preventDefault();var i="",s=e.Node.create('<div id="glossaryfilteroverlayprogress"><img src="'+M.cfg.loadingicon+'" class="spinner" />'+"</div>"),o=new e.Overlay({headerContent:i,bodyContent:s}),u,a;t.overlay=o,o.render(e.one(document.body)),u=this.getAttribute("href").replace("showentry.php","showentry_ajax.php"),a={method:"get",context:t,on:{success:function(e,t){this.display_callback(t.responseText,n)},failure:function(e,t){var n=t.statusText;M.cfg.developerdebug&&(t.statusText+=" ("+u+")"),new M.core.exception({message:n})}}},e.io(u,a)},e.one(document.body),"a.glossary.autolink.concept")})},display_callback:function(t,n){var r,i,s,o,u,a,f=this;try{r=e.JSON.parse(t);if(r.success){this.overlay.hide();for(i in r.entries)u=r.entries[i].definition+r.entries[i].attachments,s=new M.core.alert({title:r.entries[i].concept,draggable:!0,message:u,modal:!1,yesLabel:M.util.get_string("ok","moodle")}),n.notifyFilterContentUpdated(s.get("boundingBox").getDOMNode()),e.Node.one("#id_yuialertconfirm-"+s.get("COUNT")).focus(),o="#moodle-dialogue-"+s.get("COUNT"),s.on("complete",this._deletealertpanel(f.alertpanels,o)),e.Object.isEmpty(this.alertpanels)||(a=this._getLatestWindowPosition(),e.Node.one(o).setXY([a[0]+10,a[1]+10])),this.alertpanels[o]=e.Node.one(o).getXY();return!0}r.error&&new M.core.ajaxException(r)}catch(l){new M.core.exception(l)}return!1},_getLatestWindowPosition:function(){var t=[0,0];return e.Object.each(this.alertpanels,function(e){e[0]>t[0]&&(t=e)}),t},_deletealertpanel:function(e,t){delete e[t]}},{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","moodle-core-notification-exception","moodle-core-notification-ajaxexception"]});

View File

@ -22,46 +22,53 @@ Y.extend(AUTOLINKER, Y.Base, {
alertpanels: {},
initializer : function() {
var self = this;
Y.delegate('click', function(e){
e.preventDefault();
require(['core/event'], function(event) {
Y.delegate('click', function(e){
e.preventDefault();
//display a progress indicator
var title = '',
content = Y.Node.create('<div id="glossaryfilteroverlayprogress">' +
'<img src="' + M.cfg.loadingicon + '" class="spinner" />' +
'</div>'),
o = new Y.Overlay({
headerContent : title,
bodyContent : content
}),
fullurl,
cfg;
self.overlay = o;
o.render(Y.one(document.body));
//display a progress indicator
var title = '',
content = Y.Node.create('<div id="glossaryfilteroverlayprogress">' +
'<img src="' + M.cfg.loadingicon + '" class="spinner" />' +
'</div>'),
o = new Y.Overlay({
headerContent : title,
bodyContent : content
}),
fullurl,
cfg;
self.overlay = o;
o.render(Y.one(document.body));
//Switch over to the ajax url and fetch the glossary item
fullurl = this.getAttribute('href').replace('showentry.php','showentry_ajax.php');
cfg = {
method: 'get',
context : self,
on: {
success: function(id, o) {
this.display_callback(o.responseText);
},
failure: function(id, o) {
var debuginfo = o.statusText;
if (M.cfg.developerdebug) {
o.statusText += ' (' + fullurl + ')';
//Switch over to the ajax url and fetch the glossary item
fullurl = this.getAttribute('href').replace('showentry.php','showentry_ajax.php');
cfg = {
method: 'get',
context : self,
on: {
success: function(id, o) {
this.display_callback(o.responseText, event);
},
failure: function(id, o) {
var debuginfo = o.statusText;
if (M.cfg.developerdebug) {
o.statusText += ' (' + fullurl + ')';
}
new M.core.exception({ message: debuginfo });
}
this.display_callback('bodyContent',debuginfo);
}
}
};
Y.io(fullurl, cfg);
};
Y.io(fullurl, cfg);
}, Y.one(document.body), 'a.glossary.autolink.concept');
}, Y.one(document.body), 'a.glossary.autolink.concept');
});
},
display_callback : function(content) {
/**
* @method display_callback
* @param {String} content - Content to display
* @param {Object} event The amd event module used to fire events for jquery and yui.
*/
display_callback : function(content, event) {
var data,
key,
alertpanel,
@ -78,7 +85,8 @@ Y.extend(AUTOLINKER, Y.Base, {
definition = data.entries[key].definition + data.entries[key].attachments;
alertpanel = new M.core.alert({title:data.entries[key].concept, draggable: true,
message:definition, modal:false, yesLabel: M.util.get_string('ok', 'moodle')});
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(alertpanel.get('boundingBox')))});
// Notify the filters about the modified nodes.
event.notifyFilterContentUpdated(alertpanel.get('boundingBox').getDOMNode());
Y.Node.one('#id_yuialertconfirm-' + alertpanel.get('COUNT')).focus();
// Register alertpanel for stacking.

View File

@ -20,46 +20,53 @@ Y.extend(AUTOLINKER, Y.Base, {
alertpanels: {},
initializer : function() {
var self = this;
Y.delegate('click', function(e){
e.preventDefault();
require(['core/event'], function(event) {
Y.delegate('click', function(e){
e.preventDefault();
//display a progress indicator
var title = '',
content = Y.Node.create('<div id="glossaryfilteroverlayprogress">' +
'<img src="' + M.cfg.loadingicon + '" class="spinner" />' +
'</div>'),
o = new Y.Overlay({
headerContent : title,
bodyContent : content
}),
fullurl,
cfg;
self.overlay = o;
o.render(Y.one(document.body));
//display a progress indicator
var title = '',
content = Y.Node.create('<div id="glossaryfilteroverlayprogress">' +
'<img src="' + M.cfg.loadingicon + '" class="spinner" />' +
'</div>'),
o = new Y.Overlay({
headerContent : title,
bodyContent : content
}),
fullurl,
cfg;
self.overlay = o;
o.render(Y.one(document.body));
//Switch over to the ajax url and fetch the glossary item
fullurl = this.getAttribute('href').replace('showentry.php','showentry_ajax.php');
cfg = {
method: 'get',
context : self,
on: {
success: function(id, o) {
this.display_callback(o.responseText);
},
failure: function(id, o) {
var debuginfo = o.statusText;
if (M.cfg.developerdebug) {
o.statusText += ' (' + fullurl + ')';
//Switch over to the ajax url and fetch the glossary item
fullurl = this.getAttribute('href').replace('showentry.php','showentry_ajax.php');
cfg = {
method: 'get',
context : self,
on: {
success: function(id, o) {
this.display_callback(o.responseText, event);
},
failure: function(id, o) {
var debuginfo = o.statusText;
if (M.cfg.developerdebug) {
o.statusText += ' (' + fullurl + ')';
}
new M.core.exception({ message: debuginfo });
}
this.display_callback('bodyContent',debuginfo);
}
}
};
Y.io(fullurl, cfg);
};
Y.io(fullurl, cfg);
}, Y.one(document.body), 'a.glossary.autolink.concept');
}, Y.one(document.body), 'a.glossary.autolink.concept');
});
},
display_callback : function(content) {
/**
* @method display_callback
* @param {String} content - Content to display
* @param {Object} event The amd event module used to fire events for jquery and yui.
*/
display_callback : function(content, event) {
var data,
key,
alertpanel,
@ -76,7 +83,8 @@ Y.extend(AUTOLINKER, Y.Base, {
definition = data.entries[key].definition + data.entries[key].attachments;
alertpanel = new M.core.alert({title:data.entries[key].concept, draggable: true,
message:definition, modal:false, yesLabel: M.util.get_string('ok', 'moodle')});
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(alertpanel.get('boundingBox')))});
// Notify the filters about the modified nodes.
event.notifyFilterContentUpdated(alertpanel.get('boundingBox').getDOMNode());
Y.Node.one('#id_yuialertconfirm-' + alertpanel.get('COUNT')).focus();
// Register alertpanel for stacking.

1
lib/amd/build/event.min.js vendored Normal file
View File

@ -0,0 +1 @@
define(["jquery","core/yui"],function(a,b){return{notifyFilterContentUpdated:function(c){c=a(c),b.use("event","moodle-core-event",function(b){a("document").trigger(M.core.event.FILTER_CONTENT_UPDATED,c);var d=new b.NodeList(c.get());b.fire(M.core.event.FILTER_CONTENT_UPDATED,{nodes:d})})}}});

View File

@ -1 +1 @@
define(["core/mustache","jquery","core/ajax","core/str","core/notification","core/url","core/config","core/localstorage"],function(a,b,c,d,e,f,g,h){var i={},j=[],k=[],l=1,m="",n=function(b,c){var d,e=b.split(","),g="",h="",j="";e.length>0&&(g=e.shift().trim()),e.length>0&&(h=e.shift().trim()),e.length>0&&(j=e.join(",").trim());var k=f.imageUrl(g,h),l={attributes:[{name:"src",value:k},{name:"alt",value:c(j)},{name:"class",value:"smallicon"}]},n=i[m+"/core/pix_icon"];return d=a.render(n,l,o),d.trim()},o=function(a){var b="";return u(a,!1).done(function(a){b=a}).fail(e.exception),b},p=function(a,b){return k.push(b(a,this)),""},q=function(a,b){var c=a.split(","),d="",e="",f="";c.length>0&&(d=c.shift().trim()),c.length>0&&(e=c.shift().trim()),c.length>0&&(f=c.join(",").trim()),""!==f&&(f=b(f,this)),0===f.indexOf("{")&&0!==f.indexOf("{{")&&(f=JSON.parse(f));var g=j.length;return j.push({key:d,component:e,param:f}),"{{_s"+g+"}}"},r=function(a,b){m=b,j=[],k=[],a.uniqid=l++,a.str=function(){return q},a.pix=function(){return n},a.js=function(){return p},a.globals={config:g},a.currentTheme=b},s=function(a){var b="";k.length>0&&(b=k.join(";\n"));var c=0;for(c=0;c<a.length;c++)b=b.replace("{{_s"+c+"}}",a[c]);return b},t=function(c,e,f){var g=b.Deferred();m=f;var h=u("core/pix_icon",!0);return h.done(function(){r(e,f);var b="";try{b=a.render(c,e,o)}catch(h){g.reject(h)}j.length>0?d.get_strings(j).done(function(a){var c;for(c=0;c<a.length;c++)b=b.replace("{{_s"+c+"}}",a[c]);g.resolve(b.trim(),s(a))}).fail(function(a){g.reject(a)}):g.resolve(b.trim(),s([]))}).fail(function(a){g.reject(a)}),g.promise()},u=function(a,d){var e=b.Deferred(),f=a.split("/"),g=f.shift(),j=f.shift(),k=m+"/"+a;if(k in i)return e.resolve(i[k]),e.promise();var l=h.get("core_template/"+k);if(l)return e.resolve(l),i[k]=l,e.promise();var n=c.call([{methodname:"core_output_load_template",args:{component:g,template:j,themename:m}}],d,!1);return n[0].done(function(a){h.set("core_template/"+k,a),i[k]=a,e.resolve(a)}).fail(function(a){e.reject(a)}),e.promise()};return{render:function(a,c,d){var e=b.Deferred();"undefined"==typeof d&&(d=g.theme),m=d;var f=u(a,!0);return f.done(function(a){var b=t(a,c,d);b.done(function(a,b){e.resolve(a,b)}).fail(function(a){e.reject(a)})}).fail(function(a){e.reject(a)}),e.promise()},runTemplateJS:function(a){var c=b("<script>").attr("type","text/javascript").html(a);b("head").append(c)}}});
define(["core/mustache","jquery","core/ajax","core/str","core/notification","core/url","core/config","core/localstorage","core/event"],function(a,b,c,d,e,f,g,h,i){var j={},k=[],l=[],m=1,n="",o=function(b,c){var d,e=b.split(","),g="",h="",i="";e.length>0&&(g=e.shift().trim()),e.length>0&&(h=e.shift().trim()),e.length>0&&(i=e.join(",").trim());var k=f.imageUrl(g,h),l={attributes:[{name:"src",value:k},{name:"alt",value:c(i)},{name:"class",value:"smallicon"}]},m=j[n+"/core/pix_icon"];return d=a.render(m,l,p),d.trim()},p=function(a){var b="";return v(a,!1).done(function(a){b=a}).fail(e.exception),b},q=function(a,b){return l.push(b(a,this)),""},r=function(a,b){var c=a.split(","),d="",e="",f="";c.length>0&&(d=c.shift().trim()),c.length>0&&(e=c.shift().trim()),c.length>0&&(f=c.join(",").trim()),""!==f&&(f=b(f,this)),0===f.indexOf("{")&&0!==f.indexOf("{{")&&(f=JSON.parse(f));var g=k.length;return k.push({key:d,component:e,param:f}),"{{_s"+g+"}}"},s=function(a,b){n=b,k=[],l=[],a.uniqid=m++,a.str=function(){return r},a.pix=function(){return o},a.js=function(){return q},a.globals={config:g},a.currentTheme=b},t=function(a){var b="";l.length>0&&(b=l.join(";\n"));var c=0;for(c=0;c<a.length;c++)b=b.replace("{{_s"+c+"}}",a[c]);return b},u=function(c,e,f){var g=b.Deferred();n=f;var h=v("core/pix_icon",!0);return h.done(function(){s(e,f);var b="";try{b=a.render(c,e,p)}catch(h){g.reject(h)}k.length>0?d.get_strings(k).done(function(a){var c;for(c=0;c<a.length;c++)b=b.replace("{{_s"+c+"}}",a[c]);g.resolve(b.trim(),t(a))}).fail(function(a){g.reject(a)}):g.resolve(b.trim(),t([]))}).fail(function(a){g.reject(a)}),g.promise()},v=function(a,d){var e=b.Deferred(),f=a.split("/"),g=f.shift(),i=f.shift(),k=n+"/"+a;if(k in j)return e.resolve(j[k]),e.promise();var l=h.get("core_template/"+k);if(l)return e.resolve(l),j[k]=l,e.promise();var m=c.call([{methodname:"core_output_load_template",args:{component:g,template:i,themename:n}}],d,!1);return m[0].done(function(a){h.set("core_template/"+k,a),j[k]=a,e.resolve(a)}).fail(function(a){e.reject(a)}),e.promise()},w=function(a){if(""!==a.trim()){var c=b("<script>").attr("type","text/javascript").html(a);b("head").append(c)}},x=function(a,c,d,e){var f=b(a);if(f.length){var g=b(c);e?(f.empty(),f.append(g)):f.replaceWith(g),w(d),i.notifyFilterContentUpdated(g)}};return{render:function(a,c,d){var e=b.Deferred();"undefined"==typeof d&&(d=g.theme),n=d;var f=v(a,!0);return f.done(function(a){var b=u(a,c,d);b.done(function(a,b){e.resolve(a,b)}).fail(function(a){e.reject(a)})}).fail(function(a){e.reject(a)}),e.promise()},runTemplateJS:w,replaceNodeContents:function(a,b,c){return x(a,b,c,!0)},replaceNode:function(a,b,c){return x(a,b,c,!1)}}});

52
lib/amd/src/event.js Normal file
View File

@ -0,0 +1,52 @@
// 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/>.
/**
* Global registry of core events that can be triggered/listened for.
*
* @module core/event
* @package core
* @class event
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 3.0
*/
define([ 'jquery', 'core/yui' ],
function($, Y) {
return /** @alias module:core/event */ {
// Public variables and functions.
/**
* Trigger an event using both JQuery and YUI
*
* @method notifyFilterContentUpdated
* @param {string}|{JQuery} nodes - Selector or list of elements that were inserted.
*/
notifyFilterContentUpdated: function(nodes) {
nodes = $(nodes);
Y.use('event', 'moodle-core-event', function(Y) {
// Trigger it the JQuery way.
$('document').trigger(M.core.event.FILTER_CONTENT_UPDATED, nodes);
// Create a YUI NodeList from our JQuery Object.
var yuiNodes = new Y.NodeList(nodes.get());
// And again for YUI.
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, { nodes: yuiNodes });
});
},
};
});

View File

@ -30,9 +30,10 @@ define([ 'core/mustache',
'core/notification',
'core/url',
'core/config',
'core/localstorage'
'core/localstorage',
'core/event'
],
function(mustache, $, ajax, str, notification, coreurl, config, storage) {
function(mustache, $, ajax, str, notification, coreurl, config, storage, event) {
// Private variables and functions.
@ -326,6 +327,50 @@ define([ 'core/mustache',
return deferred.promise();
};
/**
* Execute a block of JS returned from a template.
* Call this AFTER adding the template HTML into the DOM so the nodes can be found.
*
* @method runTemplateJS
* @param {string} source - A block of javascript.
*/
var runTemplateJS = function(source) {
if (source.trim() !== '') {
var newscript = $('<script>').attr('type','text/javascript').html(source);
$('head').append(newscript);
}
};
/**
* Do some DOM replacement and trigger correct events and fire javascript.
*
* @method domReplace
* @private
* @param {JQuery} element - Element or selector to replace.
* @param {String} newHTML - HTML to insert / replace.
* @param {String} newJS - Javascript to run after the insertion.
* @param {Boolean} replaceChildNodes - Replace only the childnodes, alternative is to replace the entire node.
*/
var domReplace = function(element, newHTML, newJS, replaceChildNodes) {
var replaceNode = $(element);
if (replaceNode.length) {
// First create the dom nodes so we have a reference to them.
var newNodes = $(newHTML);
// Do the replacement in the page.
if (replaceChildNodes) {
replaceNode.empty();
replaceNode.append(newNodes);
} else {
replaceNode.replaceWith(newNodes);
}
// Run any javascript associated with the new HTML.
runTemplateJS(newJS);
// Notify all filters about the new content.
event.notifyFilterContentUpdated(newNodes);
}
};
return /** @alias module:core/templates */ {
// Public variables and functions.
/**
@ -379,12 +424,28 @@ define([ 'core/mustache',
* Call this AFTER adding the template HTML into the DOM so the nodes can be found.
*
* @method runTemplateJS
* @private
* @param {string} source - A block of javascript.
*/
runTemplateJS: function(source) {
var newscript = $('<script>').attr('type','text/javascript').html(source);
$('head').append(newscript);
runTemplateJS: runTemplateJS,
/**
* Replace a node in the page with some new HTML and run the JS.
*
* @method replaceNodeContents
* @param {string} source - A block of javascript.
*/
replaceNodeContents: function(element, newHTML, newJS) {
return domReplace(element, newHTML, newJS, true);
},
/**
* Insert a node in the page with some new HTML and run the JS.
*
* @method replaceNode
* @param {string} source - A block of javascript.
*/
replaceNode: function(element, newHTML, newJS) {
return domReplace(element, newHTML, newJS, false);
}
};
});

View File

@ -32,7 +32,6 @@ YUI.add('moodle-atto_equation-button', function (Y, NAME) {
* @class Button
* @extends M.editor_atto.EditorPlugin
*/
var COMPONENTNAME = 'atto_equation',
LOGNAME = 'atto_equation',
CSS = {
@ -231,8 +230,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
tabview.render();
dialogue.show();
// Trigger any JS filters to reprocess the new nodes.
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(dialogue.get('boundingBox')))});
// Notify the filters about the modified nodes.
require(['core/event'], function(event) {
event.notifyFilterContentUpdated(dialogue.get('boundingBox').getDOMNode());
});
if (equation) {
content.one(SELECTORS.EQUATION_TEXT).set('text', equation);
@ -496,7 +497,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
if (preview.status === 200) {
previewNode.setHTML(preview.responseText);
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(previewNode))});
// Notify the filters about the modified nodes.
require(['core/event'], function(event) {
event.notifyFilterContentUpdated(previewNode.getDOMNode());
});
}
},

View File

@ -32,7 +32,6 @@ YUI.add('moodle-atto_equation-button', function (Y, NAME) {
* @class Button
* @extends M.editor_atto.EditorPlugin
*/
var COMPONENTNAME = 'atto_equation',
LOGNAME = 'atto_equation',
CSS = {
@ -231,8 +230,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
tabview.render();
dialogue.show();
// Trigger any JS filters to reprocess the new nodes.
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(dialogue.get('boundingBox')))});
// Notify the filters about the modified nodes.
require(['core/event'], function(event) {
event.notifyFilterContentUpdated(dialogue.get('boundingBox').getDOMNode());
});
if (equation) {
content.one(SELECTORS.EQUATION_TEXT).set('text', equation);
@ -496,7 +497,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
if (preview.status === 200) {
previewNode.setHTML(preview.responseText);
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(previewNode))});
// Notify the filters about the modified nodes.
require(['core/event'], function(event) {
event.notifyFilterContentUpdated(previewNode.getDOMNode());
});
}
},

View File

@ -30,7 +30,6 @@
* @class Button
* @extends M.editor_atto.EditorPlugin
*/
var COMPONENTNAME = 'atto_equation',
LOGNAME = 'atto_equation',
CSS = {
@ -229,8 +228,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
tabview.render();
dialogue.show();
// Trigger any JS filters to reprocess the new nodes.
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(dialogue.get('boundingBox')))});
// Notify the filters about the modified nodes.
require(['core/event'], function(event) {
event.notifyFilterContentUpdated(dialogue.get('boundingBox').getDOMNode());
});
if (equation) {
content.one(SELECTORS.EQUATION_TEXT).set('text', equation);
@ -494,7 +495,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
if (preview.status === 200) {
previewNode.setHTML(preview.responseText);
Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(previewNode))});
// Notify the filters about the modified nodes.
require(['core/event'], function(event) {
event.notifyFilterContentUpdated(previewNode.getDOMNode());
});
}
},