Inject Javascript in certain courses

Inject Javascript in certain courses

by Tim Pietz -
Number of replies: 9

Our school is currently trying to use moodle more actively and got some of the teachers of the lower classes to design exercises. They've decided to let a student do the work of actually implementing it, because it certainly is the cheapest option. That student happens to be me, and I just noticed that they probably ripped me off, since it isn't even close to the "Just copy&paste it" they said it was going to be.

While I've somehow managed to work my way through most of it, some of the teachers had special requests that I can't fulfill using the usual go-to question type cloze. One particular request I am currently stuck with comes from the German teacher that decided it would be a good idea to include dialogue sequences between tasks, in which three characters discuss their issues with grammar and stuff. She sent me a script like the ones you get in theater class, and with it came an image with the three characters. She told me to use image editing magic to add speech bubbles, and probably expects me to do that for every. single. sentence.. No way I'm doing that, it's like Romeo and Juliet act I through V worth of text.

My idea was to just copy&paste it into the question (usually the description type), put the whole thing into a <p> tag with a certain class, and just let javascript parse it, replace the paragraph with a canvas, and let it figure out by itself where to put the the text, which size it has to be and all that stuff. Idea got accepted because I argued that "it would save a significant amount of bandwidth" (and my time). I put it together two days ago, and it honestly somehow works even better than I expected. But I've literally made zero progress since then, since I just can't figure out how to actually add it to moodle itself.

I could send it to the CS teacher so he can upload it to the server, but I don't know where to go from that point onward. It would probably work fine if I just add a reference to it in every single question it would be used in like


<p class="conversation">

Horst: ...
Lieselotte: ...
...
</p>

<script src="http://www.example.com/conversation.js"></script>


but what would happen if multiple of those questions were visible at the same time? I don't think loading it more than once would be particularly beneficial. Since only the German courses will be using it, I don't really want to include it through Site administration → Appearance → Additional HTML, even though that would probably do the job. Is there a setting like this which is limited to one particular course? Is this even the right way to approach this?


Any help would be appreciated. Thanks in advance
... I am not sure anymore whether two months worth of pocket money are actually worth it

Average of ratings: -
In reply to Tim Pietz

Re: Inject Javascript in certain courses

by Davo Smith -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Generally you can't inject javascript into a course, without writing a plugin to support it - for security reasons, Moodle strips out any arbitrary javascript entered via the front end.

That said, if you were able to put the relevant javascript into a .js file accessible over the internet (preferably saved on your Moodle server), then you could possibly use the Generico plugin ( https://moodle.org/plugins/view/filter_generico ) to load that javascript, when you inserted a particular tag into the page. Disclaimer - I've never actually used the Generico plugin (it has just always sounded like a really good solution to many issues).


Average of ratings: Useful (1)
In reply to Davo Smith

Re: Inject Javascript in certain courses

by Tim Pietz -

I'm probably just missing something, but I don't see how exactly this would help me. Wouldn't the Generico tag still be additional HTML I somehow have to get on every single page in the course and practically just replace the

<script src="http://www.example.com/conversation.js"></script>

with a {GENERICO:type=conversation}?

The one alternative I see this might open would be to give each paragraph containing a conversation a unique id instead of the class "conversation", and passing that directly into the javascript code through generico. The script could still potentially be loaded and executed more than once on a single page, they however would at least not interfere, since every instance would know which conversation it has to manage.

I don't know whether it is better to load the same script potentially ten times on a single page or to load the 4kb script on every single page and have it switch itself off if it isn't needed on that particular one.

In reply to Tim Pietz

Re: Inject Javascript in certain courses

by Davo Smith -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I was assuming you'd add the generico filter item at the same time as you added the '<p class="conversation>...</p>' entry, or possibly even putting the conversation content as an attribute for the generico filter (which would give more flexibility to later adjust the HTML required for this to work). This would then load the javascript onto that page for you.

If you just want to load the script onto every page, regardless of whether or not it is needed in that case, then you could add it as part of your site's theme.

Average of ratings: Useful (1)
In reply to Davo Smith

Re: Inject Javascript in certain courses

by Marcus Green -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers

Perhaps this could be done via a filter, they are quite easy to create and can be turned on and off on a course by course basis. I built one recently and was pleased with the result.

In reply to Davo Smith

Re: Inject Javascript in certain courses

by Tim Pietz -

The plan was to add it after every single '<p class="conversation>...</p>', but the problem with that is that I can't control whether there are multiple of these conversations visible at once, and adding the Generico filter after every single one would lead to the script being loaded more than once on a single page. Every single instance would try to scan the whole page for these conversations and handle every single one of them, and I could see that causing problems. The way I understand it, the Generico filter would simply replace the script tag after every '<p class="conversation>...</p>' from the original post, and because of that, would not solve the problem of the script being loaded more than once. Now I don't expect there to be something that allows me to add a script if a particular type of filter occurs at least once on a page instead of adding a script for every single time the filter is found.

My next best solution would be to add the script to every single page, regardless of whether or not it is needed (even though I don't really like it that way). But I also don't want to include it in literally every single page in every single course including maths, CS, English and so on, just because the German teacher thought it would be a good idea. This is why I'm asking if either there is a way to add it to the German course exclusively or if anyone here has got another idea I haven't even thought about.

Generico surely looks interesting, and you have already helped me solve the problem I would have asked about next with it (thanks for that!), but I don't know yet whether it is the solution to this one.

In reply to Tim Pietz

Re: Inject Javascript in certain courses

by Justin Hunt -
Picture of Particularly helpful Moodlers Picture of Plugin developers

I am a bit late to this thread, sorry. 

You would only need to put one Generico tag on the page and tell it to parse all passages of class "conversation."

If you have jquery available on the site, then the script part of the generico template would look a bit like this:

$('.conversation').each(function () {
   //call some function from conversation.js and probably pass "this" as a ref. to the relevant p tag 
});

If you don't have jquery, then you would do it with YUI. I think that would be:

M.filter_generico.gyui.all('.conversation').each(function(conversation){
  //call some function from conversation.js and pass conversation as a ref to the p tag
});

For each generico tag, your script will get run. Actually thats not so bad. Moodle will only load your javascript file (in this case, conversation.js) once. And even that should get cached. 

But in the examples I have given you only need one Generico tag on the page and it will just hunt down all the "conversation" classed passages and deal with them. 



In reply to Tim Pietz

Re: Inject Javascript in certain courses

by Justin Hunt -
Picture of Particularly helpful Moodlers Picture of Plugin developers

I am a bit late to this thread, sorry. 

You would only need to put one Generico tag on the page and tell it to parse all passages of class "conversation."

If you have jquery available on the site, then the script part of the generico template would look a bit like this:

$('.conversation').each(function () {
   //call some function from conversation.js and probably pass "this" as a ref. to the relevant p tag 
});

If you don't have jquery, then you would do it with YUI. I think that would be:

M.filter_generico.gyui.all('.conversation').each(function(conversation){
  //call some function from conversation.js and pass conversation as a ref to the p tag
});

For each generico tag, your script will get run. Actually thats not so bad. Moodle will only load your javascript file (in this case, conversation.js) once. And even that should get cached. 

But in the examples I have given you only need one Generico tag on the page and it will just hunt down all the "conversation" classed passages and deal with them. 

If the situation is more that you have to put the generico tag with each question, and goodness knows how many questions will be on the page, then just add a class "conversationprocessed" to the passage when done. And check for the existence/absence of that before beginning processing.



In reply to Tim Pietz

Re: Inject Javascript in certain courses

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Davo has already given you a better technical answer than I could think of. (Otherwise, Additional HTML is probably the least bad option.)

However, I just wanted to express the hope that while the pocket money may not have been worth it, I hope, and it seems, that you have had quite an interesting time learning about Moodle, and how to achieve these things. Also, later, this might turn out to be a valuable thing to put as experience on future job applications.

Average of ratings: Useful (2)
In reply to Tim Hunt

Re: Inject Javascript in certain courses

by Marcus Green -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers

That is one of the best requests for help from a student I have read in these forums. The ability to ask a well thought out question is an underrated but very useful talent. 

Average of ratings: Useful (2)