<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ryanwyllie</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ryanwyllie"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Ryanwyllie"/>
	<updated>2026-04-13T11:34:33Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=56319</id>
		<title>Javascript Modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=56319"/>
		<updated>2019-08-05T06:19:52Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: /* ES6 Modules (Moodle v3.8 and above) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
= Javascript Modules =&lt;br /&gt;
&lt;br /&gt;
== What is a Javascript module and why do I care? ==&lt;br /&gt;
&lt;br /&gt;
A Javascript module is nothing more than a collection of Javascript code that can be used (reliably) from other pieces of Javascript. &lt;br /&gt;
&lt;br /&gt;
== Why should I package my code as a module? ==&lt;br /&gt;
&lt;br /&gt;
By packaging your code as a module you break your code up into smaller reusable pieces. This is good because:&lt;br /&gt;
&lt;br /&gt;
a) Each smaller piece is simpler to understand / debug&lt;br /&gt;
&lt;br /&gt;
b) Each smaller piece is simpler to test&lt;br /&gt;
&lt;br /&gt;
c) You can re-use common code instead of duplicating it&lt;br /&gt;
&lt;br /&gt;
= How do I write a Javascript module in Moodle? =&lt;br /&gt;
&lt;br /&gt;
Since version 2.9, Moodle supports Javascript modules written using the Asynchronous Module Definition ([https://github.com/amdjs/amdjs-api/wiki/AMD AMD]) API. This is a standard API for creating Javascript modules and you will find many useful third party libraries that are already using this format. &lt;br /&gt;
&lt;br /&gt;
To edit or create an AMD module in Moodle you need to do a couple of things. &lt;br /&gt;
&lt;br /&gt;
Since version 3.8, Moodle supports [https://github.com/lukehoban/es6features#readme ECMAScript 2015 features] (aka ES6) in a cross browser compatible way thanks to [https://babeljs.io/ Babel JS]. In order to achieve the compatibility with older browsers Babel will compile the newer ES6 features back into ES5 Javascript. Unfortunately this means that in order for your Javascript changes to show in the browser they must be compiled by running Grunt, even with the cachejs config setting set to false (i.e. &amp;quot;Development mode&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Install grunt ==&lt;br /&gt;
&lt;br /&gt;
The AMD modules in Moodle must be processed by some build tools before they will be visible to your web browser. We use &amp;quot;[[grunt]]&amp;quot; as a build tool to wrap our different processes. Grunt is a build tool written in Javascript that runs in the &amp;quot;[http://nodejs.org/ nodejs]&amp;quot; environment.&lt;br /&gt;
&lt;br /&gt;
This means you first have to &#039;&#039;&#039;install nodejs&#039;&#039;&#039; - and its package manager [https://www.npmjs.com/ npm]. The details of how to install those packages will vary by operating system, but on Linux it&#039;s probably similar to &amp;quot;sudo apt-get install nodejs npm&amp;quot;. There are downloadable packages for other operating systems here: http://nodejs.org/download/. Moodle currently requires node {{NodeJSVersion}}.&lt;br /&gt;
&lt;br /&gt;
Once this is done, you can &#039;&#039;&#039;run the command&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
 npm install&lt;br /&gt;
 npm install -g grunt-cli&lt;br /&gt;
&lt;br /&gt;
from the top of the Moodle directory to install all of the required tools. (You may need extra permissions to use the -g option.)&lt;br /&gt;
&lt;br /&gt;
== Development mode (Moodle v2.9 to v3.7)  ==&lt;br /&gt;
&lt;br /&gt;
To avoid having to constantly run grunt, make sure you set the following in your config.php&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moodle will now run your module from the amd/src module. Don&#039;t forget to switch this off and run &#039;grunt&#039; before deploying the new version!&lt;br /&gt;
&lt;br /&gt;
In this mode - if you get a strange message in your javascript console like &amp;quot;No define call for core/first&amp;quot; it means you have a syntax error in the javascript you are developing. &lt;br /&gt;
Or, &amp;quot;No define call for theme_XXX/loader&amp;quot; as you are probably missing the &#039;src&#039; folder with relevant JS files. which might happen when you turn debugging ON on a theme that was bought, without &#039;src&#039; folder :-(&lt;br /&gt;
&lt;br /&gt;
== Development mode (Moodle v3.8 and above)  ==&lt;br /&gt;
&lt;br /&gt;
All Javascript code is now compiled using Babel which means Moodle will only ever serve minified Javascript to the browser, even in development mode. However in development mode Moodle will also send the browser the corresponding source map files for each of the Javascript modules. The source map files will tell the browser how to map the minified source code back to the unminified original source code so that the original source files will be displayed in the sources section of the browser&#039;s development tools.&lt;br /&gt;
&lt;br /&gt;
While in development mode each of the Javascript modules will appear in the browser&#039;s source tree as separate modules (no more giant first.js file!) and they will also be loaded with individual network requests (this is a compromise we had to make thanks to some browser bugs with source map files).&lt;br /&gt;
&lt;br /&gt;
To enable development mode set the &#039;&#039;&#039;cachejs&#039;&#039;&#039; config value to &#039;&#039;&#039;false&#039;&#039;&#039; in the admin settings or directly in your config.php file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since all Javascript must now be compiled you must run Grunt in order for you changes to appear in the browser. However rather than running Grunt manually each time on either the whole project or each file you modified, it is recommended that you just run the &#039;&#039;&#039;grunt watch&#039;&#039;&#039; task at the root of your Moodle directory. The grunt watch task will listen for changes to the Javascript files in the Moodle directory and will automatically lint and compile only the file that is changed after each change is detected. This removes the need to manually run grunt after each change.&lt;br /&gt;
&lt;br /&gt;
== Running grunt ==&lt;br /&gt;
&lt;br /&gt;
You can run grunt in your plugin&#039;s &#039;amd&#039; directory and it will only operate on your modules. If you&#039;re having problems or just want to check your work it is worth running for the &#039;lint&#039; feature. This can find basic problems. This sub-directory support wont work on Windows unfortunately but there is an alternative: Run grunt from the top directory with the --root=path/to/dir to limit execution to a sub-directory.&lt;br /&gt;
&lt;br /&gt;
See [[Grunt#Running_grunt]] for more details of specific grunt commands which can be used.&lt;br /&gt;
&lt;br /&gt;
If you get the error message&lt;br /&gt;
&lt;br /&gt;
 /usr/bin/env: node: No such file or directory&lt;br /&gt;
&lt;br /&gt;
Then see the thread https://github.com/nodejs/node-v0.x-archive/issues/3911&lt;br /&gt;
&lt;br /&gt;
On Ubuntu 14.04 this fixed it for me:&lt;br /&gt;
&lt;br /&gt;
 sudo ln -fs /usr/bin/nodejs /usr/local/bin/node&lt;br /&gt;
&lt;br /&gt;
Note: Once you have run grunt and built your code, you will then need to purge Moodle caches otherwise the changes made to your minified files may not be picked up by Moodle.&lt;br /&gt;
&lt;br /&gt;
== ES6 Modules (Moodle v3.8 and above) ==&lt;br /&gt;
&lt;br /&gt;
In addition to AMD module syntax Moodle now supports the [https://github.com/lukehoban/es6features#modules ES6 syntax] for writing Javascript modules. All modules (defined using either syntax) are compatible with one another. Behind the scenes the ES6 module syntax is converted into an AMD syntax as part of the Babel compiling process.&lt;br /&gt;
&lt;br /&gt;
=== Export default ===&lt;br /&gt;
There is one slight difference between the ES6 definition for exporting modules and the RequireJS (AMD) definition.&lt;br /&gt;
&lt;br /&gt;
ES6 allows you to export a “default” value which is actually no different to exporting a named value where the name is “default”. Unfortunately, RequireJS allows for unnamed default exports (e.g. you can do &amp;quot;return SomeClass;&amp;quot;) which can be imported by just requiring them in other AMD modules.&lt;br /&gt;
&lt;br /&gt;
That’s a bit confusing, get to the point! Well, it basically means that in Moodle you won’t be able to write an ES6 module that exports both a default and named exports, e.g. &amp;quot;export default function() {...}&amp;quot; and &amp;quot;export const FOO = &#039;bar&#039;&amp;quot; in the same module. The export default will simply override all other exports in that module.&lt;br /&gt;
&lt;br /&gt;
=== Inline Javascript ===&lt;br /&gt;
Another important note is that ES6 support is only for stand alone Javascript files because it relies on the compilation from Babel and Grunt. That means any inline Javascript (either in PHP or in Mustache templates) won&#039;t support the ES6 features. Instead it would be best to keep the inline Javascript as minimal as possible and only use it to load a stand alone Javascript module.&lt;br /&gt;
&lt;br /&gt;
== Minimum (getting started) module for plugins ==&lt;br /&gt;
&lt;br /&gt;
This shows the absolute minimum module you need to get started adding modules to your plugins. It&#039;s actually quite simple...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Put this file in path/to/plugin/amd/src&lt;br /&gt;
// You can call it anything you like&lt;br /&gt;
&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
&lt;br /&gt;
            // Put whatever you like here. $ is available&lt;br /&gt;
            // to you as normal.&lt;br /&gt;
            $(&amp;quot;.someclass&amp;quot;).change(function() {&lt;br /&gt;
                alert(&amp;quot;It changed!!&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code passes the jquery module into our function (parameter $). There are a number of other useful modules available in Moodle, some of which you&#039;ll probably need in a practical application. See [[Useful_core_Javascript_modules]]. Simply list them in both the define() first parameter and the function callback. E.g.,&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    define([&#039;jquery&#039;, &#039;core/str&#039;, &#039;core/ajax&#039;], function($, str, ajax) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The idea here is that we will run the &#039;init&#039; function from our (PHP) code to set things up. This is called from PHP like this...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;frankenstyle_path/your_js_filename&#039;, &#039;init&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to supply the complete &#039;[[Frankenstyle]]&#039; path. The .js is not needed. &lt;br /&gt;
&lt;br /&gt;
js_call_amd takes a third parameter which is an &#039;&#039;array&#039;&#039; of parameters. These will translate to individual parameters in the &#039;init&#039; function call. For example...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;block_iomad_company_admin/department_select&#039;, &#039;init&#039;, array($first, $last));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...calls&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    return {&lt;br /&gt;
        init: function(first, last) {&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A more comprehensive explanation follows...&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Hello World&amp;quot; I am a Javascript Module ==&lt;br /&gt;
Lets now create a simple Javascript module so we can see how to lay things out. &lt;br /&gt;
&lt;br /&gt;
Each Javascript module is contained in a single source file in the &amp;lt;componentdir&amp;gt;/amd/src folder. The final name of the module is taken from the file name and the component name. E.g. block_overview/amd/src/helloworld.js would be a module named &amp;quot;block_overview/helloworld&amp;quot;. the name of the module is important when you want to call it from somewhere else in the code. &lt;br /&gt;
&lt;br /&gt;
After running grunt - the minified Javascript files are stored in the &amp;lt;componentdir&amp;gt;/amd/build folder. The javascript files are renamed to show that they are minified (helloworld.js becomes helloworld.min.js). &lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to add the built files (the ones in amd/build) to your git commits, or in production no-one will see your changes. &lt;br /&gt;
&lt;br /&gt;
Lets create a simple module now:&lt;br /&gt;
&lt;br /&gt;
blocks/overview/amd/src/helloworld.js&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Standard license block omitted.&lt;br /&gt;
/*&lt;br /&gt;
 * @package    block_overview&lt;br /&gt;
 * @copyright  2015 Someone cool&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * @module block_overview/helloworld&lt;br /&gt;
  */&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&lt;br /&gt;
     /** &lt;br /&gt;
      * Give me blue.&lt;br /&gt;
      * @access private&lt;br /&gt;
      * @return {string}&lt;br /&gt;
      */&lt;br /&gt;
     var makeItBlue = function() {&lt;br /&gt;
          // We can use our jquery dependency here.&lt;br /&gt;
          return $(&#039;.blue&#039;).show();&lt;br /&gt;
     };&lt;br /&gt;
      &lt;br /&gt;
    /**&lt;br /&gt;
     * @constructor&lt;br /&gt;
     * @alias module:block_overview/helloworld&lt;br /&gt;
     */&lt;br /&gt;
    var greeting = function() {&lt;br /&gt;
        /** @access private */&lt;br /&gt;
        var privateThoughts = &#039;I like the colour blue&#039;;&lt;br /&gt;
        &lt;br /&gt;
        /** @access public */&lt;br /&gt;
        this.publicThoughts = &#039;I like the colour orange&#039;;&lt;br /&gt;
&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * A formal greeting.&lt;br /&gt;
     * @access public&lt;br /&gt;
     * @return {string}&lt;br /&gt;
     */&lt;br /&gt;
    greeting.prototype.formal = function() {&lt;br /&gt;
        return &#039;How do you do?&#039;;&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * An informal greeting.&lt;br /&gt;
     * @access public&lt;br /&gt;
     * @return {string}&lt;br /&gt;
     */&lt;br /&gt;
    greeting.prototype.informal = function() {&lt;br /&gt;
        return &#039;Wassup!&#039;;&lt;br /&gt;
    };&lt;br /&gt;
    return greeting;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The most interesting line above is:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All AMD modules must call &amp;quot;define()&amp;quot; as the first and only global scoped piece of code. This ensures the javascript code contains no global variables and will not conflict with any other loaded module. The name of the module does not need to be specified because it is determined from the filename and component (but it can be listed in a comment for JSDoc as shown here). &lt;br /&gt;
&lt;br /&gt;
The first argument to &amp;quot;define&amp;quot; is the list of dependencies for the module. This argument must be passed as an array, even if there is only one. In this example &amp;quot;jquery&amp;quot; is a dependency. &amp;quot;jquery&amp;quot; is shipped as a core module is available to all AMD modules. &lt;br /&gt;
&lt;br /&gt;
The second argument to &amp;quot;define&amp;quot; is the function that defines the module. This function will receive as arguments, each of the requested dependencies in the same order they were requested. In this example we receive JQuery as an argument and we name the variable &amp;quot;$&amp;quot; (it&#039;s a JQuery thing). We can then access JQuery normally through the $ variable which is in scope for any code in our module. &lt;br /&gt;
&lt;br /&gt;
The rest of the code in this example is a standard way to define a Javascript module with public/private variables and methods. There are many ways to do this, this is only one.&lt;br /&gt;
&lt;br /&gt;
It is important that we are returning &#039;greeting&#039;. If there is no return then your module will be declared as undefined.&lt;br /&gt;
&lt;br /&gt;
== Loading modules dynamically ==&lt;br /&gt;
What do you do if you don&#039;t know in advance which modules will be required? Stuffing all possible required modules in the define call is one solution, but it&#039;s ugly and it only works for code that is in an AMD module (what about inline code in the page?). AMD lets you load a dependency any time you like. &lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Load a new dependency.&lt;br /&gt;
require([&#039;mod_wiki/timer&#039;], function(timer) {&lt;br /&gt;
   // timer is available to do my bidding.&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Including an external javascript/jquery library ==&lt;br /&gt;
If you want to include a javascript / jquery library downloaded from the internet you can do so as follows:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning: if the library you download, supports AMD but is already &amp;quot;named&amp;quot; you will not be able to include it directly&#039;&#039;&#039;&lt;br /&gt;
e.g. &lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
        define(&amp;quot;typeahead.js&amp;quot;, *[ &amp;quot;jquery&amp;quot; ], function(a0) {&lt;br /&gt;
            return factory(a0);&lt;br /&gt;
        });&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
will not work, as moodle injects it&#039;s own define name when loading the library.&lt;br /&gt;
&lt;br /&gt;
If the library is in AMD format and has a define:&lt;br /&gt;
e.g. i want to include the jquery final countdown timer on my page ( hilios.github.io/jQuery.countdown/ )&lt;br /&gt;
* download the module in both normal and minified versions&lt;br /&gt;
* place the modules in your moodle install e.g. your custom theme dir, or plugin dir&lt;br /&gt;
* /theme/mytheme/amd/src/jquery.countdown.js&lt;br /&gt;
&lt;br /&gt;
you can now include the module and initialise it (there are multiple ways to do this)&lt;br /&gt;
php:&lt;br /&gt;
&lt;br /&gt;
1. Create your own AMD module and initialise it:&lt;br /&gt;
&lt;br /&gt;
In your PHP file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;theme_mytheme/countdowntimer&#039;, &#039;initialise&#039;, $params);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Javascript module:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// /theme/mytheme/amd/src/countdowntimer.js&lt;br /&gt;
define([&#039;jquery&#039;, &#039;theme_mytheme/jquery.countdown&#039;], function($, c) {&lt;br /&gt;
    return {&lt;br /&gt;
        initialise: function ($params) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Put the javascript into a mustache template:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// /theme/mytheme/templates/countdowntimer.mustache&lt;br /&gt;
&amp;lt;span id=&amp;quot;clock&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require([&#039;jquery&#039;, &#039;theme_mytheme/jquery.countdown&#039;], function($) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Call the javascript directly from php (although who would want to put javascript into php? ergh):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_amd_inline(&#039;&lt;br /&gt;
require([&#039;theme_mytheme/jquery.countdown&#039;], function(min) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
});&lt;br /&gt;
&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Note: It could be useful when you wish to pass a big chunk of data from php directly into a JS variable, to workaround MDL-62468 .&amp;lt;br&amp;gt;&lt;br /&gt;
Example: https://github.com/moodle/moodle/blob/master/media/player/videojs/classes/plugin.php#L386&lt;br /&gt;
&lt;br /&gt;
===More examples of including 3rd-party JS modules===&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=327579#p1317252 Adding custom js via AMD (highcharts) to essential theme]&lt;br /&gt;
&lt;br /&gt;
== Embedding AMD code in a page ==&lt;br /&gt;
So you have created lots of cool Javascript modules. Great. How do we actually call them? Any javascript code that calls an AMD module must execute AFTER the requirejs module loader has finished loading. We have provided a function &amp;quot;js_call_amd&amp;quot; that will call a single function from an AMD module with parameters.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd($modulename, $functionname, $params);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
that will &amp;quot;do the right thing&amp;quot; with your block of AMD code and execute it at the end of the page, after our AMD module loader has loaded. &lt;br /&gt;
Notes:&lt;br /&gt;
* the $modulename is the &#039;componentname/modulename&#039; discussed above&lt;br /&gt;
* the $functionname is the name of a public function exposed by the amd module. &lt;br /&gt;
* the $params is an array of params passed as arguments to the function. These should be simple types that can be handled by json_encode (no recursive arrays, or complex classes please). &lt;br /&gt;
* if the size of the params array is too large (&amp;gt; 1Kb), this will produce a developer warning. Do not attempt to pass large amounts of data through this function, it will pollute the page size. A preferred approach is to pass css selectors for DOM elements that contain data-attributes for any required data, or fetch data via ajax in the background.&lt;br /&gt;
&lt;br /&gt;
AMD / JS code can also be embedded on a page via mustache templates&lt;br /&gt;
see here: https://docs.moodle.org/dev/Templates#What_if_a_template_contains_javascript.3F&lt;br /&gt;
&lt;br /&gt;
== But I have a mega JS file I don&#039;t want loaded on every page? ==&lt;br /&gt;
Loading all JS files at once and stuffing them in the browser cache is the right choice for MOST js files, there are probably some exceptions. For these files, you can rename the javascript file to end with the suffix &amp;quot;-lazy.js&amp;quot; which indicates that the module will not be loaded by default, it will be requested the first time it is used. There is no difference in usage for lazy loaded modules, the require() call looks exactly the same, it&#039;s just that the module name will also have the &amp;quot;-lazy&amp;quot; suffix.&lt;br /&gt;
&lt;br /&gt;
== Useful links ==&lt;br /&gt;
* [https://assets.moodlemoot.org/sites/15/20171004085436/JavaScript-AMD-with-RequireJS-presented-by-Daniel-Roperto-Catalyst.pdf JavaScript AMD with RequireJS] presented by Daniel Roperto, Catalyst. (MoodleMOOT AU 2017)&lt;br /&gt;
* [[Useful_core_Javascript_modules]]&lt;br /&gt;
*[[Guide_to_adding_third_party_jQuery_for_AMD]] by Patrick Thibaudeau&lt;br /&gt;
*[https://moodle.org/mod/forum/discuss.php?d=378112#p1524459 How to get variables from PHP into javascript AMD modules in M3.5] Justin Hunt, on Moodle forums.&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=56318</id>
		<title>Javascript Modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=56318"/>
		<updated>2019-08-05T06:14:15Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
= Javascript Modules =&lt;br /&gt;
&lt;br /&gt;
== What is a Javascript module and why do I care? ==&lt;br /&gt;
&lt;br /&gt;
A Javascript module is nothing more than a collection of Javascript code that can be used (reliably) from other pieces of Javascript. &lt;br /&gt;
&lt;br /&gt;
== Why should I package my code as a module? ==&lt;br /&gt;
&lt;br /&gt;
By packaging your code as a module you break your code up into smaller reusable pieces. This is good because:&lt;br /&gt;
&lt;br /&gt;
a) Each smaller piece is simpler to understand / debug&lt;br /&gt;
&lt;br /&gt;
b) Each smaller piece is simpler to test&lt;br /&gt;
&lt;br /&gt;
c) You can re-use common code instead of duplicating it&lt;br /&gt;
&lt;br /&gt;
= How do I write a Javascript module in Moodle? =&lt;br /&gt;
&lt;br /&gt;
Since version 2.9, Moodle supports Javascript modules written using the Asynchronous Module Definition ([https://github.com/amdjs/amdjs-api/wiki/AMD AMD]) API. This is a standard API for creating Javascript modules and you will find many useful third party libraries that are already using this format. &lt;br /&gt;
&lt;br /&gt;
To edit or create an AMD module in Moodle you need to do a couple of things. &lt;br /&gt;
&lt;br /&gt;
Since version 3.8, Moodle supports [https://github.com/lukehoban/es6features#readme ECMAScript 2015 features] (aka ES6) in a cross browser compatible way thanks to [https://babeljs.io/ Babel JS]. In order to achieve the compatibility with older browsers Babel will compile the newer ES6 features back into ES5 Javascript. Unfortunately this means that in order for your Javascript changes to show in the browser they must be compiled by running Grunt, even with the cachejs config setting set to false (i.e. &amp;quot;Development mode&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Install grunt ==&lt;br /&gt;
&lt;br /&gt;
The AMD modules in Moodle must be processed by some build tools before they will be visible to your web browser. We use &amp;quot;[[grunt]]&amp;quot; as a build tool to wrap our different processes. Grunt is a build tool written in Javascript that runs in the &amp;quot;[http://nodejs.org/ nodejs]&amp;quot; environment.&lt;br /&gt;
&lt;br /&gt;
This means you first have to &#039;&#039;&#039;install nodejs&#039;&#039;&#039; - and its package manager [https://www.npmjs.com/ npm]. The details of how to install those packages will vary by operating system, but on Linux it&#039;s probably similar to &amp;quot;sudo apt-get install nodejs npm&amp;quot;. There are downloadable packages for other operating systems here: http://nodejs.org/download/. Moodle currently requires node {{NodeJSVersion}}.&lt;br /&gt;
&lt;br /&gt;
Once this is done, you can &#039;&#039;&#039;run the command&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
 npm install&lt;br /&gt;
 npm install -g grunt-cli&lt;br /&gt;
&lt;br /&gt;
from the top of the Moodle directory to install all of the required tools. (You may need extra permissions to use the -g option.)&lt;br /&gt;
&lt;br /&gt;
== Development mode (Moodle v2.9 to v3.7)  ==&lt;br /&gt;
&lt;br /&gt;
To avoid having to constantly run grunt, make sure you set the following in your config.php&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moodle will now run your module from the amd/src module. Don&#039;t forget to switch this off and run &#039;grunt&#039; before deploying the new version!&lt;br /&gt;
&lt;br /&gt;
In this mode - if you get a strange message in your javascript console like &amp;quot;No define call for core/first&amp;quot; it means you have a syntax error in the javascript you are developing. &lt;br /&gt;
Or, &amp;quot;No define call for theme_XXX/loader&amp;quot; as you are probably missing the &#039;src&#039; folder with relevant JS files. which might happen when you turn debugging ON on a theme that was bought, without &#039;src&#039; folder :-(&lt;br /&gt;
&lt;br /&gt;
== Development mode (Moodle v3.8 and above)  ==&lt;br /&gt;
&lt;br /&gt;
All Javascript code is now compiled using Babel which means Moodle will only ever serve minified Javascript to the browser, even in development mode. However in development mode Moodle will also send the browser the corresponding source map files for each of the Javascript modules. The source map files will tell the browser how to map the minified source code back to the unminified original source code so that the original source files will be displayed in the sources section of the browser&#039;s development tools.&lt;br /&gt;
&lt;br /&gt;
While in development mode each of the Javascript modules will appear in the browser&#039;s source tree as separate modules (no more giant first.js file!) and they will also be loaded with individual network requests (this is a compromise we had to make thanks to some browser bugs with source map files).&lt;br /&gt;
&lt;br /&gt;
To enable development mode set the &#039;&#039;&#039;cachejs&#039;&#039;&#039; config value to &#039;&#039;&#039;false&#039;&#039;&#039; in the admin settings or directly in your config.php file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since all Javascript must now be compiled you must run Grunt in order for you changes to appear in the browser. However rather than running Grunt manually each time on either the whole project or each file you modified, it is recommended that you just run the &#039;&#039;&#039;grunt watch&#039;&#039;&#039; task at the root of your Moodle directory. The grunt watch task will listen for changes to the Javascript files in the Moodle directory and will automatically lint and compile only the file that is changed after each change is detected. This removes the need to manually run grunt after each change.&lt;br /&gt;
&lt;br /&gt;
== Running grunt ==&lt;br /&gt;
&lt;br /&gt;
You can run grunt in your plugin&#039;s &#039;amd&#039; directory and it will only operate on your modules. If you&#039;re having problems or just want to check your work it is worth running for the &#039;lint&#039; feature. This can find basic problems. This sub-directory support wont work on Windows unfortunately but there is an alternative: Run grunt from the top directory with the --root=path/to/dir to limit execution to a sub-directory.&lt;br /&gt;
&lt;br /&gt;
See [[Grunt#Running_grunt]] for more details of specific grunt commands which can be used.&lt;br /&gt;
&lt;br /&gt;
If you get the error message&lt;br /&gt;
&lt;br /&gt;
 /usr/bin/env: node: No such file or directory&lt;br /&gt;
&lt;br /&gt;
Then see the thread https://github.com/nodejs/node-v0.x-archive/issues/3911&lt;br /&gt;
&lt;br /&gt;
On Ubuntu 14.04 this fixed it for me:&lt;br /&gt;
&lt;br /&gt;
 sudo ln -fs /usr/bin/nodejs /usr/local/bin/node&lt;br /&gt;
&lt;br /&gt;
Note: Once you have run grunt and built your code, you will then need to purge Moodle caches otherwise the changes made to your minified files may not be picked up by Moodle.&lt;br /&gt;
&lt;br /&gt;
== ES6 Modules (Moodle v3.8 and above) ==&lt;br /&gt;
&lt;br /&gt;
In addition to AMD module syntax Moodle now supports the [https://github.com/lukehoban/es6features#modules ES6 syntax] for writing Javascript modules. All modules (defined using either syntax) are compatible with one another. Behind the scenes the ES6 module syntax is converted into an AMD syntax as part of the Babel compiling process.&lt;br /&gt;
&lt;br /&gt;
There is one slight difference between the ES6 definition for exporting modules and the RequireJS (AMD) definition.&lt;br /&gt;
&lt;br /&gt;
ES6 allows you to export a “default” value which is actually no different to exporting a named value where the name is “default”. Unfortunately, RequireJS allows for unnamed default exports (e.g. you can do &amp;quot;return SomeClass;&amp;quot;) which can be imported by just requiring them in other AMD modules.&lt;br /&gt;
&lt;br /&gt;
That’s a bit confusing, get to the point! Well, it basically means that in Moodle you won’t be able to write an ES6 module that exports both a default and named exports, e.g. &amp;quot;export default function() {...}&amp;quot; and &amp;quot;export const FOO = &#039;bar&#039;&amp;quot; in the same module. The export default will simply override all other exports in that module.&lt;br /&gt;
&lt;br /&gt;
== Minimum (getting started) module for plugins ==&lt;br /&gt;
&lt;br /&gt;
This shows the absolute minimum module you need to get started adding modules to your plugins. It&#039;s actually quite simple...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Put this file in path/to/plugin/amd/src&lt;br /&gt;
// You can call it anything you like&lt;br /&gt;
&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
&lt;br /&gt;
            // Put whatever you like here. $ is available&lt;br /&gt;
            // to you as normal.&lt;br /&gt;
            $(&amp;quot;.someclass&amp;quot;).change(function() {&lt;br /&gt;
                alert(&amp;quot;It changed!!&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code passes the jquery module into our function (parameter $). There are a number of other useful modules available in Moodle, some of which you&#039;ll probably need in a practical application. See [[Useful_core_Javascript_modules]]. Simply list them in both the define() first parameter and the function callback. E.g.,&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    define([&#039;jquery&#039;, &#039;core/str&#039;, &#039;core/ajax&#039;], function($, str, ajax) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The idea here is that we will run the &#039;init&#039; function from our (PHP) code to set things up. This is called from PHP like this...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;frankenstyle_path/your_js_filename&#039;, &#039;init&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to supply the complete &#039;[[Frankenstyle]]&#039; path. The .js is not needed. &lt;br /&gt;
&lt;br /&gt;
js_call_amd takes a third parameter which is an &#039;&#039;array&#039;&#039; of parameters. These will translate to individual parameters in the &#039;init&#039; function call. For example...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;block_iomad_company_admin/department_select&#039;, &#039;init&#039;, array($first, $last));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...calls&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    return {&lt;br /&gt;
        init: function(first, last) {&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A more comprehensive explanation follows...&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Hello World&amp;quot; I am a Javascript Module ==&lt;br /&gt;
Lets now create a simple Javascript module so we can see how to lay things out. &lt;br /&gt;
&lt;br /&gt;
Each Javascript module is contained in a single source file in the &amp;lt;componentdir&amp;gt;/amd/src folder. The final name of the module is taken from the file name and the component name. E.g. block_overview/amd/src/helloworld.js would be a module named &amp;quot;block_overview/helloworld&amp;quot;. the name of the module is important when you want to call it from somewhere else in the code. &lt;br /&gt;
&lt;br /&gt;
After running grunt - the minified Javascript files are stored in the &amp;lt;componentdir&amp;gt;/amd/build folder. The javascript files are renamed to show that they are minified (helloworld.js becomes helloworld.min.js). &lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to add the built files (the ones in amd/build) to your git commits, or in production no-one will see your changes. &lt;br /&gt;
&lt;br /&gt;
Lets create a simple module now:&lt;br /&gt;
&lt;br /&gt;
blocks/overview/amd/src/helloworld.js&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Standard license block omitted.&lt;br /&gt;
/*&lt;br /&gt;
 * @package    block_overview&lt;br /&gt;
 * @copyright  2015 Someone cool&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * @module block_overview/helloworld&lt;br /&gt;
  */&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&lt;br /&gt;
     /** &lt;br /&gt;
      * Give me blue.&lt;br /&gt;
      * @access private&lt;br /&gt;
      * @return {string}&lt;br /&gt;
      */&lt;br /&gt;
     var makeItBlue = function() {&lt;br /&gt;
          // We can use our jquery dependency here.&lt;br /&gt;
          return $(&#039;.blue&#039;).show();&lt;br /&gt;
     };&lt;br /&gt;
      &lt;br /&gt;
    /**&lt;br /&gt;
     * @constructor&lt;br /&gt;
     * @alias module:block_overview/helloworld&lt;br /&gt;
     */&lt;br /&gt;
    var greeting = function() {&lt;br /&gt;
        /** @access private */&lt;br /&gt;
        var privateThoughts = &#039;I like the colour blue&#039;;&lt;br /&gt;
        &lt;br /&gt;
        /** @access public */&lt;br /&gt;
        this.publicThoughts = &#039;I like the colour orange&#039;;&lt;br /&gt;
&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * A formal greeting.&lt;br /&gt;
     * @access public&lt;br /&gt;
     * @return {string}&lt;br /&gt;
     */&lt;br /&gt;
    greeting.prototype.formal = function() {&lt;br /&gt;
        return &#039;How do you do?&#039;;&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * An informal greeting.&lt;br /&gt;
     * @access public&lt;br /&gt;
     * @return {string}&lt;br /&gt;
     */&lt;br /&gt;
    greeting.prototype.informal = function() {&lt;br /&gt;
        return &#039;Wassup!&#039;;&lt;br /&gt;
    };&lt;br /&gt;
    return greeting;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The most interesting line above is:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All AMD modules must call &amp;quot;define()&amp;quot; as the first and only global scoped piece of code. This ensures the javascript code contains no global variables and will not conflict with any other loaded module. The name of the module does not need to be specified because it is determined from the filename and component (but it can be listed in a comment for JSDoc as shown here). &lt;br /&gt;
&lt;br /&gt;
The first argument to &amp;quot;define&amp;quot; is the list of dependencies for the module. This argument must be passed as an array, even if there is only one. In this example &amp;quot;jquery&amp;quot; is a dependency. &amp;quot;jquery&amp;quot; is shipped as a core module is available to all AMD modules. &lt;br /&gt;
&lt;br /&gt;
The second argument to &amp;quot;define&amp;quot; is the function that defines the module. This function will receive as arguments, each of the requested dependencies in the same order they were requested. In this example we receive JQuery as an argument and we name the variable &amp;quot;$&amp;quot; (it&#039;s a JQuery thing). We can then access JQuery normally through the $ variable which is in scope for any code in our module. &lt;br /&gt;
&lt;br /&gt;
The rest of the code in this example is a standard way to define a Javascript module with public/private variables and methods. There are many ways to do this, this is only one.&lt;br /&gt;
&lt;br /&gt;
It is important that we are returning &#039;greeting&#039;. If there is no return then your module will be declared as undefined.&lt;br /&gt;
&lt;br /&gt;
== Loading modules dynamically ==&lt;br /&gt;
What do you do if you don&#039;t know in advance which modules will be required? Stuffing all possible required modules in the define call is one solution, but it&#039;s ugly and it only works for code that is in an AMD module (what about inline code in the page?). AMD lets you load a dependency any time you like. &lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Load a new dependency.&lt;br /&gt;
require([&#039;mod_wiki/timer&#039;], function(timer) {&lt;br /&gt;
   // timer is available to do my bidding.&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Including an external javascript/jquery library ==&lt;br /&gt;
If you want to include a javascript / jquery library downloaded from the internet you can do so as follows:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning: if the library you download, supports AMD but is already &amp;quot;named&amp;quot; you will not be able to include it directly&#039;&#039;&#039;&lt;br /&gt;
e.g. &lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
        define(&amp;quot;typeahead.js&amp;quot;, *[ &amp;quot;jquery&amp;quot; ], function(a0) {&lt;br /&gt;
            return factory(a0);&lt;br /&gt;
        });&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
will not work, as moodle injects it&#039;s own define name when loading the library.&lt;br /&gt;
&lt;br /&gt;
If the library is in AMD format and has a define:&lt;br /&gt;
e.g. i want to include the jquery final countdown timer on my page ( hilios.github.io/jQuery.countdown/ )&lt;br /&gt;
* download the module in both normal and minified versions&lt;br /&gt;
* place the modules in your moodle install e.g. your custom theme dir, or plugin dir&lt;br /&gt;
* /theme/mytheme/amd/src/jquery.countdown.js&lt;br /&gt;
&lt;br /&gt;
you can now include the module and initialise it (there are multiple ways to do this)&lt;br /&gt;
php:&lt;br /&gt;
&lt;br /&gt;
1. Create your own AMD module and initialise it:&lt;br /&gt;
&lt;br /&gt;
In your PHP file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;theme_mytheme/countdowntimer&#039;, &#039;initialise&#039;, $params);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Javascript module:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// /theme/mytheme/amd/src/countdowntimer.js&lt;br /&gt;
define([&#039;jquery&#039;, &#039;theme_mytheme/jquery.countdown&#039;], function($, c) {&lt;br /&gt;
    return {&lt;br /&gt;
        initialise: function ($params) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Put the javascript into a mustache template:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// /theme/mytheme/templates/countdowntimer.mustache&lt;br /&gt;
&amp;lt;span id=&amp;quot;clock&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require([&#039;jquery&#039;, &#039;theme_mytheme/jquery.countdown&#039;], function($) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Call the javascript directly from php (although who would want to put javascript into php? ergh):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_amd_inline(&#039;&lt;br /&gt;
require([&#039;theme_mytheme/jquery.countdown&#039;], function(min) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
});&lt;br /&gt;
&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Note: It could be useful when you wish to pass a big chunk of data from php directly into a JS variable, to workaround MDL-62468 .&amp;lt;br&amp;gt;&lt;br /&gt;
Example: https://github.com/moodle/moodle/blob/master/media/player/videojs/classes/plugin.php#L386&lt;br /&gt;
&lt;br /&gt;
===More examples of including 3rd-party JS modules===&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=327579#p1317252 Adding custom js via AMD (highcharts) to essential theme]&lt;br /&gt;
&lt;br /&gt;
== Embedding AMD code in a page ==&lt;br /&gt;
So you have created lots of cool Javascript modules. Great. How do we actually call them? Any javascript code that calls an AMD module must execute AFTER the requirejs module loader has finished loading. We have provided a function &amp;quot;js_call_amd&amp;quot; that will call a single function from an AMD module with parameters.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd($modulename, $functionname, $params);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
that will &amp;quot;do the right thing&amp;quot; with your block of AMD code and execute it at the end of the page, after our AMD module loader has loaded. &lt;br /&gt;
Notes:&lt;br /&gt;
* the $modulename is the &#039;componentname/modulename&#039; discussed above&lt;br /&gt;
* the $functionname is the name of a public function exposed by the amd module. &lt;br /&gt;
* the $params is an array of params passed as arguments to the function. These should be simple types that can be handled by json_encode (no recursive arrays, or complex classes please). &lt;br /&gt;
* if the size of the params array is too large (&amp;gt; 1Kb), this will produce a developer warning. Do not attempt to pass large amounts of data through this function, it will pollute the page size. A preferred approach is to pass css selectors for DOM elements that contain data-attributes for any required data, or fetch data via ajax in the background.&lt;br /&gt;
&lt;br /&gt;
AMD / JS code can also be embedded on a page via mustache templates&lt;br /&gt;
see here: https://docs.moodle.org/dev/Templates#What_if_a_template_contains_javascript.3F&lt;br /&gt;
&lt;br /&gt;
== But I have a mega JS file I don&#039;t want loaded on every page? ==&lt;br /&gt;
Loading all JS files at once and stuffing them in the browser cache is the right choice for MOST js files, there are probably some exceptions. For these files, you can rename the javascript file to end with the suffix &amp;quot;-lazy.js&amp;quot; which indicates that the module will not be loaded by default, it will be requested the first time it is used. There is no difference in usage for lazy loaded modules, the require() call looks exactly the same, it&#039;s just that the module name will also have the &amp;quot;-lazy&amp;quot; suffix.&lt;br /&gt;
&lt;br /&gt;
== Useful links ==&lt;br /&gt;
* [https://assets.moodlemoot.org/sites/15/20171004085436/JavaScript-AMD-with-RequireJS-presented-by-Daniel-Roperto-Catalyst.pdf JavaScript AMD with RequireJS] presented by Daniel Roperto, Catalyst. (MoodleMOOT AU 2017)&lt;br /&gt;
* [[Useful_core_Javascript_modules]]&lt;br /&gt;
*[[Guide_to_adding_third_party_jQuery_for_AMD]] by Patrick Thibaudeau&lt;br /&gt;
*[https://moodle.org/mod/forum/discuss.php?d=378112#p1524459 How to get variables from PHP into javascript AMD modules in M3.5] Justin Hunt, on Moodle forums.&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=56317</id>
		<title>Javascript Modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=56317"/>
		<updated>2019-08-05T05:57:08Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: /* How do I write a Javascript module in Moodle? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
= Javascript Modules =&lt;br /&gt;
&lt;br /&gt;
== What is a Javascript module and why do I care? ==&lt;br /&gt;
&lt;br /&gt;
A Javascript module is nothing more than a collection of Javascript code that can be used (reliably) from other pieces of Javascript. &lt;br /&gt;
&lt;br /&gt;
== Why should I package my code as a module? ==&lt;br /&gt;
&lt;br /&gt;
By packaging your code as a module you break your code up into smaller reusable pieces. This is good because:&lt;br /&gt;
&lt;br /&gt;
a) Each smaller piece is simpler to understand / debug&lt;br /&gt;
&lt;br /&gt;
b) Each smaller piece is simpler to test&lt;br /&gt;
&lt;br /&gt;
c) You can re-use common code instead of duplicating it&lt;br /&gt;
&lt;br /&gt;
= How do I write a Javascript module in Moodle? =&lt;br /&gt;
&lt;br /&gt;
Since version 2.9, Moodle supports Javascript modules written using the Asynchronous Module Definition ([https://github.com/amdjs/amdjs-api/wiki/AMD AMD]) API. This is a standard API for creating Javascript modules and you will find many useful third party libraries that are already using this format. &lt;br /&gt;
&lt;br /&gt;
To edit or create an AMD module in Moodle you need to do a couple of things. &lt;br /&gt;
&lt;br /&gt;
Since version 3.8, Moodle supports [https://babeljs.io/docs/en/learn#ecmascript-2015-features ECMAScript 2015 features] (aka ES6) in a cross browser compatible way thanks to [https://babeljs.io/ Babel JS]. In order to achieve the compatibility with older browsers Babel will compile the newer ES6 features back into ES5 Javascript. Unfortunately this means that in order for your Javascript changes to show in the browser they must be compiled by running Grunt, even with the cachejs config setting set to false (i.e. &amp;quot;Development mode&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Install grunt ==&lt;br /&gt;
&lt;br /&gt;
The AMD modules in Moodle must be processed by some build tools before they will be visible to your web browser. We use &amp;quot;[[grunt]]&amp;quot; as a build tool to wrap our different processes. Grunt is a build tool written in Javascript that runs in the &amp;quot;[http://nodejs.org/ nodejs]&amp;quot; environment.&lt;br /&gt;
&lt;br /&gt;
This means you first have to &#039;&#039;&#039;install nodejs&#039;&#039;&#039; - and its package manager [https://www.npmjs.com/ npm]. The details of how to install those packages will vary by operating system, but on Linux it&#039;s probably similar to &amp;quot;sudo apt-get install nodejs npm&amp;quot;. There are downloadable packages for other operating systems here: http://nodejs.org/download/. Moodle currently requires node {{NodeJSVersion}}.&lt;br /&gt;
&lt;br /&gt;
Once this is done, you can &#039;&#039;&#039;run the command&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
 npm install&lt;br /&gt;
 npm install -g grunt-cli&lt;br /&gt;
&lt;br /&gt;
from the top of the Moodle directory to install all of the required tools. (You may need extra permissions to use the -g option.)&lt;br /&gt;
&lt;br /&gt;
== Development mode (Moodle v2.9 to v3.7)  ==&lt;br /&gt;
&lt;br /&gt;
To avoid having to constantly run grunt, make sure you set the following in your config.php&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moodle will now run your module from the amd/src module. Don&#039;t forget to switch this off and run &#039;grunt&#039; before deploying the new version!&lt;br /&gt;
&lt;br /&gt;
In this mode - if you get a strange message in your javascript console like &amp;quot;No define call for core/first&amp;quot; it means you have a syntax error in the javascript you are developing. &lt;br /&gt;
Or, &amp;quot;No define call for theme_XXX/loader&amp;quot; as you are probably missing the &#039;src&#039; folder with relevant JS files. which might happen when you turn debugging ON on a theme that was bought, without &#039;src&#039; folder :-(&lt;br /&gt;
&lt;br /&gt;
== Development mode (Moodle v3.8 and above)  ==&lt;br /&gt;
&lt;br /&gt;
All Javascript code is now compiled using Babel which means Moodle will only ever serve minified Javascript to the browser, even in development mode. However in development mode Moodle will also send the browser the corresponding source map files for each of the Javascript modules. The source map files will tell the browser how to map the minified source code back to the unminified original source code so that the original source files will be displayed in the sources section of the browser&#039;s development tools.&lt;br /&gt;
&lt;br /&gt;
While in development mode each of the Javascript modules will appear in the browser&#039;s source tree as separate modules (no more giant first.js file!) and they will also be loaded with individual network requests (this is a compromise we had to make thanks to some browser bugs with source map files).&lt;br /&gt;
&lt;br /&gt;
To enable development mode set the &#039;&#039;&#039;cachejs&#039;&#039;&#039; config value to &#039;&#039;&#039;false&#039;&#039;&#039; in the admin settings or directly in your config.php file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since all Javascript must now be compiled you must run Grunt in order for you changes to appear in the browser. However rather than running Grunt manually each time on either the whole project or each file you modified, it is recommended that you just run the &#039;&#039;&#039;grunt watch&#039;&#039;&#039; task at the root of your Moodle directory. The grunt watch task will listen for changes to the Javascript files in the Moodle directory and will automatically lint and compile only the file that is changed after each change is detected. This removes the need to manually run grunt after each change.&lt;br /&gt;
&lt;br /&gt;
== Running grunt ==&lt;br /&gt;
&lt;br /&gt;
You can run grunt in your plugin&#039;s &#039;amd&#039; directory and it will only operate on your modules. If you&#039;re having problems or just want to check your work it is worth running for the &#039;lint&#039; feature. This can find basic problems. This sub-directory support wont work on Windows unfortunately but there is an alternative: Run grunt from the top directory with the --root=path/to/dir to limit execution to a sub-directory.&lt;br /&gt;
&lt;br /&gt;
See [[Grunt#Running_grunt]] for more details of specific grunt commands which can be used.&lt;br /&gt;
&lt;br /&gt;
If you get the error message&lt;br /&gt;
&lt;br /&gt;
 /usr/bin/env: node: No such file or directory&lt;br /&gt;
&lt;br /&gt;
Then see the thread https://github.com/nodejs/node-v0.x-archive/issues/3911&lt;br /&gt;
&lt;br /&gt;
On Ubuntu 14.04 this fixed it for me:&lt;br /&gt;
&lt;br /&gt;
 sudo ln -fs /usr/bin/nodejs /usr/local/bin/node&lt;br /&gt;
&lt;br /&gt;
Note: Once you have run grunt and built your code, you will then need to purge Moodle caches otherwise the changes made to your minified files may not be picked up by Moodle.&lt;br /&gt;
&lt;br /&gt;
== Minimum (getting started) module for plugins ==&lt;br /&gt;
&lt;br /&gt;
This shows the absolute minimum module you need to get started adding modules to your plugins. It&#039;s actually quite simple...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Put this file in path/to/plugin/amd/src&lt;br /&gt;
// You can call it anything you like&lt;br /&gt;
&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
&lt;br /&gt;
            // Put whatever you like here. $ is available&lt;br /&gt;
            // to you as normal.&lt;br /&gt;
            $(&amp;quot;.someclass&amp;quot;).change(function() {&lt;br /&gt;
                alert(&amp;quot;It changed!!&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code passes the jquery module into our function (parameter $). There are a number of other useful modules available in Moodle, some of which you&#039;ll probably need in a practical application. See [[Useful_core_Javascript_modules]]. Simply list them in both the define() first parameter and the function callback. E.g.,&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    define([&#039;jquery&#039;, &#039;core/str&#039;, &#039;core/ajax&#039;], function($, str, ajax) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The idea here is that we will run the &#039;init&#039; function from our (PHP) code to set things up. This is called from PHP like this...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;frankenstyle_path/your_js_filename&#039;, &#039;init&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to supply the complete &#039;[[Frankenstyle]]&#039; path. The .js is not needed. &lt;br /&gt;
&lt;br /&gt;
js_call_amd takes a third parameter which is an &#039;&#039;array&#039;&#039; of parameters. These will translate to individual parameters in the &#039;init&#039; function call. For example...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;block_iomad_company_admin/department_select&#039;, &#039;init&#039;, array($first, $last));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...calls&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    return {&lt;br /&gt;
        init: function(first, last) {&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A more comprehensive explanation follows...&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Hello World&amp;quot; I am a Javascript Module ==&lt;br /&gt;
Lets now create a simple Javascript module so we can see how to lay things out. &lt;br /&gt;
&lt;br /&gt;
Each Javascript module is contained in a single source file in the &amp;lt;componentdir&amp;gt;/amd/src folder. The final name of the module is taken from the file name and the component name. E.g. block_overview/amd/src/helloworld.js would be a module named &amp;quot;block_overview/helloworld&amp;quot;. the name of the module is important when you want to call it from somewhere else in the code. &lt;br /&gt;
&lt;br /&gt;
After running grunt - the minified Javascript files are stored in the &amp;lt;componentdir&amp;gt;/amd/build folder. The javascript files are renamed to show that they are minified (helloworld.js becomes helloworld.min.js). &lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to add the built files (the ones in amd/build) to your git commits, or in production no-one will see your changes. &lt;br /&gt;
&lt;br /&gt;
Lets create a simple module now:&lt;br /&gt;
&lt;br /&gt;
blocks/overview/amd/src/helloworld.js&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Standard license block omitted.&lt;br /&gt;
/*&lt;br /&gt;
 * @package    block_overview&lt;br /&gt;
 * @copyright  2015 Someone cool&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * @module block_overview/helloworld&lt;br /&gt;
  */&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&lt;br /&gt;
     /** &lt;br /&gt;
      * Give me blue.&lt;br /&gt;
      * @access private&lt;br /&gt;
      * @return {string}&lt;br /&gt;
      */&lt;br /&gt;
     var makeItBlue = function() {&lt;br /&gt;
          // We can use our jquery dependency here.&lt;br /&gt;
          return $(&#039;.blue&#039;).show();&lt;br /&gt;
     };&lt;br /&gt;
      &lt;br /&gt;
    /**&lt;br /&gt;
     * @constructor&lt;br /&gt;
     * @alias module:block_overview/helloworld&lt;br /&gt;
     */&lt;br /&gt;
    var greeting = function() {&lt;br /&gt;
        /** @access private */&lt;br /&gt;
        var privateThoughts = &#039;I like the colour blue&#039;;&lt;br /&gt;
        &lt;br /&gt;
        /** @access public */&lt;br /&gt;
        this.publicThoughts = &#039;I like the colour orange&#039;;&lt;br /&gt;
&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * A formal greeting.&lt;br /&gt;
     * @access public&lt;br /&gt;
     * @return {string}&lt;br /&gt;
     */&lt;br /&gt;
    greeting.prototype.formal = function() {&lt;br /&gt;
        return &#039;How do you do?&#039;;&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * An informal greeting.&lt;br /&gt;
     * @access public&lt;br /&gt;
     * @return {string}&lt;br /&gt;
     */&lt;br /&gt;
    greeting.prototype.informal = function() {&lt;br /&gt;
        return &#039;Wassup!&#039;;&lt;br /&gt;
    };&lt;br /&gt;
    return greeting;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The most interesting line above is:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All AMD modules must call &amp;quot;define()&amp;quot; as the first and only global scoped piece of code. This ensures the javascript code contains no global variables and will not conflict with any other loaded module. The name of the module does not need to be specified because it is determined from the filename and component (but it can be listed in a comment for JSDoc as shown here). &lt;br /&gt;
&lt;br /&gt;
The first argument to &amp;quot;define&amp;quot; is the list of dependencies for the module. This argument must be passed as an array, even if there is only one. In this example &amp;quot;jquery&amp;quot; is a dependency. &amp;quot;jquery&amp;quot; is shipped as a core module is available to all AMD modules. &lt;br /&gt;
&lt;br /&gt;
The second argument to &amp;quot;define&amp;quot; is the function that defines the module. This function will receive as arguments, each of the requested dependencies in the same order they were requested. In this example we receive JQuery as an argument and we name the variable &amp;quot;$&amp;quot; (it&#039;s a JQuery thing). We can then access JQuery normally through the $ variable which is in scope for any code in our module. &lt;br /&gt;
&lt;br /&gt;
The rest of the code in this example is a standard way to define a Javascript module with public/private variables and methods. There are many ways to do this, this is only one.&lt;br /&gt;
&lt;br /&gt;
It is important that we are returning &#039;greeting&#039;. If there is no return then your module will be declared as undefined.&lt;br /&gt;
&lt;br /&gt;
== Loading modules dynamically ==&lt;br /&gt;
What do you do if you don&#039;t know in advance which modules will be required? Stuffing all possible required modules in the define call is one solution, but it&#039;s ugly and it only works for code that is in an AMD module (what about inline code in the page?). AMD lets you load a dependency any time you like. &lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Load a new dependency.&lt;br /&gt;
require([&#039;mod_wiki/timer&#039;], function(timer) {&lt;br /&gt;
   // timer is available to do my bidding.&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Including an external javascript/jquery library ==&lt;br /&gt;
If you want to include a javascript / jquery library downloaded from the internet you can do so as follows:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning: if the library you download, supports AMD but is already &amp;quot;named&amp;quot; you will not be able to include it directly&#039;&#039;&#039;&lt;br /&gt;
e.g. &lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
        define(&amp;quot;typeahead.js&amp;quot;, *[ &amp;quot;jquery&amp;quot; ], function(a0) {&lt;br /&gt;
            return factory(a0);&lt;br /&gt;
        });&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
will not work, as moodle injects it&#039;s own define name when loading the library.&lt;br /&gt;
&lt;br /&gt;
If the library is in AMD format and has a define:&lt;br /&gt;
e.g. i want to include the jquery final countdown timer on my page ( hilios.github.io/jQuery.countdown/ )&lt;br /&gt;
* download the module in both normal and minified versions&lt;br /&gt;
* place the modules in your moodle install e.g. your custom theme dir, or plugin dir&lt;br /&gt;
* /theme/mytheme/amd/src/jquery.countdown.js&lt;br /&gt;
&lt;br /&gt;
you can now include the module and initialise it (there are multiple ways to do this)&lt;br /&gt;
php:&lt;br /&gt;
&lt;br /&gt;
1. Create your own AMD module and initialise it:&lt;br /&gt;
&lt;br /&gt;
In your PHP file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;theme_mytheme/countdowntimer&#039;, &#039;initialise&#039;, $params);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Javascript module:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// /theme/mytheme/amd/src/countdowntimer.js&lt;br /&gt;
define([&#039;jquery&#039;, &#039;theme_mytheme/jquery.countdown&#039;], function($, c) {&lt;br /&gt;
    return {&lt;br /&gt;
        initialise: function ($params) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Put the javascript into a mustache template:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// /theme/mytheme/templates/countdowntimer.mustache&lt;br /&gt;
&amp;lt;span id=&amp;quot;clock&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require([&#039;jquery&#039;, &#039;theme_mytheme/jquery.countdown&#039;], function($) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Call the javascript directly from php (although who would want to put javascript into php? ergh):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_amd_inline(&#039;&lt;br /&gt;
require([&#039;theme_mytheme/jquery.countdown&#039;], function(min) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
});&lt;br /&gt;
&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Note: It could be useful when you wish to pass a big chunk of data from php directly into a JS variable, to workaround MDL-62468 .&amp;lt;br&amp;gt;&lt;br /&gt;
Example: https://github.com/moodle/moodle/blob/master/media/player/videojs/classes/plugin.php#L386&lt;br /&gt;
&lt;br /&gt;
===More examples of including 3rd-party JS modules===&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=327579#p1317252 Adding custom js via AMD (highcharts) to essential theme]&lt;br /&gt;
&lt;br /&gt;
== Embedding AMD code in a page ==&lt;br /&gt;
So you have created lots of cool Javascript modules. Great. How do we actually call them? Any javascript code that calls an AMD module must execute AFTER the requirejs module loader has finished loading. We have provided a function &amp;quot;js_call_amd&amp;quot; that will call a single function from an AMD module with parameters.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd($modulename, $functionname, $params);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
that will &amp;quot;do the right thing&amp;quot; with your block of AMD code and execute it at the end of the page, after our AMD module loader has loaded. &lt;br /&gt;
Notes:&lt;br /&gt;
* the $modulename is the &#039;componentname/modulename&#039; discussed above&lt;br /&gt;
* the $functionname is the name of a public function exposed by the amd module. &lt;br /&gt;
* the $params is an array of params passed as arguments to the function. These should be simple types that can be handled by json_encode (no recursive arrays, or complex classes please). &lt;br /&gt;
* if the size of the params array is too large (&amp;gt; 1Kb), this will produce a developer warning. Do not attempt to pass large amounts of data through this function, it will pollute the page size. A preferred approach is to pass css selectors for DOM elements that contain data-attributes for any required data, or fetch data via ajax in the background.&lt;br /&gt;
&lt;br /&gt;
AMD / JS code can also be embedded on a page via mustache templates&lt;br /&gt;
see here: https://docs.moodle.org/dev/Templates#What_if_a_template_contains_javascript.3F&lt;br /&gt;
&lt;br /&gt;
== But I have a mega JS file I don&#039;t want loaded on every page? ==&lt;br /&gt;
Loading all JS files at once and stuffing them in the browser cache is the right choice for MOST js files, there are probably some exceptions. For these files, you can rename the javascript file to end with the suffix &amp;quot;-lazy.js&amp;quot; which indicates that the module will not be loaded by default, it will be requested the first time it is used. There is no difference in usage for lazy loaded modules, the require() call looks exactly the same, it&#039;s just that the module name will also have the &amp;quot;-lazy&amp;quot; suffix.&lt;br /&gt;
&lt;br /&gt;
== Useful links ==&lt;br /&gt;
* [https://assets.moodlemoot.org/sites/15/20171004085436/JavaScript-AMD-with-RequireJS-presented-by-Daniel-Roperto-Catalyst.pdf JavaScript AMD with RequireJS] presented by Daniel Roperto, Catalyst. (MoodleMOOT AU 2017)&lt;br /&gt;
* [[Useful_core_Javascript_modules]]&lt;br /&gt;
*[[Guide_to_adding_third_party_jQuery_for_AMD]] by Patrick Thibaudeau&lt;br /&gt;
*[https://moodle.org/mod/forum/discuss.php?d=378112#p1524459 How to get variables from PHP into javascript AMD modules in M3.5] Justin Hunt, on Moodle forums.&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Useful_core_Javascript_modules&amp;diff=55236</id>
		<title>Useful core Javascript modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Useful_core_Javascript_modules&amp;diff=55236"/>
		<updated>2018-12-06T06:17:44Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: /* PubSub (core/pubsub) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
The source code for all these modules (and a number of others) can be found in lib/amd/src. &lt;br /&gt;
&lt;br /&gt;
== Configuration settings (core/config) ==&lt;br /&gt;
&lt;br /&gt;
Example of using config module:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/config’], function(mdlcfg) {&lt;br /&gt;
    console.log(mdlcfg.wwwroot); // outputs the wwwroot of moodle to console&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Language strings (core/str) ==&lt;br /&gt;
&lt;br /&gt;
Example of using language strings module (retrieved via ajax, if the string is not yet loaded)&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([‘core/str’], function(str) {&lt;br /&gt;
    // start retrieving the localized string; store the promise that some time in the future the string will be there.&lt;br /&gt;
    var editaPresent = str.get_string(&#039;edita&#039;, &#039;core&#039;, stringargument);&lt;br /&gt;
    // as soon as the string is retrieved, i.e. the promise has been fulfilled,&lt;br /&gt;
    // edit the text of a UI element so that it then is the localized string&lt;br /&gt;
    // Note: $.when can be used with an arbitrary number of promised things&lt;br /&gt;
    $.when(editaPresent).done(function(localizedEditString) {&lt;br /&gt;
         $(&amp;quot;someUIElementSelector&amp;quot;).text = localizedEditString;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The string will be retrieved via AJAX request on the first use and cached in browser local storage until purge caches or site upgrade&lt;br /&gt;
&lt;br /&gt;
IT IS NOT RECOMMENDED to call:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;string_for_js(&#039;edita&#039;, &#039;core&#039;); // You do not need this!&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because:&lt;br /&gt;
* The list of strings used now needs to be maintained in 2 places&lt;br /&gt;
* The strings are always sent, and bloat the page size even if they are not used&lt;br /&gt;
* All strings fetched via the AJAX method above are cached in browser local storage anyway, so these strings will never be used 99% of the time&lt;br /&gt;
&lt;br /&gt;
==Notifications (core/notification)==&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/notification’], function(notification) {&lt;br /&gt;
    notification.alert(&#039;Hello&#039;, &#039;Welcome to my site!&#039;, &#039;Continue&#039;);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Strings and notifications:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/str&#039;, &#039;core/notification’], function(str, notification) {&lt;br /&gt;
                str.get_strings([&lt;br /&gt;
                        {&#039;key&#039; : &#039;delete&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;confirmdeletetag&#039;, component : &#039;tag&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;yes&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;no&#039;},&lt;br /&gt;
                    ]).done(function(s) {&lt;br /&gt;
                        notification.confirm(s[0], s[1], s[2], s[3], function() {&lt;br /&gt;
                            window.location.href = href;&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                ).fail(notification.exception);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== URL module (core/url) ==&lt;br /&gt;
&lt;br /&gt;
Useful Functions:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Generate an absolute URL by using the relative path to a file and optionally slash arguments&lt;br /&gt;
url.fileUrl(relativeScript, slashArgs)&lt;br /&gt;
// Generate an absolute URL from the given relative path, include the URL parameters and possibly the current session key&lt;br /&gt;
url.relativeUrl(relativePath, params, includeSessionKey)&lt;br /&gt;
// Generates an image url using the filename of the image and the Moodle component (core, plugin, etc.) where it can be found&lt;br /&gt;
url.imageUrl(imagename, component)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Prerequisites:&lt;br /&gt;
// - A Javascript file is present under $CFG-&amp;gt;wwwroot.&amp;quot;/path/to/file.js&amp;quot;&lt;br /&gt;
require([&#039;core/url&#039;], function(url) {&lt;br /&gt;
    url.fileUrl(&amp;quot;/path/to/file.js&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
    console.log(&amp;quot;Generated URL: &amp;quot; + url);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ajax Module (core/ajax) ==&lt;br /&gt;
&lt;br /&gt;
The preferred way to write new ajax interactions in Moodle is to use the javascript module &amp;quot;core/ajax&amp;quot; which can directly call existing web service functions. This saves having to worry about security in ajax functionality because it&#039;s all done for you. &lt;br /&gt;
&lt;br /&gt;
For the full story, see [[AJAX]]&lt;br /&gt;
&lt;br /&gt;
== Tree (core/tree) ==&lt;br /&gt;
{{Moodle 3.1}}&lt;br /&gt;
If you want to add a hierarchical interface, you should use the tree module. It will handle user interaction and accessibility for you.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;, &#039;core/tree&#039;], function($, Tree) {&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
            new Tree(&amp;quot;css/jquery selector of the tree container&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read more about the [[Tree]] module&lt;br /&gt;
&lt;br /&gt;
== Modal (core/modal) ==&lt;br /&gt;
{{Moodle 3.2}}&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to add a modal to your page the modal modules will handle all of the magic for you, all you need to bring is your content!&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;], function($, ModalFactory) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    title: &#039;test title&#039;,&lt;br /&gt;
    body: &#039;&amp;lt;p&amp;gt;test body content&amp;lt;/p&amp;gt;&#039;,&lt;br /&gt;
    footer: &#039;test footer content&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your new modal.&lt;br /&gt;
&lt;br /&gt;
    // Maybe... add a class to the modal dialog, to be able to style it.&lt;br /&gt;
    modal.getRoot().addClass(&#039;mydialog&#039;);&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read more about the [[AMD_Modal]] module&lt;br /&gt;
&lt;br /&gt;
== Paged content (core/paged_content_factory) ==&lt;br /&gt;
{{Moodle 3.6}}&lt;br /&gt;
&lt;br /&gt;
If you need to create a paged content region to asynchronously load the pages as the user requests them then you can use the paged content modules.&lt;br /&gt;
&lt;br /&gt;
Read more about the [[AMD_paged_content]] module&lt;br /&gt;
&lt;br /&gt;
== PubSub (core/pubsub) ==&lt;br /&gt;
{{Moodle 3.6}}&lt;br /&gt;
&lt;br /&gt;
A simple module to do event subscription and publishing in JavaScript without the need for jQuery.&lt;br /&gt;
&lt;br /&gt;
Read more about the [[AMD_pubsub}} module&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Useful_core_Javascript_modules&amp;diff=55235</id>
		<title>Useful core Javascript modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Useful_core_Javascript_modules&amp;diff=55235"/>
		<updated>2018-12-06T06:17:22Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
The source code for all these modules (and a number of others) can be found in lib/amd/src. &lt;br /&gt;
&lt;br /&gt;
== Configuration settings (core/config) ==&lt;br /&gt;
&lt;br /&gt;
Example of using config module:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/config’], function(mdlcfg) {&lt;br /&gt;
    console.log(mdlcfg.wwwroot); // outputs the wwwroot of moodle to console&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Language strings (core/str) ==&lt;br /&gt;
&lt;br /&gt;
Example of using language strings module (retrieved via ajax, if the string is not yet loaded)&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([‘core/str’], function(str) {&lt;br /&gt;
    // start retrieving the localized string; store the promise that some time in the future the string will be there.&lt;br /&gt;
    var editaPresent = str.get_string(&#039;edita&#039;, &#039;core&#039;, stringargument);&lt;br /&gt;
    // as soon as the string is retrieved, i.e. the promise has been fulfilled,&lt;br /&gt;
    // edit the text of a UI element so that it then is the localized string&lt;br /&gt;
    // Note: $.when can be used with an arbitrary number of promised things&lt;br /&gt;
    $.when(editaPresent).done(function(localizedEditString) {&lt;br /&gt;
         $(&amp;quot;someUIElementSelector&amp;quot;).text = localizedEditString;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The string will be retrieved via AJAX request on the first use and cached in browser local storage until purge caches or site upgrade&lt;br /&gt;
&lt;br /&gt;
IT IS NOT RECOMMENDED to call:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;string_for_js(&#039;edita&#039;, &#039;core&#039;); // You do not need this!&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because:&lt;br /&gt;
* The list of strings used now needs to be maintained in 2 places&lt;br /&gt;
* The strings are always sent, and bloat the page size even if they are not used&lt;br /&gt;
* All strings fetched via the AJAX method above are cached in browser local storage anyway, so these strings will never be used 99% of the time&lt;br /&gt;
&lt;br /&gt;
==Notifications (core/notification)==&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/notification’], function(notification) {&lt;br /&gt;
    notification.alert(&#039;Hello&#039;, &#039;Welcome to my site!&#039;, &#039;Continue&#039;);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Strings and notifications:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/str&#039;, &#039;core/notification’], function(str, notification) {&lt;br /&gt;
                str.get_strings([&lt;br /&gt;
                        {&#039;key&#039; : &#039;delete&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;confirmdeletetag&#039;, component : &#039;tag&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;yes&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;no&#039;},&lt;br /&gt;
                    ]).done(function(s) {&lt;br /&gt;
                        notification.confirm(s[0], s[1], s[2], s[3], function() {&lt;br /&gt;
                            window.location.href = href;&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                ).fail(notification.exception);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== URL module (core/url) ==&lt;br /&gt;
&lt;br /&gt;
Useful Functions:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Generate an absolute URL by using the relative path to a file and optionally slash arguments&lt;br /&gt;
url.fileUrl(relativeScript, slashArgs)&lt;br /&gt;
// Generate an absolute URL from the given relative path, include the URL parameters and possibly the current session key&lt;br /&gt;
url.relativeUrl(relativePath, params, includeSessionKey)&lt;br /&gt;
// Generates an image url using the filename of the image and the Moodle component (core, plugin, etc.) where it can be found&lt;br /&gt;
url.imageUrl(imagename, component)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Prerequisites:&lt;br /&gt;
// - A Javascript file is present under $CFG-&amp;gt;wwwroot.&amp;quot;/path/to/file.js&amp;quot;&lt;br /&gt;
require([&#039;core/url&#039;], function(url) {&lt;br /&gt;
    url.fileUrl(&amp;quot;/path/to/file.js&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
    console.log(&amp;quot;Generated URL: &amp;quot; + url);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ajax Module (core/ajax) ==&lt;br /&gt;
&lt;br /&gt;
The preferred way to write new ajax interactions in Moodle is to use the javascript module &amp;quot;core/ajax&amp;quot; which can directly call existing web service functions. This saves having to worry about security in ajax functionality because it&#039;s all done for you. &lt;br /&gt;
&lt;br /&gt;
For the full story, see [[AJAX]]&lt;br /&gt;
&lt;br /&gt;
== Tree (core/tree) ==&lt;br /&gt;
{{Moodle 3.1}}&lt;br /&gt;
If you want to add a hierarchical interface, you should use the tree module. It will handle user interaction and accessibility for you.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;, &#039;core/tree&#039;], function($, Tree) {&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
            new Tree(&amp;quot;css/jquery selector of the tree container&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read more about the [[Tree]] module&lt;br /&gt;
&lt;br /&gt;
== Modal (core/modal) ==&lt;br /&gt;
{{Moodle 3.2}}&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to add a modal to your page the modal modules will handle all of the magic for you, all you need to bring is your content!&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;], function($, ModalFactory) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    title: &#039;test title&#039;,&lt;br /&gt;
    body: &#039;&amp;lt;p&amp;gt;test body content&amp;lt;/p&amp;gt;&#039;,&lt;br /&gt;
    footer: &#039;test footer content&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your new modal.&lt;br /&gt;
&lt;br /&gt;
    // Maybe... add a class to the modal dialog, to be able to style it.&lt;br /&gt;
    modal.getRoot().addClass(&#039;mydialog&#039;);&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read more about the [[AMD_Modal]] module&lt;br /&gt;
&lt;br /&gt;
== Paged content (core/paged_content_factory) ==&lt;br /&gt;
{{Moodle 3.6}}&lt;br /&gt;
&lt;br /&gt;
If you need to create a paged content region to asynchronously load the pages as the user requests them then you can use the paged content modules.&lt;br /&gt;
&lt;br /&gt;
Read more about the [[AMD_paged_content]] module&lt;br /&gt;
&lt;br /&gt;
== PubSub (core/pubsub) ==&lt;br /&gt;
&lt;br /&gt;
A simple module to do event subscription and publishing in JavaScript without the need for jQuery.&lt;br /&gt;
&lt;br /&gt;
Read more about the [[AMD_pubsub}} module&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=AMD_pubsub&amp;diff=55234</id>
		<title>AMD pubsub</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=AMD_pubsub&amp;diff=55234"/>
		<updated>2018-12-06T06:17:11Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.6}}&lt;br /&gt;
&lt;br /&gt;
= What is this? =&lt;br /&gt;
A simple module to do event subscription and publishing in JavaScript. It was added to avoid the need to use jQuery and the DOM.&lt;br /&gt;
&lt;br /&gt;
= Why would I use it? =&lt;br /&gt;
Allows modules to communicate with one another indirectly without the need to include jQuery or touch the DOM.&lt;br /&gt;
&lt;br /&gt;
= Example =&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Module A.&lt;br /&gt;
require([&#039;core/pubsub&#039;], function(PubSub) {&lt;br /&gt;
    PubSub.publish(&#039;example-event&#039;, someData);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// Module B.&lt;br /&gt;
require([&#039;core/pubsub&#039;], function(PubSub) {&lt;br /&gt;
    PubSub.subscribe(&#039;example-event&#039;, function(someData) {&lt;br /&gt;
        console.log(&#039;Received&#039;, someData);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=AMD_pubsub&amp;diff=55233</id>
		<title>AMD pubsub</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=AMD_pubsub&amp;diff=55233"/>
		<updated>2018-12-06T06:15:19Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: Created page with &amp;quot;{{Moodle 3.6}}  = What is this? = A simply module to do event subscription and publishing in JavaScript. It was added to avoid the need to use jQuery and the DOM.  = Why would...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.6}}&lt;br /&gt;
&lt;br /&gt;
= What is this? =&lt;br /&gt;
A simply module to do event subscription and publishing in JavaScript. It was added to avoid the need to use jQuery and the DOM.&lt;br /&gt;
&lt;br /&gt;
= Why would I use it? =&lt;br /&gt;
Allows modules to communicate with one another indirectly without the need to include jQuery or touch the DOM.&lt;br /&gt;
&lt;br /&gt;
= Example =&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Module A.&lt;br /&gt;
require([&#039;core/pubsub&#039;], function(PubSub) {&lt;br /&gt;
    PubSub.publish(&#039;example-event&#039;, someData);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// Module B.&lt;br /&gt;
require([&#039;core/pubsub&#039;], function(PubSub) {&lt;br /&gt;
    PubSub.subscribe(&#039;example-event&#039;, function(someData) {&lt;br /&gt;
        console.log(&#039;Received&#039;, someData);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Useful_core_Javascript_modules&amp;diff=55232</id>
		<title>Useful core Javascript modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Useful_core_Javascript_modules&amp;diff=55232"/>
		<updated>2018-12-06T06:03:54Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
The source code for all these modules (and a number of others) can be found in lib/amd/src. &lt;br /&gt;
&lt;br /&gt;
== Configuration settings (core/config) ==&lt;br /&gt;
&lt;br /&gt;
Example of using config module:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/config’], function(mdlcfg) {&lt;br /&gt;
    console.log(mdlcfg.wwwroot); // outputs the wwwroot of moodle to console&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Language strings (core/str) ==&lt;br /&gt;
&lt;br /&gt;
Example of using language strings module (retrieved via ajax, if the string is not yet loaded)&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([‘core/str’], function(str) {&lt;br /&gt;
    // start retrieving the localized string; store the promise that some time in the future the string will be there.&lt;br /&gt;
    var editaPresent = str.get_string(&#039;edita&#039;, &#039;core&#039;, stringargument);&lt;br /&gt;
    // as soon as the string is retrieved, i.e. the promise has been fulfilled,&lt;br /&gt;
    // edit the text of a UI element so that it then is the localized string&lt;br /&gt;
    // Note: $.when can be used with an arbitrary number of promised things&lt;br /&gt;
    $.when(editaPresent).done(function(localizedEditString) {&lt;br /&gt;
         $(&amp;quot;someUIElementSelector&amp;quot;).text = localizedEditString;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The string will be retrieved via AJAX request on the first use and cached in browser local storage until purge caches or site upgrade&lt;br /&gt;
&lt;br /&gt;
IT IS NOT RECOMMENDED to call:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;string_for_js(&#039;edita&#039;, &#039;core&#039;); // You do not need this!&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because:&lt;br /&gt;
* The list of strings used now needs to be maintained in 2 places&lt;br /&gt;
* The strings are always sent, and bloat the page size even if they are not used&lt;br /&gt;
* All strings fetched via the AJAX method above are cached in browser local storage anyway, so these strings will never be used 99% of the time&lt;br /&gt;
&lt;br /&gt;
==Notifications (core/notification)==&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/notification’], function(notification) {&lt;br /&gt;
    notification.alert(&#039;Hello&#039;, &#039;Welcome to my site!&#039;, &#039;Continue&#039;);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Strings and notifications:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/str&#039;, &#039;core/notification’], function(str, notification) {&lt;br /&gt;
                str.get_strings([&lt;br /&gt;
                        {&#039;key&#039; : &#039;delete&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;confirmdeletetag&#039;, component : &#039;tag&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;yes&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;no&#039;},&lt;br /&gt;
                    ]).done(function(s) {&lt;br /&gt;
                        notification.confirm(s[0], s[1], s[2], s[3], function() {&lt;br /&gt;
                            window.location.href = href;&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                ).fail(notification.exception);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== URL module (core/url) ==&lt;br /&gt;
&lt;br /&gt;
Useful Functions:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Generate an absolute URL by using the relative path to a file and optionally slash arguments&lt;br /&gt;
url.fileUrl(relativeScript, slashArgs)&lt;br /&gt;
// Generate an absolute URL from the given relative path, include the URL parameters and possibly the current session key&lt;br /&gt;
url.relativeUrl(relativePath, params, includeSessionKey)&lt;br /&gt;
// Generates an image url using the filename of the image and the Moodle component (core, plugin, etc.) where it can be found&lt;br /&gt;
url.imageUrl(imagename, component)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Prerequisites:&lt;br /&gt;
// - A Javascript file is present under $CFG-&amp;gt;wwwroot.&amp;quot;/path/to/file.js&amp;quot;&lt;br /&gt;
require([&#039;core/url&#039;], function(url) {&lt;br /&gt;
    url.fileUrl(&amp;quot;/path/to/file.js&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
    console.log(&amp;quot;Generated URL: &amp;quot; + url);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ajax Module (core/ajax) ==&lt;br /&gt;
&lt;br /&gt;
The preferred way to write new ajax interactions in Moodle is to use the javascript module &amp;quot;core/ajax&amp;quot; which can directly call existing web service functions. This saves having to worry about security in ajax functionality because it&#039;s all done for you. &lt;br /&gt;
&lt;br /&gt;
For the full story, see [[AJAX]]&lt;br /&gt;
&lt;br /&gt;
== Tree (core/tree) ==&lt;br /&gt;
{{Moodle 3.1}}&lt;br /&gt;
If you want to add a hierarchical interface, you should use the tree module. It will handle user interaction and accessibility for you.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;, &#039;core/tree&#039;], function($, Tree) {&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
            new Tree(&amp;quot;css/jquery selector of the tree container&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read more about the [[Tree]] module&lt;br /&gt;
&lt;br /&gt;
== Modal (core/modal) ==&lt;br /&gt;
{{Moodle 3.2}}&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to add a modal to your page the modal modules will handle all of the magic for you, all you need to bring is your content!&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;], function($, ModalFactory) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    title: &#039;test title&#039;,&lt;br /&gt;
    body: &#039;&amp;lt;p&amp;gt;test body content&amp;lt;/p&amp;gt;&#039;,&lt;br /&gt;
    footer: &#039;test footer content&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your new modal.&lt;br /&gt;
&lt;br /&gt;
    // Maybe... add a class to the modal dialog, to be able to style it.&lt;br /&gt;
    modal.getRoot().addClass(&#039;mydialog&#039;);&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read more about the [[AMD_Modal]] module&lt;br /&gt;
&lt;br /&gt;
== Paged content (core/paged_content_factory) ==&lt;br /&gt;
{{Moodle 3.6}}&lt;br /&gt;
&lt;br /&gt;
If you need to create a paged content region to asynchronously load the pages as the user requests them then you can use the paged content modules.&lt;br /&gt;
&lt;br /&gt;
Read more about the [[AMD_paged_content]] module&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=AMD_paged_content&amp;diff=55231</id>
		<title>AMD paged content</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=AMD_paged_content&amp;diff=55231"/>
		<updated>2018-12-06T05:59:41Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: Created page with &amp;quot;{{Moodle 3.6}}  = What is this? = The paged content factory allows you to quickly and easily create a paged content region (see [https://getbootstrap.com/docs/4.0/components/p...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.6}}&lt;br /&gt;
&lt;br /&gt;
= What is this? =&lt;br /&gt;
The paged content factory allows you to quickly and easily create a paged content region (see [https://getbootstrap.com/docs/4.0/components/pagination/]). The factory will handle creating and configuring the region for you so that it confirms with the standard Bootstrap markup (on the Boost and Clean themes).&lt;br /&gt;
&lt;br /&gt;
= PHP =&lt;br /&gt;
This can be used to render the paged content in PHP however it requires that all pages be preloaded and rendered in PHP and doesn&#039;t support AJAX loading of additional pages.&lt;br /&gt;
&lt;br /&gt;
If you render the paged content in PHP it will initialise all of the JavaScript required to control the navigation between pages for the user.&lt;br /&gt;
&lt;br /&gt;
To render it in PHP simply render the [https://github.com/moodle/moodle/blob/master/lib/templates/paged_content.mustache] template with the appropriate context.&lt;br /&gt;
&lt;br /&gt;
= JavaScript =&lt;br /&gt;
This is the real strength of this module. Core comes shipped with a paged content factory module which will create and enhance the paged content region for you. It allows you to very quickly and easily create a paged content region that asynchronously loads the pages as the user requests them.&lt;br /&gt;
&lt;br /&gt;
== How do I use it? ==&lt;br /&gt;
The paged content factory has a few different ways to create the element depending on how you&#039;d like it to behave. The creation methods can be split into two categories, either asynchronous (you don&#039;t have all of the data loaded) or static (you already have all of the data you want to paginate).&lt;br /&gt;
&lt;br /&gt;
If you have all of the data up front then you can give it all to the createFromStaticList list function along with a few options and the factory will create the paged content element for you.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to load the data asynchronously then you can use one of the other create functions, depending on whether you&#039;d like to specify the limit of items per page and/or the total number of items. All of the async create functions require you to provide a callback function which will be called in order to load and render the requested pages.&lt;br /&gt;
&lt;br /&gt;
Each create function also optionally takes a config object (more information below).&lt;br /&gt;
&lt;br /&gt;
=== Load and render callback ===&lt;br /&gt;
As part of the create functions you will be required to provide a callback function that the paged content code will call when the user requests a page. The callback function will be provided a list of pages being requested (this is typically just one page but not guaranteed to be). Each page data contains the page number (indexed from 1), the limit, and offset to use to load the data.&lt;br /&gt;
&lt;br /&gt;
The callback must return an array of promises (order matching the given array) that resolve with the rendered HTML for that page.&lt;br /&gt;
&lt;br /&gt;
The second parameter to the callback will be an object containing actions which can be called to trigger behaviour in the paged content. At the moment the only action that can be called is allItemsLoaded which your callback function should call to tell the paged content code that there are no more items to load. This is only required if you created the paged content area without a total upfront.&lt;br /&gt;
&lt;br /&gt;
=== Config ===&lt;br /&gt;
You can provide a configuration object to the paged content factory in order to control certain behaviours&lt;br /&gt;
&lt;br /&gt;
The current options are:&lt;br /&gt;
* dropdown - bool (default: false) - If the pagination controls should be a dropdown instead of a paging bar&lt;br /&gt;
* maxPages - int - Maximum number of page options for the dropdown (only works if dropdown is set to true)&lt;br /&gt;
* ignoreControlWhileLoading - boolean (default: true) - Disable the pagination controls while a page is being loaded&lt;br /&gt;
* controlPlacementBottom - boolean (default: false) - Put the pagination controls under the paged content area (default is above)&lt;br /&gt;
* eventNamespace - string (default: a generated unique id) - Provide a custom namespace to prefix the pagination events with. This can be used if you have code that wants to listen to events for a specific paged content region.&lt;br /&gt;
* persistentLimitKey - string (default: null) - If provided the factory will automatically use this value as the key to save the selected limit option in user preferences so that they persist between page loads&lt;br /&gt;
&lt;br /&gt;
= Example: Async load with unknown total number of items =&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require(&lt;br /&gt;
[&lt;br /&gt;
    &#039;jquery&#039;,&lt;br /&gt;
    &#039;core/paged_content_factory&#039;,&lt;br /&gt;
    &#039;core/templates&#039;&lt;br /&gt;
],&lt;br /&gt;
function(&lt;br /&gt;
    $,&lt;br /&gt;
    PagedContentFactory,&lt;br /&gt;
    Templates&lt;br /&gt;
) {&lt;br /&gt;
    // Some container for your paged content.&lt;br /&gt;
    var container = $(&#039;#container&#039;);&lt;br /&gt;
    &lt;br /&gt;
    PagedContentFactory.createWithLimit(&lt;br /&gt;
        // Show 10 items per page.&lt;br /&gt;
        10,&lt;br /&gt;
        // Callback to load and render the items as the user clicks on the pages.&lt;br /&gt;
        function(pagesData, actions) {&lt;br /&gt;
            return pagesData.map(function(pageData) {&lt;br /&gt;
                // Your function to load the data for the given limit and offset.&lt;br /&gt;
                return loadData(pageData.limit, pageData.offset)&lt;br /&gt;
                    .then(function(data) {&lt;br /&gt;
                        // You criteria for when all of the data has been loaded.&lt;br /&gt;
                        if (data.length &amp;gt; 100) {&lt;br /&gt;
                            // Tell the page content code everything has been loaded now.&lt;br /&gt;
                            actions.allItemsLoaded(pageData.pageNumber);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        // Your function to render the data you&#039;ve loaded.&lt;br /&gt;
                        return renderData(data);&lt;br /&gt;
                    });&lt;br /&gt;
            });&lt;br /&gt;
        },&lt;br /&gt;
        // Config to set up the paged content.&lt;br /&gt;
        {&lt;br /&gt;
            controlPlacementBottom: true,&lt;br /&gt;
            eventNamespace: &#039;example-paged-content&#039;,&lt;br /&gt;
            persistentLimitKey: &#039;example-paged-content-limit-key&#039;&lt;br /&gt;
        }&lt;br /&gt;
    ).then(function(html, js) {&lt;br /&gt;
        // Add the paged content into the page.&lt;br /&gt;
        Templates.replaceNodeContents(container, html, js);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=53236</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=53236"/>
		<updated>2017-11-14T02:34:13Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Event priority==&lt;br /&gt;
There might be cases that an activity event will have user and/or group overrides. Therefore we need a way to show only the relevant event on the user&#039;s calendar. This is where the &#039;priority&#039; field comes in. &lt;br /&gt;
&lt;br /&gt;
The event priority is set to the following:&lt;br /&gt;
* NULL for non-override events.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;priority = null;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* 0 for user override events.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;priority = CALENDAR_EVENT_USER_OVERRIDE_PRIORITY;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* A positive integer for group events.&lt;br /&gt;
&lt;br /&gt;
For integer and non-null event priorities, the lower the value, the higher the priority is. Meaning, user overrides always have a higher priority than group overrides. Group override priorities are currently being determined in two ways in core activities:&lt;br /&gt;
# In the assignment module, the event priorities for group overrides are being determined from the &#039;sortorder&#039; column in the &#039;assign_overrides&#039; table.&lt;br /&gt;
# In the lesson and quiz modules, the event priorities for group overrides are being calculated using the functions lesson_get_group_override_priorities($lessonid) and quiz_get_group_override_priorities($quizid).&lt;br /&gt;
&lt;br /&gt;
Should you ever decide to sort out group override priorities by implementing *_get_group_override_priorities(), the recommended return structure would be something like&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
[&lt;br /&gt;
    &#039;youreventtype1&#039; =&amp;gt; $prioritiesforeventtype1, &lt;br /&gt;
    ...&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
where &#039;$prioritiesforeventtype1&#039; is an associative array that has the timestamp of the group override event as key and the calculated priority as value. For more details, please see the implementation for the lesson module below:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Calculates the priorities of timeopen and timeclose values for group overrides for a lesson.&lt;br /&gt;
 *&lt;br /&gt;
 * @param int $lessonid The lesson ID.&lt;br /&gt;
 * @return array|null Array of group override priorities for open and close times. Null if there are no group overrides.&lt;br /&gt;
 */&lt;br /&gt;
function lesson_get_group_override_priorities($lessonid) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
&lt;br /&gt;
    // Fetch group overrides.&lt;br /&gt;
    $where = &#039;lessonid = :lessonid AND groupid IS NOT NULL&#039;;&lt;br /&gt;
    $params = [&#039;lessonid&#039; =&amp;gt; $lessonid];&lt;br /&gt;
    $overrides = $DB-&amp;gt;get_records_select(&#039;lesson_overrides&#039;, $where, $params, &#039;&#039;, &#039;id, groupid, available, deadline&#039;);&lt;br /&gt;
    if (!$overrides) {&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $grouptimeopen = [];&lt;br /&gt;
    $grouptimeclose = [];&lt;br /&gt;
    foreach ($overrides as $override) {&lt;br /&gt;
        if ($override-&amp;gt;available !== null &amp;amp;&amp;amp; !in_array($override-&amp;gt;available, $grouptimeopen)) {&lt;br /&gt;
            $grouptimeopen[] = $override-&amp;gt;available;&lt;br /&gt;
        }&lt;br /&gt;
        if ($override-&amp;gt;deadline !== null &amp;amp;&amp;amp; !in_array($override-&amp;gt;deadline, $grouptimeclose)) {&lt;br /&gt;
            $grouptimeclose[] = $override-&amp;gt;deadline;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Sort open times in ascending manner. The earlier open time gets higher priority.&lt;br /&gt;
    sort($grouptimeopen);&lt;br /&gt;
    // Set priorities.&lt;br /&gt;
    $opengrouppriorities = [];&lt;br /&gt;
    $openpriority = 1;&lt;br /&gt;
    foreach ($grouptimeopen as $timeopen) {&lt;br /&gt;
        $opengrouppriorities[$timeopen] = $openpriority++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Sort close times in descending manner. The later close time gets higher priority.&lt;br /&gt;
    rsort($grouptimeclose);&lt;br /&gt;
    // Set priorities.&lt;br /&gt;
    $closegrouppriorities = [];&lt;br /&gt;
    $closepriority = 1;&lt;br /&gt;
    foreach ($grouptimeclose as $timeclose) {&lt;br /&gt;
        $closegrouppriorities[$timeclose] = $closepriority++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;open&#039; =&amp;gt; $opengrouppriorities,&lt;br /&gt;
        &#039;close&#039; =&amp;gt; $closegrouppriorities&lt;br /&gt;
    ];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION. The events are also sorted on the dashboard by the value specified in the &#039;timesort&#039; field (unixtime) for the event.&lt;br /&gt;
&lt;br /&gt;
Example of the changes to the above code would be to change the &#039;type&#039; and to specify the &#039;timesort&#039; value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_ACTION;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeclose;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible()====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown in block_myoverview (but will still be shown in the calendar block). This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Refreshing calendar events of activity modules==&lt;br /&gt;
A new ad-hoc task  &#039;refresh_mod_calendar_events_task&#039; has been created. This task basically loops through all of the activity modules that implement the &#039;*_refresh_events()&#039; hook.&lt;br /&gt;
&lt;br /&gt;
Sample usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Create the instance.&lt;br /&gt;
$refreshtask = new refresh_mod_calendar_events_task();&lt;br /&gt;
&lt;br /&gt;
// Add custom data.&lt;br /&gt;
$customdata = [&lt;br /&gt;
    &#039;plugins&#039; =&amp;gt; [&#039;assign&#039;, &#039;lesson&#039;, &#039;quiz&#039;] // Optional. If not specified, it will refresh the events of all of the activity modules.&lt;br /&gt;
];&lt;br /&gt;
$refreshtask-&amp;gt;set_custom_data($customdata);&lt;br /&gt;
&lt;br /&gt;
// Queue it.&lt;br /&gt;
\core\task\manager::queue_adhoc_task($refreshtask);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==calendar_get_legacy_events()==&lt;br /&gt;
This functions accepts the same inputs as &#039;calendar_get_events()&#039; but is now utilising the new Moodle Calendar API system. It respects overrides and will also add the action properties, whenever appropriate.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this function will not work as expected if you pass a list of user ids as the current user session is internally used to determine which events should be visible. More info in https://tracker.moodle.org/browse/MDL-60340&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Changes to Behat==&lt;br /&gt;
The &amp;quot;And I follow &amp;quot;Course1&amp;quot;&amp;quot; Behat step won&#039;t work from the Dashboard anymore and has been replaced with &amp;quot;And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;quot; where &#039;Course 1&#039; is the fullname of the course.&lt;br /&gt;
&lt;br /&gt;
==Drag &amp;amp; drop==&lt;br /&gt;
&lt;br /&gt;
The calendar supports dragging and dropping events within the calendar in order to change the start day for the event. Each type of calendar event can be dragged by a user with sufficient permissions to edit the event.&lt;br /&gt;
&lt;br /&gt;
===Dragging action events===&lt;br /&gt;
&lt;br /&gt;
When an action event is dragged the corresponding property will also be updated in the activity instance that generated the event. For example, dragging the assignment due date event will result in the assignment activity’s due date to be changed.&lt;br /&gt;
&lt;br /&gt;
In order to drag an action event the logged in user must have the moodle/course:manageactivities capability in the activity that generated the event.&lt;br /&gt;
&lt;br /&gt;
For an action event to be draggable the activity that generated it will need to have implemented at least one (but ideally both) callback to handle updating itself after the calendar event is dragged.&lt;br /&gt;
&lt;br /&gt;
====core_calendar_event_timestart_updated (required)====&lt;br /&gt;
This callback is required to be implemented by any activity that wishes to have it’s action events draggable in the calendar.&lt;br /&gt;
&lt;br /&gt;
This callback handles updating the activity instance based on the changed action event. The callback will receive the updated calendar event and the corresponding activity instance.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_feedback_core_calendar_event_timestart_updated(\calendar_event $event, \stdClass $feedback) {&lt;br /&gt;
    global $CFG, $DB;&lt;br /&gt;
&lt;br /&gt;
    if (empty($event-&amp;gt;instance) || $event-&amp;gt;modulename != &#039;feedback&#039;) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;instance != $feedback-&amp;gt;id) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!in_array($event-&amp;gt;eventtype, [FEEDBACK_EVENT_TYPE_OPEN, FEEDBACK_EVENT_TYPE_CLOSE])) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $courseid = $event-&amp;gt;courseid;&lt;br /&gt;
    $modulename = $event-&amp;gt;modulename;&lt;br /&gt;
    $instanceid = $event-&amp;gt;instance;&lt;br /&gt;
    $modified = false;&lt;br /&gt;
&lt;br /&gt;
    $coursemodule = get_fast_modinfo($courseid)-&amp;gt;instances[$modulename][$instanceid];&lt;br /&gt;
    $context = context_module::instance($coursemodule-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    // The user does not have the capability to modify this activity.&lt;br /&gt;
    if (!has_capability(&#039;moodle/course:manageactivities&#039;, $context)) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == FEEDBACK_EVENT_TYPE_OPEN) {&lt;br /&gt;
        // If the event is for the feedback activity opening then we should&lt;br /&gt;
        // set the start time of the feedback activity to be the new start&lt;br /&gt;
        // time of the event.&lt;br /&gt;
        if ($feedback-&amp;gt;timeopen != $event-&amp;gt;timestart) {&lt;br /&gt;
            $feedback-&amp;gt;timeopen = $event-&amp;gt;timestart;&lt;br /&gt;
            $feedback-&amp;gt;timemodified = time();&lt;br /&gt;
            $modified = true;&lt;br /&gt;
        }&lt;br /&gt;
    } else if ($event-&amp;gt;eventtype == FEEDBACK_EVENT_TYPE_CLOSE) {&lt;br /&gt;
        // If the event is for the feedback activity closing then we should&lt;br /&gt;
        // set the end time of the feedback activity to be the new start&lt;br /&gt;
        // time of the event.&lt;br /&gt;
        if ($feedback-&amp;gt;timeclose != $event-&amp;gt;timestart) {&lt;br /&gt;
            $feedback-&amp;gt;timeclose = $event-&amp;gt;timestart;&lt;br /&gt;
            $modified = true;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($modified) {&lt;br /&gt;
        $feedback-&amp;gt;timemodified = time();&lt;br /&gt;
        $DB-&amp;gt;update_record(&#039;feedback&#039;, $feedback);&lt;br /&gt;
        $event = \core\event\course_module_updated::create_from_cm($coursemodule, $context);&lt;br /&gt;
        $event-&amp;gt;trigger();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core_calendar_get_valid_event_timestart_range====&lt;br /&gt;
This callback should calculate the minimum and maximum allowed timestart property for the given calendar event. This will typically be based on the properties of the activity instance, for example the timeopen and timeclose properties of the activity could form the minimum and maximum bounds, respectively.&lt;br /&gt;
&lt;br /&gt;
These values will be used to provide a visual indicator to the user in the calendar UI for which days are valid for the event to be dragged to. It will also be used to validate that the calendar event is being updated to a valid timestart value.&lt;br /&gt;
&lt;br /&gt;
The callback should return an array with two values, the first value representing the minimum cutoff and the second the maximum.&lt;br /&gt;
&lt;br /&gt;
The callback can return an array for each of the minimum and maximum cutoffs, if it has them. The array should contain the timestamp of the cutoff and an error message to be displayed to the user if they attempt to drag an event to a day that violates the limit. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
[&lt;br /&gt;
     [1505704373, &#039;The due date must be after the sbumission start date&#039;], // Minimum cutoff.&lt;br /&gt;
     [1506741172, &#039;The due date must be before the cutoff date&#039;] // Maximum cutoff.&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the calendar event has no limits then it should return null in for either/both of the min and max cutoff values to indicate that it isn’t limited. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
[null, null] // No limits.&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
 &amp;lt;code php&amp;gt;&lt;br /&gt;
[null, [1510625037, “This is the maximum cutoff”]] // No minimum cutoff.&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
[[1510625037, “This is the minimum cutoff”], null] // No maximum cutoff.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the calendar event has no valid timestart values then the callback should return [false, false]. This is used to prevent the drag and drop of override events in activities that support them (e.g. Assign, Quiz).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_feedback_core_calendar_get_valid_event_timestart_range(\calendar_event $event, \stdClass $instance) {&lt;br /&gt;
    $mindate = null;&lt;br /&gt;
    $maxdate = null;&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == FEEDBACK_EVENT_TYPE_OPEN) {&lt;br /&gt;
        // The start time of the open event can&#039;t be equal to or after the&lt;br /&gt;
        // close time of the choice activity.&lt;br /&gt;
        if (!empty($instance-&amp;gt;timeclose)) {&lt;br /&gt;
            $maxdate = [&lt;br /&gt;
                $instance-&amp;gt;timeclose,&lt;br /&gt;
                get_string(&#039;openafterclose&#039;, &#039;feedback&#039;)&lt;br /&gt;
            ];&lt;br /&gt;
        }&lt;br /&gt;
    } else if ($event-&amp;gt;eventtype == FEEDBACK_EVENT_TYPE_CLOSE) {&lt;br /&gt;
        // The start time of the close event can&#039;t be equal to or earlier than the&lt;br /&gt;
        // open time of the choice activity.&lt;br /&gt;
        if (!empty($instance-&amp;gt;timeopen)) {&lt;br /&gt;
            $mindate = [&lt;br /&gt;
                $instance-&amp;gt;timeopen,&lt;br /&gt;
                get_string(&#039;closebeforeopen&#039;, &#039;feedback&#039;)&lt;br /&gt;
            ];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return [$mindate, $maxdate];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Themes_overview&amp;diff=53229</id>
		<title>Themes overview</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Themes_overview&amp;diff=53229"/>
		<updated>2017-11-13T08:28:14Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Themes}}&lt;br /&gt;
Welcome to the new world of themes in Moodle!&lt;br /&gt;
&lt;br /&gt;
A Moodle theme allows the user to change the look and feel of a Moodle site.  Themes can be applied on the site, category, course and activity levels by users with permissions to do so.  Themes can be designed for specific devices such as mobile phones or tablets. This page explains how themes work in Moodle and is intended to help you create or modify most themes for Moodle.&lt;br /&gt;
&lt;br /&gt;
You can use contributed themes or create your entire own to share with the community. Themes can also be based on parent themes with only few customizations. Themes accomplish this using CSS, changing the underlying markup structure and also adding Javascript to add more advanced behaviors.&lt;br /&gt;
&lt;br /&gt;
Most theme developers simply add a few changes to their new theme by basing it on an existing one. The Moodle Theme architecture is designed in such a way whereby the base theme will act as a fall-back that is used when nothing has been defined in the theme based on it. This makes it easy to create new themes that simply seek out to make minor changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Whats new?==&lt;br /&gt;
&lt;br /&gt;
When Moodle releases a new version. All changes that affect themes are listed in the theme/upgrade.txt file. This is the most up-to date place to find about all changes to a specific version of Moodle and will always be kept up to date. &lt;br /&gt;
&lt;br /&gt;
[https://github.com/moodle/moodle/blob/master/theme/upgrade.txt View upgrade notes]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==The structure of a theme==&lt;br /&gt;
&lt;br /&gt;
Some important things to know when building good themes:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;config.php&#039;&#039;&#039; - this file is required in every theme.  It defines configuration settings and definitions required to make the theme work in Moodle. These include theme, file, region, default region and options. &lt;br /&gt;
# &#039;&#039;&#039;Layouts and layout files&#039;&#039;&#039; -  in config.php there is one definition for each page type (see [[#theme_layouts_table|Appendix A: Theme layouts]] for a list of over 12 types).  Each page type definition tells Moodle which layout file will be used, what block regions this page type should display and so on.  The layout file contains the HTML and the minimum PHP required to display basic structure of pages.&lt;br /&gt;
# &#039;&#039;&#039;The boost theme&#039;&#039;&#039; - is intended to be the best theme to use as a starting point for building a new theme. It supports all the latest theme features and it tries to stay as true to the [http://getbootstrap.com/ Bootstrap] css framework as possible. [[Creating a theme based on boost]] &lt;br /&gt;
&lt;br /&gt;
===Files and folders===&lt;br /&gt;
A theme&#039;s files are placed in a folder with under moodle/theme folder and have subfolders. They are laid out like this:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Directory&lt;br /&gt;
! File&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| /&lt;br /&gt;
| config.php&lt;br /&gt;
| Contains all of the configuration and definitions for each theme&lt;br /&gt;
|-&lt;br /&gt;
| /&lt;br /&gt;
| lib.php &lt;br /&gt;
| Contains speciality functions that are used by theme&lt;br /&gt;
|-&lt;br /&gt;
| /classes&lt;br /&gt;
| *.php&lt;br /&gt;
| Contains auto-loaded classes for the theme. See [[Automatic class loading]] for more details.&lt;br /&gt;
|-&lt;br /&gt;
| /classes/output&lt;br /&gt;
| *.php&lt;br /&gt;
| This is the location for the theme to define overridden renderers. See [[Output renderers]] for more details.&lt;br /&gt;
|-&lt;br /&gt;
| /&lt;br /&gt;
| settings.php &lt;br /&gt;
| Contains custom theme settings. These local settings are defined by the theme allowing an administrator to easily alter something about the way it looks or operates. (eg a background colour, or a header image)&lt;br /&gt;
|-&lt;br /&gt;
| /&lt;br /&gt;
| version.php &lt;br /&gt;
| Contains the theme name, version number and Moodle version requirements for using the theme&lt;br /&gt;
|-&lt;br /&gt;
| /fonts/&lt;br /&gt;
| *.woff, *.ttf, *.eot, *.svg, *.otf&lt;br /&gt;
| Theme fonts (since 2.6).&lt;br /&gt;
|-&lt;br /&gt;
| /fonts_core/ &lt;br /&gt;
| *.woff, *.ttf, *.eot, *.svg, *.otf&lt;br /&gt;
| Contains fonts that override standard core fonts (since 2.6).&lt;br /&gt;
|-&lt;br /&gt;
| /fonts_plugins/plugintype/pluginname/ &lt;br /&gt;
| *.woff, *.ttf, *.eot, *.svg, *.otf&lt;br /&gt;
| Contains fonts that override plugin fonts (since 2.6).&lt;br /&gt;
|-&lt;br /&gt;
| /amd/src/ &lt;br /&gt;
| *.js&lt;br /&gt;
| All specialty JavaScript files the theme requires should be located in here. Javascript should be written as an AMD module. For more information see [[Javascript Modules]]. &lt;br /&gt;
|-&lt;br /&gt;
| /lang/[langcode]/&lt;br /&gt;
| *.php&lt;br /&gt;
| Any special language files the theme requires should be located in here. &lt;br /&gt;
|-&lt;br /&gt;
| /templates/ &lt;br /&gt;
| *.mustache&lt;br /&gt;
| Contains the mustache template files for the themes. (Including overridden ones). See [[Templates]] for more information.&lt;br /&gt;
|-&lt;br /&gt;
| /layout/ &lt;br /&gt;
| *.php&lt;br /&gt;
| Contains the layout files for the theme.&lt;br /&gt;
|-&lt;br /&gt;
| /pix/ &lt;br /&gt;
| *.png, *.jpg, *.gif, *.svg&lt;br /&gt;
| Contains any images the theme makes use of either in CSS or in the layout files.&lt;br /&gt;
|-&lt;br /&gt;
|  /pix/&lt;br /&gt;
| favicon.ico &lt;br /&gt;
| The favicon to display for this theme.&lt;br /&gt;
|-&lt;br /&gt;
| /pix/&lt;br /&gt;
| screenshot.png &lt;br /&gt;
| A screenshot of the theme to be displayed in on the theme selection screen.&lt;br /&gt;
|-&lt;br /&gt;
| /pix_core/ &lt;br /&gt;
| *.png, *.jpg, *.gif, *.svg&lt;br /&gt;
| Contains images that override standard core images.&lt;br /&gt;
|-&lt;br /&gt;
| /pix_plugins/plugintype/pluginname/ &lt;br /&gt;
| *.png, *.jpg, *.gif, *.svg&lt;br /&gt;
| Contains images that override plugin images.&lt;br /&gt;
|-&lt;br /&gt;
| /style/&lt;br /&gt;
| *.css&lt;br /&gt;
| Default location for CSS files.&lt;br /&gt;
|-&lt;br /&gt;
| /less/&lt;br /&gt;
| *.less&lt;br /&gt;
| Default location for Less files if your theme uses less.&lt;br /&gt;
|-&lt;br /&gt;
| /scss/&lt;br /&gt;
| *.scss&lt;br /&gt;
| Default location for SCSS files if your theme uses SCSS.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
There are also several other places that stylesheets can be included from (see the CSS how and why section below).&lt;br /&gt;
&lt;br /&gt;
It is possible to override icons used in base themes without interfering with core code by placing these in dataroot/pix and dataroot/pix_plugins. Where a theme extends a base theme and provides its own icons, these icons will still be used.&lt;br /&gt;
&lt;br /&gt;
It is possible to override mustache templates used in base themes without interfering with core code by placing these in templates/[componentname]/[templatename].mustache.&lt;br /&gt;
&lt;br /&gt;
==Theme options==&lt;br /&gt;
All theme options are set within the config.php file for the theme.  The settings that are most used are: parents, sheets, layouts, and javascripts. Have a look at the &#039;&#039;&#039;[[#theme_options_table|theme options table]]&#039;&#039;&#039; for a complete list of theme options which include lesser used specialised or advanced settings.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Basic theme config example===&lt;br /&gt;
Lets have a look at the boost theme configuration file and the different bits that make it up:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
require_once(__DIR__ . &#039;/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$THEME-&amp;gt;name = &#039;boost&#039;;&lt;br /&gt;
$THEME-&amp;gt;sheets = [];&lt;br /&gt;
$THEME-&amp;gt;editor_sheets = [];&lt;br /&gt;
$THEME-&amp;gt;scss = function($theme) {&lt;br /&gt;
    return theme_boost_get_main_scss_content($theme);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
$THEME-&amp;gt;layouts = [&lt;br /&gt;
    // Most backwards compatible layout without the blocks - this is the layout used by default.&lt;br /&gt;
    &#039;base&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns1.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
    ),&lt;br /&gt;
    // Standard layout with blocks, this is recommended for most pages with general information.&lt;br /&gt;
    &#039;standard&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns2.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    // Main course page.&lt;br /&gt;
    &#039;course&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns2.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;langmenu&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;coursecategory&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns2.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    // Part of course, typical for modules - default page layout if $cm specified in require_login().&lt;br /&gt;
    &#039;incourse&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns2.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    // The site home page.&lt;br /&gt;
    &#039;frontpage&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns2.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;nonavbar&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
    // Server administration scripts.&lt;br /&gt;
    &#039;admin&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns2.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    // My dashboard page.&lt;br /&gt;
    &#039;mydashboard&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns2.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;langmenu&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
    // My public page.&lt;br /&gt;
    &#039;mypublic&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns2.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;login&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;login.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;langmenu&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    // Pages that appear in pop-up windows - no navigation, no blocks, no header.&lt;br /&gt;
    &#039;popup&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns1.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;nofooter&#039; =&amp;gt; true, &#039;nonavbar&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
    // No blocks and minimal footer - used for legacy frame layouts only!&lt;br /&gt;
    &#039;frametop&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns1.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;nofooter&#039; =&amp;gt; true, &#039;nocoursefooter&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
    // Embeded pages, like iframe/object embeded in moodleform - it needs as much space as possible.&lt;br /&gt;
    &#039;embedded&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;embedded.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array()&lt;br /&gt;
    ),&lt;br /&gt;
    // Used during upgrade and install, and for the &#039;This site is undergoing maintenance&#039; message.&lt;br /&gt;
    // This must not have any blocks, links, or API calls that would lead to database or cache interaction.&lt;br /&gt;
    // Please be extremely careful if you are modifying this layout.&lt;br /&gt;
    &#039;maintenance&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;maintenance.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
    ),&lt;br /&gt;
    // Should display the content and basic headers only.&lt;br /&gt;
    &#039;print&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns1.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;nofooter&#039; =&amp;gt; true, &#039;nonavbar&#039; =&amp;gt; false),&lt;br /&gt;
    ),&lt;br /&gt;
    // The pagelayout used when a redirection is occuring.&lt;br /&gt;
    &#039;redirect&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;embedded.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
    ),&lt;br /&gt;
    // The pagelayout used for reports.&lt;br /&gt;
    &#039;report&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns2.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    // The pagelayout used for safebrowser and securewindow.&lt;br /&gt;
    &#039;secure&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;secure.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;&lt;br /&gt;
    )&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
$THEME-&amp;gt;parents = [];&lt;br /&gt;
$THEME-&amp;gt;enable_dock = false;&lt;br /&gt;
$THEME-&amp;gt;csstreepostprocessor = &#039;theme_boost_css_tree_post_processor&#039;;&lt;br /&gt;
$THEME-&amp;gt;extrascsscallback = &#039;theme_boost_get_extra_scss&#039;;&lt;br /&gt;
$THEME-&amp;gt;prescsscallback = &#039;theme_boost_get_pre_scss&#039;;&lt;br /&gt;
$THEME-&amp;gt;yuicssmodules = array();&lt;br /&gt;
$THEME-&amp;gt;rendererfactory = &#039;theme_overridden_renderer_factory&#039;;&lt;br /&gt;
$THEME-&amp;gt;undeletableblocktypes = &#039;&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Basic theme example settings explained===&lt;br /&gt;
First up you will notice everything is added to $THEME. This is the theme&#039;s configuration object, it is created by Moodle using default settings and is then updated by whatever settings you add to it.&lt;br /&gt;
&lt;br /&gt;
; $THEME-&amp;gt;name : The first setting, is the theme&#039;s name. This should simply be whatever your theme&#039;s name is, most likely whatever you named your theme directory.&lt;br /&gt;
&lt;br /&gt;
; $THEME-&amp;gt;sheets : An array containing the names of the CSS stylesheets to include for this theme. Boost uses scss instead of css so it doesn&#039;t list any files here. Note that it is just the name of the stylesheet and does not contain the directory or the file extension. Moodle assumes that the theme&#039;s stylesheets will be located in the styles directory of the theme and have .css as an extension.&lt;br /&gt;
&lt;br /&gt;
; $THEME-&amp;gt;editorsheets : An array containing the names of the CSS stylesheets to include for the TinyMCE text editor content area. Boost does not list any stylesheets here so TinyMCE will use plain text styles.&lt;br /&gt;
&lt;br /&gt;
; $THEME-&amp;gt;layouts : In this example, boost maps each of the 18 different layout types to one of 6 different layout files. For more information see the [[#Layouts|layouts]] section below.&lt;br /&gt;
&lt;br /&gt;
; $THEME-&amp;gt;parents : This defines the themes that the theme will extend. Boost has no parents, but if you were extending boost you would list it here like: $THEME-&amp;gt;parents = [&#039;boost&#039;];&lt;br /&gt;
&lt;br /&gt;
; $THEME-&amp;gt;enable_dock : Boost does not support docking blocks. For a example of a theme with a dock for blocks, see theme_bootstrapbase.&lt;br /&gt;
&lt;br /&gt;
; $THEME-&amp;gt;csstreepostprocessor : Boost uses a function to post process the CSS. This is an advanced feature and is used in boost to automatically apply vendor prefixes to CSS styles.&lt;br /&gt;
&lt;br /&gt;
; $THEME-&amp;gt;yuicssmodules : This is an old setting that defines a list of YUI css files to load. These files interfere with existing styles and it is recommended to set this to an empty string to prevent any files being included.&lt;br /&gt;
&lt;br /&gt;
; $THEME-&amp;gt;rendererfactory : Almost all themes need this setting to be set to &#039;theme_overridden_renderer_factory&#039; or the theme will not be able to customise any core renderers.&lt;br /&gt;
&lt;br /&gt;
; $THEME-&amp;gt;undeletableblocktypes : This is a comma separated list of block types that cannot be deleted in this theme. If you don&#039;t define this - the admin and settings blocks will be undeletable by default. Because Boost provides alternate ways to navigate it does not require any blocks.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Note&#039;&#039;&#039;&#039;&#039;: When you first begin writing themes, make sure you take a look at the configuration files of the other themes that get shipped with Moodle. You will get a good picture of how everything works, and what is going on in a theme, simply by reading it and taking notice of what it is including or excluding.&lt;br /&gt;
&lt;br /&gt;
==CSS==&lt;br /&gt;
===Locations of CSS files===&lt;br /&gt;
First lets look at where CSS can be included from within Moodle:&lt;br /&gt;
; \theme\themename\style\*.css : This is the default location for all of the stylesheets that are used by a theme and the place which should be used by a theme designer if this theme is using CSS. Alternatives to CSS are LESS and SCSS which are more powerful, flexible and easier to maintain.&lt;br /&gt;
&lt;br /&gt;
New theme developers should note that the order in which CSS files are found and included creates a hierarchy.  This order ensures that the rules, within a theme&#039;s style sheets, take precedence over identical rules in other files that may have been introduced before.  This can both extend another files definitions (see parent array in the config file) and also ensures that the current theme&#039;s CSS rules/definitions have the last say.&lt;br /&gt;
&lt;br /&gt;
There are other locations that can be used (although very rarely) to include CSS in a page. A developer of a php file can manually specify a stylesheet from anywhere within Moodle, like the database. Usually, if code is doing this, it is because there is a non-theme config or plugin setting that contains information requires special CSS information.  As a theme designer you should be aware of, but not have to worry about, these locations of CSS files.  Here are some examples:&lt;br /&gt;
&lt;br /&gt;
; {pluginpath}\styles.css e.g. \block\blockname\styles.css or \mod\modname\styles.css : Every plugin can have its own styles.css file. This file should only contain the required CSS rules for the module and should not add anything to the look of the plugin such as colours, font sizes, or margins other than those that are truly required.&amp;lt;br /&amp;gt;Theme specific styles for a plugin should be located within the themes styles directory.&lt;br /&gt;
; {pluginpath}\styles_themename.css : This should only ever be used by plugin developers. It allows them to write CSS that is designed for a specific theme without having to make changes to that theme. You will notice that this is never used within Moodle and is designed to be used only by contributed code.&lt;br /&gt;
&lt;br /&gt;
As theme designers, we will only use the first method of introducing CSS: adding rules to a stylesheet file located in the theme&#039;s style directory.&lt;br /&gt;
===Better than CSS===&lt;br /&gt;
Browsers understand CSS well - but it is hard to write and maintain. The language does not support inheritance and reuse and does not allow configuration with variables. This is why CSS pre-processors were invented. Moodle supports 2 different types of CSS pre-processors (Less and Sass) but the Sass pre-processor is recommended by far. &lt;br /&gt;
&lt;br /&gt;
For more information on Less and Sass see: &lt;br /&gt;
* [https://en.wikipedia.org/wiki/Less_(stylesheet_language) Less (wikipedia)]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Sass_(stylesheet_language) Sass (wikipedia)]&lt;br /&gt;
&lt;br /&gt;
To use either one, define $THEME-&amp;gt;lessfile = &#039;filename&#039;; or $THEME-&amp;gt;scss = &#039;filename&#039;; in your themes config.php. Moodle will then use one of it&#039;s in-built CSS pre-processor to compile the CSS the first time it is loaded (or everytime if themedesignermode is enabled in $CFG).&lt;br /&gt;
&lt;br /&gt;
===Moodle&#039;s core CSS organisation===&lt;br /&gt;
The next thing to look at is the organisation of CSS and rules within a theme. Although as a theme designer it is entirely up to you as to how you create and organise your CSS. Please note that none of the themes provided in the standard install by Moodle use CSS stylesheets directly. Instead they use either LESS or SCSS to generate the style sheets. They all list one main LESS or SCSS file named &amp;quot;moodle&amp;quot; in the less or scss folders and this file uses imports to load all other required files.&lt;br /&gt;
&lt;br /&gt;
===How to write effective CSS rules within Moodle===&lt;br /&gt;
Writing good CSS rules is incredibly important.&lt;br /&gt;
&lt;br /&gt;
Due to performance requirements and browser limitations, all of the CSS files are combined into a single CSS file that gets included every time. This means that rules need to be written in such a way as to minimise the chances of a collision leading to unwanted styles being applied. Whilst writing good CSS is something most designers strive for we have implemented several new body classes and prompt developers to use appropriate classnames.&lt;br /&gt;
&lt;br /&gt;
====&amp;lt;body&amp;gt; CSS id and classes ====&lt;br /&gt;
The ID tag that gets applied to the body will always be a representation of the URI. For example if you are looking at a forum posting and the URI is &#039;/mod/forum/view.php&#039; then the body tags ID will be &#039;#page-mod-forum-view&#039;.&lt;br /&gt;
&lt;br /&gt;
As well as the body&#039;s ID attribute the URI is also exploded to form several CSS classes that get added to the body tag, so in the above example &#039;/mod/forum/view&#039; you would end up with the following classes being added to the body tag &#039;.path-mod&#039;, &#039;.path-mod-forum&#039;. Note that &#039;.path-mod-forum-view&#039; is not added as a class, this is intentionally left out to lessen confusion and duplication as rules can relate directly to the page by using the ID and do not require the final class.&lt;br /&gt;
&lt;br /&gt;
The body ID and body classes described above will form the bread and butter for many of the CSS rules you will need to write for your theme, however there are also several other very handy classes that get added to the body tag that will be beneficial to you once you start your journey down the rabbit hole that is themeing. Some of the more interesting classes are listed below.&lt;br /&gt;
&lt;br /&gt;
* If JavaScript is enabled then &#039;jsenabled&#039; will be added as a class to the body tag allowing you to style based on JavaScript being enabled or not.&lt;br /&gt;
* Either &#039;dir-rtl&#039; or &#039;dir-ltr&#039; will be added to the body as a class depending on the direction of the language pack: rtl = right to left, ltr = left to right. This allows you to determine your text-alignment based on language if required.&lt;br /&gt;
* A class will be added to represent the language pack currently in use, by default en_utf8 is used by Moodle and will result in the class &#039;lang-en_utf8&#039; being added to the body tag.&lt;br /&gt;
* The wwwroot for Moodle will also be converted to a class and added to the body tag allowing you to stylise your theme based on the URL through which it was reached. e.g. http://sam.moodle.local/moodle/ will become &#039;.sam-moodle-local—moodle&#039;&lt;br /&gt;
* If the current user is not logged then &#039;.notloggedin&#039; will be added to the body tag.&lt;br /&gt;
* The course format type will be added such as format-weeks&lt;br /&gt;
* The course id, context id and category id are all added as in &amp;quot;course-11 context-616 cmid-202 category-1&amp;quot;&lt;br /&gt;
* The pagelayout is added as &amp;quot;pagelayout-incourse&amp;quot;&lt;br /&gt;
&lt;br /&gt;
What does all of this look like in practise? Well using the above example /mod/forum/view.php you would get at least the following body tag:&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
&amp;lt;body id=&amp;quot;page-mod-forum-view&amp;quot; class=&amp;quot;format-weeks forumtype-social  path-mod path-mod-forum safari dir-ltr lang-en yui-skin-sam yui3-skin-sam damyon-per-in-moodle-com--stable_master pagelayout-incourse course-11 context-616 cmid-202 category-1  jsenabled&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Writing your rules====&lt;br /&gt;
&lt;br /&gt;
By following the [[CSS coding style]] and CSS best-practices and understanding the [http://htmlhelp.com/reference/css/structure.html#cascade cascading order] of CSS a theme developer will reduce collisions and lines of CSS that is written. CSS classes have been placed where it is believed anyone may want to apply their own styles.&lt;br /&gt;
&lt;br /&gt;
When starting to write rules make sure that you have a good understanding of where you want those rules to be applied, it is a good idea to make the most of the body classes mentioned above.&lt;br /&gt;
If you want to write a rule for a specific page make use of the body tag&#039;s ID, e.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code css&amp;gt;#page-mod-forum-view .forumpost {&lt;br /&gt;
    border: 1px solid blue;&lt;br /&gt;
}&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write a rule that will be applied all throughout the forum.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code css&amp;gt;.path-mod-forum .forumpost {&lt;br /&gt;
    border: 1px solid blue;&lt;br /&gt;
}&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The other very important thing to take into consideration is the structure leading up to the tag you want to style. Browsers apply conflicting styles with priority on the more specific selectors. It can be very beneficial to keep this in mind and write full selectors that rely on the structure of the tags leading to the tag you wish to style.&lt;br /&gt;
&lt;br /&gt;
By making use of body id&#039;s and classes and writing selectors to take into account the leading structure you can greatly minimise the chance of a collision both with Moodle now and in the future.&lt;br /&gt;
&lt;br /&gt;
It is also important to write as FEW rules as possible. CSS is extremely hard to maintain and lots of CSS is bad for client side performance. Themes based on the Bootstrap CSS framework can achieve most things without writing a single additional CSS rule. Please read [http://v4-alpha.getbootstrap.com/ the Bootstrap documentation] and learn how to use Bootstrap well to avoid adding unnecessary CSS rules for things already provided by the framework.&lt;br /&gt;
&lt;br /&gt;
==Layouts==&lt;br /&gt;
Layouts are defined in &#039;&#039;&#039;config.php&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
All themes are required to define the layouts they wish to be responsible for as well as create; however, many layout files are required by those layouts. If the theme is overriding another theme then it is a case of deciding which layouts this new theme should override. If the theme is a completely fresh start then you will need to define a layout for each of the different possibilities. &lt;br /&gt;
&lt;br /&gt;
It is also important to note that a new theme that will base itself on another theme (overriding it) does not need to define any layouts or use any layout files if there are no changes that it wishes to make to the layouts of the existing theme.&lt;br /&gt;
&lt;br /&gt;
As mentioned earlier, layouts are defined in config.php within $THEME-&amp;gt;layouts. The following is an example of one such layout definition:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;layouts = array(&lt;br /&gt;
    // Standard layout with blocks, this is recommended for most pages with general information&lt;br /&gt;
    &#039;standard&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;boost&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns2.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The first thing Moodle looks at is the name of the layout, in this case it is `standard` (the array key in PHP), it then looks at the settings for the layout, this is the theme, file, regions, and default region. There are also a couple of other options that can be set by a layout.&lt;br /&gt;
&lt;br /&gt;
; theme : is the theme the layout file exists in. That&#039;s right: you can make use of layouts from other installed themes. &#039;&#039;Optional&#039;&#039;&lt;br /&gt;
; file : is the name of the layout file this layout wants to use. &#039;&#039;Required&#039;&#039;&lt;br /&gt;
; regions : is the different block regions (places you can put blocks) within the theme. &#039;&#039;Required&#039;&#039;&lt;br /&gt;
; defaultregion : is the default location when adding new blocks. &#039;&#039;&#039;Required if regions is non-empty, otherwise optional&#039;&#039;&#039;&lt;br /&gt;
; options : an array of layout specific options described in detail below. &#039;&#039;&#039;Optional&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;theme&#039;&#039;&#039; is optional. Normally the the layout file is looked for in the current theme, or, if it is not there, in the parent theme. However, you can use a layout file from any other theme by giving the theme name here.&lt;br /&gt;
&lt;br /&gt;
You can define whatever regions you like. You just need to pick a name for each one. Most themes just use one or both of &#039;&#039;&#039;side_pre&#039;&#039;&#039; and &#039;&#039;&#039;side_post&#039;&#039;&#039;, which is like &#039;left side&#039; and &#039;right side&#039;, except in right to left languages, when they are reversed. If you say in config.php that your the layout provides regions called &#039;fred&#039; and &#039;barney&#039;, then you must call $OUTPUT-&amp;gt;blocks_for_region(&#039;fred&#039;) and $OUTPUT-&amp;gt;blocks_for_region(&#039;barney&#039;) somewhere in the layout file.&lt;br /&gt;
&lt;br /&gt;
The final setting &#039;&#039;&#039;options&#039;&#039;&#039; is a special case that only needs to be set if you want to make use of it. This setting allows the theme designer to specify special options that they would like to create that can be later accessed within the layout file. This allows the theme to make design decisions during the definition and react upon those decisions in what ever layout file is being used.&lt;br /&gt;
&lt;br /&gt;
One such place this has been used is within the boost theme. If you take a look first at theme/boost/config.php you will notice that several layouts specify options &#039;&#039;&#039;langmenu&#039;&#039;&#039; and &#039;&#039;&#039;nonavbar&#039;&#039;&#039; which can both be set to either true or false. The layout options can then be used on the layout .php files, mustache templates and renderers.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$hasnavbar = (empty($PAGE-&amp;gt;layout_options[&#039;nonavbar&#039;]) &amp;amp;&amp;amp; $PAGE-&amp;gt;has_navbar());&lt;br /&gt;
$hasfooter = (empty($PAGE-&amp;gt;layout_options[&#039;nofooter&#039;]));&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Layout files==&lt;br /&gt;
Layout files are used to provide a different layout of the elements of the page for different types of pages in Moodle.&lt;br /&gt;
&lt;br /&gt;
In the config.php for a theme - there is a list of &#039;layouts&#039; which map a page type to a specific php page in the layout folder for the theme.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&#039;&#039;theme/boost/config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    &#039;popup&#039; =&amp;gt; array(                                                                                                               &lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns1.php&#039;,                                                                                                   &lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),                                                                                                       &lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;nofooter&#039; =&amp;gt; true, &#039;nonavbar&#039; =&amp;gt; true),                                                                 &lt;br /&gt;
    ),                                &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means every page that has pagetype &#039;popup&#039; will be displayed with the &#039;theme/themename/layout/columns1.php&#039; file, it will have no block regions and there are some options that will be available to the page in the global variable &amp;quot;$PAGE-&amp;gt;layout_options&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
It is possible to implement a layout file directly in php by echoing the HTML for the page, or mixing php tags with HTML - but a better way to create a layout file is to gather all the information required for the layout into a context and render it with a mustache template. &lt;br /&gt;
&lt;br /&gt;
[[Templates| Read about mustache templates]]&lt;br /&gt;
&lt;br /&gt;
Using templates for layout files makes a lot of sense because they are easier to read and maintain than mixing PHP and HTML in the same file.&lt;br /&gt;
&lt;br /&gt;
A simple example of a layout file using a template is at:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme/boost/layout/columns1.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$bodyattributes = $OUTPUT-&amp;gt;body_attributes([]);                                                                                     &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
$templatecontext = [                                                                                                                &lt;br /&gt;
    &#039;sitename&#039; =&amp;gt; format_string($SITE-&amp;gt;shortname, true, [&#039;context&#039; =&amp;gt; context_course::instance(SITEID), &amp;quot;escape&amp;quot; =&amp;gt; false]),        &lt;br /&gt;
    &#039;output&#039; =&amp;gt; $OUTPUT,                                                                                                            &lt;br /&gt;
    &#039;bodyattributes&#039; =&amp;gt; $bodyattributes                                                                                             &lt;br /&gt;
];                                                                                                                                  &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
echo $OUTPUT-&amp;gt;render_from_template(&#039;theme_boost/columns1&#039;, $templatecontext);  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example puts some variables into a templatecontext and then calls &amp;quot;render_from_template&amp;quot; to render the mustache template for this layout. The template is located at: &amp;quot;theme/boost/templates/columns1.mustache&amp;quot;. It is possible to put PHP classes in the context for the mustache template - and any public properties or methods which accept no arguments will be available to the template. $OUTPUT has several useful public methods which accept no arguments and is a valuable class when creating a layout template in mustache.&lt;br /&gt;
&lt;br /&gt;
The mustache template for this layout is shown here:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme/boost/templates/columns1.mustache&#039;&#039;&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
{{{ output.doctype }}}                                                                                                              &lt;br /&gt;
&amp;lt;html {{{ output.htmlattributes }}}&amp;gt;                                                                                                &lt;br /&gt;
&amp;lt;head&amp;gt;                                                                                                                              &lt;br /&gt;
    &amp;lt;title&amp;gt;{{{ output.page_title }}}&amp;lt;/title&amp;gt;                                                                                        &lt;br /&gt;
    &amp;lt;link rel=&amp;quot;shortcut icon&amp;quot; href=&amp;quot;{{{ output.favicon }}}&amp;quot; /&amp;gt;                                                                      &lt;br /&gt;
    {{{ output.standard_head_html }}}                                                                                               &lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot;&amp;gt;                                                          &lt;br /&gt;
&amp;lt;/head&amp;gt;                                                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
&amp;lt;body {{{ bodyattributes }}}&amp;gt;                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
&amp;lt;div id=&amp;quot;page-wrapper&amp;quot;&amp;gt;                                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    {{{ output.standard_top_of_body_html }}}                                                                                        &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    &amp;lt;div id=&amp;quot;page&amp;quot; class=&amp;quot;container-fluid&amp;quot;&amp;gt;                                                                                         &lt;br /&gt;
        &amp;lt;div id=&amp;quot;page-content&amp;quot; class=&amp;quot;row&amp;quot;&amp;gt;                                                                                         &lt;br /&gt;
            &amp;lt;div id=&amp;quot;region-main-box&amp;quot; class=&amp;quot;col-xs-12&amp;quot;&amp;gt;                                                                            &lt;br /&gt;
                &amp;lt;section id=&amp;quot;region-main&amp;quot;&amp;gt;                                                                                          &lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card card-block&amp;quot;&amp;gt;                                                                                   &lt;br /&gt;
                    {{{ output.course_content_header }}}                                                                            &lt;br /&gt;
                    {{{ output.main_content }}}                                                                                     &lt;br /&gt;
                    {{{ output.course_content_footer }}}                                                                            &lt;br /&gt;
                    &amp;lt;/div&amp;gt;                                                                                                          &lt;br /&gt;
                &amp;lt;/section&amp;gt;                                                                                                          &lt;br /&gt;
            &amp;lt;/div&amp;gt;                                                                                                                  &lt;br /&gt;
        &amp;lt;/div&amp;gt;                                                                                                                      &lt;br /&gt;
    &amp;lt;/div&amp;gt;                                                                                                                          &lt;br /&gt;
&amp;lt;/div&amp;gt;                                                                                                                              &lt;br /&gt;
{{{ output.standard_end_of_body_html }}}                                                                                            &lt;br /&gt;
&amp;lt;/body&amp;gt;                                                                                                                             &lt;br /&gt;
&amp;lt;/html&amp;gt;                                                                                                                             &lt;br /&gt;
{{#js}}                                                                                                                             &lt;br /&gt;
require([&#039;theme_boost/loader&#039;]);                                                                                                    &lt;br /&gt;
{{/js}} &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explaining each line of this template will answer a lot of questions. This example contains only the very minimal required functions to generate a valid layout. You should consider all of the sections below as required in every layout file (although any of the HTML tags can and should be altered). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
{{{ output.doctype }}}                                                                                                              &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is an example of calling a function on $OUTPUT in php. Because there is a public method on the output class named &amp;quot;doctype&amp;quot; which accepts no arguments - mustache will call it and return the output. We call a function to generate the doctype tag because calling this function returns us the correct HTML for the document type for this theme AND it sets a different content type header (including the charset) depending on the doc type for the theme. Setting a correct charset in every page is important to prevent a class of XSS attacks. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
&amp;lt;html {{{ output.htmlattributes }}}&amp;gt;                                                                                                &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we have returned our root tag - the html tag. We included a set of default attributes for the page by calling the htmlattributes function of our output class. This includes the correct language attribute for the entire page and can include an xml namespace for XHTML documents. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;                                                                                                                              &lt;br /&gt;
    &amp;lt;title&amp;gt;{{{ output.page_title }}}&amp;lt;/title&amp;gt;                                                                                        &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we have started the head section of our document and set the title for the page. Notice the title is already escaped by the output class so we are using triple mustache tags &amp;quot;{{{&amp;quot; to avoid double escaping.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;shortcut icon&amp;quot; href=&amp;quot;{{{ output.favicon }}}&amp;quot; /&amp;gt;                                                                      &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We call a function to get the url to the favicon. The favicon is a file in the theme pix directory and it is served through the &amp;quot;theme/image.php&amp;quot; file which adds special caching headers for images.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
    {{{ output.standard_head_html }}}                                                                                               &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The standard head html function performs a lot of setup that is required for our page. It internally creates the block regions, creates meta tags including keywords for SEO, initialises the common javascript modules, generates links to the style sheets and injects any additional HTML set by the $CFG-&amp;gt;additionalhtmlhead setting.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot;&amp;gt;                                                          &lt;br /&gt;
&amp;lt;/head&amp;gt;                                                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This viewport meta tag is recommended by bootstrap for &amp;quot;proper viewport rendering and touch zooming&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
&amp;lt;body {{{ bodyattributes }}}&amp;gt;                                                                                                       &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The body attributes include the language direction and standard classes for the page. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
&amp;lt;div id=&amp;quot;page-wrapper&amp;quot;&amp;gt;                                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the Boost theme we use a page-wrapper div to prevent content from disappearing under the fixed header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
    {{{ output.standard_top_of_body_html }}}                                                                                        &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The standard_top_of_body_html should be included in every layout and includes skip links for accessibility as well as initialising jquery, yui and our own static javascript files.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;page&amp;quot; class=&amp;quot;container-fluid&amp;quot;&amp;gt;                                                                                         &lt;br /&gt;
        &amp;lt;div id=&amp;quot;page-content&amp;quot; class=&amp;quot;row&amp;quot;&amp;gt;                                                                                         &lt;br /&gt;
            &amp;lt;div id=&amp;quot;region-main-box&amp;quot; class=&amp;quot;col-xs-12&amp;quot;&amp;gt;                                                                            &lt;br /&gt;
                &amp;lt;section id=&amp;quot;region-main&amp;quot;&amp;gt;                                                                                          &lt;br /&gt;
                    &amp;lt;div class=&amp;quot;card card-block&amp;quot;&amp;gt;                                                                                   &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is standard HTML tags defining the content region for this page. The classes come from bootstrap 4.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
                    {{{ output.course_content_header }}}                                                                            &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The course content header allows Moodle plugins to inject things in the top of the page. This is used for &amp;quot;notifications&amp;quot; for example (which are the alert boxes you see after submitting a form). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
                    {{{ output.main_content }}}                                                                                     &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The main content function returns the real content for the page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
                    {{{ output.course_content_footer }}}                                                                            &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The course content footer is used mainly by course formats to insert things after the main content.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;                                                                                                          &lt;br /&gt;
                &amp;lt;/section&amp;gt;                                                                                                          &lt;br /&gt;
            &amp;lt;/div&amp;gt;                                                                                                                  &lt;br /&gt;
        &amp;lt;/div&amp;gt;                                                                                                                      &lt;br /&gt;
    &amp;lt;/div&amp;gt;                                                                                                                          &lt;br /&gt;
&amp;lt;/div&amp;gt;                                                                                                                              &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We close all our open tags...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
{{{ output.standard_end_of_body_html }}}                                                                                            &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will add all of the javascript that was required while rendering the page. Javascript is added at the end of the document so that it does not block rendering the page. &lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;                                                                                                                             &lt;br /&gt;
&amp;lt;/html&amp;gt;                                                                                                                             &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We finish the HTML for our page. &lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
{{#js}}                                                                                                                             &lt;br /&gt;
require([&#039;theme_boost/loader&#039;]);                                                                                                    &lt;br /&gt;
{{/js}} &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This final section is required for bootstrap 4 themes and loads all the Bootstrap 4 Javascript dependencies. &lt;br /&gt;
&lt;br /&gt;
If we had block regions in this layout we would need to insert them in the template. The way we would do this is by getting the HTML for the block region in our layout php file, adding it to the context and then including it in our template.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme/boost/layout/columns2.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
$blockshtml = $OUTPUT-&amp;gt;blocks(&#039;side-pre&#039;);                                                                                          &lt;br /&gt;
$hasblocks = strpos($blockshtml, &#039;data-block=&#039;) !== false;&lt;br /&gt;
...&lt;br /&gt;
$templatecontext = [&lt;br /&gt;
...&lt;br /&gt;
    &#039;sidepreblocks&#039; =&amp;gt; $blockshtml,                                                                                                 &lt;br /&gt;
    &#039;hasblocks&#039; =&amp;gt; $hasblocks,&lt;br /&gt;
...&lt;br /&gt;
];&lt;br /&gt;
...&lt;br /&gt;
echo $OUTPUT-&amp;gt;render_from_template(&#039;theme_boost/columns2&#039;, $templatecontext);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme/boost/templates/columns2.mustache&#039;&#039;&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
                {{#hasblocks}}                                                                                                      &lt;br /&gt;
                &amp;lt;section data-region=&amp;quot;blocks-column&amp;quot; class=&amp;quot;hidden-print&amp;quot;&amp;gt;                                                          &lt;br /&gt;
                    {{{ sidepreblocks }}}                                                                                           &lt;br /&gt;
                &amp;lt;/section&amp;gt;                                                                                                          &lt;br /&gt;
                {{/hasblocks}} &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When writing layout files think about the different layouts and how the HTML that each makes use of will differ. You will most likely find you do not need a different layout file for each layout, most likely you will be able to reuse the layout files you create across several layouts. You can of course make use of layout options as well to further reduce the number of layout files you need to produce.&lt;br /&gt;
&lt;br /&gt;
Of course as mentioned above if you are customising an existing theme then you may not need to create any layouts or layout files at all.&lt;br /&gt;
&lt;br /&gt;
==Language File==&lt;br /&gt;
&lt;br /&gt;
You need to create a language file for your theme with a few standard strings in it. At a minimum create a file called lang/en/theme_themename.php in your theme folder. For example, the &#039;boost&#039; theme has a language file called lang/en/theme_boost.php. &lt;br /&gt;
&lt;br /&gt;
You &#039;&#039;&#039;must&#039;&#039;&#039; define the following lines in your file (example is from Boost theme, adapt as required):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Boost&#039;;&lt;br /&gt;
$string[&#039;region-side-pre&#039;] = &#039;Right&#039;;&lt;br /&gt;
$string[&#039;choosereadme&#039;] = &#039;Boost is a modern highly-customisable theme. This theme is intended to be used directly, or as a parent theme when creating new themes utilising Bootstrap 4.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Without the above you will get notices for the missing strings.&lt;br /&gt;
&lt;br /&gt;
==Making use of images==&lt;br /&gt;
Right at the start when listing the features of the new themes system one of the features mentioned was the ability to override any of the standard images within Moodle from within your theme. At this point we will look at both how to make use of your own images within your theme, and secondly how to override the images being used by Moodle.&lt;br /&gt;
So first up a bit about images within Moodle,&lt;br /&gt;
&lt;br /&gt;
# Images you want to use within your theme &#039;&#039;&#039;need&#039;&#039;&#039; to be located within your theme&#039;s pix directory.&lt;br /&gt;
# You can use sub directories within the pix directory of your theme.&lt;br /&gt;
# Images used by Moodle&#039;s core are located within the pix directory of Moodle.&lt;br /&gt;
# Modules, blocks and other plugins should also store their images within a pix directory.&lt;br /&gt;
&lt;br /&gt;
So making use of your own images first up. Lets assume you have added two image files to the pix directory of your theme.&lt;br /&gt;
&lt;br /&gt;
* /theme/yourthemename/pix/imageone.jpg&lt;br /&gt;
* /theme/yourthemename/pix/subdir/imagetwo.png&lt;br /&gt;
&lt;br /&gt;
Notice that one image is a JPEG image, and the second is a PNG. Also the second image is in a subdirectory.&lt;br /&gt;
&lt;br /&gt;
The following code snippet illustrates how to make use of your images within your layout file so they can be inserted by your layout template. &lt;br /&gt;
&#039;&#039;theme/yourtheme/layout/somelayout.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
$templatecontext = [&lt;br /&gt;
...&lt;br /&gt;
$imageone =&amp;gt; $OUTPUT-&amp;gt;pix_url(&#039;imageone&#039;, &#039;theme&#039;),&lt;br /&gt;
$imagetwo =&amp;gt; $OUTPUT-&amp;gt;pix_url(&#039;subdir/imagetwo&#039;, &#039;theme&#039;),&lt;br /&gt;
...&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
echo $OUTPUT-&amp;gt;render_from_template(&#039;theme_yourtheme/somelayout&#039;, $templatecontext);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a method of Moodle&#039;s output library to generate the URL to the image. Its not too important how that functions works but it is important that we use it as it is what allows images within Moodle to be over-rideable.&lt;br /&gt;
&#039;&#039;&#039;DO NOT&#039;&#039;&#039; include the image file extension. Moodle will work it out automatically and it will not work if you do include it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme/yourtheme/templates/somelayout.mustache&#039;&#039;&lt;br /&gt;
&amp;lt;code handlebars&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;img src=&amp;quot;{{{imageone}}}&amp;quot; alt=&amp;quot;Please give your image alt text or set the role to presentation&amp;quot; width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;img src=&amp;quot;{{{imagetwo}}}&amp;quot; alt=&amp;quot;Please give your image alt text or set the role to presentation&amp;quot; width=&amp;quot;50&amp;quot; height=&amp;quot;50&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is how you would use the images from within CSS, SCSS or Less as background images.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
.divone {&lt;br /&gt;
    background-image: url([[pix:theme|imageone]]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.divtwo {&lt;br /&gt;
    background-image: url([[pix:theme|subdir/imagetwo]]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If this case we have to use some special notations that Moodle looks for. Whenever Moodle hands out a CSS file it first searches for all &#039;&#039;[[something]]&#039;&#039; tags and replaces them with what is required.&lt;br /&gt;
&lt;br /&gt;
The final thing to notice with both of the cases above is that at no point do we include the images file extension. &lt;br /&gt;
The reason for this leads us into the next topic, how to override images.&lt;br /&gt;
&lt;br /&gt;
From within a theme you can VERY easily override any standard image within Moodle by simply adding the replacement image to the theme&#039;s pix directory in the same sub directory structure as it is in Moodle.&lt;br /&gt;
So for instance we wanted to override the following two images:&lt;br /&gt;
# /pix/moodlelogo.gif&lt;br /&gt;
# /pix/i/user.gif&lt;br /&gt;
We would simply need to add our replacement images to the theme in the following locations&lt;br /&gt;
# /theme/themename/pix_core/moodlelogo.gif&lt;br /&gt;
# /theme/themename/pix_core/i/user.gif&lt;br /&gt;
&#039;&#039;Note that we have created a &#039;&#039;&#039;pix_core&#039;&#039;&#039; directory in our theme. For a specific activity module like chat we need a &#039;&#039;&#039;pix_plugins/mod/chat&#039;&#039;&#039; directory. This directory is &amp;quot;pix_plugins&amp;quot; and then the plugin type (mod) and then the plugin name (chat). &lt;br /&gt;
&lt;br /&gt;
Now the other very cool thing to mention is that Moodle looks for not just replacements of the same image type (jpg, gif, etc...) but also replacements in any image format. This is why above when working with our images we never specified the images file extension.&lt;br /&gt;
This means that the following would also work:&lt;br /&gt;
# /theme/themename/pix_core/moodlelogo.png&lt;br /&gt;
# /theme/themename/pix_core/i/user.bmp&lt;br /&gt;
&lt;br /&gt;
For a more detailed description of how this all works see the page on [[Using images in a theme]].&lt;br /&gt;
&lt;br /&gt;
==Adding custom fonts==&lt;br /&gt;
{{Moodle 2.6}}&lt;br /&gt;
&lt;br /&gt;
CSS3 standard introduced the possibility to specify custom fonts, see [http://www.w3schools.com/css/css3_fonts.asp CSS3 Fonts tutorial].&lt;br /&gt;
&lt;br /&gt;
Since 2.6 Moodle includes support for plugin or theme fonts. It is very similar to theme images and pix subdirectories.&lt;br /&gt;
&lt;br /&gt;
===Font file locations===&lt;br /&gt;
&lt;br /&gt;
Depending on where you intend to use the font put it into one of the following locations:&lt;br /&gt;
* /lib/fonts/ - fonts used in core&lt;br /&gt;
* /plugindir/fonts/ - fonts used by plugin&lt;br /&gt;
* /theme/sometheme/fonts/ - theme specific fonts&lt;br /&gt;
&lt;br /&gt;
You can also override core and plugin fonts in theme:&lt;br /&gt;
* /theme/sometheme/fonts_core/ - overridden core fonts&lt;br /&gt;
* /theme/sometheme/fonts_plugins/plugintype_pluginname/ - overridden fonts of some plugin&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* subdirectories are not allowed&lt;br /&gt;
* use only lowercase alphanumeric characters and underscore in font file names&lt;br /&gt;
* WOFF (Web Open Font Format), TTF (True Type Fonts), OTF (OpenType Fonts), SVG (Scalable Vector Graphic) and EOT (Embedded OpenType) fonts are supported, but for the sake of humanity (And [https://tracker.moodle.org/browse/MDL-15169 MDL_15169] ) please use only WOFF fonts to encourage the quick death of IE8.&lt;br /&gt;
&lt;br /&gt;
===CSS placeholders===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
@font-face {&lt;br /&gt;
    font-family: ThreeDumb;&lt;br /&gt;
    src: url([[font:mod_book|3dumb.woff]]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The placeholder references file /mod/book/fonts/3dumb.woff, the new fontface could be for example used for book headings:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
.path-mod-book .book_chapter_title {&lt;br /&gt;
    font-family: ThreeDumb;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
If you want to use some font in theme only, you can for example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
@font-face {&lt;br /&gt;
    font-family: goodDogFont;&lt;br /&gt;
    src: url([[font:theme|good_dog.woff]]);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
a {font-family:goodDogFont;}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The font would be stored in /theme/yourtheme/fonts/good_dog.woff file.&lt;br /&gt;
&lt;br /&gt;
===More free fonts===&lt;br /&gt;
&lt;br /&gt;
Please respect all licenses for font redistribution, you can get some nice free fonts from [http://www.fontsquirrel.com http://www.fontsquirrel.com] for example.&lt;br /&gt;
&lt;br /&gt;
===Warning===&lt;br /&gt;
&lt;br /&gt;
This is not intended for forcing of something like Comic Sans on all your visitors...&lt;br /&gt;
&lt;br /&gt;
==Compiling LESS on the fly==&lt;br /&gt;
{{Moodle 2.7}}&lt;br /&gt;
&lt;br /&gt;
You can now provide a LESS file that will be compiled (and cached) on the fly. The purpose of this feature is to dynamically allow the customisation of LESS variables.&lt;br /&gt;
&lt;br /&gt;
===Set up your theme===&lt;br /&gt;
&lt;br /&gt;
# Create a .less file in a less folder. Eg. &amp;lt;code&amp;gt;theme/yourtheme/less/myfile.less&amp;lt;/code&amp;gt;&lt;br /&gt;
# Edit your theme config file, and set $THEME-&amp;gt;&#039;&#039;&#039;lessfile&#039;&#039;&#039; to the name of your file (do not include .less). Eg. &amp;lt;code&amp;gt;$THEME-&amp;gt;lessfile = &#039;myfile&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&#039;s it, the LESS file will be compiled and included in the page on the fly, but that is not very useful yet.&lt;br /&gt;
&lt;br /&gt;
Please note that any file referenced in $THEME-&amp;gt;sheets that shares the same name than the LESS file will be silently ignored.&lt;br /&gt;
&lt;br /&gt;
===Inheriting from a parent===&lt;br /&gt;
&lt;br /&gt;
Even if your theme is inheriting from a parent, the LESS file itself will not inherit from anything, this is something you should do manually. For instance, if you want your LESS file to include all of the LESS code provided by &#039;&#039;theme_bootstrapbase&#039;&#039;, usually to change the variables, you need to manually import the file like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
@import &amp;quot;../../bootstrapbase/less/moodle.less&amp;quot;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The path needs to be relative and not absolute. You would definitely want to add that rule first in your file and add anything else below it.&lt;br /&gt;
&lt;br /&gt;
===Programmatically injecting LESS===&lt;br /&gt;
&lt;br /&gt;
There are two theme options to specify a callback function that you need to know about:&lt;br /&gt;
&lt;br /&gt;
# $THEME-&amp;gt;&#039;&#039;&#039;extralesscallback&#039;&#039;&#039;: To return raw LESS code to be injected.&lt;br /&gt;
# $THEME-&amp;gt;&#039;&#039;&#039;lessvariablescallback&#039;&#039;&#039;: To return an array of variables and their values.&lt;br /&gt;
&lt;br /&gt;
Typically you will want to simply inject variables, but if you need to perform more complex manipulations, you can return some raw LESS code. The variables returned by the callback are always injected last.&lt;br /&gt;
&lt;br /&gt;
===Performance===&lt;br /&gt;
&lt;br /&gt;
Compiling LESS on the fly is a slow operation, and even though the result is cached you should be aware of it. If you have enabled the configuration setting &#039;&#039;themedesignermode&#039;&#039; you will definintely notice the slowness as the cache only lives for a very short period of time. Ideally your theme should precompile the LESS into CSS, but if you want to provide theme settings to your user, then using this feature is for you.&lt;br /&gt;
&lt;br /&gt;
===Example===&lt;br /&gt;
&lt;br /&gt;
You can refer to the theme &#039;&#039;theme_more&#039;&#039; for an example on how to use this feature.&lt;br /&gt;
&lt;br /&gt;
==Compiling SCSS on the fly==&lt;br /&gt;
{{Moodle 3.2}}&lt;br /&gt;
&lt;br /&gt;
You can now provide a SCSS file that will be compiled (and cached) on the fly. The purpose of this feature is to dynamically allow the customisation of SCSS variables. See the [[SCSS|dedicated page on SCSS]].&lt;br /&gt;
&lt;br /&gt;
==Unobvious Things==&lt;br /&gt;
===Getting Your Theme to Appear Correctly in Theme Selector===&lt;br /&gt;
If you follow the examples on this page to the letter, when you go to the Theme Selector page you may be discouraged to find that your theme does not appear like the other themes do. In fact, instead of your theme&#039;s name, you will see something along the lines of &amp;lt;nowiki&amp;gt;[[pluginname]]&amp;lt;/nowiki&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
To correct this, you must add the theme/THEMENAME/lang/en/theme_THEMENAME.php file, where THEMENAME is the name of the theme folder. Inside that file, add the string &amp;quot;$string[&#039;pluginname&#039;] = &#039;THEMENAME&#039;; &amp;quot;. Make THEMENAME the name of your theme, however you want it displayed in the Theme selector.&lt;br /&gt;
&lt;br /&gt;
Also, make sure to change your config.php file and version.php file to reflect the correct name:&lt;br /&gt;
&lt;br /&gt;
In config.php: $THEME-&amp;gt;name = &#039;NAME&#039;;&lt;br /&gt;
&lt;br /&gt;
In version.php: $plugin-&amp;gt;component = &#039;theme_NAME&#039;; // Full name of the plugin (used for diagnostics)&lt;br /&gt;
&lt;br /&gt;
The screenshot for the theme should be about 500x400 px.&lt;br /&gt;
&lt;br /&gt;
===Required theme divs===&lt;br /&gt;
&lt;br /&gt;
Some parts of Moodle may rely on particular divs, for example the div with id &#039;page-header&#039;.&lt;br /&gt;
&lt;br /&gt;
Consequently all themes must include at least the divs (with the same ids) that are present in the &#039;boost&#039; theme. &lt;br /&gt;
&lt;br /&gt;
Missing out these elements may result in unexpected behaviour within specific modules or other plugins.&lt;br /&gt;
&lt;br /&gt;
==Caching==&lt;br /&gt;
When Moodle is not running in theme designer mode it will look for a cached version of the compiled CSS for the current theme to serve to the browser requesting the page. If the cached file doesn&#039;t yet exist then the CSS will be built and cached during the page request.&lt;br /&gt;
&lt;br /&gt;
The cached CSS is located on disk in Moodle&#039;s local cache:&lt;br /&gt;
  &amp;lt;Moodle data directory &amp;gt;/localcache/theme/&amp;lt;global theme revision&amp;gt;/&amp;lt;theme_name&amp;gt;/css/all_&amp;lt;theme subrevision&amp;gt;.css&lt;br /&gt;
&lt;br /&gt;
The cache path consists of a global theme revision (themerev config value) and a per theme subrevision (themesubrev plugin config value). If either of those are incremented it will change the path to the cache file and cause a new file to be generated.&lt;br /&gt;
&lt;br /&gt;
Individual theme&#039;s CSS cache can be built by using the admin CLI script:&lt;br /&gt;
  php admin/cli/build_theme_css.php --themes boost&lt;br /&gt;
&lt;br /&gt;
The script will only increment the theme subrevision of the theme(s) being built which means existing theme cache&#039;s remain untouched.&lt;br /&gt;
&lt;br /&gt;
==Appendix A==&lt;br /&gt;
=== Theme options ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot; id=&amp;quot;theme_options_table&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Setting&lt;br /&gt;
! Effect&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;blockrtlmanipulations&#039;&#039;&#039;&lt;br /&gt;
|  Allows the theme to manipulate how the blocks are displayed in a &#039;&#039;right-to-left&#039;&#039; language. Not recommended since we automatically flip CSS for rtl. &lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;csspostprocess&#039;&#039;&#039;&lt;br /&gt;
|  Allows the user to provide the name of a function that all CSS should be passed to before being delivered.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;csstreepostprocessor&#039;&#039;&#039; (Since 3.2)&lt;br /&gt;
|  Allows the user to provide the name of a function that can perform manipulations on an in-memory representation of the CSS tree. Some useful manipulations are available such as the &amp;quot;theme_boost\autoprefixer&amp;quot; which will automatically add vendor prefixes to all CSS that requires them. &lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;doctype&#039;&#039;&#039;&lt;br /&gt;
|  The doctype of the served documents.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;editor_sheets&#039;&#039;&#039;&lt;br /&gt;
|  An array of stylesheets to include just within the body of the TinyMCE text editor. This is required if you want content to resemble its final appearance in the page, while it is being edited in the text editor.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;enablecourseajax&#039;&#039;&#039;&lt;br /&gt;
|  If set to false the course AJAX features will be disabled.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;enable_dock&#039;&#039;&#039;&lt;br /&gt;
|  If set to true the side dock is enabled for blocks.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;prescsscallback&#039;&#039;&#039;&lt;br /&gt;
|  The name of a function that will return some SCSS code to inject at the beginning of the SCSS file specified in $THEME-&amp;gt;scss. (Since 3.2)&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;extrascsscallback&#039;&#039;&#039;&lt;br /&gt;
|  The name of a function that will return some SCSS code to inject at the end of the SCSS file specified in $THEME-&amp;gt;scss. (Since 3.2)&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;extralesscallback&#039;&#039;&#039;&lt;br /&gt;
|  The name of a function that will return some LESS code to inject at the end of the LESS file specified in $THEME-&amp;gt;lessfile. (Since 2.7)&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;hidefromselector&#039;&#039;&#039;&lt;br /&gt;
|  Used to hide a theme from the theme selector (unless theme designer mode is on). Accepts true or false.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;javascripts&#039;&#039;&#039;&lt;br /&gt;
|  An array containing the names of JavaScript files located in /javascript/ to include in the theme. (gets included in the head). This setting should no longer be used - please use AMD [[Javascript Modules]] instead.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;javascripts_footer&#039;&#039;&#039;&lt;br /&gt;
|  As above but will be included in the page footer. This setting should no longer be used - please use AMD [[Javascript Modules]] instead.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;layouts&#039;&#039;&#039;&lt;br /&gt;
|  An array setting the layouts for the theme&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;lessfile&#039;&#039;&#039;&lt;br /&gt;
|  The name of a LESS file in the theme&#039;s less/ folder to compile on the fly. Sheets with the same name will be ignored. (Since 2.7)&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;lessvariablescallback&#039;&#039;&#039;&lt;br /&gt;
|  The name of a function that will modify some LESS variables before compiling the LESS file specified in $THEME-&amp;gt;lessfile. (Since 2.7)&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;scss&#039;&#039;&#039;&lt;br /&gt;
|  The name of a SCSS file in the theme&#039;s scss/ folder to compile on the fly. Sheets with the same name will be ignored. This can also be a function which returns SCSS, in which case all import paths will be relative to the scss folder in this theme or any of it&#039;s parents. (Since 3.2)&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|  Name of the theme. Most likely the name of the directory in which this file resides.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;parents&#039;&#039;&#039;&lt;br /&gt;
|  An array of themes to inherit from. If the theme you inherit from inherits from a parent as well, you need to indicate the grand parent here too.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;parents_exclude_javascripts&#039;&#039;&#039;&lt;br /&gt;
|  An array of JavaScript files NOT to inherit from the themes parents&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;parents_exclude_sheets&#039;&#039;&#039;&lt;br /&gt;
|  An array of stylesheets not to inherit from the themes parents&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;plugins_exclude_sheets&#039;&#039;&#039;&lt;br /&gt;
|  An array of plugin sheets to ignore and not include.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;renderfactory&#039;&#039;&#039;&lt;br /&gt;
|  Sets a custom render factory to use with the theme, used when working with custom renderers. You most likely want this set to &amp;quot;theme_overridden_renderer_factory&amp;quot;. &lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;sheets&#039;&#039;&#039;&lt;br /&gt;
|  An array of stylesheets to include for this theme. Should be located in the theme&#039;s style directory. Not required if using less or scss.&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;yuicssmodules&#039;&#039;&#039;&lt;br /&gt;
|  An array of YUI CSS modules to be included. This setting should probably be set to &#039;&#039; to prevent and YUI CSS being included. &lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;undeletableblocktypes&#039;&#039;&#039;&lt;br /&gt;
|  An array of Block types that must exist on all pages in this theme or this theme will be unusable. If a block type listed here is missing when a page is loaded - it will be auto-created (but only shown for themes that require it).&lt;br /&gt;
|-&lt;br /&gt;
|  $THEME-&amp;gt;&#039;&#039;&#039;addblockposition&#039;&#039;&#039;&lt;br /&gt;
|  Either BLOCK_ADDBLOCK_POSITION_FLATNAV, BLOCK_ADDBLOCK_POSITION_DEFAULT or BLOCK_ADDBLOCK_POSITION_CUSTOM. Defines where to put the &amp;quot;Add a block&amp;quot; controls when editing is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===The different layouts as of 21st April 2013===&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot; id=&amp;quot;theme_layouts_table&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Layout&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| base&lt;br /&gt;
| Most backwards compatible layout without the blocks - this is the layout used by default.&lt;br /&gt;
|- &lt;br /&gt;
| standard&lt;br /&gt;
| Standard layout with blocks, this is recommended for most pages with general information.&lt;br /&gt;
|- &lt;br /&gt;
| course&lt;br /&gt;
| Main course page.&lt;br /&gt;
|- &lt;br /&gt;
| coursecategory&lt;br /&gt;
| Use for browsing through course categories.&lt;br /&gt;
|- &lt;br /&gt;
| incourse&lt;br /&gt;
| Default layout while browsing a course, typical for modules.&lt;br /&gt;
|- &lt;br /&gt;
| frontpage&lt;br /&gt;
| The site home page.&lt;br /&gt;
|- &lt;br /&gt;
| admin&lt;br /&gt;
| Administration pages and scripts.&lt;br /&gt;
|- &lt;br /&gt;
| mydashboard&lt;br /&gt;
| My dashboard page.&lt;br /&gt;
|- &lt;br /&gt;
| mypublic&lt;br /&gt;
| My public page.&lt;br /&gt;
|- &lt;br /&gt;
| login&lt;br /&gt;
| The login page.&lt;br /&gt;
|-&lt;br /&gt;
| popup&lt;br /&gt;
| Pages that appear in pop-up windows - no navigation, no blocks, no header.&lt;br /&gt;
|-&lt;br /&gt;
| frametop&lt;br /&gt;
| Used for legacy frame layouts only. No blocks and minimal footer.&lt;br /&gt;
|-&lt;br /&gt;
| embedded&lt;br /&gt;
| Used for embedded pages, like iframe/object embedded in moodleform - it needs as much space as possible&lt;br /&gt;
|-&lt;br /&gt;
| maintenance&lt;br /&gt;
| Used during upgrade and install. This must not have any blocks, and it is a good idea if it does not have links to other places - for example there should not be a home link in the footer.&lt;br /&gt;
|-&lt;br /&gt;
| print&lt;br /&gt;
| Used when the page is being displayed specifically for printing.&lt;br /&gt;
|-&lt;br /&gt;
| redirect&lt;br /&gt;
| Used when a redirection is occurring&lt;br /&gt;
|-&lt;br /&gt;
| report&lt;br /&gt;
| Used for reports.&lt;br /&gt;
|-&lt;br /&gt;
| secure&lt;br /&gt;
| Used for safebrowser and securewindow.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52365</id>
		<title>Block myoverview</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52365"/>
		<updated>2017-05-12T02:48:05Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: /* Themers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
The myoverview block was designed as a replacement to the existing block_course_overview. The block displays a subset of the calendar events, those that have a corresponding action for a user to complete by a given date, for example an assignment due (calendar event) would expect the student to submit their answer by the given date (action). The intention is for the content of the block to show the logged in user an ordered list of actions they need to complete. As each item is completed it should be removed from the list.&lt;br /&gt;
&lt;br /&gt;
===What is a calendar event action?===&lt;br /&gt;
A calendar event action represents the action a user must take to satisfy the event. The actions should be discrete and finite. Each action is made up of 4 properties:&lt;br /&gt;
; name : A human readable name for the action, for example &amp;quot;add submission&amp;quot;&lt;br /&gt;
; url : A URL to direct the user to the page in which they can complete the action&lt;br /&gt;
; item count : How many items are required for this action, for example it may be a count of the number of assignments that need grading for a teacher&lt;br /&gt;
; actionable : Represents if the action can currently be actioned by the user. A true value means it is currently actionable and a false values means it will be actionable some time in the future&lt;br /&gt;
&lt;br /&gt;
==Plugin developers==&lt;br /&gt;
===How do you get events to show in block_myoverview?===&lt;br /&gt;
Note: Due to the limitations of the calendar event data structure we only support module plugins (plugins in /mod/) in block_myoverview.&lt;br /&gt;
&lt;br /&gt;
In order for your events to show in this block they will need to be [[dev:Calendar_API#Action_events|action events]]. That means they must have a few specific properties:&lt;br /&gt;
* The &amp;quot;type&amp;quot; property must be set to CALENDAR_EVENT_TYPE_ACTION to indicate that this calendar event is intended to be accompanied by an action&lt;br /&gt;
* The &amp;quot;timesort&amp;quot; property must be set to a timestamp. This value represents the time by which the user must complete the action. It is used for sorting the events and grouping them into time blocks (&#039;Today&#039;, &#039;Next 7 days&#039; etc)&lt;br /&gt;
* The &amp;quot;modulename&amp;quot; property must be the name of your module on disk, e.g. mod/lesson/ has &amp;quot;modulename&amp;quot; set to &amp;quot;lesson&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Once your events are being created with required properties you&#039;ll need to add the [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] to provide the appropriate action for the logged in user for a given event.&lt;br /&gt;
&lt;br /&gt;
===How do you get events from your non-module plugins to show in block_myoverview?===&lt;br /&gt;
Unfortunately this isn&#039;t currently supported. Only plugins in the &#039;mod/&#039; directory are supported due to limitations of the current calendar data structure.&lt;br /&gt;
&lt;br /&gt;
===How do you stop your event from showing in block_myoverview once the user has completed the action?===&lt;br /&gt;
You simply return null from your [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] once the user satisfies the criteria for completion of the action. The action events are given to your [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] each time they are request by block_myoverview so the user will only see the current state of each action they must complete. When the user has nothing left to do (indicated by returning null) it is removed from the list. &lt;br /&gt;
&lt;br /&gt;
Action events that don&#039;t have a corresponding action will still be displayed in the calendar.&lt;br /&gt;
&lt;br /&gt;
Note: There is no need to check in your callback that the user can see your activity or that they are enrolled in the course. These checks are done prior to providing the event to the callback. By the time you see the event in the callback you know that the user at least has permission to view your activity.&lt;br /&gt;
&lt;br /&gt;
===How do you get events to show in the calendar but not in block_myoverview?===&lt;br /&gt;
You can still create an event with it&#039;s &amp;quot;type&amp;quot; property set to CALENDAR_EVENT_TYPE_STANDARD. Anything other than CALENDAR_EVENT_TYPE_ACTION will be ignored by block_myoverview.&lt;br /&gt;
&lt;br /&gt;
===How do you hide an action event from both the calendar and block_myoverview?===&lt;br /&gt;
You can use the [[dev:Calendar_API#mod_xyz_core_calendar_is_event_visible.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_is_event_visible]] to control the visibility of action events globally throughout Moodle. If you return false from this callback then the action event will no appear in neither the calendar nor block_myoverview. If you do not implement this callback then it is assumed that the event should be visible.&lt;br /&gt;
&lt;br /&gt;
Typically, this callback would be used to check that the user has sufficient permissions to ever be able perform the action. For example, the assign activity ensures that a user without the appropriate role shouldn&#039;t see the grading event (i.e. a student shouldn&#039;t see the teacher&#039;s grading event).&lt;br /&gt;
&lt;br /&gt;
This callback is called after the [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] which means it has access to the properties generated in that callback. In addition, there is a default rule that any action event with an &amp;quot;itemcount&amp;quot; set to zero is deemed not to be visible.&lt;br /&gt;
&lt;br /&gt;
===How do you display the item count for an action in block_myoverview?===&lt;br /&gt;
By default the item count will not be displayed in block myoverview. However if you would like to explicitly change this behaviour then you can implement the [[dev:Calendar_API#mod_xyz_core_calendar_event_action_shows_item_count.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_event_action_shows_item_count]]. If the result of that callback is true then the item count will be displayed in the block UI. Some times you may want to show the number of items left to action, for example the assign grading event for teachers shows them the count of the number of submissions left to grade.&lt;br /&gt;
&lt;br /&gt;
===Why isn&#039;t the action name a URL when it shows in block_myoverview?===&lt;br /&gt;
Whether the action name (i.e. the &amp;quot;name&amp;quot; property on your action) is rendered as plain text or as a hyperlink is determined by the &amp;quot;actionable&amp;quot; property of the action. If &amp;quot;actionable&amp;quot; is true then it means the user can complete the action now, so we render the hyperlink to take them to the place to complete it. However if &amp;quot;actionable&amp;quot; is false then it means the user is unable to complete the action now but will be able to some time in the future, so the action name is rendered in plain text.&lt;br /&gt;
&lt;br /&gt;
===Why isn&#039;t your event being given to your *_provide_event_action callback?===&lt;br /&gt;
Some common reasons that you may not see your events in your callback:&lt;br /&gt;
* The callback is not located in lib.php within your module&#039;s directory. It should be in mod/&amp;lt;your_plugin&amp;gt;/lib.php.&lt;br /&gt;
* The callback function is not named correctly, it should be [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;your_plugin&amp;gt;_core_calendar_provide_event_action]]. For example, the callback for the assign module would be named mod_assign_core_calendar_provide_event_action.&lt;br /&gt;
* The incorrect modulename property is being set on your calendar event.&lt;br /&gt;
* The calendar event is not being set to type CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
* The calendar event does not have a timesort property set.&lt;br /&gt;
* The logged in user does not have the capability to view your activity.&lt;br /&gt;
* The logged in user is not enrolled in the course that has your activity.&lt;br /&gt;
* The eventtype property for your event is a completion event but completion is not enabled in the course.&lt;br /&gt;
&lt;br /&gt;
===Why is your event not showing in block_myoverview even though it&#039;s being passed into your *_provide_event_action callback?===&lt;br /&gt;
Some common reasons that you may not see events in block_myoverview even though they are hitting your callback are:&lt;br /&gt;
* Your callback is returning null, which indicates there is no action for the user.&lt;br /&gt;
* Your callback is returning an item count of zero, which indicates there is no action for the user.&lt;br /&gt;
* Your [[dev:Calendar_API#mod_xyz_core_calendar_is_event_visible.28.29|mod_&amp;lt;your_plugin&amp;gt;_core_calendar_is_event_visible]] is returning false.&lt;br /&gt;
* The timesort value is more than 20 events into the future. The myoverview block will only load 20 events at a time in the timeline sort by dates view and 10 events at a time for each course in the sort by courses view.&lt;br /&gt;
* In the sort by courses view only in progress courses are shown, so if your event belongs to a past or future course then it won&#039;t display on that view.&lt;br /&gt;
&lt;br /&gt;
==Themers==&lt;br /&gt;
The myoverview block has been created using [[dev:Templates|Templates]] to allow you to apply custom styling and markup for your theme. The existing styling is heavily based on Bootstrap 4 with an effort to keep custom CSS as small as possible so any changes you make to theme Bootstrap should apply nicely to the myoverview block.&lt;br /&gt;
&lt;br /&gt;
There are examples of how the templates have been overridden for the Clean theme located in theme/bootstrapbase/templates/block_myoverview/ for reference.&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52364</id>
		<title>Block myoverview</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52364"/>
		<updated>2017-05-12T02:46:58Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: /* Themers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
The myoverview block was designed as a replacement to the existing block_course_overview. The block displays a subset of the calendar events, those that have a corresponding action for a user to complete by a given date, for example an assignment due (calendar event) would expect the student to submit their answer by the given date (action). The intention is for the content of the block to show the logged in user an ordered list of actions they need to complete. As each item is completed it should be removed from the list.&lt;br /&gt;
&lt;br /&gt;
===What is a calendar event action?===&lt;br /&gt;
A calendar event action represents the action a user must take to satisfy the event. The actions should be discrete and finite. Each action is made up of 4 properties:&lt;br /&gt;
; name : A human readable name for the action, for example &amp;quot;add submission&amp;quot;&lt;br /&gt;
; url : A URL to direct the user to the page in which they can complete the action&lt;br /&gt;
; item count : How many items are required for this action, for example it may be a count of the number of assignments that need grading for a teacher&lt;br /&gt;
; actionable : Represents if the action can currently be actioned by the user. A true value means it is currently actionable and a false values means it will be actionable some time in the future&lt;br /&gt;
&lt;br /&gt;
==Plugin developers==&lt;br /&gt;
===How do you get events to show in block_myoverview?===&lt;br /&gt;
Note: Due to the limitations of the calendar event data structure we only support module plugins (plugins in /mod/) in block_myoverview.&lt;br /&gt;
&lt;br /&gt;
In order for your events to show in this block they will need to be [[dev:Calendar_API#Action_events|action events]]. That means they must have a few specific properties:&lt;br /&gt;
* The &amp;quot;type&amp;quot; property must be set to CALENDAR_EVENT_TYPE_ACTION to indicate that this calendar event is intended to be accompanied by an action&lt;br /&gt;
* The &amp;quot;timesort&amp;quot; property must be set to a timestamp. This value represents the time by which the user must complete the action. It is used for sorting the events and grouping them into time blocks (&#039;Today&#039;, &#039;Next 7 days&#039; etc)&lt;br /&gt;
* The &amp;quot;modulename&amp;quot; property must be the name of your module on disk, e.g. mod/lesson/ has &amp;quot;modulename&amp;quot; set to &amp;quot;lesson&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Once your events are being created with required properties you&#039;ll need to add the [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] to provide the appropriate action for the logged in user for a given event.&lt;br /&gt;
&lt;br /&gt;
===How do you get events from your non-module plugins to show in block_myoverview?===&lt;br /&gt;
Unfortunately this isn&#039;t currently supported. Only plugins in the &#039;mod/&#039; directory are supported due to limitations of the current calendar data structure.&lt;br /&gt;
&lt;br /&gt;
===How do you stop your event from showing in block_myoverview once the user has completed the action?===&lt;br /&gt;
You simply return null from your [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] once the user satisfies the criteria for completion of the action. The action events are given to your [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] each time they are request by block_myoverview so the user will only see the current state of each action they must complete. When the user has nothing left to do (indicated by returning null) it is removed from the list. &lt;br /&gt;
&lt;br /&gt;
Action events that don&#039;t have a corresponding action will still be displayed in the calendar.&lt;br /&gt;
&lt;br /&gt;
Note: There is no need to check in your callback that the user can see your activity or that they are enrolled in the course. These checks are done prior to providing the event to the callback. By the time you see the event in the callback you know that the user at least has permission to view your activity.&lt;br /&gt;
&lt;br /&gt;
===How do you get events to show in the calendar but not in block_myoverview?===&lt;br /&gt;
You can still create an event with it&#039;s &amp;quot;type&amp;quot; property set to CALENDAR_EVENT_TYPE_STANDARD. Anything other than CALENDAR_EVENT_TYPE_ACTION will be ignored by block_myoverview.&lt;br /&gt;
&lt;br /&gt;
===How do you hide an action event from both the calendar and block_myoverview?===&lt;br /&gt;
You can use the [[dev:Calendar_API#mod_xyz_core_calendar_is_event_visible.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_is_event_visible]] to control the visibility of action events globally throughout Moodle. If you return false from this callback then the action event will no appear in neither the calendar nor block_myoverview. If you do not implement this callback then it is assumed that the event should be visible.&lt;br /&gt;
&lt;br /&gt;
Typically, this callback would be used to check that the user has sufficient permissions to ever be able perform the action. For example, the assign activity ensures that a user without the appropriate role shouldn&#039;t see the grading event (i.e. a student shouldn&#039;t see the teacher&#039;s grading event).&lt;br /&gt;
&lt;br /&gt;
This callback is called after the [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] which means it has access to the properties generated in that callback. In addition, there is a default rule that any action event with an &amp;quot;itemcount&amp;quot; set to zero is deemed not to be visible.&lt;br /&gt;
&lt;br /&gt;
===How do you display the item count for an action in block_myoverview?===&lt;br /&gt;
By default the item count will not be displayed in block myoverview. However if you would like to explicitly change this behaviour then you can implement the [[dev:Calendar_API#mod_xyz_core_calendar_event_action_shows_item_count.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_event_action_shows_item_count]]. If the result of that callback is true then the item count will be displayed in the block UI. Some times you may want to show the number of items left to action, for example the assign grading event for teachers shows them the count of the number of submissions left to grade.&lt;br /&gt;
&lt;br /&gt;
===Why isn&#039;t the action name a URL when it shows in block_myoverview?===&lt;br /&gt;
Whether the action name (i.e. the &amp;quot;name&amp;quot; property on your action) is rendered as plain text or as a hyperlink is determined by the &amp;quot;actionable&amp;quot; property of the action. If &amp;quot;actionable&amp;quot; is true then it means the user can complete the action now, so we render the hyperlink to take them to the place to complete it. However if &amp;quot;actionable&amp;quot; is false then it means the user is unable to complete the action now but will be able to some time in the future, so the action name is rendered in plain text.&lt;br /&gt;
&lt;br /&gt;
===Why isn&#039;t your event being given to your *_provide_event_action callback?===&lt;br /&gt;
Some common reasons that you may not see your events in your callback:&lt;br /&gt;
* The callback is not located in lib.php within your module&#039;s directory. It should be in mod/&amp;lt;your_plugin&amp;gt;/lib.php.&lt;br /&gt;
* The callback function is not named correctly, it should be [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;your_plugin&amp;gt;_core_calendar_provide_event_action]]. For example, the callback for the assign module would be named mod_assign_core_calendar_provide_event_action.&lt;br /&gt;
* The incorrect modulename property is being set on your calendar event.&lt;br /&gt;
* The calendar event is not being set to type CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
* The calendar event does not have a timesort property set.&lt;br /&gt;
* The logged in user does not have the capability to view your activity.&lt;br /&gt;
* The logged in user is not enrolled in the course that has your activity.&lt;br /&gt;
* The eventtype property for your event is a completion event but completion is not enabled in the course.&lt;br /&gt;
&lt;br /&gt;
===Why is your event not showing in block_myoverview even though it&#039;s being passed into your *_provide_event_action callback?===&lt;br /&gt;
Some common reasons that you may not see events in block_myoverview even though they are hitting your callback are:&lt;br /&gt;
* Your callback is returning null, which indicates there is no action for the user.&lt;br /&gt;
* Your callback is returning an item count of zero, which indicates there is no action for the user.&lt;br /&gt;
* Your [[dev:Calendar_API#mod_xyz_core_calendar_is_event_visible.28.29|mod_&amp;lt;your_plugin&amp;gt;_core_calendar_is_event_visible]] is returning false.&lt;br /&gt;
* The timesort value is more than 20 events into the future. The myoverview block will only load 20 events at a time in the timeline sort by dates view and 10 events at a time for each course in the sort by courses view.&lt;br /&gt;
* In the sort by courses view only in progress courses are shown, so if your event belongs to a past or future course then it won&#039;t display on that view.&lt;br /&gt;
&lt;br /&gt;
==Themers==&lt;br /&gt;
The myoverview block has been created using [[dev:Templates|Templates]] to allow you to apply custom styling and markup your theme. The existing styling is heavily based on Bootstrap 4 with an effort to keep custom CSS as small as possible so any changes you make to theme Bootstrap should apply nicely to the myoverview block.&lt;br /&gt;
&lt;br /&gt;
There are examples of how the templates have been overridden for the Clean theme located in theme/bootstrapbase/templates/block_myoverview/ for reference.&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52348</id>
		<title>Block myoverview</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52348"/>
		<updated>2017-05-11T04:02:12Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
The myoverview block was designed as a replacement to the existing block_course_overview. The block displays a subset of the calendar events, those that have a corresponding action for a user to complete by a given date, for example an assignment due (calendar event) would expect the student to submit their answer by the given date (action). The intention is for the content of the block to show the logged in user an ordered list of actions they need to complete. As each item is completed it should be removed from the list.&lt;br /&gt;
&lt;br /&gt;
===What is a calendar event action?===&lt;br /&gt;
A calendar event action represents the action a user must take to satisfy the event. The actions should be discrete and finite. Each action is made up of 4 properties:&lt;br /&gt;
; name : A human readable name for the action, for example &amp;quot;add submission&amp;quot;&lt;br /&gt;
; url : A URL to direct the user to the page in which they can complete the action&lt;br /&gt;
; item count : How many items are required for this action, for example it may be a count of the number of assignments that need grading for a teacher&lt;br /&gt;
; actionable : Represents if the action can currently be actioned by the user. A true value means it is currently actionable and a false values means it will be actionable some time in the future&lt;br /&gt;
&lt;br /&gt;
==Plugin developers==&lt;br /&gt;
===How do you get events to show in block_myoverview?===&lt;br /&gt;
Note: Due to the limitations of the calendar event data structure we only support module plugins (plugins in /mod/) in block_myoverview.&lt;br /&gt;
&lt;br /&gt;
In order for your events to show in this block they will need to be [[dev:Calendar_API#Action_events|action events]]. That means they must have a few specific properties:&lt;br /&gt;
* The &amp;quot;type&amp;quot; property must be set to CALENDAR_EVENT_TYPE_ACTION to indicate that this calendar event is intended to be accompanied by an action&lt;br /&gt;
* The &amp;quot;timesort&amp;quot; property must be set to a timestamp. This value represents the time by which the user must complete the action. It is used for sorting the events and grouping them into time blocks (&#039;Today&#039;, &#039;Next 7 days&#039; etc)&lt;br /&gt;
* The &amp;quot;modulename&amp;quot; property must be the name of your module on disk, e.g. mod/lesson/ has &amp;quot;modulename&amp;quot; set to &amp;quot;lesson&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Once your events are being created with required properties you&#039;ll need to add the [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] to provide the appropriate action for the logged in user for a given event.&lt;br /&gt;
&lt;br /&gt;
===How do you get events from your non-module plugins to show in block_myoverview?===&lt;br /&gt;
Unfortunately this isn&#039;t currently supported. Only plugins in the &#039;mod/&#039; directory are supported due to limitations of the current calendar data structure.&lt;br /&gt;
&lt;br /&gt;
===How do you stop your event from showing in block_myoverview once the user has completed the action?===&lt;br /&gt;
You simply return null from your [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] once the user satisfies the criteria for completion of the action. The action events are given to your [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] each time they are request by block_myoverview so the user will only see the current state of each action they must complete. When the user has nothing left to do (indicated by returning null) it is removed from the list. &lt;br /&gt;
&lt;br /&gt;
Action events that don&#039;t have a corresponding action will still be displayed in the calendar.&lt;br /&gt;
&lt;br /&gt;
Note: There is no need to check in your callback that the user can see your activity or that they are enrolled in the course. These checks are done prior to providing the event to the callback. By the time you see the event in the callback you know that the user at least has permission to view your activity.&lt;br /&gt;
&lt;br /&gt;
===How do you get events to show in the calendar but not in block_myoverview?===&lt;br /&gt;
You can still create an event with it&#039;s &amp;quot;type&amp;quot; property set to CALENDAR_EVENT_TYPE_STANDARD. Anything other than CALENDAR_EVENT_TYPE_ACTION will be ignored by block_myoverview.&lt;br /&gt;
&lt;br /&gt;
===How do you hide an action event from both the calendar and block_myoverview?===&lt;br /&gt;
You can use the [[dev:Calendar_API#mod_xyz_core_calendar_is_event_visible.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_is_event_visible]] to control the visibility of action events globally throughout Moodle. If you return false from this callback then the action event will no appear in neither the calendar nor block_myoverview. If you do not implement this callback then it is assumed that the event should be visible.&lt;br /&gt;
&lt;br /&gt;
Typically, this callback would be used to check that the user has sufficient permissions to ever be able perform the action. For example, the assign activity ensures that a user without the appropriate role shouldn&#039;t see the grading event (i.e. a student shouldn&#039;t see the teacher&#039;s grading event).&lt;br /&gt;
&lt;br /&gt;
This callback is called after the [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] which means it has access to the properties generated in that callback. In addition, there is a default rule that any action event with an &amp;quot;itemcount&amp;quot; set to zero is deemed not to be visible.&lt;br /&gt;
&lt;br /&gt;
===How do you display the item count for an action in block_myoverview?===&lt;br /&gt;
By default the item count will not be displayed in block myoverview. However if you would like to explicitly change this behaviour then you can implement the [[dev:Calendar_API#mod_xyz_core_calendar_event_action_shows_item_count.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_event_action_shows_item_count]]. If the result of that callback is true then the item count will be displayed in the block UI. Some times you may want to show the number of items left to action, for example the assign grading event for teachers shows them the count of the number of submissions left to grade.&lt;br /&gt;
&lt;br /&gt;
===Why isn&#039;t the action name a URL when it shows in block_myoverview?===&lt;br /&gt;
Whether the action name (i.e. the &amp;quot;name&amp;quot; property on your action) is rendered as plain text or as a hyperlink is determined by the &amp;quot;actionable&amp;quot; property of the action. If &amp;quot;actionable&amp;quot; is true then it means the user can complete the action now, so we render the hyperlink to take them to the place to complete it. However if &amp;quot;actionable&amp;quot; is false then it means the user is unable to complete the action now but will be able to some time in the future, so the action name is rendered in plain text.&lt;br /&gt;
&lt;br /&gt;
===Why isn&#039;t your event being given to your *_provide_event_action callback?===&lt;br /&gt;
Some common reasons that you may not see your events in your callback:&lt;br /&gt;
* The callback is not located in lib.php within your module&#039;s directory. It should be in mod/&amp;lt;your_plugin&amp;gt;/lib.php.&lt;br /&gt;
* The callback function is not named correctly, it should be [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;your_plugin&amp;gt;_core_calendar_provide_event_action]]. For example, the callback for the assign module would be named mod_assign_core_calendar_provide_event_action.&lt;br /&gt;
* The incorrect modulename property is being set on your calendar event.&lt;br /&gt;
* The calendar event is not being set to type CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
* The calendar event does not have a timesort property set.&lt;br /&gt;
* The logged in user does not have the capability to view your activity.&lt;br /&gt;
* The logged in user is not enrolled in the course that has your activity.&lt;br /&gt;
* The eventtype property for your event is a completion event but completion is not enabled in the course.&lt;br /&gt;
&lt;br /&gt;
===Why is your event not showing in block_myoverview even though it&#039;s being passed into your *_provide_event_action callback?===&lt;br /&gt;
Some common reasons that you may not see events in block_myoverview even though they are hitting your callback are:&lt;br /&gt;
* Your callback is returning null, which indicates there is no action for the user.&lt;br /&gt;
* Your callback is returning an item count of zero, which indicates there is no action for the user.&lt;br /&gt;
* Your [[dev:Calendar_API#mod_xyz_core_calendar_is_event_visible.28.29|mod_&amp;lt;your_plugin&amp;gt;_core_calendar_is_event_visible]] is returning false.&lt;br /&gt;
* The timesort value is more than 20 events into the future. The myoverview block will only load 20 events at a time in the timeline sort by dates view and 10 events at a time for each course in the sort by courses view.&lt;br /&gt;
* In the sort by courses view only in progress courses are shown, so if your event belongs to a past or future course then it won&#039;t display on that view.&lt;br /&gt;
&lt;br /&gt;
==Themers==&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52341</id>
		<title>Block myoverview</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52341"/>
		<updated>2017-05-10T07:57:36Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
The myoverview block was designed as a replacement to the existing block_course_overview. The block displays a subset of the calendar events, those that have a corresponding action for a user to complete by a given date, for example an assignment due (calendar event) would expect the student to submit their answer by the given date (action). The intention is for the content of the block to show the logged in user an ordered list of actions they need to complete. As each item is completed it should be removed from the list.&lt;br /&gt;
&lt;br /&gt;
===What is a calendar event action?===&lt;br /&gt;
A calendar event action represents the action a user must take to satisfy the event. The actions should be discrete and finite. Each action is made up of 4 properties:&lt;br /&gt;
; name : A human readable name for the action, for example &amp;quot;add submission&amp;quot;&lt;br /&gt;
; url : A URL to direct the user to the page in which they can complete the action&lt;br /&gt;
; item count : How many items are required for this action, for example it may be a count of the number of assignments that need grading for a teacher&lt;br /&gt;
; actionable : Represents if the action can currently be actioned by the user. A true value means it is currently actionable and a false values means it will be actionable some time in the future&lt;br /&gt;
&lt;br /&gt;
==Plugin developers==&lt;br /&gt;
===How do you get events to show in block_myoverview?===&lt;br /&gt;
Note: Due to the limitations of the calendar event data structure we only support module plugins (plugins in /mod/) in block_myoverview.&lt;br /&gt;
&lt;br /&gt;
In order for your events to show in this block they will need to be [[dev:Calendar_API#Action_events|action events]]. That means they must have a few specific properties:&lt;br /&gt;
* The &amp;quot;type&amp;quot; property must be set to CALENDAR_EVENT_TYPE_ACTION to indicate that this calendar event is intended to be accompanied by an action&lt;br /&gt;
* The &amp;quot;timesort&amp;quot; property must be set to a timestamp. This value represents the time by which the user must complete the action. It is used for sorting the events and grouping them into time blocks (&#039;Today&#039;, &#039;Next 7 days&#039; etc)&lt;br /&gt;
* The &amp;quot;modulename&amp;quot; property must be the name of your module on disk, e.g. mod/lesson/ has &amp;quot;modulename&amp;quot; set to &amp;quot;lesson&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Once your events are being created with required properties you&#039;ll need to add the [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] to provide the appropriate action for the logged in user for a given event.&lt;br /&gt;
&lt;br /&gt;
===How do you get events from your non-module plugins to show in block_myoverview?===&lt;br /&gt;
Unfortunately this isn&#039;t currently supported. Only plugins in the &#039;mod/&#039; directory are supported due to limitations of the current calendar data structure.&lt;br /&gt;
&lt;br /&gt;
===How do you stop your event from showing in block_myoverview once the user has completed the action?===&lt;br /&gt;
You simply return null from your [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] once the user satisfies the criteria for completion of the action. The action events are given to your [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] each time they are request by block_myoverview so the user will only see the current state of each action they must complete. When the user has nothing left to do (indicated by returning null) it is removed from the list. &lt;br /&gt;
&lt;br /&gt;
Action events that don&#039;t have a corresponding action will still be displayed in the calendar.&lt;br /&gt;
&lt;br /&gt;
Note: There is no need to check in your callback that the user can see your activity or that they are enrolled in the course. These checks are done prior to providing the event to the callback. By the time you see the event in the callback you know that the user at least has permission to view your activity.&lt;br /&gt;
&lt;br /&gt;
===How do you get events to show in the calendar but not in block_myoverview?===&lt;br /&gt;
You can still create an event with it&#039;s &amp;quot;type&amp;quot; property set to CALENDAR_EVENT_TYPE_STANDARD. Anything other than CALENDAR_EVENT_TYPE_ACTION will be ignored by block_myoverview.&lt;br /&gt;
&lt;br /&gt;
===How do you hide an action event from both the calendar and block_myoverview?===&lt;br /&gt;
You can use the [[dev:Calendar_API#mod_xyz_core_calendar_is_event_visible.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_is_event_visible]] to control the visibility of action events globally throughout Moodle. If you return false from this callback then the action event will no appear in neither the calendar nor block_myoverview. If you do not implement this callback then it is assumed that the event should be visible.&lt;br /&gt;
&lt;br /&gt;
Typically, this callback would be used to check that the user has sufficient permissions to ever be able perform the action. For example, the assign activity ensures that a user without the appropriate role shouldn&#039;t see the grading event (i.e. a student shouldn&#039;t see the teacher&#039;s grading event).&lt;br /&gt;
&lt;br /&gt;
This callback is called after the [[dev:Calendar_API#mod_xyz_core_calendar_provide_event_action.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_provide_event_action callback]] which means it has access to the properties generated in that callback. In addition, there is a default rule that any action event with an &amp;quot;itemcount&amp;quot; set to zero is deemed not to be visible.&lt;br /&gt;
&lt;br /&gt;
===How do you display the item count for an action in block_myoverview?===&lt;br /&gt;
By default the item count will not be displayed in block myoverview. However if you would like to explicitly change this behaviour then you can implement the [[dev:Calendar_API#mod_xyz_core_calendar_event_action_shows_item_count.28.29|mod_&amp;lt;plugin&amp;gt;_core_calendar_event_action_shows_item_count]]. If the result of that callback is true then the item count will be displayed in the block UI. Some times you may want to show the number of items left to action, for example the assign grading event for teachers shows them the count of the number of submissions left to grade.&lt;br /&gt;
&lt;br /&gt;
===Why isn&#039;t the action text a URL when it shows in block_myoverview?===&lt;br /&gt;
===Why isn&#039;t your event being given to your *_provide_event_action callback?===&lt;br /&gt;
===Why is your event not showing in block_myoverview even though it&#039;s being passed into your *_provide_event_action callback?===&lt;br /&gt;
&lt;br /&gt;
==Themers==&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=52327</id>
		<title>Templates</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=52327"/>
		<updated>2017-05-10T02:19:52Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: /* What other helpers can I use? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
= Templates =&lt;br /&gt;
&lt;br /&gt;
== What is a template? ==&lt;br /&gt;
A template is an alternative to writing blocks of HTML directly in javascript / php by concatenating strings. The end result is the same, but templates have a number of advantages:&lt;br /&gt;
* It is easier to see the final result of the template because the code for a template is very close to what the final HTML will look like&lt;br /&gt;
* Because the templating language is intentionally limited, it is hard to introduce complex logic into a template. This makes it far easier for a theme designer to override a template, without breaking the logic&lt;br /&gt;
* Templates can be rendered from javascript. This allows ajax operations to re-render a portion of the page.&lt;br /&gt;
&lt;br /&gt;
== How do I write a template? ==&lt;br /&gt;
Templates are written in a language called &amp;quot;[http://mustache.github.io/mustache.5.html Mustache]&amp;quot;. Mustache is written as HTML with additional tags used to format the display of the data. Mustache tags are made of 2 opening and closing curly braces &amp;lt;code xml&amp;gt;{{tag}}&amp;lt;/code&amp;gt;. There are a few variations of these tags that behave differently.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{raiden}}&amp;lt;/code&amp;gt; This is a simple variable substitution. The variable named &amp;quot;raiden&amp;quot; will be searched for in the current context (and any parent contexts) and when a value is found, the entire tag will be replaced by the variable (HTML escaped).&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{{galaga}}}&amp;lt;/code&amp;gt; This is an unescaped variable substitution. Instead of escaping the variable before replacing it in the template, the variable is included raw. This is useful when the variable contains a block of HTML (for example).&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{#lemmings}} jump off cliff {{/lemmings}}&amp;lt;/code&amp;gt; These are opening and closing section tags. If the lemmings variable exists and evaluates to &amp;quot;not false&amp;quot; value, the variable is pushed on the stack, the contents of the section are parsed and included in the result. If the variable does not exist, or evaluates to false - the section will be skipped. If the variable lemmings evaluates to an array, the section will be repeated for each item in the array with the items of the array on the context. This is how to output a list.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{^lemmings}} enjoy view {{/lemmings}}&amp;lt;/code&amp;gt; Equivalent of &amp;quot;if-not&amp;quot; block, there is no &amp;quot;else&amp;quot; in mustache.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{&amp;gt; franken_style/name_of_template }}&amp;lt;/code&amp;gt; This is a partial. Think of it like an include. Templates can include other templates using this tag. In the called template, the data it sees (for including values is the same as the data available where the partial is included.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{$blockvar}} ... {{/blockvar}}&amp;lt;/code&amp;gt; This is a block variable. It defines a section of the template that can be overridden when it&#039;s included in another template.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{&amp;lt; template_name}} ... {{/template_name}}&amp;lt;/code&amp;gt; This is similar to including a partial but specifically indicates that you&#039;d like to override one or more block variables defined within the template you&#039;re including. You can override the block variables by defining a block variable within these tags that matches the name of the block variable you&#039;d like to override in the included template.&lt;br /&gt;
&lt;br /&gt;
So - putting this all together:&lt;br /&gt;
&lt;br /&gt;
recipe.mustache&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;{{recipename}}&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;{{description}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;h4&amp;gt;Ingredients&amp;lt;/h4&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
{{#ingredients}}&lt;br /&gt;
&amp;lt;li&amp;gt;{{.}}&amp;lt;/li&amp;gt;&lt;br /&gt;
{{/ingredients}}&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;h4&amp;gt;Steps&amp;lt;/h4&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
{{#steps}}&lt;br /&gt;
&amp;lt;li&amp;gt;{{{.}}}&amp;lt;/li&amp;gt;&lt;br /&gt;
{{/steps}}&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
{{ &amp;gt; ratethisrecipe }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When given this data:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  recipename: &amp;quot;Cheese sandwich&amp;quot;,&lt;br /&gt;
  description: &amp;quot;Who doesn&#039;t like a good cheese sandwich?&amp;quot;,&lt;br /&gt;
  ingredients: [&amp;quot;bread&amp;quot;, &amp;quot;cheese&amp;quot;, &amp;quot;butter&amp;quot;],&lt;br /&gt;
  steps: [&amp;quot;&amp;lt;p&amp;gt;Step 1 is to spread the butter on the bread&amp;lt;/p&amp;gt;&amp;quot;, &amp;quot;&amp;lt;p&amp;gt;Step 2 is to put the cheese &amp;amp;quot;in&amp;amp;quot; the bread (not on top, or underneath)&amp;lt;/p&amp;gt;&amp;quot;]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gives this: &amp;lt;span style=&amp;quot;font-size:4em&amp;quot;&amp;gt;😋&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More info - there are much clearer explanations of templates on the [http://mustache.github.io/mustache.5.html Mustache] website. Try reading those pages &amp;quot;before&amp;quot; posting on stack overflow :) .&lt;br /&gt;
&lt;br /&gt;
=== Blocks (Moodle 3.0 onwards) ===&lt;br /&gt;
Blocks are a feature of Mustache that deserves a special mention. The are used as a form of inheritance - and are crucial to building a library of re-usable templates. To make use of &amp;quot;blocks&amp;quot; you define a parent template with replaceable sections. Each of those sections is marked with a &amp;quot;blocks&amp;quot; tag like this (A blocks tag looks like a regular tag, but the variable name is preceded with $):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;section&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;{{$sectionheading}}Default heading{{/sectionheading}}&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
{{$content}}Content for section{{/content}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now - wherever I need to re-use this template I can include it and replace the content of those sections at the same time. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{&amp;lt; section}}&lt;br /&gt;
{{$sectionheading}}Latest News{{/sectionheading}}&lt;br /&gt;
{{$content}}Nothing happened today - sorry!{{/content}}&lt;br /&gt;
{{/section}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that when I include a template and I want to make use of blocks - the include tag points the other way:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{&amp;lt; section}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Not&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{&amp;gt; section}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Blocks support looping and many other cool things - for more info see https://github.com/bobthecow/mustache.php/wiki/BLOCKS-pragma&lt;br /&gt;
&lt;br /&gt;
== Where do I put my templates? ==&lt;br /&gt;
&lt;br /&gt;
Templates go in the &amp;lt;componentdir&amp;gt;/templates folder and must have a .mustache file extension. When loading templates the template name is &amp;lt;componentname&amp;gt;/&amp;lt;filename&amp;gt; (no file extension). &lt;br /&gt;
&lt;br /&gt;
So &amp;quot;mod_lesson/timer&amp;quot; would load the template at mod/lesson/templates/timer.mustache.&lt;br /&gt;
&lt;br /&gt;
Note: Do not try and put your templates in sub folders under the &amp;quot;/templates&amp;quot; directory. This is not supported and will not work.&lt;br /&gt;
&lt;br /&gt;
== How do I call a template from javascript? ==&lt;br /&gt;
&lt;br /&gt;
Rendering a template from javascript is fairly easy. There is a new AMD module that can load/cache and render a template for you. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// This is AMD code for loading the &amp;quot;core/templates&amp;quot; module. see [Javascript Modules].&lt;br /&gt;
require([&#039;core/templates&#039;], function(templates) {&lt;br /&gt;
&lt;br /&gt;
    // This will be the context for our template. So {{name}} in the template will resolve to &amp;quot;Tweety bird&amp;quot;.&lt;br /&gt;
    var context = { name: &#039;Tweety bird&#039;, intelligence: 2 };&lt;br /&gt;
&lt;br /&gt;
    // This will call the function to load and render our template. &lt;br /&gt;
    templates.render(&#039;block_looneytunes/profile&#039;, context);&lt;br /&gt;
&lt;br /&gt;
    // It returns a promise that needs to be resoved.&lt;br /&gt;
            .then(function(html, js) {&lt;br /&gt;
                // Here eventually I have my compiled template, and any javascript that it generated.&lt;br /&gt;
                // The templates object has append, prepend and replace functions.&lt;br /&gt;
                templates.appendNodeContents(&#039;.block_looneytunes .content&#039;, source, javascript);&lt;br /&gt;
            }).fail(function(ex) {&lt;br /&gt;
                // Deal with this exception (I recommend core/notify exception function for this).&lt;br /&gt;
            });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Under the hood, this did many clever things for us. It loaded the template via an ajax call if it was not cached. It found any missing lang strings in the template and loaded them in a single ajax request, it split the JS from the HTML and returned us both in easy to use way. Read on for how to nicely deal with the javascript parameter.&lt;br /&gt;
&lt;br /&gt;
Note: with some nice chaining and sugar, we can shorten the above example quite a bit:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/templates&#039;, &#039;core/notification&#039;], function(templates, notification) {&lt;br /&gt;
    var context = { name: &#039;Tweety bird&#039;, intelligence: 2 };&lt;br /&gt;
    templates.render(&#039;block_looneytunes/profile&#039;, context)&lt;br /&gt;
        .then(doneCallback)&lt;br /&gt;
        .fail(notification.exception);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What if a template contains javascript? ==&lt;br /&gt;
&lt;br /&gt;
Sometimes a template requires that some JS be run when it is added to the page in order to give it more features. In the template we can include blocks of javascript, but we should use a special section tag that has a &amp;quot;helper&amp;quot; method registered to handle javascript carefully. &lt;br /&gt;
&lt;br /&gt;
Example&lt;br /&gt;
profile.mustache&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;profile&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Name: {{name}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Intelligence: {{intelligence}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require(&#039;jquery&#039;, function($) {&lt;br /&gt;
    // Effects! Can we have &amp;quot;blink&amp;quot;?&lt;br /&gt;
    $(&#039;#profile&#039;).slideDown();&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If this template is rendered by PHP, the javascript is separated from the HTML, and is appended to a special section in the footer of the page &amp;quot;after&amp;quot; requirejs has loaded. This provides the optimal page loading speed. If the template is rendered by javascript, the javascript source will be passed to the &amp;quot;done&amp;quot; handler from the promise. Then, when the &amp;quot;done&amp;quot; handler has added the template to the DOM, it can call &lt;br /&gt;
&amp;lt;code javascript&amp;gt;templates.runTemplateJS(javascript);&amp;lt;/code&amp;gt; &lt;br /&gt;
which will run the javascript (by creating a new script tag and appending it to the page head).&lt;br /&gt;
&lt;br /&gt;
== What other helpers can I use? ==&lt;br /&gt;
&lt;br /&gt;
=== {{# str }} ===&lt;br /&gt;
&lt;br /&gt;
There is a string helper for loading language strings.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{# str }} helloworld, mod_greeting {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first 2 parameters are the string id and the component name. So this is effectively Mustache variant of &amp;lt;code&amp;gt;get_string(&#039;helloworld&#039;, &#039;mod_greeting&#039;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The optional third parameter defines the value for the string&#039;s &amp;lt;code&amp;gt;$a&amp;lt;/code&amp;gt; placeholder:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{# str }} iscool, mod_cool, David Beckham {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example would effectively do what &amp;lt;code&amp;gt;get_string(&#039;iscool&#039;, &#039;mod_cool&#039;, &#039;David Beckham&#039;)&amp;lt;/code&amp;gt; does in Moodle PHP code.&lt;br /&gt;
&lt;br /&gt;
Variable tags are allowed to define the value of the &amp;lt;code&amp;gt;$a&amp;lt;/code&amp;gt; placeholder:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{# str }} iscool, mod_cool, {{ name }} {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For strings that accept complex placeholder, see the following section.&lt;br /&gt;
&lt;br /&gt;
=== {{# quote }} ===&lt;br /&gt;
&lt;br /&gt;
As shown in the previous section, the &amp;lt;code&amp;gt;{{# str }}&amp;lt;/code&amp;gt; helper may need complex data structures passed as the value of the &amp;lt;code&amp;gt;$a&amp;lt;/code&amp;gt; placeholder. You can use a JSON object syntax in that case:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{# str }} iscool, mod_cool, { &amp;quot;firstname&amp;quot;: &amp;quot;David&amp;quot;, &amp;quot;lastname&amp;quot;: &amp;quot;Beckham&amp;quot; } {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you wanted to use the context values instead of literal strings, you might intuitively use something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{! DO NOT DO THIS !}}&lt;br /&gt;
{{# str }} iscool, mod_cool, { &amp;quot;firstname&amp;quot;: &amp;quot;{{ firstname }}&amp;quot;, &amp;quot;lastname&amp;quot;: &amp;quot;{{ lastname }}&amp;quot; } {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a potential problem though. If the variable tag &amp;lt;code&amp;gt;{{ firstname }}&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;{{ lastname }}&amp;lt;/code&amp;gt; evaluates to a string containing the double quote character, that will break the JSON syntax. We need to escape the double quotes potentially appearing in the variable tags. For this, use the &amp;lt;code&amp;gt;{{# quote }}&amp;lt;/code&amp;gt; helper:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{! This is OK !}}&lt;br /&gt;
{{# str }} iscool, mod_cool, { &amp;quot;firstname&amp;quot;:  {{# quote }}{{ firstname }}{{/ quote }}, &amp;quot;lastname&amp;quot;: {{# quote }}{{ lastname }}{{/ quote }} } {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See MDL-52136 for details.&lt;br /&gt;
=== {{# pix }} ===&lt;br /&gt;
&lt;br /&gt;
There is a pix icon helper for generating pix icon tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{# pix }} t/edit, core, Edit David Beckham {{/ pix }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first 2 parameters are the string id and the component name, the rest is the alt text for the image.&lt;br /&gt;
&lt;br /&gt;
=== {{# userdate }} ===&lt;br /&gt;
This mustache template helper will format unix timestamps into a given human readable date format while using the user&#039;s timezone settings configured (if any) in Moodle. The helper will accept hardcoded values, context variables, or other helpers. &lt;br /&gt;
&lt;br /&gt;
The recommended way to use this helper is to use the string helper to get one of the core Moodle formats because they have been translated into other languages so you&#039;ll get multi-lang support for free (that&#039;s a pretty good deal!).&lt;br /&gt;
&lt;br /&gt;
==== Using the string helper (recommended) ====&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
// Assuming we had a context variable named &amp;quot;time&amp;quot; set to 1293876000.&lt;br /&gt;
{{#userdate}} {{time}}, {{#str}} strftimedate {{/str}} {{/userdate}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will ask the Moodle server for the string &amp;quot;strftimedate&amp;quot; and will use the value (which in this case is &amp;quot;%d %B %Y&amp;quot;)  to format the user date. So the resulting formatted timestamp from the userdate helper will be &amp;quot;01 January 2011&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Using context variables ====&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
// Assuming we had a context variable named &amp;quot;time&amp;quot; set to 1293876000.&lt;br /&gt;
{{#userdate}} {{time}}, %A, %d %B %Y, %I:%M %p {{/userdate}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Will produce &amp;quot;Saturday, 01 January 2011, 10:00 AM&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Using hardcoded values ====&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#userdate}} 1293876000, %A, %d %B %Y, %I:%M %p {{/userdate}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Will produce &amp;quot;Saturday, 01 January 2011, 10:00 AM&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== {{# shortentext }} ===&lt;br /&gt;
This helper can be used to shorten a large amount of text to a specified length and will append a trailing ellipsis to signify that the text has been shortened. &lt;br /&gt;
&lt;br /&gt;
The algorithm will attempt to preserve words while shortening to text. Words, for the purposes of the helper, are considered to be groups of consecutive characters broken by a space or, in the case of a multi-byte character, after the completion of the multi-byte character (rather than in the middle of the character).&lt;br /&gt;
&lt;br /&gt;
It will also attempt to preserve HTML in the text by keeping the opening and closing tags. Only text within the tags will be considered when calculating how much should be truncated to reach the desired length.&lt;br /&gt;
&lt;br /&gt;
The helper takes two comma separated arguments. The first is the desired length and the second is the text to be shortened. Both can be provided as context variables.&lt;br /&gt;
&lt;br /&gt;
==== Plain text ====&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
{{#shortentext}} 30, long text without any tags blah de blah blah blah what {{/shortentext}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Will produce:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
long text without any tags ...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== HTML text ====&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
{{#shortentext}} 30, &amp;lt;div class=&#039;frog&#039;&amp;gt;&amp;lt;p&amp;gt;&amp;lt;blockquote&amp;gt;Long text with tags that will be chopped off but &amp;lt;b&amp;gt;should be added back again&amp;lt;/b&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/p&amp;gt; {{/shortentext}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Will produce:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&amp;lt;div class=&#039;frog&#039;&amp;gt;&amp;lt;p&amp;gt;&amp;lt;blockquote&amp;gt;Long text with tags that ...&amp;lt;/blockquote&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Multi-byte text ====&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
{{#shortentext}} 6, 𠮟𠮟𠮟𠮟𠮟𠮟𠮟𠮟𠮟𠮟𠮟𠮟 {{/shortentext}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Will produce:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
𠮟𠮟𠮟...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How do I call a template from php? ==&lt;br /&gt;
&lt;br /&gt;
The templates in php are attached to the renderers. There is a renderer method &amp;quot;render_from_template($templatename, $context)&amp;quot; that does the trick.&lt;br /&gt;
&lt;br /&gt;
== How do templates work with renderers? ==&lt;br /&gt;
&lt;br /&gt;
Extra care must be taken to ensure that the data passed to the context parameter is useful to the templating language. The template language cannot:&lt;br /&gt;
* Call functions&lt;br /&gt;
* Perform any boolean logic&lt;br /&gt;
* Render renderables&lt;br /&gt;
* Do capability checks&lt;br /&gt;
* Make DB queries&lt;br /&gt;
&lt;br /&gt;
So - I have &amp;quot;some&amp;quot; data in my renderable and some logic and HTML generation in my render method for that renderable - how do I refactor this to use a template?&lt;br /&gt;
&lt;br /&gt;
The first thing to note, is that you don&#039;t have to use a template if you don&#039;t want to. It just means that themers will still have to override your render method, instead of just overriding the template. But if you DO want to use a template, you will earn &amp;quot;cred&amp;quot; with themers, and you will be able to re-render parts of your interface from javascript in response to ajax requests without reloading the whole page (that&#039;s cool).&lt;br /&gt;
&lt;br /&gt;
There is a simple pattern to use to hook a template into a render method. If you make your renderable implement templatable as well as renderable - it will have to implement a new method &amp;quot;export_for_template(renderer_base $output)&amp;quot;. This method takes the data stored in the renderable and &amp;quot;flattens it&amp;quot; so it can be used in a template. If there is some nested data in the renderable (like other renderables) and they do not support templates, they can be &amp;quot;rendered&amp;quot; into the flat data structure using the renderer parameter. It should return an stdClass with properties that are only made of simple types: int, string, bool, float, stdClass or arrays of these types. Then the render method can updated to export the data and render it with the template.&lt;br /&gt;
&lt;br /&gt;
In the renderable:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;canmanage = $this-&amp;gt;canmanage;&lt;br /&gt;
        $data-&amp;gt;things = array();&lt;br /&gt;
        foreach ($this-&amp;gt;things as $thing) {&lt;br /&gt;
            $data-&amp;gt;things[] = $thing-&amp;gt;to_record();&lt;br /&gt;
        }&lt;br /&gt;
        $data-&amp;gt;navigation = array();&lt;br /&gt;
        foreach ($this-&amp;gt;navigation as $button) {&lt;br /&gt;
            $data-&amp;gt;navigation[] = $output-&amp;gt;render($button);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the renderer class:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param mywidget $widget&lt;br /&gt;
     *&lt;br /&gt;
     * @return string HTML for the page&lt;br /&gt;
     */&lt;br /&gt;
    render(mywidget $widget) {&lt;br /&gt;
        $data = $widget-&amp;gt;export_for_template($this);&lt;br /&gt;
        return $this-&amp;gt;render_from_template(&#039;mywidget&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How to I override a template in my theme? ==&lt;br /&gt;
&lt;br /&gt;
Templates can be overridden a bit easier than overriding a renderer. First - find the template that you want to change. E.g. &amp;quot;mod/wiki/templates/ratingui.mustache&amp;quot;. Now, create a sub-folder under your themes &amp;quot;templates&amp;quot; directory with the component name of the plugin you are overriding. E.g &amp;quot;theme/timtam/templates/mod_wiki&amp;quot;. Finally, copy the ratingui.mustache file into the newly created &amp;quot;theme/timtam/templates/mod_wiki&amp;quot; and edit it. You should see your changes immediately if theme designer mode is on. Note: templates are cached just like CSS, so if you are not using theme designer mode you will need to purge all caches to see the latest version of an edited template. If the template you are overriding contains a documentation comment (see next section) it is recommended to remove it, it will still show the documentation in the template library.&lt;br /&gt;
&lt;br /&gt;
== Should I document my templates? ==&lt;br /&gt;
&lt;br /&gt;
Yes!!!! Theme designers need to know the limits of what they can expect to change without breaking anything. As a further benefit - your beautiful new template can be displayed in the &amp;quot;Template Library&amp;quot; tool shipped with Moodle. In order to provide nice documentation and examples for the Template Library, you should follow these conventions when documenting your template.&lt;br /&gt;
&lt;br /&gt;
=== Add a documentation comment to your template ===&lt;br /&gt;
Mustache comments look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  {{! &lt;br /&gt;
   I am a comment.&lt;br /&gt;
   I can span multiple lines.&lt;br /&gt;
  }}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The template library will look for a mustache comment that contains this special marker as the documentation to display, and the source of an example context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
@template component/templatename&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Useful things to include in the documentation for a template ====&lt;br /&gt;
===== Classes required for JS =====&lt;br /&gt;
This is a list of classes that are used by the javascript for this template. If removing a class from an element in the template will break the javascript, list it here.&lt;br /&gt;
&lt;br /&gt;
===== Data attributes required for JS =====&lt;br /&gt;
This is a list of data attributes (e.g. data-enhance=&amp;quot;true&amp;quot;) that are used by the javascript for this template. If removing a data attribute from an element in the template will break the javascript, list it here.&lt;br /&gt;
&lt;br /&gt;
===== Context variables required for this template =====&lt;br /&gt;
This is a description of the data that may be contained in the context that is passed to the template. Be explicit and document every attribute.&lt;br /&gt;
&lt;br /&gt;
===== Example context (JSON) =====&lt;br /&gt;
The Template Library will look for this data in your documentation comment as it allows it to render a &amp;quot;preview&amp;quot; of the template right in the Template Library. This is useful for theme designers to test all the available templates in their new theme to make sure they look nice in a new theme. It is also useful to make sure the template responds to different screen sizes, languages and devices. The format is a JSON-encoded object that is passed directly into the render method for this template. &lt;br /&gt;
&lt;br /&gt;
==== A full example ====&lt;br /&gt;
lib/templates/pix_icon.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  {{!                                                                                                                                 &lt;br /&gt;
    This file is part of Moodle - http://moodle.org/                                                                                &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle is free software: you can redistribute it and/or modify                                                                  &lt;br /&gt;
    it under the terms of the GNU General Public License as published by                                                            &lt;br /&gt;
    the Free Software Foundation, either version 3 of the License, or                                                               &lt;br /&gt;
    (at your option) any later version.                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle is distributed in the hope that it will be useful,                                                                       &lt;br /&gt;
    but WITHOUT ANY WARRANTY; without even the implied warranty of                                                                  &lt;br /&gt;
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                                                   &lt;br /&gt;
    GNU General Public License for more details.                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    You should have received a copy of the GNU General Public License                                                               &lt;br /&gt;
    along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.                                                                 &lt;br /&gt;
  }}                                                                                                                                  &lt;br /&gt;
  {{!                                                                                                                                 &lt;br /&gt;
    @template core/pix_icon                                                                                                         &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle pix_icon template.                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    The purpose of this template is to render a pix_icon.                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Classes required for JS:                                                                                                        &lt;br /&gt;
    * none                                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Data attributes required for JS:                                                                                                &lt;br /&gt;
    * none                                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Context variables required for this template:                                                                                   &lt;br /&gt;
    * attributes Array of name / value pairs.                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Example context (json):                                                                                                         &lt;br /&gt;
    {                                                                                                                               &lt;br /&gt;
        &amp;quot;attributes&amp;quot;: [                                                                                                             &lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;src&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;http://moodle.com/wp-content/themes/moodle/images/logo-hat2.png&amp;quot; },                          &lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;class&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;iconsmall&amp;quot; }                                                                               &lt;br /&gt;
        ]                                                                                                                           &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
  }}                                                                                                                                  &lt;br /&gt;
  &amp;lt;img {{#attributes}}{{name}}=&amp;quot;{{value}}&amp;quot; {{/attributes}}/&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Coding style for templates ==&lt;br /&gt;
This section documents some coding style guidelines to follow when writing templates. The reason for these guidelines is to promote consistency, and interoperability of the templates.&lt;br /&gt;
&lt;br /&gt;
=== Include GPL at the top of each template ===&lt;br /&gt;
&lt;br /&gt;
Templates are a form of code and it is appropriate to license them like any other code.&lt;br /&gt;
&lt;br /&gt;
===Include a documentation comment for each template===&lt;br /&gt;
&lt;br /&gt;
The exception is when you are overriding a template, if the documentation from the parent still applies, you do not need to copy it to the overridden template.&lt;br /&gt;
&lt;br /&gt;
===Use data-attributes for JS hooks===&lt;br /&gt;
&lt;br /&gt;
Data attributes are ideal for adding javascript hooks to templates because:&lt;br /&gt;
* Classes are meant for styling - theme designers should be able to change the classes at will without breaking any functionality.&lt;br /&gt;
* IDs must be unique in the page, but it is not possible to control how many times the same template might be included in the page.&lt;br /&gt;
* Data attributes can have meaningful names and can be efficiently queried with a selector&lt;br /&gt;
&lt;br /&gt;
===Avoid custom CSS for templates===&lt;br /&gt;
&lt;br /&gt;
This is not a hard rule, but a preference. We already have too much CSS in Moodle - where ever possible we should try and re-use the existing CSS instead of adding new CSS to support every new template.&lt;br /&gt;
&lt;br /&gt;
===Re-use core templates as much as possible===&lt;br /&gt;
&lt;br /&gt;
First we need to build the core set of reusable templates - but once that is in place we should always try to re-use those core templates to build interfaces. This will make Moodle more consistent, attractive and customisable.&lt;br /&gt;
&lt;br /&gt;
===Do use the CSS framework classes directly in the templates===&lt;br /&gt;
&lt;br /&gt;
We have bootstrap in core - so lets make the most of it. There is no problem using bootstrap classes in core templates, as long as the &amp;quot;base&amp;quot; theme is also tested, and an overridden template is added there if required.&lt;br /&gt;
&lt;br /&gt;
===Avoid IDs for styling or javascript===&lt;br /&gt;
&lt;br /&gt;
IDs should never evet be used for styling as they have a high CSS specificity, and so are hard to override. In addition, IDs should be unique in the page, which implies that a template could only be used once in a page. IDs are also not ideal for javascript, for the same reason (must be unique in a page).&lt;br /&gt;
&lt;br /&gt;
The only acceptable case to use an ID is you need to create a one to one connection between the JS and template. In this case use the uniqid helper to generate an ID that will not conflict with any other template on the page, and use it as part of the ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{uniqid}}-somethingspecific&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    callFunction(&#039;{{uniqid}}-somethingspecific&#039;);&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Follow CSS coding style===&lt;br /&gt;
&lt;br /&gt;
https://docs.moodle.org/dev/CSS_coding_style&lt;br /&gt;
&lt;br /&gt;
Use hyphens as word-separators for class names. &lt;br /&gt;
Use lower case class names.&lt;br /&gt;
&lt;br /&gt;
===Wrap each template in one node with a classname that matches the template name===&lt;br /&gt;
&lt;br /&gt;
Generate a class name by combining the component and template names and separating words with underscore.&lt;br /&gt;
&lt;br /&gt;
e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;core_user_header&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;br /&gt;
[[Category:Output]]&lt;br /&gt;
&lt;br /&gt;
===Iterating over php arrays in a mustache template===&lt;br /&gt;
&lt;br /&gt;
Mustache treats hashes and arrays differently because of cross language compatibility&lt;br /&gt;
In php arrays and hashes are the same, but mustache treats them differently&lt;br /&gt;
It decides a php array is a hash and will not iterate over it if it is non 0 indexed and/or has a gap in the key numbers&lt;br /&gt;
so in short&lt;br /&gt;
you need to&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$datafortemplate-&amp;gt;mylist =  array_values($myarraywithnonnumerickeys)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
you could also use &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$datafortemplate-&amp;gt;mylist = new ArrayIterator($myarraywithnonnumerickeys);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
BUT this fails when $myarraywithnonnumerickeys is empty and you try to use&lt;br /&gt;
&amp;lt;code html5&amp;gt;&lt;br /&gt;
{{#mylist}}&lt;br /&gt;
with an array iterator if mylist is empty this block will not run&lt;br /&gt;
{{/mylist}}&lt;br /&gt;
{{^mylist}}&lt;br /&gt;
with an array iterator mylist will not run this block either because it is not quite empty&lt;br /&gt;
{{/mylist}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How do I write core templates? ==&lt;br /&gt;
Core templates should ideally be simple generic components that can be used within other templates to create more complex page layouts. They should be flexible enough for developers and themers to easily use without having to replace the template. The templates should attempt to encapsulate some core structure for the element as well as key classes while allowing the content to be easily overridden. Ultimately we want to avoid having duplicate HTML copied from template to template where possible, particularly if the HTML element has some classes associated with it.&lt;br /&gt;
&lt;br /&gt;
Mustache relies on variables to substitute context data into the template but unfortunately it&#039;s very unlikely that the the names of the context data will match what the template is expecting for all the places that the template might be used. So in order to allow easy extensibility and avoid having to duplicate templates just to rename the variables we can wrap them in block variables which would allow the template that is including our template to replace that variable with one from it&#039;s own context inline.&lt;br /&gt;
&lt;br /&gt;
There are a few key points to keep in mind when writing a core template:&lt;br /&gt;
* Consider how your template will actually be used. Try writing a test page that uses your template to help discover some of the assumptions you might have in the template.&lt;br /&gt;
* The example context you provide in the template is mostly just for showing the template in the template library and is likely not how your template will actually be used. Most uses of the template will have a different context all together.&lt;br /&gt;
* Try to enforce a core structure but avoid enforcing a specific context. Content should be overridable.&lt;br /&gt;
* Use block variables to indicate sections of your template that people are likely to want to change. Typically where they will be wanting to substitute in their own content.&lt;br /&gt;
* Try to keep any javascript that accompanies the template as decoupled from the HTML / CSS structure of the template as possible. Instead of relying on the existence of certain HTML elements or CSS classes it is generally better to leverage data-attributes which can be added to any element.&lt;br /&gt;
&lt;br /&gt;
=== An example: tabs ===&lt;br /&gt;
Let&#039;s go through an example to illustrate how you might build a core template. For the example we&#039;ll be building a tabs template, since it&#039;s a fairly complex component that requires the use of block variables and javascript.&lt;br /&gt;
&lt;br /&gt;
First we can create a basic template to get the general structure down, let&#039;s call it tabs. Here&#039;s what it might look like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
		{{# tabs }}&lt;br /&gt;
			&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
					data-target=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
					data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
					aria-controls=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
					aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
				&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{{ name }}}&amp;lt;/a&amp;gt;&lt;br /&gt;
			&amp;lt;/li&amp;gt;&lt;br /&gt;
		{{/ tabs }}&lt;br /&gt;
	&amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
		{{# tabs }}&lt;br /&gt;
			&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
				class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
				id=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
				{{{ content }}}&lt;br /&gt;
			&amp;lt;/div&amp;gt;&lt;br /&gt;
		{{/ tabs }}&lt;br /&gt;
	&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The template requires a context that looks something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;tabs&amp;quot;: [&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab1&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 1&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 1 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab2&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 2&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 2 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab3&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 3&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 3 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;}&lt;br /&gt;
	]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The javascript required to power the tabs element (keyboard navigation, show / hide panels etc) is written as an AMD module and is included by the template. The javascript is a little too large to go through here, but some key points to consider when writing it are:&lt;br /&gt;
It should ideally be independent of the HTML structure, so if someone wants to completely rewrite the tabs to be different elements (e.g. buttons or a set of divs) then the same javascript can be used without needing to change it. In order to achieve this it is important to identify the key components of the template.&lt;br /&gt;
&lt;br /&gt;
In this case it is a tab list, a tab and it&#039;s content. One way to identify these components would be to inspect the structure of the DOM, for example you might say &amp;quot;find me the ul element&amp;quot; when looking for the tab list and then &amp;quot;find my the child li elements&amp;quot; to find the tabs. While this would work, it couples your javascript to the HTML structure and makes it difficult to change later. A different approach would be to use the element attributes, for example you might say &amp;quot;find my the element with the role &#039;tablist&#039;&amp;quot; to get the tab list and then &amp;quot;find me the elements with the role &#039;tab&#039;&amp;quot; to get the tabs. This allows the HTML structure to change without breaking the javascript (as long as the correct attributes are set, of course).&lt;br /&gt;
&lt;br /&gt;
Another point of consideration for this example is what class to apply to a tab when it is selected. It makes sense to just apply something like &amp;quot;active&amp;quot; in the javascript, but that once again couples it to a particular CSS framework which makes it more difficult to change without modifying the javascript. In this case I chose to add a data attribute to the element to indicate which class will be set when the tab is selected. This means the javascript doesn&#039;t have to guess what the appropriate class is, it can just get it from the template.&lt;br /&gt;
&lt;br /&gt;
Ok, so we&#039;ve got our basic template. It&#039;s time to use it! Let&#039;s say we want to create a simple user profile page that might show 2 tabs, the first tab will be the user&#039;s name and the second tab will be the user&#039;s email address (please excuse the contrived example).&lt;br /&gt;
&lt;br /&gt;
Here&#039;s what the page might look like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;lt; core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That looks pretty simple! The only problem is, how do I get my content there? I would have to supply a context like this in order to display the tabs I want:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;tabs&amp;quot;: [&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab1&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Name&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;Your name is Mr. Test User.&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab2&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Email&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;Your email is testuser@example.com&amp;quot;},&lt;br /&gt;
	]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume that the context for this page doesn&#039;t match what the tabs template is expecting though (as will be the case most of the time). Let&#039;s assume the tabs template is being rendered with this context:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;name&amp;quot;:&amp;quot;Mr. Test User&amp;quot;,&lt;br /&gt;
	&amp;quot;email&amp;quot;:&amp;quot;testuser@example.com&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unfortunately, we&#039;ll almost certainly never have complete control over all of the contexts that our template will be rendered in which means we&#039;ll be expecting people to write new webservices to supply the same data in different formats every time they want to use a template. It becomes an unmanageable problem.&lt;br /&gt;
&lt;br /&gt;
Enter blocks! We can make the template more flexible by defining sections of the template that can be overriden when they are included. Pretty neat! This will allow us to enforce a certain core structure but not enforce a context on the template that is including the tabs.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s have another go at that template, this time leverging blocks:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
	{{$ tabheader }}&lt;br /&gt;
		&amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
							data-target=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
							data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
							aria-controls=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
							aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
						&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{{ name }}}&amp;lt;/a&amp;gt;&lt;br /&gt;
					&amp;lt;/li&amp;gt;&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
		&amp;lt;/ul&amp;gt;&lt;br /&gt;
	{{/ tabheader }}&lt;br /&gt;
	{{$ tabbody }}&lt;br /&gt;
		&amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
						class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
						id=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
						{{{ content }}}&lt;br /&gt;
					&amp;lt;/div&amp;gt;&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
	{{/ tabbody }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A summary of what we&#039;ve changed:&lt;br /&gt;
* Added a $tabheader block around the tab list, in case someone wants to change the ul element to something else.&lt;br /&gt;
* Added a $tablist block around the group of tabs to allow them to be overriden on incldue.&lt;br /&gt;
* Added a $tabbody block around the content, in case someone wants to change the content elements from divs.&lt;br /&gt;
* Added a $tabcontent block around the tab variable for the content to allow the content to be overriden on inlcude.&lt;br /&gt;
&lt;br /&gt;
Now let&#039;s see what using this template looks like for your User Profile page:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;gt; core/tabs }}&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
						data-target=&amp;quot;{{ uniqid }}-tab1&amp;quot;&lt;br /&gt;
						data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
						aria-controls=&amp;quot;{{ uniqid }}-tab1&amp;quot;&lt;br /&gt;
						aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Name&amp;lt;/a&amp;gt;&lt;br /&gt;
				&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
						data-target=&amp;quot;{{ uniqid }}-tab2&amp;quot;&lt;br /&gt;
						data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
						aria-controls=&amp;quot;{{ uniqid }}-tab2&amp;quot;&lt;br /&gt;
						aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Email&amp;lt;/a&amp;gt;&lt;br /&gt;
				&amp;lt;/li&amp;gt;&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
					class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
					id=&amp;quot;{{ uniqid }}-tab1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					Your name is {{ name }}.&lt;br /&gt;
				&amp;lt;/div&amp;gt;&lt;br /&gt;
				&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
					class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
					id=&amp;quot;{{ uniqid }}-tab2&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					Your email address is {{ email }}.&lt;br /&gt;
				&amp;lt;/div&amp;gt;&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		{{/ core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That looks a bit better! Now we&#039;ve been able to use the blocks to successfully change the template to use the context available to this page, we no longer need a &amp;quot;tabs&amp;quot; array with &amp;quot;name&amp;quot; and &amp;quot;content&amp;quot;. Even the javascript will continue to work because we&#039;ve kept the correct element attributes. &lt;br /&gt;
&lt;br /&gt;
We&#039;ve still got a slight problem though... In order to change the data for the template we&#039;ve had to copy &amp;amp; paste the HTML from the original template into our blocks as we do the override. While this works fine in this example, it means we don&#039;t quite get the encapsulation we want within the templates since we&#039;re leaking internal implementation details. If we ever wanted to change the CSS framework we use for Moodle (say from bootstrap 2 to boostrap 3 or 4) we&#039;d have to find all the places in the code where this tabs template is used and make sure that the HTML is correct in their block overrides.&lt;br /&gt;
&lt;br /&gt;
With that in mind, let&#039;s take one more pass at this template and see if we can improve it slightly again. This time we&#039;re doing to split the template out into 3 templates.&lt;br /&gt;
&lt;br /&gt;
tabs.mustache:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
	{{$ tabheader }}&lt;br /&gt;
		&amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					{{&amp;lt; core/tab_header_item }}		&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
		&amp;lt;/ul&amp;gt;&lt;br /&gt;
	{{/ tabheader }}&lt;br /&gt;
	{{$ tabbody }}&lt;br /&gt;
		&amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					{{&amp;lt; core/tab_content_item }}&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
	{{/ tabbody }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tab_header_item.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
		data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
		aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{$ tabname }}{{{ name }}}{{/ tabname }}&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tab_content_item.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
	class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	{{$ tabpanelcontent }}{{{ content }}}{{/ tabpanelcontent }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A summary of the changes:&lt;br /&gt;
* Split the template into 3, moving the tab into it&#039;s own template and the content into it&#039;s own and then including them in the tabs template.&lt;br /&gt;
* Removed the ids from the tabs and content. The javascript would be updating to assign these ids at runtime so that they don&#039;t need to be provided as part of the template context.&lt;br /&gt;
* Added a $tabname block for in the tab_header_item template to make the name flexible on import.&lt;br /&gt;
* Added a $tabpanelcontant block in the tab_content_item template to make the content flexible on import.&lt;br /&gt;
&lt;br /&gt;
Cool, so let&#039;s see what that looks like in our example now:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;gt; core/tabs }}&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{&amp;gt; core/tab_header_item }}&lt;br /&gt;
					{{$ tabname }}Name{{/ tabname }}&lt;br /&gt;
				{{/ core/tab_header_item }}&lt;br /&gt;
				{{&amp;gt; core/tab_header_item }}&lt;br /&gt;
					{{$ tabname }}Email{{/ tabname }}&lt;br /&gt;
				{{/ core/tab_header_item }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{&amp;gt; core/tab_content_item }}&lt;br /&gt;
					{{$ tabpanelcontent }}Your name is {{ name }}.{{/ tabpanelcontent }}&lt;br /&gt;
				{{/ core/tab_content_item }}&lt;br /&gt;
				{{&amp;gt; core/tab_content_item }}&lt;br /&gt;
					{{$ tabpanelcontent }}Your email address is {{ email }}.{{/ tabpanelcontent }}&lt;br /&gt;
				{{/ core/tab_content_item }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		{{/ core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And we&#039;re done! After making the changes above we&#039;ve been able to keep the benefits of the previous change to allow the context changes but we&#039;ve also removed the need to copy &amp;amp; paste the HTML everywhere. Instead we&#039;re able to use the child templates with a few additional blocks defined to get the content in there.&lt;br /&gt;
&lt;br /&gt;
Now if we want to change tabs HTML or CSS frameworks we can just change the core tabs templates and this page will receive the updates for free.&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=52300</id>
		<title>Templates</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=52300"/>
		<updated>2017-05-09T07:38:43Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: /* What other helpers can I use? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
= Templates =&lt;br /&gt;
&lt;br /&gt;
== What is a template? ==&lt;br /&gt;
A template is an alternative to writing blocks of HTML directly in javascript / php by concatenating strings. The end result is the same, but templates have a number of advantages:&lt;br /&gt;
* It is easier to see the final result of the template because the code for a template is very close to what the final HTML will look like&lt;br /&gt;
* Because the templating language is intentionally limited, it is hard to introduce complex logic into a template. This makes it far easier for a theme designer to override a template, without breaking the logic&lt;br /&gt;
* Templates can be rendered from javascript. This allows ajax operations to re-render a portion of the page.&lt;br /&gt;
&lt;br /&gt;
== How do I write a template? ==&lt;br /&gt;
Templates are written in a language called &amp;quot;[http://mustache.github.io/mustache.5.html Mustache]&amp;quot;. Mustache is written as HTML with additional tags used to format the display of the data. Mustache tags are made of 2 opening and closing curly braces &amp;lt;code xml&amp;gt;{{tag}}&amp;lt;/code&amp;gt;. There are a few variations of these tags that behave differently.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{raiden}}&amp;lt;/code&amp;gt; This is a simple variable substitution. The variable named &amp;quot;raiden&amp;quot; will be searched for in the current context (and any parent contexts) and when a value is found, the entire tag will be replaced by the variable (HTML escaped).&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{{galaga}}}&amp;lt;/code&amp;gt; This is an unescaped variable substitution. Instead of escaping the variable before replacing it in the template, the variable is included raw. This is useful when the variable contains a block of HTML (for example).&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{#lemmings}} jump off cliff {{/lemmings}}&amp;lt;/code&amp;gt; These are opening and closing section tags. If the lemmings variable exists and evaluates to &amp;quot;not false&amp;quot; value, the variable is pushed on the stack, the contents of the section are parsed and included in the result. If the variable does not exist, or evaluates to false - the section will be skipped. If the variable lemmings evaluates to an array, the section will be repeated for each item in the array with the items of the array on the context. This is how to output a list.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{^lemmings}} enjoy view {{/lemmings}}&amp;lt;/code&amp;gt; Equivalent of &amp;quot;if-not&amp;quot; block, there is no &amp;quot;else&amp;quot; in mustache.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{&amp;gt; franken_style/name_of_template }}&amp;lt;/code&amp;gt; This is a partial. Think of it like an include. Templates can include other templates using this tag. In the called template, the data it sees (for including values is the same as the data available where the partial is included.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{$blockvar}} ... {{/blockvar}}&amp;lt;/code&amp;gt; This is a block variable. It defines a section of the template that can be overridden when it&#039;s included in another template.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{&amp;lt; template_name}} ... {{/template_name}}&amp;lt;/code&amp;gt; This is similar to including a partial but specifically indicates that you&#039;d like to override one or more block variables defined within the template you&#039;re including. You can override the block variables by defining a block variable within these tags that matches the name of the block variable you&#039;d like to override in the included template.&lt;br /&gt;
&lt;br /&gt;
So - putting this all together:&lt;br /&gt;
&lt;br /&gt;
recipe.mustache&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;{{recipename}}&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;{{description}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;h4&amp;gt;Ingredients&amp;lt;/h4&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
{{#ingredients}}&lt;br /&gt;
&amp;lt;li&amp;gt;{{.}}&amp;lt;/li&amp;gt;&lt;br /&gt;
{{/ingredients}}&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;h4&amp;gt;Steps&amp;lt;/h4&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
{{#steps}}&lt;br /&gt;
&amp;lt;li&amp;gt;{{{.}}}&amp;lt;/li&amp;gt;&lt;br /&gt;
{{/steps}}&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
{{ &amp;gt; ratethisrecipe }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When given this data:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  recipename: &amp;quot;Cheese sandwich&amp;quot;,&lt;br /&gt;
  description: &amp;quot;Who doesn&#039;t like a good cheese sandwich?&amp;quot;,&lt;br /&gt;
  ingredients: [&amp;quot;bread&amp;quot;, &amp;quot;cheese&amp;quot;, &amp;quot;butter&amp;quot;],&lt;br /&gt;
  steps: [&amp;quot;&amp;lt;p&amp;gt;Step 1 is to spread the butter on the bread&amp;lt;/p&amp;gt;&amp;quot;, &amp;quot;&amp;lt;p&amp;gt;Step 2 is to put the cheese &amp;amp;quot;in&amp;amp;quot; the bread (not on top, or underneath)&amp;lt;/p&amp;gt;&amp;quot;]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gives this: &amp;lt;span style=&amp;quot;font-size:4em&amp;quot;&amp;gt;😋&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More info - there are much clearer explanations of templates on the [http://mustache.github.io/mustache.5.html Mustache] website. Try reading those pages &amp;quot;before&amp;quot; posting on stack overflow :) .&lt;br /&gt;
&lt;br /&gt;
=== Blocks (Moodle 3.0 onwards) ===&lt;br /&gt;
Blocks are a feature of Mustache that deserves a special mention. The are used as a form of inheritance - and are crucial to building a library of re-usable templates. To make use of &amp;quot;blocks&amp;quot; you define a parent template with replaceable sections. Each of those sections is marked with a &amp;quot;blocks&amp;quot; tag like this (A blocks tag looks like a regular tag, but the variable name is preceded with $):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;section&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;{{$sectionheading}}Default heading{{/sectionheading}}&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
{{$content}}Content for section{{/content}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now - wherever I need to re-use this template I can include it and replace the content of those sections at the same time. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{&amp;lt; section}}&lt;br /&gt;
{{$sectionheading}}Latest News{{/sectionheading}}&lt;br /&gt;
{{$content}}Nothing happened today - sorry!{{/content}}&lt;br /&gt;
{{/section}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that when I include a template and I want to make use of blocks - the include tag points the other way:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{&amp;lt; section}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Not&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{&amp;gt; section}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Blocks support looping and many other cool things - for more info see https://github.com/bobthecow/mustache.php/wiki/BLOCKS-pragma&lt;br /&gt;
&lt;br /&gt;
== Where do I put my templates? ==&lt;br /&gt;
&lt;br /&gt;
Templates go in the &amp;lt;componentdir&amp;gt;/templates folder and must have a .mustache file extension. When loading templates the template name is &amp;lt;componentname&amp;gt;/&amp;lt;filename&amp;gt; (no file extension). &lt;br /&gt;
&lt;br /&gt;
So &amp;quot;mod_lesson/timer&amp;quot; would load the template at mod/lesson/templates/timer.mustache.&lt;br /&gt;
&lt;br /&gt;
Note: Do not try and put your templates in sub folders under the &amp;quot;/templates&amp;quot; directory. This is not supported and will not work.&lt;br /&gt;
&lt;br /&gt;
== How do I call a template from javascript? ==&lt;br /&gt;
&lt;br /&gt;
Rendering a template from javascript is fairly easy. There is a new AMD module that can load/cache and render a template for you. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// This is AMD code for loading the &amp;quot;core/templates&amp;quot; module. see [Javascript Modules].&lt;br /&gt;
require([&#039;core/templates&#039;], function(templates) {&lt;br /&gt;
&lt;br /&gt;
    // This will be the context for our template. So {{name}} in the template will resolve to &amp;quot;Tweety bird&amp;quot;.&lt;br /&gt;
    var context = { name: &#039;Tweety bird&#039;, intelligence: 2 };&lt;br /&gt;
&lt;br /&gt;
    // This will call the function to load and render our template. &lt;br /&gt;
    templates.render(&#039;block_looneytunes/profile&#039;, context);&lt;br /&gt;
&lt;br /&gt;
    // It returns a promise that needs to be resoved.&lt;br /&gt;
            .then(function(html, js) {&lt;br /&gt;
                // Here eventually I have my compiled template, and any javascript that it generated.&lt;br /&gt;
                // The templates object has append, prepend and replace functions.&lt;br /&gt;
                templates.appendNodeContents(&#039;.block_looneytunes .content&#039;, source, javascript);&lt;br /&gt;
            }).fail(function(ex) {&lt;br /&gt;
                // Deal with this exception (I recommend core/notify exception function for this).&lt;br /&gt;
            });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Under the hood, this did many clever things for us. It loaded the template via an ajax call if it was not cached. It found any missing lang strings in the template and loaded them in a single ajax request, it split the JS from the HTML and returned us both in easy to use way. Read on for how to nicely deal with the javascript parameter.&lt;br /&gt;
&lt;br /&gt;
Note: with some nice chaining and sugar, we can shorten the above example quite a bit:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/templates&#039;, &#039;core/notification&#039;], function(templates, notification) {&lt;br /&gt;
    var context = { name: &#039;Tweety bird&#039;, intelligence: 2 };&lt;br /&gt;
    templates.render(&#039;block_looneytunes/profile&#039;, context)&lt;br /&gt;
        .then(doneCallback)&lt;br /&gt;
        .fail(notification.exception);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What if a template contains javascript? ==&lt;br /&gt;
&lt;br /&gt;
Sometimes a template requires that some JS be run when it is added to the page in order to give it more features. In the template we can include blocks of javascript, but we should use a special section tag that has a &amp;quot;helper&amp;quot; method registered to handle javascript carefully. &lt;br /&gt;
&lt;br /&gt;
Example&lt;br /&gt;
profile.mustache&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;profile&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Name: {{name}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Intelligence: {{intelligence}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require(&#039;jquery&#039;, function($) {&lt;br /&gt;
    // Effects! Can we have &amp;quot;blink&amp;quot;?&lt;br /&gt;
    $(&#039;#profile&#039;).slideDown();&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If this template is rendered by PHP, the javascript is separated from the HTML, and is appended to a special section in the footer of the page &amp;quot;after&amp;quot; requirejs has loaded. This provides the optimal page loading speed. If the template is rendered by javascript, the javascript source will be passed to the &amp;quot;done&amp;quot; handler from the promise. Then, when the &amp;quot;done&amp;quot; handler has added the template to the DOM, it can call &lt;br /&gt;
&amp;lt;code javascript&amp;gt;templates.runTemplateJS(javascript);&amp;lt;/code&amp;gt; &lt;br /&gt;
which will run the javascript (by creating a new script tag and appending it to the page head).&lt;br /&gt;
&lt;br /&gt;
== What other helpers can I use? ==&lt;br /&gt;
&lt;br /&gt;
=== {{# str }} ===&lt;br /&gt;
&lt;br /&gt;
There is a string helper for loading language strings.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{# str }} helloworld, mod_greeting {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first 2 parameters are the string id and the component name. So this is effectively Mustache variant of &amp;lt;code&amp;gt;get_string(&#039;helloworld&#039;, &#039;mod_greeting&#039;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The optional third parameter defines the value for the string&#039;s &amp;lt;code&amp;gt;$a&amp;lt;/code&amp;gt; placeholder:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{# str }} iscool, mod_cool, David Beckham {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example would effectively do what &amp;lt;code&amp;gt;get_string(&#039;iscool&#039;, &#039;mod_cool&#039;, &#039;David Beckham&#039;)&amp;lt;/code&amp;gt; does in Moodle PHP code.&lt;br /&gt;
&lt;br /&gt;
Variable tags are allowed to define the value of the &amp;lt;code&amp;gt;$a&amp;lt;/code&amp;gt; placeholder:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{# str }} iscool, mod_cool, {{ name }} {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For strings that accept complex placeholder, see the following section.&lt;br /&gt;
&lt;br /&gt;
=== {{# quote }} ===&lt;br /&gt;
&lt;br /&gt;
As shown in the previous section, the &amp;lt;code&amp;gt;{{# str }}&amp;lt;/code&amp;gt; helper may need complex data structures passed as the value of the &amp;lt;code&amp;gt;$a&amp;lt;/code&amp;gt; placeholder. You can use a JSON object syntax in that case:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{# str }} iscool, mod_cool, { &amp;quot;firstname&amp;quot;: &amp;quot;David&amp;quot;, &amp;quot;lastname&amp;quot;: &amp;quot;Beckham&amp;quot; } {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you wanted to use the context values instead of literal strings, you might intuitively use something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{! DO NOT DO THIS !}}&lt;br /&gt;
{{# str }} iscool, mod_cool, { &amp;quot;firstname&amp;quot;: &amp;quot;{{ firstname }}&amp;quot;, &amp;quot;lastname&amp;quot;: &amp;quot;{{ lastname }}&amp;quot; } {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a potential problem though. If the variable tag &amp;lt;code&amp;gt;{{ firstname }}&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;{{ lastname }}&amp;lt;/code&amp;gt; evaluates to a string containing the double quote character, that will break the JSON syntax. We need to escape the double quotes potentially appearing in the variable tags. For this, use the &amp;lt;code&amp;gt;{{# quote }}&amp;lt;/code&amp;gt; helper:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{! This is OK !}}&lt;br /&gt;
{{# str }} iscool, mod_cool, { &amp;quot;firstname&amp;quot;:  {{# quote }}{{ firstname }}{{/ quote }}, &amp;quot;lastname&amp;quot;: {{# quote }}{{ lastname }}{{/ quote }} } {{/ str }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See MDL-52136 for details.&lt;br /&gt;
=== {{# pix }} ===&lt;br /&gt;
&lt;br /&gt;
There is a pix icon helper for generating pix icon tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{# pix }} t/edit, core, Edit David Beckham {{/ pix }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first 2 parameters are the string id and the component name, the rest is the alt text for the image.&lt;br /&gt;
&lt;br /&gt;
=== {{# userdate }} ===&lt;br /&gt;
This mustache template helper will format unix timestamps into a given human readable date format while using the user&#039;s timezone settings configured (if any) in Moodle. The helper will accept hardcoded values, context variables, or other helpers. &lt;br /&gt;
&lt;br /&gt;
The recommended way to use this helper is to use the string helper to get one of the core Moodle formats because they have been translated into other languages so you&#039;ll get multi-lang support for free (that&#039;s a pretty good deal!).&lt;br /&gt;
&lt;br /&gt;
==== Using the string helper (recommended) ====&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
// Assuming we had a context variable named &amp;quot;time&amp;quot; set to 1293876000.&lt;br /&gt;
{{#userdate}} {{time}}, {{#str}} strftimedate {{/str}} {{/userdate}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will ask the Moodle server for the string &amp;quot;strftimedate&amp;quot; and will use the value (which in this case is &amp;quot;%d %B %Y&amp;quot;)  to format the user date. So the resulting formatted timestamp from the userdate helper will be &amp;quot;01 January 2011&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== Using context variables ====&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
// Assuming we had a context variable named &amp;quot;time&amp;quot; set to 1293876000.&lt;br /&gt;
{{#userdate}} {{time}}, %A, %d %B %Y, %I:%M %p {{/userdate}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Will produce &amp;quot;Saturday, 01 January 2011, 10:00 AM&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Using hardcoded values ====&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#userdate}} 1293876000, %A, %d %B %Y, %I:%M %p {{/userdate}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Will produce &amp;quot;Saturday, 01 January 2011, 10:00 AM&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== How do I call a template from php? ==&lt;br /&gt;
&lt;br /&gt;
The templates in php are attached to the renderers. There is a renderer method &amp;quot;render_from_template($templatename, $context)&amp;quot; that does the trick.&lt;br /&gt;
&lt;br /&gt;
== How do templates work with renderers? ==&lt;br /&gt;
&lt;br /&gt;
Extra care must be taken to ensure that the data passed to the context parameter is useful to the templating language. The template language cannot:&lt;br /&gt;
* Call functions&lt;br /&gt;
* Perform any boolean logic&lt;br /&gt;
* Render renderables&lt;br /&gt;
* Do capability checks&lt;br /&gt;
* Make DB queries&lt;br /&gt;
&lt;br /&gt;
So - I have &amp;quot;some&amp;quot; data in my renderable and some logic and HTML generation in my render method for that renderable - how do I refactor this to use a template?&lt;br /&gt;
&lt;br /&gt;
The first thing to note, is that you don&#039;t have to use a template if you don&#039;t want to. It just means that themers will still have to override your render method, instead of just overriding the template. But if you DO want to use a template, you will earn &amp;quot;cred&amp;quot; with themers, and you will be able to re-render parts of your interface from javascript in response to ajax requests without reloading the whole page (that&#039;s cool).&lt;br /&gt;
&lt;br /&gt;
There is a simple pattern to use to hook a template into a render method. If you make your renderable implement templatable as well as renderable - it will have to implement a new method &amp;quot;export_for_template(renderer_base $output)&amp;quot;. This method takes the data stored in the renderable and &amp;quot;flattens it&amp;quot; so it can be used in a template. If there is some nested data in the renderable (like other renderables) and they do not support templates, they can be &amp;quot;rendered&amp;quot; into the flat data structure using the renderer parameter. It should return an stdClass with properties that are only made of simple types: int, string, bool, float, stdClass or arrays of these types. Then the render method can updated to export the data and render it with the template.&lt;br /&gt;
&lt;br /&gt;
In the renderable:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;canmanage = $this-&amp;gt;canmanage;&lt;br /&gt;
        $data-&amp;gt;things = array();&lt;br /&gt;
        foreach ($this-&amp;gt;things as $thing) {&lt;br /&gt;
            $data-&amp;gt;things[] = $thing-&amp;gt;to_record();&lt;br /&gt;
        }&lt;br /&gt;
        $data-&amp;gt;navigation = array();&lt;br /&gt;
        foreach ($this-&amp;gt;navigation as $button) {&lt;br /&gt;
            $data-&amp;gt;navigation[] = $output-&amp;gt;render($button);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the renderer class:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param mywidget $widget&lt;br /&gt;
     *&lt;br /&gt;
     * @return string HTML for the page&lt;br /&gt;
     */&lt;br /&gt;
    render(mywidget $widget) {&lt;br /&gt;
        $data = $widget-&amp;gt;export_for_template($this);&lt;br /&gt;
        return $this-&amp;gt;render_from_template(&#039;mywidget&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How to I override a template in my theme? ==&lt;br /&gt;
&lt;br /&gt;
Templates can be overridden a bit easier than overriding a renderer. First - find the template that you want to change. E.g. &amp;quot;mod/wiki/templates/ratingui.mustache&amp;quot;. Now, create a sub-folder under your themes &amp;quot;templates&amp;quot; directory with the component name of the plugin you are overriding. E.g &amp;quot;theme/timtam/templates/mod_wiki&amp;quot;. Finally, copy the ratingui.mustache file into the newly created &amp;quot;theme/timtam/templates/mod_wiki&amp;quot; and edit it. You should see your changes immediately if theme designer mode is on. Note: templates are cached just like CSS, so if you are not using theme designer mode you will need to purge all caches to see the latest version of an edited template. If the template you are overriding contains a documentation comment (see next section) it is recommended to remove it, it will still show the documentation in the template library.&lt;br /&gt;
&lt;br /&gt;
== Should I document my templates? ==&lt;br /&gt;
&lt;br /&gt;
Yes!!!! Theme designers need to know the limits of what they can expect to change without breaking anything. As a further benefit - your beautiful new template can be displayed in the &amp;quot;Template Library&amp;quot; tool shipped with Moodle. In order to provide nice documentation and examples for the Template Library, you should follow these conventions when documenting your template.&lt;br /&gt;
&lt;br /&gt;
=== Add a documentation comment to your template ===&lt;br /&gt;
Mustache comments look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  {{! &lt;br /&gt;
   I am a comment.&lt;br /&gt;
   I can span multiple lines.&lt;br /&gt;
  }}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The template library will look for a mustache comment that contains this special marker as the documentation to display, and the source of an example context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
@template component/templatename&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Useful things to include in the documentation for a template ====&lt;br /&gt;
===== Classes required for JS =====&lt;br /&gt;
This is a list of classes that are used by the javascript for this template. If removing a class from an element in the template will break the javascript, list it here.&lt;br /&gt;
&lt;br /&gt;
===== Data attributes required for JS =====&lt;br /&gt;
This is a list of data attributes (e.g. data-enhance=&amp;quot;true&amp;quot;) that are used by the javascript for this template. If removing a data attribute from an element in the template will break the javascript, list it here.&lt;br /&gt;
&lt;br /&gt;
===== Context variables required for this template =====&lt;br /&gt;
This is a description of the data that may be contained in the context that is passed to the template. Be explicit and document every attribute.&lt;br /&gt;
&lt;br /&gt;
===== Example context (JSON) =====&lt;br /&gt;
The Template Library will look for this data in your documentation comment as it allows it to render a &amp;quot;preview&amp;quot; of the template right in the Template Library. This is useful for theme designers to test all the available templates in their new theme to make sure they look nice in a new theme. It is also useful to make sure the template responds to different screen sizes, languages and devices. The format is a JSON-encoded object that is passed directly into the render method for this template. &lt;br /&gt;
&lt;br /&gt;
==== A full example ====&lt;br /&gt;
lib/templates/pix_icon.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  {{!                                                                                                                                 &lt;br /&gt;
    This file is part of Moodle - http://moodle.org/                                                                                &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle is free software: you can redistribute it and/or modify                                                                  &lt;br /&gt;
    it under the terms of the GNU General Public License as published by                                                            &lt;br /&gt;
    the Free Software Foundation, either version 3 of the License, or                                                               &lt;br /&gt;
    (at your option) any later version.                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle is distributed in the hope that it will be useful,                                                                       &lt;br /&gt;
    but WITHOUT ANY WARRANTY; without even the implied warranty of                                                                  &lt;br /&gt;
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                                                   &lt;br /&gt;
    GNU General Public License for more details.                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    You should have received a copy of the GNU General Public License                                                               &lt;br /&gt;
    along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.                                                                 &lt;br /&gt;
  }}                                                                                                                                  &lt;br /&gt;
  {{!                                                                                                                                 &lt;br /&gt;
    @template core/pix_icon                                                                                                         &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle pix_icon template.                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    The purpose of this template is to render a pix_icon.                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Classes required for JS:                                                                                                        &lt;br /&gt;
    * none                                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Data attributes required for JS:                                                                                                &lt;br /&gt;
    * none                                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Context variables required for this template:                                                                                   &lt;br /&gt;
    * attributes Array of name / value pairs.                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Example context (json):                                                                                                         &lt;br /&gt;
    {                                                                                                                               &lt;br /&gt;
        &amp;quot;attributes&amp;quot;: [                                                                                                             &lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;src&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;http://moodle.com/wp-content/themes/moodle/images/logo-hat2.png&amp;quot; },                          &lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;class&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;iconsmall&amp;quot; }                                                                               &lt;br /&gt;
        ]                                                                                                                           &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
  }}                                                                                                                                  &lt;br /&gt;
  &amp;lt;img {{#attributes}}{{name}}=&amp;quot;{{value}}&amp;quot; {{/attributes}}/&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Coding style for templates ==&lt;br /&gt;
This section documents some coding style guidelines to follow when writing templates. The reason for these guidelines is to promote consistency, and interoperability of the templates.&lt;br /&gt;
&lt;br /&gt;
=== Include GPL at the top of each template ===&lt;br /&gt;
&lt;br /&gt;
Templates are a form of code and it is appropriate to license them like any other code.&lt;br /&gt;
&lt;br /&gt;
===Include a documentation comment for each template===&lt;br /&gt;
&lt;br /&gt;
The exception is when you are overriding a template, if the documentation from the parent still applies, you do not need to copy it to the overridden template.&lt;br /&gt;
&lt;br /&gt;
===Use data-attributes for JS hooks===&lt;br /&gt;
&lt;br /&gt;
Data attributes are ideal for adding javascript hooks to templates because:&lt;br /&gt;
* Classes are meant for styling - theme designers should be able to change the classes at will without breaking any functionality.&lt;br /&gt;
* IDs must be unique in the page, but it is not possible to control how many times the same template might be included in the page.&lt;br /&gt;
* Data attributes can have meaningful names and can be efficiently queried with a selector&lt;br /&gt;
&lt;br /&gt;
===Avoid custom CSS for templates===&lt;br /&gt;
&lt;br /&gt;
This is not a hard rule, but a preference. We already have too much CSS in Moodle - where ever possible we should try and re-use the existing CSS instead of adding new CSS to support every new template.&lt;br /&gt;
&lt;br /&gt;
===Re-use core templates as much as possible===&lt;br /&gt;
&lt;br /&gt;
First we need to build the core set of reusable templates - but once that is in place we should always try to re-use those core templates to build interfaces. This will make Moodle more consistent, attractive and customisable.&lt;br /&gt;
&lt;br /&gt;
===Do use the CSS framework classes directly in the templates===&lt;br /&gt;
&lt;br /&gt;
We have bootstrap in core - so lets make the most of it. There is no problem using bootstrap classes in core templates, as long as the &amp;quot;base&amp;quot; theme is also tested, and an overridden template is added there if required.&lt;br /&gt;
&lt;br /&gt;
===Avoid IDs for styling or javascript===&lt;br /&gt;
&lt;br /&gt;
IDs should never evet be used for styling as they have a high CSS specificity, and so are hard to override. In addition, IDs should be unique in the page, which implies that a template could only be used once in a page. IDs are also not ideal for javascript, for the same reason (must be unique in a page).&lt;br /&gt;
&lt;br /&gt;
The only acceptable case to use an ID is you need to create a one to one connection between the JS and template. In this case use the uniqid helper to generate an ID that will not conflict with any other template on the page, and use it as part of the ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{uniqid}}-somethingspecific&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    callFunction(&#039;{{uniqid}}-somethingspecific&#039;);&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Follow CSS coding style===&lt;br /&gt;
&lt;br /&gt;
https://docs.moodle.org/dev/CSS_coding_style&lt;br /&gt;
&lt;br /&gt;
Use hyphens as word-separators for class names. &lt;br /&gt;
Use lower case class names.&lt;br /&gt;
&lt;br /&gt;
===Wrap each template in one node with a classname that matches the template name===&lt;br /&gt;
&lt;br /&gt;
Generate a class name by combining the component and template names and separating words with underscore.&lt;br /&gt;
&lt;br /&gt;
e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;core_user_header&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;br /&gt;
[[Category:Output]]&lt;br /&gt;
&lt;br /&gt;
===Iterating over php arrays in a mustache template===&lt;br /&gt;
&lt;br /&gt;
Mustache treats hashes and arrays differently because of cross language compatibility&lt;br /&gt;
In php arrays and hashes are the same, but mustache treats them differently&lt;br /&gt;
It decides a php array is a hash and will not iterate over it if it is non 0 indexed and/or has a gap in the key numbers&lt;br /&gt;
so in short&lt;br /&gt;
you need to&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$datafortemplate-&amp;gt;mylist =  array_values($myarraywithnonnumerickeys)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
you could also use &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$datafortemplate-&amp;gt;mylist = new ArrayIterator($myarraywithnonnumerickeys);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
BUT this fails when $myarraywithnonnumerickeys is empty and you try to use&lt;br /&gt;
&amp;lt;code html5&amp;gt;&lt;br /&gt;
{{#mylist}}&lt;br /&gt;
with an array iterator if mylist is empty this block will not run&lt;br /&gt;
{{/mylist}}&lt;br /&gt;
{{^mylist}}&lt;br /&gt;
with an array iterator mylist will not run this block either because it is not quite empty&lt;br /&gt;
{{/mylist}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How do I write core templates? ==&lt;br /&gt;
Core templates should ideally be simple generic components that can be used within other templates to create more complex page layouts. They should be flexible enough for developers and themers to easily use without having to replace the template. The templates should attempt to encapsulate some core structure for the element as well as key classes while allowing the content to be easily overridden. Ultimately we want to avoid having duplicate HTML copied from template to template where possible, particularly if the HTML element has some classes associated with it.&lt;br /&gt;
&lt;br /&gt;
Mustache relies on variables to substitute context data into the template but unfortunately it&#039;s very unlikely that the the names of the context data will match what the template is expecting for all the places that the template might be used. So in order to allow easy extensibility and avoid having to duplicate templates just to rename the variables we can wrap them in block variables which would allow the template that is including our template to replace that variable with one from it&#039;s own context inline.&lt;br /&gt;
&lt;br /&gt;
There are a few key points to keep in mind when writing a core template:&lt;br /&gt;
* Consider how your template will actually be used. Try writing a test page that uses your template to help discover some of the assumptions you might have in the template.&lt;br /&gt;
* The example context you provide in the template is mostly just for showing the template in the template library and is likely not how your template will actually be used. Most uses of the template will have a different context all together.&lt;br /&gt;
* Try to enforce a core structure but avoid enforcing a specific context. Content should be overridable.&lt;br /&gt;
* Use block variables to indicate sections of your template that people are likely to want to change. Typically where they will be wanting to substitute in their own content.&lt;br /&gt;
* Try to keep any javascript that accompanies the template as decoupled from the HTML / CSS structure of the template as possible. Instead of relying on the existence of certain HTML elements or CSS classes it is generally better to leverage data-attributes which can be added to any element.&lt;br /&gt;
&lt;br /&gt;
=== An example: tabs ===&lt;br /&gt;
Let&#039;s go through an example to illustrate how you might build a core template. For the example we&#039;ll be building a tabs template, since it&#039;s a fairly complex component that requires the use of block variables and javascript.&lt;br /&gt;
&lt;br /&gt;
First we can create a basic template to get the general structure down, let&#039;s call it tabs. Here&#039;s what it might look like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
		{{# tabs }}&lt;br /&gt;
			&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
					data-target=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
					data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
					aria-controls=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
					aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
				&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{{ name }}}&amp;lt;/a&amp;gt;&lt;br /&gt;
			&amp;lt;/li&amp;gt;&lt;br /&gt;
		{{/ tabs }}&lt;br /&gt;
	&amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
		{{# tabs }}&lt;br /&gt;
			&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
				class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
				id=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
				{{{ content }}}&lt;br /&gt;
			&amp;lt;/div&amp;gt;&lt;br /&gt;
		{{/ tabs }}&lt;br /&gt;
	&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The template requires a context that looks something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;tabs&amp;quot;: [&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab1&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 1&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 1 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab2&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 2&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 2 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab3&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 3&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 3 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;}&lt;br /&gt;
	]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The javascript required to power the tabs element (keyboard navigation, show / hide panels etc) is written as an AMD module and is included by the template. The javascript is a little too large to go through here, but some key points to consider when writing it are:&lt;br /&gt;
It should ideally be independent of the HTML structure, so if someone wants to completely rewrite the tabs to be different elements (e.g. buttons or a set of divs) then the same javascript can be used without needing to change it. In order to achieve this it is important to identify the key components of the template.&lt;br /&gt;
&lt;br /&gt;
In this case it is a tab list, a tab and it&#039;s content. One way to identify these components would be to inspect the structure of the DOM, for example you might say &amp;quot;find me the ul element&amp;quot; when looking for the tab list and then &amp;quot;find my the child li elements&amp;quot; to find the tabs. While this would work, it couples your javascript to the HTML structure and makes it difficult to change later. A different approach would be to use the element attributes, for example you might say &amp;quot;find my the element with the role &#039;tablist&#039;&amp;quot; to get the tab list and then &amp;quot;find me the elements with the role &#039;tab&#039;&amp;quot; to get the tabs. This allows the HTML structure to change without breaking the javascript (as long as the correct attributes are set, of course).&lt;br /&gt;
&lt;br /&gt;
Another point of consideration for this example is what class to apply to a tab when it is selected. It makes sense to just apply something like &amp;quot;active&amp;quot; in the javascript, but that once again couples it to a particular CSS framework which makes it more difficult to change without modifying the javascript. In this case I chose to add a data attribute to the element to indicate which class will be set when the tab is selected. This means the javascript doesn&#039;t have to guess what the appropriate class is, it can just get it from the template.&lt;br /&gt;
&lt;br /&gt;
Ok, so we&#039;ve got our basic template. It&#039;s time to use it! Let&#039;s say we want to create a simple user profile page that might show 2 tabs, the first tab will be the user&#039;s name and the second tab will be the user&#039;s email address (please excuse the contrived example).&lt;br /&gt;
&lt;br /&gt;
Here&#039;s what the page might look like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;lt; core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That looks pretty simple! The only problem is, how do I get my content there? I would have to supply a context like this in order to display the tabs I want:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;tabs&amp;quot;: [&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab1&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Name&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;Your name is Mr. Test User.&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab2&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Email&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;Your email is testuser@example.com&amp;quot;},&lt;br /&gt;
	]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume that the context for this page doesn&#039;t match what the tabs template is expecting though (as will be the case most of the time). Let&#039;s assume the tabs template is being rendered with this context:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;name&amp;quot;:&amp;quot;Mr. Test User&amp;quot;,&lt;br /&gt;
	&amp;quot;email&amp;quot;:&amp;quot;testuser@example.com&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unfortunately, we&#039;ll almost certainly never have complete control over all of the contexts that our template will be rendered in which means we&#039;ll be expecting people to write new webservices to supply the same data in different formats every time they want to use a template. It becomes an unmanageable problem.&lt;br /&gt;
&lt;br /&gt;
Enter blocks! We can make the template more flexible by defining sections of the template that can be overriden when they are included. Pretty neat! This will allow us to enforce a certain core structure but not enforce a context on the template that is including the tabs.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s have another go at that template, this time leverging blocks:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
	{{$ tabheader }}&lt;br /&gt;
		&amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
							data-target=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
							data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
							aria-controls=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
							aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
						&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{{ name }}}&amp;lt;/a&amp;gt;&lt;br /&gt;
					&amp;lt;/li&amp;gt;&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
		&amp;lt;/ul&amp;gt;&lt;br /&gt;
	{{/ tabheader }}&lt;br /&gt;
	{{$ tabbody }}&lt;br /&gt;
		&amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
						class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
						id=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
						{{{ content }}}&lt;br /&gt;
					&amp;lt;/div&amp;gt;&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
	{{/ tabbody }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A summary of what we&#039;ve changed:&lt;br /&gt;
* Added a $tabheader block around the tab list, in case someone wants to change the ul element to something else.&lt;br /&gt;
* Added a $tablist block around the group of tabs to allow them to be overriden on incldue.&lt;br /&gt;
* Added a $tabbody block around the content, in case someone wants to change the content elements from divs.&lt;br /&gt;
* Added a $tabcontent block around the tab variable for the content to allow the content to be overriden on inlcude.&lt;br /&gt;
&lt;br /&gt;
Now let&#039;s see what using this template looks like for your User Profile page:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;gt; core/tabs }}&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
						data-target=&amp;quot;{{ uniqid }}-tab1&amp;quot;&lt;br /&gt;
						data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
						aria-controls=&amp;quot;{{ uniqid }}-tab1&amp;quot;&lt;br /&gt;
						aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Name&amp;lt;/a&amp;gt;&lt;br /&gt;
				&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
						data-target=&amp;quot;{{ uniqid }}-tab2&amp;quot;&lt;br /&gt;
						data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
						aria-controls=&amp;quot;{{ uniqid }}-tab2&amp;quot;&lt;br /&gt;
						aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Email&amp;lt;/a&amp;gt;&lt;br /&gt;
				&amp;lt;/li&amp;gt;&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
					class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
					id=&amp;quot;{{ uniqid }}-tab1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					Your name is {{ name }}.&lt;br /&gt;
				&amp;lt;/div&amp;gt;&lt;br /&gt;
				&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
					class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
					id=&amp;quot;{{ uniqid }}-tab2&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					Your email address is {{ email }}.&lt;br /&gt;
				&amp;lt;/div&amp;gt;&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		{{/ core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That looks a bit better! Now we&#039;ve been able to use the blocks to successfully change the template to use the context available to this page, we no longer need a &amp;quot;tabs&amp;quot; array with &amp;quot;name&amp;quot; and &amp;quot;content&amp;quot;. Even the javascript will continue to work because we&#039;ve kept the correct element attributes. &lt;br /&gt;
&lt;br /&gt;
We&#039;ve still got a slight problem though... In order to change the data for the template we&#039;ve had to copy &amp;amp; paste the HTML from the original template into our blocks as we do the override. While this works fine in this example, it means we don&#039;t quite get the encapsulation we want within the templates since we&#039;re leaking internal implementation details. If we ever wanted to change the CSS framework we use for Moodle (say from bootstrap 2 to boostrap 3 or 4) we&#039;d have to find all the places in the code where this tabs template is used and make sure that the HTML is correct in their block overrides.&lt;br /&gt;
&lt;br /&gt;
With that in mind, let&#039;s take one more pass at this template and see if we can improve it slightly again. This time we&#039;re doing to split the template out into 3 templates.&lt;br /&gt;
&lt;br /&gt;
tabs.mustache:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
	{{$ tabheader }}&lt;br /&gt;
		&amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					{{&amp;lt; core/tab_header_item }}		&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
		&amp;lt;/ul&amp;gt;&lt;br /&gt;
	{{/ tabheader }}&lt;br /&gt;
	{{$ tabbody }}&lt;br /&gt;
		&amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					{{&amp;lt; core/tab_content_item }}&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
	{{/ tabbody }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tab_header_item.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
		data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
		aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{$ tabname }}{{{ name }}}{{/ tabname }}&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tab_content_item.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
	class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	{{$ tabpanelcontent }}{{{ content }}}{{/ tabpanelcontent }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A summary of the changes:&lt;br /&gt;
* Split the template into 3, moving the tab into it&#039;s own template and the content into it&#039;s own and then including them in the tabs template.&lt;br /&gt;
* Removed the ids from the tabs and content. The javascript would be updating to assign these ids at runtime so that they don&#039;t need to be provided as part of the template context.&lt;br /&gt;
* Added a $tabname block for in the tab_header_item template to make the name flexible on import.&lt;br /&gt;
* Added a $tabpanelcontant block in the tab_content_item template to make the content flexible on import.&lt;br /&gt;
&lt;br /&gt;
Cool, so let&#039;s see what that looks like in our example now:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;gt; core/tabs }}&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{&amp;gt; core/tab_header_item }}&lt;br /&gt;
					{{$ tabname }}Name{{/ tabname }}&lt;br /&gt;
				{{/ core/tab_header_item }}&lt;br /&gt;
				{{&amp;gt; core/tab_header_item }}&lt;br /&gt;
					{{$ tabname }}Email{{/ tabname }}&lt;br /&gt;
				{{/ core/tab_header_item }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{&amp;gt; core/tab_content_item }}&lt;br /&gt;
					{{$ tabpanelcontent }}Your name is {{ name }}.{{/ tabpanelcontent }}&lt;br /&gt;
				{{/ core/tab_content_item }}&lt;br /&gt;
				{{&amp;gt; core/tab_content_item }}&lt;br /&gt;
					{{$ tabpanelcontent }}Your email address is {{ email }}.{{/ tabpanelcontent }}&lt;br /&gt;
				{{/ core/tab_content_item }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		{{/ core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And we&#039;re done! After making the changes above we&#039;ve been able to keep the benefits of the previous change to allow the context changes but we&#039;ve also removed the need to copy &amp;amp; paste the HTML everywhere. Instead we&#039;re able to use the child templates with a few additional blocks defined to get the content in there.&lt;br /&gt;
&lt;br /&gt;
Now if we want to change tabs HTML or CSS frameworks we can just change the core tabs templates and this page will receive the updates for free.&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=AMD_Modal&amp;diff=52297</id>
		<title>AMD Modal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=AMD_Modal&amp;diff=52297"/>
		<updated>2017-05-09T06:26:22Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: /* How do you write a new type of modal? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is currently (2017) the recommended way to create various sorts of pop-up dialogue boxes in JavaScript.&lt;br /&gt;
&lt;br /&gt;
= Why should you use it? =&lt;br /&gt;
The AMD modal modules provide a simple interface for creating a modal within Moodle. The module will ensure all accessibility requirements are met including applying the correct aria roles, focus control, aria hiding background elements and locking keyboard navigation.&lt;br /&gt;
&lt;br /&gt;
The modals will fire events for common actions that occur within the modal, e.g. show / hide, for other code to listen to and react accordingly.&lt;br /&gt;
&lt;br /&gt;
Moodle ships with a couple of standard modal types for you to re-use including a simple cancel modal, a confirm (yes/no) modal and a save/cancel modal. Hopefully with more to come!&lt;br /&gt;
&lt;br /&gt;
= How do you create a basic modal? =&lt;br /&gt;
If you&#039;d simply like to display a modal with some simple content then all you&#039;ll need is the modal factory. The factory provides a create function that accepts some configuration for your modal that the factory will use to create the modal and optionally a trigger element (the element that will open the modal when activated). The create function will return a promise that is resolved with the created modal.&lt;br /&gt;
&lt;br /&gt;
The configuration is provided as an object with key/value pairs. The options are:&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! &#039;&#039;&#039;key&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| title&lt;br /&gt;
| the title to display in the modal header - note: this wont render HTML&lt;br /&gt;
|-&lt;br /&gt;
| body&lt;br /&gt;
| the main content to be rendered in the modal body&lt;br /&gt;
|-&lt;br /&gt;
| footer&lt;br /&gt;
| the content to be rendered in the modal footer&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| one of the modal types registered with the factory&lt;br /&gt;
|-&lt;br /&gt;
| large&lt;br /&gt;
| a boolean to indicate if the modal should be wider than the default size&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example 1&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;], function($, ModalFactory) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    title: &#039;test title&#039;,&lt;br /&gt;
    body: &#039;&amp;lt;p&amp;gt;test body content&amp;lt;/p&amp;gt;&#039;,&lt;br /&gt;
    footer: &#039;test footer content&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your new modal.&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The modals will also accept a promise for the body and footer content. It is expected that the promise will be resolved with two strings, the html content and any associated javascript. This allows the modal module to work natively with the templates module, such as in the example below.&lt;br /&gt;
&lt;br /&gt;
Example 2&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;, &#039;core/templates&#039;], function($, ModalFactory, Templates) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    title: &#039;test title&#039;,&lt;br /&gt;
    // Can include JS which is run when modal is attached to DOM.&lt;br /&gt;
    body: Templates.render(&#039;core/modal_test_3&#039;, {}),&lt;br /&gt;
    footer: &#039;test footer content&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your modal.&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the modals aren&#039;t actually added to the DOM until they are made visible any javascript resolved with the promise is cached and only run after all of the elements are added to the DOM,  so you don&#039;t have to worry about any special handling in the javascript that is being loaded from the template.&lt;br /&gt;
&lt;br /&gt;
= How do you create a different type of modal? =&lt;br /&gt;
Moodle comes with a few specialised types of modals for common use cases. These can be created using the factory, similar to the examples above, by specifying the type of modal in the configuration provided to the create function. Each of the modal types may have different configuration options, for example the save/cancel modal doesn&#039;t allow you to set the footer content.&lt;br /&gt;
&lt;br /&gt;
Example 3&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;, &#039;core/templates&#039;], function($, ModalFactory, Templates) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    type: ModalFactory.types.SAVE_CANCEL,&lt;br /&gt;
    title: &#039;Modal save cancel&#039;,&lt;br /&gt;
    body: &#039;This modal is a save/cancel modal&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your modal.&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each type of modal may fire additional events to allow your code to handle the new functionality being offered. See the modal_events.js module for a list of events that can be fired. For example, if you wanted to have a save/cancel modal that you did some form validation on before saving you could do something like the example below.&lt;br /&gt;
&lt;br /&gt;
Example 4&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;, &#039;core/modal_events&#039;, &#039;core/templates&#039;],&lt;br /&gt;
        function($, ModalFactory, ModalEvents, Templates) {&lt;br /&gt;
  &lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    type: ModalFactory.types.SAVE_CANCEL,&lt;br /&gt;
    title: &#039;Modal save cancel&#039;,&lt;br /&gt;
    body: &#039;This modal is a save/cancel modal&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    modal.getRoot().on(ModalEvents.save, function(e) {&lt;br /&gt;
      // Stop the default save button behaviour which is to close the modal.&lt;br /&gt;
      e.preventDefault();&lt;br /&gt;
      // Do your form validation here.&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= How do you write a new type of modal? =&lt;br /&gt;
If you&#039;d like to write a new type of modal to be re-used throughout your code you can extend the default modal implementation and make any customisations you require. In order to create a new modal type you&#039;ll need to create a new AMD module and import the core/modal module to extend. You can also optionally create a new modal template that builds upon the core/modal template. Finally, you can register your new type with the modal registry to allow you to create your new type using the modal factory.&lt;br /&gt;
&lt;br /&gt;
For example, let&#039;s create a modal that opens a login form:&lt;br /&gt;
First we can create the HTML for out modal by including and extending the core modal template. All we need to do is override the block defined in that template with our new title, body and footer content.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume the file is &amp;lt;your_module&amp;gt;/templates/modal_login.mustache&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
{{&amp;lt; core/modal }}&lt;br /&gt;
    {{$title}}{{#str}} login {{/str}}{{/title}}&lt;br /&gt;
    {{$body}}&lt;br /&gt;
        &amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;form&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;form-group row&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;label for=&amp;quot;inputEmail&amp;quot; class=&amp;quot;col-sm-2 col-form-label&amp;quot;&amp;gt;{{#str}} email {{/str}}&amp;lt;/label&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;col-sm-10&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;input type=&amp;quot;email&amp;quot; class=&amp;quot;form-control&amp;quot; id=&amp;quot;inputEmail&amp;quot; placeholder=&amp;quot;{{#str}} email {{/str}}&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;form-group row&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;label for=&amp;quot;inputPassword&amp;quot; class=&amp;quot;col-sm-2 col-form-label&amp;quot;&amp;gt;{{#str}} password {{/str}}&amp;lt;/label&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;col-sm-10&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;input type=&amp;quot;password&amp;quot; class=&amp;quot;form-control&amp;quot; id=&amp;quot;inputPassword&amp;quot; placeholder=&amp;quot;{{#str}} password {{/str}}&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/form&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    {{/body}}&lt;br /&gt;
    {{$footer}}&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;btn btn-primary&amp;quot; data-action=&amp;quot;login&amp;quot;&amp;gt;{{#str}} login {{/str}}&amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot; data-action=&amp;quot;cancel&amp;quot;&amp;gt;{{#str}} cancel {{/str}}&amp;lt;/button&amp;gt;&lt;br /&gt;
    {{/footer}}&lt;br /&gt;
{{/ core/modal }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next we can create the new AMD module for the login modal. You can extend the existing modal module which will give you all of the core modal functionality for free allowing you to focus on writing only the specific logic you need. In this example we would only need to write the logic for handling the login.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume the file is &amp;lt;your_module&amp;gt;/amd/src/modal_login.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;, &#039;core/notification&#039;, &#039;core/custom_interaction_events&#039;, &#039;core/modal&#039;, &#039;core/modal_registry&#039;],&lt;br /&gt;
        function($, Notification, CustomEvents, Modal, ModalRegistry) {&lt;br /&gt;
&lt;br /&gt;
    var registered = false;&lt;br /&gt;
    var SELECTORS = {&lt;br /&gt;
        LOGIN_BUTTON: &#039;[data-action=&amp;quot;login&amp;quot;]&#039;,&lt;br /&gt;
        CANCEL_BUTTON: &#039;[data-action=&amp;quot;cancel&amp;quot;]&#039;,&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Constructor for the Modal.&lt;br /&gt;
     *&lt;br /&gt;
     * @param {object} root The root jQuery element for the modal&lt;br /&gt;
     */&lt;br /&gt;
    var ModalLogin = function(root) {&lt;br /&gt;
        Modal.call(this, root);&lt;br /&gt;
&lt;br /&gt;
        if (!this.getFooter().find(SELECTORS.LOGIN_BUTTON).length) {&lt;br /&gt;
            Notification.exception({message: &#039;No login button found&#039;});&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!this.getFooter().find(SELECTORS.CANCEL_BUTTON).length) {&lt;br /&gt;
            Notification.exception({message: &#039;No cancel button found&#039;});&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    ModalLogin.TYPE = &#039;your_module-login&#039;;&lt;br /&gt;
    ModalLogin.prototype = Object.create(Modal.prototype);&lt;br /&gt;
    ModalLogin.prototype.constructor = ModalLogin;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Set up all of the event handling for the modal.&lt;br /&gt;
     *&lt;br /&gt;
     * @method registerEventListeners&lt;br /&gt;
     */&lt;br /&gt;
    ModalLogin.prototype.registerEventListeners = function() {&lt;br /&gt;
        // Apply parent event listeners.&lt;br /&gt;
        Modal.prototype.registerEventListeners.call(this);&lt;br /&gt;
&lt;br /&gt;
        this.getModal().on(CustomEvents.events.activate, SELECTORS.LOGIN_BUTTON, function(e, data) {&lt;br /&gt;
            // Add your logic for when the login button is clicked. This could include the form validation,&lt;br /&gt;
            // loading animations, error handling etc.&lt;br /&gt;
        }.bind(this));&lt;br /&gt;
&lt;br /&gt;
        this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, function(e, data) {&lt;br /&gt;
            // Add your logic for when the cancel button is clicked.&lt;br /&gt;
        }.bind(this));&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    // Automatically register with the modal registry the first time this module is imported so that you can create modals&lt;br /&gt;
    // of this type using the modal factory.&lt;br /&gt;
    if (!registered) {&lt;br /&gt;
        ModalRegistry.register(ModalLogin.TYPE, ModalLogin, &#039;&amp;lt;your_module&amp;gt;/modal_login&#039;);&lt;br /&gt;
        registered = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return ModalLogin;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once you have both your template and javascript ready to go then all you need to do is tie them into where ever you&#039;d like to launch the modal. For the purpose of this example let&#039;s assume that we&#039;ve got a page with a login button with id=&amp;quot;login&amp;quot; then you might add this javascript to the page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/templates&#039;, &#039;core/modal_factory&#039;, &#039;&amp;lt;your_module&amp;gt;/modal_login&#039;], function($, Templates, ModalFactory, ModalLogin) {&lt;br /&gt;
    var trigger = $(&#039;#login&#039;);&lt;br /&gt;
&lt;br /&gt;
    ModalFactory.create({type: ModalLogin.TYPE}, trigger); &lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51850</id>
		<title>My course overview improvements</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51850"/>
		<updated>2017-02-06T06:15:39Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page will detail the technical specification for the improvements to the My course overview block.&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Improvements to my course overview block.&lt;br /&gt;
|state = Starting&lt;br /&gt;
|tracker = MDL-55611&lt;br /&gt;
|discussion = https://tracker.moodle.org/browse/UX-8&lt;br /&gt;
|assignee = HQ Projects Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
The new design for the UI for the course overview block requires the ability for Moodle to efficiently query plugins for a list of &amp;quot;date based&amp;quot; tasks for the current user.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;quot;mod print_overview&amp;quot; callbacks do not have sufficient functionality (no separation of fields, inefficient, incomplete, no relation to completion API, inconsistently implemented across modules) so we will have to build a new API (and deprecate mod_xx_print_overview). &lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
https://docs.google.com/document/d/13ukTgOBdDzkKmPhfyMH81inWkbfJL5CPsyQmLBDWq5k/edit&lt;br /&gt;
&lt;br /&gt;
== Technical Details ==&lt;br /&gt;
=== Course Overview Block ===&lt;br /&gt;
The course overview block will communicate exclusively with the Todo API and will present the Todo&#039;s as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.&lt;br /&gt;
&lt;br /&gt;
* Mustache templates:&lt;br /&gt;
** General template for the block (wrapping template)&lt;br /&gt;
*** Timeline view&lt;br /&gt;
**** Sort by dates (wrapping template)&lt;br /&gt;
***** Template for displaying single todo (rendered in list)&lt;br /&gt;
**** Sort by courses (wrapping template)&lt;br /&gt;
***** Single course section, includes list of todos similar to &amp;quot;sort by dates&amp;quot; (can maybe re-use the template for a single todo here)&lt;br /&gt;
** Courses view&lt;br /&gt;
*** Single template can probably be re-used for &amp;quot;in progress&amp;quot;, &amp;quot;upcoming&amp;quot; and &amp;quot;completed&amp;quot; views, just rendered with different data&lt;br /&gt;
*** As above, single template for a course&lt;br /&gt;
* Javascript&lt;br /&gt;
** Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)&lt;br /&gt;
** Module for timeline view (maybe even have separate modules for &amp;quot;sort by dates&amp;quot; and &amp;quot;sort by courses&amp;quot;?). Handles requesting the data and rendering the templates etc.&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Module for courses view that handles requesting the data and rendering the templates&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Use the new pie chart we add&lt;br /&gt;
** User the todo api javascript module to interact with the server external API&lt;br /&gt;
* CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)&lt;br /&gt;
** Style Boost theme&lt;br /&gt;
** Style bootstrap base theme (e.g. clean)&lt;br /&gt;
** Add responsive styling (need to ask the UX team for some mock ups of smaller resolutions)&lt;br /&gt;
* Accessibility: Add the appropriate aria attributes to each of the templates above to make the block accessible by a screen reader (more work than it seems)&lt;br /&gt;
* Update blocks/course_overview/block_course_overview.php &amp;quot;get_content&amp;quot; to render a template via the renderer (need to add a new function)&lt;br /&gt;
* Remove the existing functions being used to render the course overview (including functions in the renderer and lib.php)&lt;br /&gt;
* Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)&lt;br /&gt;
&lt;br /&gt;
=== Action Event API ===&lt;br /&gt;
This will be a new API in core to represent the concept of &amp;quot;action events&amp;quot; in Moodle, i.e. the list of items displayed in the course overview block. A action event is made up of a calendar event and an associated action for the user. &lt;br /&gt;
&lt;br /&gt;
The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can&#039;t be started until after another module has been completed etc. &lt;br /&gt;
&lt;br /&gt;
Given the intensity of some of these calculations we&#039;ll need to look into aggressively caching results and maybe even avoid doing the calculations per request.&lt;br /&gt;
&lt;br /&gt;
Since we&#039;re leveraging the existing calendar events for the static data we may not need to actually persist the todos anywhere other than caching.&lt;br /&gt;
&lt;br /&gt;
* Add a todo class (pretty please can we have an actual class rather than just stdClass)&lt;br /&gt;
** Some properties of the class:&lt;br /&gt;
*** unique id (context id, component, area and item id?)&lt;br /&gt;
*** name - the name of the thing the todo relates to (e.g. activity name)&lt;br /&gt;
*** url - the url of the thing the todo relates to (e.g. view.php of the module)&lt;br /&gt;
*** user id - the id of the user this todo belong to&lt;br /&gt;
*** course id - the course if that the todo relates to&lt;br /&gt;
*** icon url - the icon for the todo (default to the module icon)&lt;br /&gt;
*** start date (optional) - when the todo starts&lt;br /&gt;
*** end date (optional) - when the todo must be actioned by&lt;br /&gt;
*** item count - how many associated items there are (e.g. 4 unread posts)&lt;br /&gt;
*** action name - display name of the todo (e.g. &amp;quot;submit assignment&amp;quot;)&lt;br /&gt;
*** action url - url of the todo action (e.g. link to the assignment submission page)&lt;br /&gt;
*** action start date - a date after which the todo can be actioned (only display the action url after this date)&lt;br /&gt;
*** action state - Has this been actioned? Eg, The assignment was submitted.&lt;br /&gt;
* Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).&lt;br /&gt;
** Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).&lt;br /&gt;
* Add a data access layer that abstracts away all of the SQL so that we don&#039;t have that logic everywhere (ideally).&lt;br /&gt;
** The API class would benefit from this.&lt;br /&gt;
** It can also hide the fact that we&#039;re piggy backing on the calendar events, just in case we want to change that in the future.&lt;br /&gt;
** It can also handle all of the caching&lt;br /&gt;
** Support pagination as above&lt;br /&gt;
* Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).&lt;br /&gt;
** The core action event API can&#039;t (and shouldn&#039;t) know every place that will want to create a action event, so we need to provide a standard way for each plugin to register itself as something that will create an action event and an interface for them to do the data manipulation required.&lt;br /&gt;
* Add an external API class.&lt;br /&gt;
** This class shouldn&#039;t contain any business logic (that all lives in the API class). &lt;br /&gt;
** It needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the action event.&lt;br /&gt;
** All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.&lt;br /&gt;
* Add some renderables for the action event&lt;br /&gt;
** The action events should probably just be renderable / template-able themselves&lt;br /&gt;
** These will be used by the external API class.&lt;br /&gt;
* Improve performance using caching (this will be trial and error with the performance testing)&lt;br /&gt;
* Write unit tests for all new API functions and external API functions&lt;br /&gt;
* Add a javascript module to interact with the action event API (no bespoke ajax requests everywhere please)&lt;br /&gt;
&lt;br /&gt;
=== Chart.js ===&lt;br /&gt;
* Add a new chart type (pie chart) to Moodle&#039;s chart API for use in the templates above&lt;br /&gt;
&lt;br /&gt;
=== Calendar Event API ===&lt;br /&gt;
We&#039;ll be using the existing calendar events as the basis for the &amp;quot;action events&amp;quot;. The current calendar event data structure contains most of the data that we&#039;ll need so we&#039;ll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we&#039;ll need.&lt;br /&gt;
&lt;br /&gt;
* Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation&lt;br /&gt;
* Add indexes to the event table if they are missing&lt;br /&gt;
** display/order by date&lt;br /&gt;
** course id&lt;br /&gt;
** user id&lt;br /&gt;
* Add functions to the calendar event API to retrieve groups of events for a given user(s)&lt;br /&gt;
** currently it seems the API only loads one at a time so you need to do direct SQL in the calling code&lt;br /&gt;
** API should probably handle grouping of results, e.g. events for a user would be the distinct set of any course level events + group event override + user event override, where each has higher precedence than the last in the result set&lt;br /&gt;
** API needs to support order by new date field&lt;br /&gt;
** API needs to support limit and offset&lt;br /&gt;
* Add unit tests for new API functions&lt;br /&gt;
&lt;br /&gt;
=== Calendar Block ===&lt;br /&gt;
* Make sure all of the action events are showing up in the calendar for the user&lt;br /&gt;
** Note: we *should* get this for free since we are simply creating calendar events&lt;br /&gt;
* Make sure we are only displaying appropriate events (ie. if there is a user override then show that for the user, not multiple).&lt;br /&gt;
&lt;br /&gt;
=== Course Completion Tracking ===&lt;br /&gt;
* Develop a way to track completion on for all courses&lt;br /&gt;
** This needs to take into account all activities within the course, even ones that don&#039;t have any completion tracking enabled&lt;br /&gt;
* Add an API to query the completion status of a course that implements the agreed approach&lt;br /&gt;
* Do we need to persist the course progress somewhere or can it be calculated at run time?&lt;br /&gt;
** Assess performance of both options&lt;br /&gt;
* If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate&lt;br /&gt;
&lt;br /&gt;
==== Notes ====&lt;br /&gt;
There are different ways of calculating the completion percentage for a course and some will be more informative than others, depending on the type of usage of the course.&lt;br /&gt;
&lt;br /&gt;
Some possible options are:&lt;br /&gt;
* The number of completed+visible activities / The number of visible activities&lt;br /&gt;
* The number of completed activities / The number of activities&lt;br /&gt;
* The current week / the number of weeks&lt;br /&gt;
* The (current date - course start date) / (course end date - course start date) * Requires a course end date&lt;br /&gt;
* The current course grade / the required course grade (don’t expose hidden grades)&lt;br /&gt;
* The enrolment duration / the required enrolment duration&lt;br /&gt;
&lt;br /&gt;
Because each course completion criteria requires a different calculation, one possible method is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;If course completion is enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
for each course completion criteria - get the current and total possible values for completion&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;if all are required:&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
normalise and sum/average the values&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;if any is required&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
calculate the highest percentage completion&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;If only activity completion is enabled (and not course completion)&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
calculate the completion percentage purely on the number of activities complete / the total number of activities. (Ignoring activities with no completion - should we ignore activities the current user cannot see via access restrictions?)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;If course completion is not enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Try and calculation the completion based purely on the course start / end date&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;To calculate the current and total values for each completion criteria:&#039;&#039;&#039;&lt;br /&gt;
* Activity completion - number of activities complete / number of activities required to be completed&lt;br /&gt;
* Completion of other courses - number of courses complete / number of courses required to be completed&lt;br /&gt;
* Enrolment Date - the current date - course start date / the enrolled until date - course start date. If there is no course start date use the enrolment start date. Max of 1.&lt;br /&gt;
* Enroled duration - the number of days enrolled / the number of days required to be enrolled. Max of 1.&lt;br /&gt;
* Unenrollment. 0 if enrolled, 1 if unenrolled.&lt;br /&gt;
* Course grade - current course grade / required course grade. Max of 1.&lt;br /&gt;
* Manual self completion. 0 if not complete, 1 if complete&lt;br /&gt;
* Manual completion by others. 0 if not complete, 1 if complete&lt;br /&gt;
&lt;br /&gt;
=== General Moodle stuff ===&lt;br /&gt;
* Remove all uses of the &amp;quot;print_overview&amp;quot; callback thingo we&#039;re using through Moodle for modules to add stuff to the course overview block&lt;br /&gt;
* Find all of the places in Moodle that need to generate create a todo and have them create appropriate calendar events&lt;br /&gt;
** A list has been started here https://docs.google.com/document/d/1qfl2MEzdZcNlT2rvBSsIgWhRZsloRnsb2m5TALFn_C8/edit&lt;br /&gt;
* Find all of the places that may affect the status of a calendar event and update the event to make sure it is accurate (eg. editing a module, submitting an assignment, changing course dates etc)&lt;br /&gt;
* Add an implementation of the callback interface thingo to each module that will be creating a todo &lt;br /&gt;
** This implementation will take a calendar event and the user and do all of the appropriate checks to see if the user should see the todo, etc&lt;br /&gt;
** It will then create the appropriate todo from the calendar event and add all of the action stuff.&lt;br /&gt;
&lt;br /&gt;
=== General Testing ===&lt;br /&gt;
* We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51570</id>
		<title>My course overview improvements</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51570"/>
		<updated>2016-12-13T03:08:53Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page will detail the technical specification for the improvements to the My course overview block.&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Improvements to my course overview block.&lt;br /&gt;
|state = Starting&lt;br /&gt;
|tracker = MDL-55611&lt;br /&gt;
|discussion = https://tracker.moodle.org/browse/UX-8&lt;br /&gt;
|assignee = HQ Projects Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
The new design for the UI for the course overview block requires the ability for Moodle to efficiently query plugins for a list of &amp;quot;date based&amp;quot; tasks for the current user.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;quot;mod print_overview&amp;quot; callbacks do not have sufficient functionality (no separation of fields, inefficient, incomplete, no relation to completion API, inconsistently implemented across modules) so we will have to build a new API (and deprecate mod_xx_print_overview). &lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Course Overview Block ===&lt;br /&gt;
The course overview block will communicate exclusively with the Todo API and will present the Todo&#039;s as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.&lt;br /&gt;
&lt;br /&gt;
* Mustache templates:&lt;br /&gt;
** General template for the block (wrapping template)&lt;br /&gt;
*** Timeline view&lt;br /&gt;
**** Sort by dates (wrapping template)&lt;br /&gt;
***** Template for displaying single todo (rendered in list)&lt;br /&gt;
**** Sort by courses (wrapping template)&lt;br /&gt;
***** Single course section, includes list of todos similar to &amp;quot;sort by dates&amp;quot; (can maybe re-use the template for a single todo here)&lt;br /&gt;
** Courses view&lt;br /&gt;
*** Single template can probably be re-used for &amp;quot;in progress&amp;quot;, &amp;quot;upcoming&amp;quot; and &amp;quot;completed&amp;quot; views, just rendered with different data&lt;br /&gt;
*** As above, single template for a course&lt;br /&gt;
* Javascript&lt;br /&gt;
** Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)&lt;br /&gt;
** Module for timeline view (maybe even have separate modules for &amp;quot;sort by dates&amp;quot; and &amp;quot;sort by courses&amp;quot;?). Handles requesting the data and rendering the templates etc.&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Module for courses view that handles requesting the data and rendering the templates&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Use the new pie chart we add&lt;br /&gt;
** User the todo api javascript module to interact with the server external API&lt;br /&gt;
* CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)&lt;br /&gt;
** Style Boost theme&lt;br /&gt;
** Style bootstrap base theme (e.g. clean)&lt;br /&gt;
** Add responsive styling (need to ask the UX team for some mock ups of smaller resolutions)&lt;br /&gt;
* Accessibility: Add the appropriate aria attributes to each of the templates above to make the block accessible by a screen reader (more work than it seems)&lt;br /&gt;
* Update blocks/course_overview/block_course_overview.php &amp;quot;get_content&amp;quot; to render a template via the renderer (need to add a new function)&lt;br /&gt;
* Remove the existing functions being used to render the course overview (including functions in the renderer and lib.php)&lt;br /&gt;
* Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)&lt;br /&gt;
&lt;br /&gt;
=== Todo API ===&lt;br /&gt;
This will be a new API in core to represent the concept of &amp;quot;todos&amp;quot; in Moodle, i.e. the list of items displayed in the course overview block. A todo is made up of a calendar event and an associated action for the user. &lt;br /&gt;
&lt;br /&gt;
The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can&#039;t be started until after another module has been completed etc. &lt;br /&gt;
&lt;br /&gt;
Given the intensity of some of these calculations we&#039;ll need to look into aggressively caching results and maybe even avoid doing the calculations per request.&lt;br /&gt;
&lt;br /&gt;
Since we&#039;re leveraging the existing calendar events for the static data we may not need to actually persist the todos anywhere other than caching.&lt;br /&gt;
&lt;br /&gt;
* Add a todo class (pretty please can we have an actual class rather than just stdClass)&lt;br /&gt;
** Some properties of the class:&lt;br /&gt;
*** unique id (context id, component, area and item id?)&lt;br /&gt;
*** name - the name of the thing the todo relates to (e.g. activity name)&lt;br /&gt;
*** url - the url of the thing the todo relates to (e.g. view.php of the module)&lt;br /&gt;
*** user id - the id of the user this todo belong to&lt;br /&gt;
*** course id - the course if that the todo relates to&lt;br /&gt;
*** icon url - the icon for the todo (default to the module icon)&lt;br /&gt;
*** start date (optional) - when the todo starts&lt;br /&gt;
*** end date (optional) - when the todo must be actioned by&lt;br /&gt;
*** item count - how many associated items there are (e.g. 4 unread posts)&lt;br /&gt;
*** action name - display name of the todo (e.g. &amp;quot;submit assignment&amp;quot;)&lt;br /&gt;
*** action url - url of the todo action (e.g. link to the assignment submission page)&lt;br /&gt;
*** action start date - a date after which the todo can be actioned (only display the action url after this date)&lt;br /&gt;
* Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).&lt;br /&gt;
** Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).&lt;br /&gt;
* Add a data access layer that abstracts away all of the SQL so that we don&#039;t have that logic everywhere (ideally).&lt;br /&gt;
** The API class would benefit from this.&lt;br /&gt;
** It can also hide the fact that we&#039;re piggy backing on the calendar events, just in case we want to change that in the future.&lt;br /&gt;
** It can also handle all of the caching&lt;br /&gt;
** Support pagination as above&lt;br /&gt;
* Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).&lt;br /&gt;
** The core todo API can&#039;t (and shouldn&#039;t) know every place that will want to create a todo, so we need to provide a standard way for each plugin to register itself as something that will create a todo and an interface for them to do the data manipulation required.&lt;br /&gt;
* Add an external API class.&lt;br /&gt;
** This class shouldn&#039;t contain any business logic (that all lives in the API class). &lt;br /&gt;
** It needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the todo.&lt;br /&gt;
** All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.&lt;br /&gt;
* Add some renderables for the todo&lt;br /&gt;
** The todos should probably just be renderable / template-able themselves&lt;br /&gt;
** These will be used by the external API class.&lt;br /&gt;
* Improve performance using caching (this will be trial and error with the performance testing)&lt;br /&gt;
* Write unit tests for all new API functions and external API functions&lt;br /&gt;
* Add a javascript module to interact with the Todo API (no bespoke ajax requests everywhere please)&lt;br /&gt;
&lt;br /&gt;
=== Chart.js ===&lt;br /&gt;
* Add a new chart type (pie chart) to Moodle&#039;s chart API for use in the templates above&lt;br /&gt;
&lt;br /&gt;
=== Calendar Event API ===&lt;br /&gt;
We&#039;ll be using the existing calendar events as the basis for the &amp;quot;todos&amp;quot;. The current calendar event data structure contains most of the data that we&#039;ll need so we&#039;ll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we&#039;ll need.&lt;br /&gt;
&lt;br /&gt;
* Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation&lt;br /&gt;
* Add indexes to the event table if they are missing&lt;br /&gt;
** display/order by date&lt;br /&gt;
** course id&lt;br /&gt;
** user id&lt;br /&gt;
* Add functions to the calendar event API to retrieve groups of events for a given user(s)&lt;br /&gt;
** currently it seems the API only loads one at a time so you need to do direct SQL in the calling code&lt;br /&gt;
** API should probably handle grouping of results, e.g. events for a user would be the distinct set of any course level events + group event override + user event override, where each has higher precedence than the last in the result set&lt;br /&gt;
** API needs to support order by new date field&lt;br /&gt;
** API needs to support limit and offset&lt;br /&gt;
* Add unit tests for new API functions&lt;br /&gt;
&lt;br /&gt;
=== Calendar Block ===&lt;br /&gt;
* Make sure all of the todos are showing up in the calendar for the user&lt;br /&gt;
** Note: we *should* get this for free since we are simply creating calendar events&lt;br /&gt;
&lt;br /&gt;
=== Course Completion Tracking ===&lt;br /&gt;
* Develop a way to track completion on for all courses&lt;br /&gt;
** This needs to take into account all activities within the course, even ones that don&#039;t have any completion tracking enabled&lt;br /&gt;
* Add an API to query the completion status of a course that implements the agreed approach&lt;br /&gt;
* Do we need to persist the course progress somewhere or can it be calculated at run time?&lt;br /&gt;
** Assess performance of both options&lt;br /&gt;
* If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate&lt;br /&gt;
&lt;br /&gt;
=== General Moodle stuff ===&lt;br /&gt;
* Remove all uses of the &amp;quot;print_overview&amp;quot; callback thingo we&#039;re using through Moodle for modules to add stuff to the course overview block&lt;br /&gt;
* Find all of the places in Moodle that need to generate create a todo and have them create appropriate calendar events&lt;br /&gt;
** A list has been started here https://docs.google.com/document/d/1qfl2MEzdZcNlT2rvBSsIgWhRZsloRnsb2m5TALFn_C8/edit&lt;br /&gt;
* Find all of the places that may affect the status of a calendar event and update the event to make sure it is accurate (eg. editing a module, submitting an assignment, changing course dates etc)&lt;br /&gt;
* Add an implementation of the callback interface thingo to each module that will be creating a todo &lt;br /&gt;
** This implementation will take a calendar event and the user and do all of the appropriate checks to see if the user should see the todo, etc&lt;br /&gt;
** It will then create the appropriate todo from the calendar event and add all of the action stuff.&lt;br /&gt;
&lt;br /&gt;
=== General Testing ===&lt;br /&gt;
* We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.&lt;br /&gt;
&lt;br /&gt;
=== Proof Of Concept Code ===&lt;br /&gt;
I&#039;ve knocked together a little proof of concept type branch that does a skeleton implementation of some of this stuff. You can find it here https://github.com/moodle/moodle/compare/e6cb76d...ryanwyllie:todos_poc_2&lt;br /&gt;
&lt;br /&gt;
Please review it and add any comments or what ever.&lt;br /&gt;
&lt;br /&gt;
== Questions for the UX team ==&lt;br /&gt;
* How many items to display in &amp;quot;Next 7 days&amp;quot;? Is there a limit, or we always show all of the items?&lt;br /&gt;
* In the prototype 6c (the one that we are supposed to develop from) the todo disappears from the list when it is actioned. Is this the correct behaviour? What happens to the corresponding event in the calendar? Does that also get removed?&lt;br /&gt;
* What do we show when a todo is only available for a certain duration? E.g. chat where it&#039;s open for only 3 days. Only having the end date seems weird in that case.&lt;br /&gt;
* Is the list of courses paginated in the courses view? Is there a &amp;quot;More&amp;quot; button to load more courses?&lt;br /&gt;
* What happens with courses which do not have a start date, and end date? Will they show in &amp;quot;In progress&amp;quot; for as long as I am enrolled in them? Note that if I unenrol from the course, I will lose access to it.&lt;br /&gt;
* Are all the three tabs (in progress, upcoming, completed) always shown, even if they are empty?&lt;br /&gt;
* When an activity combines both a &#039;&#039;due date&#039;&#039; and an &#039;&#039;expected completed on&#039;&#039; date (e.g. assignment module with completion), what is the date of the task?&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51568</id>
		<title>My course overview improvements</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51568"/>
		<updated>2016-12-13T01:22:27Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page will detail the technical specification for the improvements to the My course overview block.&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Improvements to my course overview block.&lt;br /&gt;
|state = Starting&lt;br /&gt;
|tracker = MDL-55611&lt;br /&gt;
|discussion = https://tracker.moodle.org/browse/UX-8&lt;br /&gt;
|assignee = HQ Projects Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
The new design for the UI for the course overview block requires the ability for Moodle to efficiently query plugins for a list of &amp;quot;date based&amp;quot; tasks for the current user.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;quot;mod print_overview&amp;quot; callbacks do not have sufficient functionality (no separation of fields, inefficient, incomplete, no relation to completion API, inconsistently implemented across modules) so we will have to build a new API (and deprecate mod_xx_print_overview). &lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Course Overview Block ===&lt;br /&gt;
The course overview block will communicate exclusively with the Todo API and will present the Todo&#039;s as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.&lt;br /&gt;
&lt;br /&gt;
* Mustache templates:&lt;br /&gt;
** General template for the block (wrapping template)&lt;br /&gt;
*** Timeline view&lt;br /&gt;
**** Sort by dates (wrapping template)&lt;br /&gt;
***** Template for displaying single todo (rendered in list)&lt;br /&gt;
**** Sort by courses (wrapping template)&lt;br /&gt;
***** Single course section, includes list of todos similar to &amp;quot;sort by dates&amp;quot; (can maybe re-use the template for a single todo here)&lt;br /&gt;
** Courses view&lt;br /&gt;
*** Single template can probably be re-used for &amp;quot;in progress&amp;quot;, &amp;quot;upcoming&amp;quot; and &amp;quot;completed&amp;quot; views, just rendered with different data&lt;br /&gt;
*** As above, single template for a course&lt;br /&gt;
* Javascript&lt;br /&gt;
** Add a module to interact with the Todo API (no bespoke ajax requests everywhere please)&lt;br /&gt;
** Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)&lt;br /&gt;
** Module for timeline view (maybe even have separate modules for &amp;quot;sort by dates&amp;quot; and &amp;quot;sort by courses&amp;quot;?). Handles requesting the data and rendering the templates etc.&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Module for courses view that handles requesting the data and rendering the templates&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Use the new pie chart we add&lt;br /&gt;
* CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)&lt;br /&gt;
** Style Boost theme&lt;br /&gt;
** Style bootstrap base theme (e.g. clean)&lt;br /&gt;
** Add responsive styling (need to ask the UX team for some mock ups of smaller resolutions)&lt;br /&gt;
* Accessibility: Add the appropriate aria attributes to each of the templates above to make the block accessible by a screen reader (more work than it seems)&lt;br /&gt;
* Update blocks/course_overview/block_course_overview.php &amp;quot;get_content&amp;quot; to render a template via the renderer (need to add a new function)&lt;br /&gt;
* Remove the existing functions being used to render the course overview (including functions in the renderer and lib.php)&lt;br /&gt;
* Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)&lt;br /&gt;
&lt;br /&gt;
=== Todo API ===&lt;br /&gt;
This will be a new API in core to represent the concept of &amp;quot;todos&amp;quot; in Moodle, i.e. the list of items displayed in the course overview block. A todo is made up of a calendar event and an associated action for the user. &lt;br /&gt;
&lt;br /&gt;
The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can&#039;t be started until after another module has been completed etc. &lt;br /&gt;
&lt;br /&gt;
Given the intensity of some of these calculations we&#039;ll need to look into aggressively caching results and maybe even avoid doing the calculations per request.&lt;br /&gt;
&lt;br /&gt;
Since we&#039;re leveraging the existing calendar events for the static data we may not need to actually persist the todos anywhere other than caching.&lt;br /&gt;
&lt;br /&gt;
* Add a todo class (pretty please can we have an actual class rather than just stdClass)&lt;br /&gt;
** Some properties of the class:&lt;br /&gt;
*** unique id (context id, component, area and item id?)&lt;br /&gt;
*** name - the name of the thing the todo relates to (e.g. activity name)&lt;br /&gt;
*** url - the url of the thing the todo relates to (e.g. view.php of the module)&lt;br /&gt;
*** user id - the id of the user this todo belong to&lt;br /&gt;
*** course id - the course if that the todo relates to&lt;br /&gt;
*** icon url - the icon for the todo (default to the module icon)&lt;br /&gt;
*** start date (optional) - when the todo starts&lt;br /&gt;
*** end date (optional) - when the todo must be actioned by&lt;br /&gt;
*** item count - how many associated items there are (e.g. 4 unread posts)&lt;br /&gt;
*** action name - display name of the todo (e.g. &amp;quot;submit assignment&amp;quot;)&lt;br /&gt;
*** action url - url of the todo action (e.g. link to the assignment submission page)&lt;br /&gt;
*** action start date - a date after which the todo can be actioned (only display the action url after this date)&lt;br /&gt;
* Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).&lt;br /&gt;
** Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).&lt;br /&gt;
* Add a data access layer that abstracts away all of the SQL so that we don&#039;t have that logic everywhere (ideally).&lt;br /&gt;
** The API class would benefit from this.&lt;br /&gt;
** It can also hide the fact that we&#039;re piggy backing on the calendar events, just in case we want to change that in the future.&lt;br /&gt;
** It can also handle all of the caching&lt;br /&gt;
** Support pagination as above&lt;br /&gt;
* Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).&lt;br /&gt;
** The core todo API can&#039;t (and shouldn&#039;t) know every place that will want to create a todo, so we need to provide a standard way for each plugin to register itself as something that will create a todo and an interface for them to do the data manipulation required.&lt;br /&gt;
* Add an external API class.&lt;br /&gt;
** This class shouldn&#039;t contain any business logic (that all lives in the API class). &lt;br /&gt;
** It needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the todo.&lt;br /&gt;
** All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.&lt;br /&gt;
* Add some renderables for the todo&lt;br /&gt;
** The todos should probably just be renderable / template-able themselves&lt;br /&gt;
** These will be used by the external API class.&lt;br /&gt;
* Improve performance using caching (this will be trial and error with the performance testing)&lt;br /&gt;
* Write unit tests for all new API functions and external API functions&lt;br /&gt;
&lt;br /&gt;
=== Chart.js ===&lt;br /&gt;
* Add a new chart type (pie chart) to Moodle&#039;s chart API for use in the templates above&lt;br /&gt;
&lt;br /&gt;
=== Calendar Event API ===&lt;br /&gt;
We&#039;ll be using the existing calendar events as the basis for the &amp;quot;todos&amp;quot;. The current calendar event data structure contains most of the data that we&#039;ll need so we&#039;ll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we&#039;ll need.&lt;br /&gt;
&lt;br /&gt;
* Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation&lt;br /&gt;
* Add indexes to the event table if they are missing&lt;br /&gt;
** display/order by date&lt;br /&gt;
** course id&lt;br /&gt;
** user id&lt;br /&gt;
* Add functions to the calendar event API to retrieve groups of events for a given user(s)&lt;br /&gt;
** currently it seems the API only loads one at a time so you need to do direct SQL in the calling code&lt;br /&gt;
** API should probably handle grouping of results, e.g. events for a user would be the distinct set of any course level events + group event override + user event override, where each has higher precedence than the last in the result set&lt;br /&gt;
** API needs to support order by new date field&lt;br /&gt;
** API needs to support limit and offset&lt;br /&gt;
* Add unit tests for new API functions&lt;br /&gt;
&lt;br /&gt;
=== Calendar Block ===&lt;br /&gt;
* Make sure all of the todos are showing up in the calendar for the user&lt;br /&gt;
** Note: we *should* get this for free since we are simply creating calendar events&lt;br /&gt;
&lt;br /&gt;
=== Course Completion Tracking ===&lt;br /&gt;
* Develop a way to track completion on for all courses&lt;br /&gt;
** This needs to take into account all activities within the course, even ones that don&#039;t have any completion tracking enabled&lt;br /&gt;
* Add an API to query the completion status of a course that implements the agreed approach&lt;br /&gt;
* Do we need to persist the course progress somewhere or can it be calculated at run time?&lt;br /&gt;
** Assess performance of both options&lt;br /&gt;
* If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate&lt;br /&gt;
&lt;br /&gt;
=== General Moodle stuff ===&lt;br /&gt;
* Remove all uses of the &amp;quot;print_overview&amp;quot; callback thingo we&#039;re using through Moodle for modules to add stuff to the course overview block&lt;br /&gt;
* Find all of the places in Moodle that need to generate create a todo and have them create appropriate calendar events&lt;br /&gt;
** A list has been started here https://docs.google.com/document/d/1qfl2MEzdZcNlT2rvBSsIgWhRZsloRnsb2m5TALFn_C8/edit&lt;br /&gt;
* Find all of the places that may affect the status of a calendar event and update the event to make sure it is accurate (eg. editing a module, submitting an assignment, changing course dates etc)&lt;br /&gt;
* Add an implementation of the callback interface thingo to each module that will be creating a todo &lt;br /&gt;
** This implementation will take a calendar event and the user and do all of the appropriate checks to see if the user should see the todo, etc&lt;br /&gt;
** It will then create the appropriate todo from the calendar event and add all of the action stuff.&lt;br /&gt;
&lt;br /&gt;
=== General Testing ===&lt;br /&gt;
* We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.&lt;br /&gt;
&lt;br /&gt;
=== Proof Of Concept Code ===&lt;br /&gt;
I&#039;ve knocked together a little proof of concept type branch that does a skeleton implementation of some of this stuff. You can find it here https://github.com/moodle/moodle/compare/e6cb76d...ryanwyllie:todos_poc_2&lt;br /&gt;
&lt;br /&gt;
Please review it and add any comments or what ever.&lt;br /&gt;
&lt;br /&gt;
== Questions for the UX team ==&lt;br /&gt;
* How many items to display in &amp;quot;Next 7 days&amp;quot;? Is there a limit, or we always show all of the items?&lt;br /&gt;
* In the prototype 6c (the one that we are supposed to develop from) the todo disappears from the list when it is actioned. Is this the correct behaviour? What happens to the corresponding event in the calendar? Does that also get removed?&lt;br /&gt;
* What do we show when a todo is only available for a certain duration? E.g. chat where it&#039;s open for only 3 days. Only having the end date seems weird in that case.&lt;br /&gt;
* Is the list of courses paginated in the courses view? Is there a &amp;quot;More&amp;quot; button to load more courses?&lt;br /&gt;
* What happens with courses which do not have a start date, and end date? Will they show in &amp;quot;In progress&amp;quot; for as long as I am enrolled in them? Note that if I unenrol from the course, I will lose access to it.&lt;br /&gt;
* Are all the three tabs (in progress, upcoming, completed) always shown, even if they are empty?&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51567</id>
		<title>My course overview improvements</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51567"/>
		<updated>2016-12-13T01:18:51Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page will detail the technical specification for the improvements to the My course overview block.&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Improvements to my course overview block.&lt;br /&gt;
|state = Starting&lt;br /&gt;
|tracker = MDL-55611&lt;br /&gt;
|discussion = https://tracker.moodle.org/browse/UX-8&lt;br /&gt;
|assignee = HQ Projects Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
The new design for the UI for the course overview block requires the ability for Moodle to efficiently query plugins for a list of &amp;quot;date based&amp;quot; tasks for the current user.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;quot;mod print_overview&amp;quot; callbacks do not have sufficient functionality (no separation of fields, inefficient, incomplete, no relation to completion API, inconsistently implemented across modules) so we will have to build a new API (and deprecate mod_xx_print_overview). &lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Course Overview Block ===&lt;br /&gt;
The course overview block will communicate exclusively with the Todo API and will present the Todo&#039;s as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.&lt;br /&gt;
&lt;br /&gt;
* Mustache templates:&lt;br /&gt;
** General template for the block (wrapping template)&lt;br /&gt;
*** Timeline view&lt;br /&gt;
**** Sort by dates (wrapping template)&lt;br /&gt;
***** Template for displaying single todo (rendered in list)&lt;br /&gt;
**** Sort by courses (wrapping template)&lt;br /&gt;
***** Single course section, includes list of todos similar to &amp;quot;sort by dates&amp;quot; (can maybe re-use the template for a single todo here)&lt;br /&gt;
** Courses view&lt;br /&gt;
*** Single template can probably be re-used for &amp;quot;in progress&amp;quot;, &amp;quot;upcoming&amp;quot; and &amp;quot;completed&amp;quot; views, just rendered with different data&lt;br /&gt;
*** As above, single template for a course&lt;br /&gt;
* Javascript&lt;br /&gt;
** Add a module to interact with the Todo API (no bespoke ajax requests everywhere please)&lt;br /&gt;
** Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)&lt;br /&gt;
** Module for timeline view (maybe even have separate modules for &amp;quot;sort by dates&amp;quot; and &amp;quot;sort by courses&amp;quot;?). Handles requesting the data and rendering the templates etc.&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Module for courses view that handles requesting the data and rendering the templates&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Use the new pie chart we add&lt;br /&gt;
* CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)&lt;br /&gt;
** Style Boost theme&lt;br /&gt;
** Style bootstrap base theme (e.g. clean)&lt;br /&gt;
** Add responsive styling (need to ask the UX team for some mock ups of smaller resolutions)&lt;br /&gt;
* Accessibility: Add the appropriate aria attributes to each of the templates above to make the block accessible by a screen reader (more work than it seems)&lt;br /&gt;
* Update blocks/course_overview/block_course_overview.php &amp;quot;get_content&amp;quot; to render a template via the renderer (need to add a new function)&lt;br /&gt;
* Remove the existing functions being used to render the course overview (including functions in the renderer and lib.php)&lt;br /&gt;
* Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)&lt;br /&gt;
&lt;br /&gt;
=== Todo API ===&lt;br /&gt;
This will be a new API in core to represent the concept of &amp;quot;todos&amp;quot; in Moodle, i.e. the list of items displayed in the course overview block. A todo is made up of a calendar event and an associated action for the user. &lt;br /&gt;
&lt;br /&gt;
The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can&#039;t be started until after another module has been completed etc. &lt;br /&gt;
&lt;br /&gt;
Given the intensity of some of these calculations we&#039;ll need to look into aggressively caching results and maybe even avoid doing the calculations per request.&lt;br /&gt;
&lt;br /&gt;
Since we&#039;re leveraging the existing calendar events for the static data we may not need to actually persist the todos anywhere other than caching.&lt;br /&gt;
&lt;br /&gt;
* Add a todo class (pretty please can we have an actual class rather than just stdClass)&lt;br /&gt;
** Some properties of the class:&lt;br /&gt;
*** unique id (context id, component, area and item id?)&lt;br /&gt;
*** name - the name of the thing the todo relates to (e.g. activity name)&lt;br /&gt;
*** url - the url of the thing the todo relates to (e.g. view.php of the module)&lt;br /&gt;
*** user id - the id of the user this todo belong to&lt;br /&gt;
*** course id - the course if that the todo relates to&lt;br /&gt;
*** icon url - the icon for the todo (default to the module icon)&lt;br /&gt;
*** start date (optional) - when the todo starts&lt;br /&gt;
*** end date (optional) - when the todo must be actioned by&lt;br /&gt;
*** item count - how many associated items there are (e.g. 4 unread posts)&lt;br /&gt;
*** action name - display name of the todo (e.g. &amp;quot;submit assignment&amp;quot;)&lt;br /&gt;
*** action url - url of the todo action (e.g. link to the assignment submission page)&lt;br /&gt;
*** action start date - a date after which the todo can be actioned (only display the action url after this date)&lt;br /&gt;
* Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).&lt;br /&gt;
** Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).&lt;br /&gt;
* Add a data access layer that abstracts away all of the SQL so that we don&#039;t have that logic everywhere (ideally).&lt;br /&gt;
** The API class would benefit from this.&lt;br /&gt;
** It can also hide the fact that we&#039;re piggy backing on the calendar events, just in case we want to change that in the future.&lt;br /&gt;
** It can also handle all of the caching&lt;br /&gt;
** Support pagination as above&lt;br /&gt;
* Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).&lt;br /&gt;
** The core todo API can&#039;t (and shouldn&#039;t) know every place that will want to create a todo, so we need to provide a standard way for each plugin to register itself as something that will create a todo and an interface for them to do the data manipulation required.&lt;br /&gt;
* Add an external API class.&lt;br /&gt;
** This class shouldn&#039;t contain any business logic (that all lives in the API class). &lt;br /&gt;
** It needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the todo.&lt;br /&gt;
** All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.&lt;br /&gt;
* Add some renderables for the todo&lt;br /&gt;
** The todos should probably just be renderable / template-able themselves&lt;br /&gt;
** These will be used by the external API class.&lt;br /&gt;
* Improve performance using caching (this will be trial and error with the performance testing)&lt;br /&gt;
* Write unit tests for all new API functions and external API functions&lt;br /&gt;
&lt;br /&gt;
=== Chart.js ===&lt;br /&gt;
* Add a new chart type (pie chart) to Moodle&#039;s chart API for use in the templates above&lt;br /&gt;
&lt;br /&gt;
=== Calendar Event API ===&lt;br /&gt;
We&#039;ll be using the existing calendar events as the basis for the &amp;quot;todos&amp;quot;. The current calendar event data structure contains most of the data that we&#039;ll need so we&#039;ll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we&#039;ll need.&lt;br /&gt;
&lt;br /&gt;
* Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation&lt;br /&gt;
* Add indexes to the event table if they are missing&lt;br /&gt;
** display/order by date&lt;br /&gt;
** course id&lt;br /&gt;
** user id&lt;br /&gt;
* Add functions to the calendar event API to retrieve groups of events for a given user(s)&lt;br /&gt;
** currently it seems the API only loads one at a time so you need to do direct SQL in the calling code&lt;br /&gt;
** API should probably handle grouping of results, e.g. events for a user would be the distinct set of any course level events + group event override + user event override, where each has higher precedence than the last in the result set&lt;br /&gt;
** API needs to support order by new date field&lt;br /&gt;
** API needs to support limit and offset&lt;br /&gt;
* Add unit tests for new API functions&lt;br /&gt;
&lt;br /&gt;
=== Calendar Block ===&lt;br /&gt;
* Make sure all of the todos are showing up in the calendar for the user&lt;br /&gt;
** Note: we *should* get this for free since we are simply creating calendar events&lt;br /&gt;
&lt;br /&gt;
=== Course Completion Tracking ===&lt;br /&gt;
* Develop a way to track completion on for all courses&lt;br /&gt;
** This needs to take into account all activities within the course, even ones that don&#039;t have any completion tracking enabled&lt;br /&gt;
* Add an API to query the completion status of a course that implements the agreed approach&lt;br /&gt;
* Do we need to persist the course progress somewhere or can it be calculated at run time?&lt;br /&gt;
** Assess performance of both options&lt;br /&gt;
* If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate&lt;br /&gt;
&lt;br /&gt;
=== General Moodle stuff ===&lt;br /&gt;
* Remove all uses of the &amp;quot;print_overview&amp;quot; callback thingo we&#039;re using through Moodle for modules to add stuff to the course overview block&lt;br /&gt;
* Find all of the places in Moodle that need to generate create a todo and have them create appropriate calendar events&lt;br /&gt;
** A list has been started here https://docs.google.com/document/d/1qfl2MEzdZcNlT2rvBSsIgWhRZsloRnsb2m5TALFn_C8/edit&lt;br /&gt;
* Find all of the places that may affect the status of a calendar event and update the event to make sure it is accurate (eg. editing a module, submitting an assignment, changing course dates etc)&lt;br /&gt;
* Add an implementation of the callback interface thingo to each module that will be creating a todo &lt;br /&gt;
** This implementation will take a calendar event and the user and do all of the appropriate checks to see if the user should see the todo, etc&lt;br /&gt;
** It will then create the appropriate todo from the calendar event and add all of the action stuff.&lt;br /&gt;
&lt;br /&gt;
=== General Testing ===&lt;br /&gt;
* We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.&lt;br /&gt;
&lt;br /&gt;
== Questions for the UX team ==&lt;br /&gt;
* How many items to display in &amp;quot;Next 7 days&amp;quot;? Is there a limit, or we always show all of the items?&lt;br /&gt;
* In the prototype 6c (the one that we are supposed to develop from) the todo disappears from the list when it is actioned. Is this the correct behaviour? What happens to the corresponding event in the calendar? Does that also get removed?&lt;br /&gt;
* What do we show when a todo is only available for a certain duration? E.g. chat where it&#039;s open for only 3 days. Only having the end date seems weird in that case.&lt;br /&gt;
* Is the list of courses paginated in the courses view? Is there a &amp;quot;More&amp;quot; button to load more courses?&lt;br /&gt;
* What happens with courses which do not have a start date, and end date? Will they show in &amp;quot;In progress&amp;quot; for as long as I am enrolled in them? Note that if I unenrol from the course, I will lose access to it.&lt;br /&gt;
* Are all the three tabs (in progress, upcoming, completed) always shown, even if they are empty?&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Useful_core_Javascript_modules&amp;diff=51410</id>
		<title>Useful core Javascript modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Useful_core_Javascript_modules&amp;diff=51410"/>
		<updated>2016-12-02T05:23:03Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
== Configuration settings (core/config) ==&lt;br /&gt;
&lt;br /&gt;
Example of using config module:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/config’], function(mdlcfg) {&lt;br /&gt;
    console.log(mdlcfg.wwwroot); // outputs the wwwroot of moodle to console&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Language strings (core/str) ==&lt;br /&gt;
&lt;br /&gt;
Example of using language strings module (retrieved via ajax, if the string is not yet loaded)&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([‘core/str’], function(str) {&lt;br /&gt;
    str.get_string(&#039;edita&#039;, &#039;core&#039;, stringargument).done(function(s) {&lt;br /&gt;
       console.log(s);&lt;br /&gt;
    }).fail(console.log(e));&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The string will be retrieved via AJAX request on the first use and cached in browser local storage until purge caches or site upgrade&lt;br /&gt;
&lt;br /&gt;
IT IS NOT RECOMMENDED to call:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;string_for_js(&#039;edita&#039;, &#039;core&#039;); // You do not need this!&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because:&lt;br /&gt;
* The list of strings used now needs to be maintained in 2 places&lt;br /&gt;
* The strings are always sent, and bloat the page size even if they are not used&lt;br /&gt;
* All strings fetched via the AJAX method above are cached in browser local storage anyway, so these strings will never be used 99% of the time&lt;br /&gt;
&lt;br /&gt;
==Notifications (core/notification)==&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/notification’], function(notification) {&lt;br /&gt;
    notification.alert(&#039;Hello&#039;, &#039;Welcome to my site!&#039;, &#039;Continue&#039;);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Strings and notifications:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/str&#039;, &#039;core/notification’], function(str, notification) {&lt;br /&gt;
                str.get_strings([&lt;br /&gt;
                        {&#039;key&#039; : &#039;delete&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;confirmdeletetag&#039;, component : &#039;tag&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;yes&#039;},&lt;br /&gt;
                        {&#039;key&#039; : &#039;no&#039;},&lt;br /&gt;
                    ]).done(function(s) {&lt;br /&gt;
                        notification.confirm(s[0], s[1], s[2], s[3], function() {&lt;br /&gt;
                            window.location.href = href;&lt;br /&gt;
                        });&lt;br /&gt;
                    }&lt;br /&gt;
                ).fail(notification.exception);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== URL module (core/url) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/url&#039;], function(url) {&lt;br /&gt;
    url.fileUrl(relativeScript, slashArg);&lt;br /&gt;
    url.relativeUrl(relativePath);&lt;br /&gt;
    url.imageUrl(imagename, component);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tree (core/tree) ==&lt;br /&gt;
{{Moodle 3.1}}&lt;br /&gt;
If you want to add a hierarchical interface, you should use the tree module. It will handle user interaction and accessibility for you.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;, &#039;core/tree&#039;], function($, Tree) {&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
            new Tree(&amp;quot;css/jquery selector of the tree container&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read more about the [[Tree]] module&lt;br /&gt;
&lt;br /&gt;
== Modal (core/modal) ==&lt;br /&gt;
If you&#039;d like to add a modal to your page the modal modules will handle all of the magic for you, all you need to bring is your content!&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;], function($, ModalFactory) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    title: &#039;test title&#039;,&lt;br /&gt;
    body: &#039;&amp;lt;p&amp;gt;test body content&amp;lt;/p&amp;gt;&#039;,&lt;br /&gt;
    footer: &#039;test footer content&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your new modal.&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read more about the [[AMD_Modal]] module&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.2_release_notes&amp;diff=51364</id>
		<title>Moodle 3.2 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.2_release_notes&amp;diff=51364"/>
		<updated>2016-12-01T07:15:26Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 28 November 2016 (not yet released)&lt;br /&gt;
&lt;br /&gt;
{{Work in progress}}&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.2%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.2].&lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software up-to-date.&lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 2.7 or later (if upgrading from earlier versions, you must upgrade to 2.7.14 as a first step)&lt;br /&gt;
* PHP version: minimum PHP 5.6.5 (important! minimum PHP version has changed since Moodle 3.1). PHP 7.0 is supported but has some [https://docs.moodle.org/dev/Moodle_and_PHP7#Can_I_use_PHP7_yet.3F engine limitations]. PHP 7.1 will be supported when released.&lt;br /&gt;
&lt;br /&gt;
=== Database requirements ===&lt;br /&gt;
&lt;br /&gt;
Moodle supports the following database servers. Again, version numbers are just the minimum supported version. We recommend running the latest stable version of any software.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Database&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.postgresql.org/ PostgreSQL]&lt;br /&gt;
| 9.1&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.microsoft.com/en-us/server-cloud/products/sql-server/ Microsoft SQL Server]&lt;br /&gt;
| 2008&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.oracle.com/us/products/database/overview/index.html Oracle Database]&lt;br /&gt;
| 10.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
=== Browser support ===&lt;br /&gt;
Moodle is compatible with any standards compliant web browser. We regularly test Moodle with the following browsers:&lt;br /&gt;
&lt;br /&gt;
Desktop:&lt;br /&gt;
* Chrome&lt;br /&gt;
* Firefox&lt;br /&gt;
* Safari&lt;br /&gt;
* Edge&lt;br /&gt;
* Internet Explorer&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date. https://whatbrowser.org&lt;br /&gt;
&lt;br /&gt;
Note: Legacy browsers with known compatibility issues with Moodle 3.2:&lt;br /&gt;
* Internet Explorer 10 and below&lt;br /&gt;
* Safari 7 and below&lt;br /&gt;
&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
Coming soon.&lt;br /&gt;
&lt;br /&gt;
=== For developers ===&lt;br /&gt;
&lt;br /&gt;
* MDL-55071, MDL-55074 - New &amp;quot;Boost&amp;quot; Bootstrap 4 theme, block and navigation changes&lt;br /&gt;
* MDL-38158 - Introduction of Media players plugin type ([https://docs.moodle.org/dev/Media_players documentation])&lt;br /&gt;
* MDL-55727 - Create AMD modal module ([https://docs.moodle.org/dev/AMD_Modal documentation])&lt;br /&gt;
* MDL-49599 - Deprecate old boxnet v1 API&lt;br /&gt;
* MDL-53306 - Add hook to be executed before user login in authentication plugins&lt;br /&gt;
* MDL-55048 - Grunt and npm build dependencies now require node version 4 or above&lt;br /&gt;
* MDL-47162 - Add course id to message eventdata&lt;br /&gt;
* MDL-50937 - Update to JQuery 3.1&lt;br /&gt;
* MDL-48114 - Add Meta-Information to composer.json&lt;br /&gt;
* MDL-54987 - Introduce a new chart API and library ([https://docs.moodle.org/dev/Charts_API documentation])&lt;br /&gt;
* MDL-52127 - Linting for Javascript with ESLint&lt;br /&gt;
* MDL-55058 - Linting for CSS with stylelint&lt;br /&gt;
* MDL-55072 - Upgrades to Behat so it can work with different themes&lt;br /&gt;
* MDL-55141 - Add debugging option when running scheduled tasks from CLI ([https://docs.moodle.org/en/Administration_via_command_line#Scheduled_tasks documentation])&lt;br /&gt;
* MDL-31243 - Refactor similar SQL generation code from get_users_by_capability &amp;amp; get_enrolled_uses to make get_with_capability_sql&lt;br /&gt;
* MDL-54941 - Add filesize as a new field returned in all the Web Services returning file information&lt;br /&gt;
* MDL-55091 - Upgrade phpunit to 5.x&lt;br /&gt;
* MDL-56082 - Expose external authentication methods (loginpage_idp_list) in login block ([https://docs.moodle.org/dev/Authentication_plugins#loginpage_idp_list.28.29 documentation])&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.1 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.2]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.2]]&lt;br /&gt;
[[es:Notas de Moodle 3.2]]&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=AMD_Modal&amp;diff=51348</id>
		<title>AMD Modal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=AMD_Modal&amp;diff=51348"/>
		<updated>2016-12-01T06:44:06Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: /* How do you create a basic modal? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Why should you use it? =&lt;br /&gt;
The AMD modal modules provide a simple interface for creating a modal within Moodle. The module will ensure all accessibility requirements are met including applying the correct aria roles, focus control, aria hiding background elements and locking keyboard navigation.&lt;br /&gt;
&lt;br /&gt;
The modals will fire events for common actions that occur within the modal, e.g. show / hide, for other code to listen to and react accordingly.&lt;br /&gt;
&lt;br /&gt;
Moodle ships with a couple of standard modal types for you to re-use including a simple cancel modal, a confirm (yes/no) modal and a save/cancel modal. Hopefully with more to come!&lt;br /&gt;
&lt;br /&gt;
= How do you create a basic modal? =&lt;br /&gt;
If you&#039;d simply like to display a modal with some simple content then all you&#039;ll need is the modal factory. The factory provides a create function that accepts some configuration for your modal that the factory will use to create the modal and optionally a trigger element (the element that will open the modal when activated). The create function will return a promise that is resolved with the created modal.&lt;br /&gt;
&lt;br /&gt;
The configuration is provided as an object with key/value pairs. The options are:&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! &#039;&#039;&#039;key&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;description&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| title&lt;br /&gt;
| the title to display in the modal header - note: this wont render HTML&lt;br /&gt;
|-&lt;br /&gt;
| body&lt;br /&gt;
| the main content to be rendered in the modal body&lt;br /&gt;
|-&lt;br /&gt;
| footer&lt;br /&gt;
| the content to be rendered in the modal footer&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| one of the modal types registered with the factory&lt;br /&gt;
|-&lt;br /&gt;
| large&lt;br /&gt;
| a boolean to indicate if the modal should be wider than the default size&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example 1&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;], function($, ModalFactory) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    title: &#039;test title&#039;,&lt;br /&gt;
    body: &#039;&amp;lt;p&amp;gt;test body content&amp;lt;/p&amp;gt;&#039;,&lt;br /&gt;
    footer: &#039;test footer content&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your new modal.&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The modals will also accept a promise for the body and footer content. It is expected that the promise will be resolved with two strings, the html content and any associated javascript. This allows the modal module to work natively with the templates module, such as in the example below.&lt;br /&gt;
&lt;br /&gt;
Example 2&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;, &#039;core/templates&#039;], function($, ModalFactory, Templates) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    title: &#039;test title&#039;,&lt;br /&gt;
    // Can include JS which is run when modal is attached to DOM.&lt;br /&gt;
    body: Templates.render(&#039;core/modal_test_3&#039;, {}),&lt;br /&gt;
    footer: &#039;test footer content&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your modal.&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the modals aren&#039;t actually added to the DOM until they are made visible any javascript resolved with the promise is cached and only run after all of the elements are added to the DOM,  so you don&#039;t have to worry about any special handling in the javascript that is being loaded from the template.&lt;br /&gt;
&lt;br /&gt;
= How do you create a different type of modal? =&lt;br /&gt;
Moodle comes with a few specialised types of modals for common use cases. These can be created using the factory, similar to the examples above, by specifying the type of modal in the configuration provided to the create function. Each of the modal types may have different configuration options, for example the save/cancel modal doesn&#039;t allow you to set the footer content.&lt;br /&gt;
&lt;br /&gt;
Example 3&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;, &#039;core/templates&#039;], function($, ModalFactory, Templates) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    type: ModalFactory.types.SAVE_CANCEL,&lt;br /&gt;
    title: &#039;Modal save cancel&#039;,&lt;br /&gt;
    body: &#039;This modal is a save/cancel modal&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your modal.&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each type of modal may fire additional events to allow your code to handle the new functionality being offered. See the modal_events.js module for a list of events that can be fired. For example, if you wanted to have a save/cancel modal that you did some form validation on before saving you could do something like the example below.&lt;br /&gt;
&lt;br /&gt;
Example 4&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;, &#039;core/modal_events&#039;, &#039;core/templates&#039;],&lt;br /&gt;
        function($, ModalFactory, ModalEvents, Templates) {&lt;br /&gt;
  &lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    type: ModalFactory.types.SAVE_CANCEL,&lt;br /&gt;
    title: &#039;Modal save cancel&#039;,&lt;br /&gt;
    body: &#039;This modal is a save/cancel modal&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    modal.getRoot().on(ModalEvents.save, function(e) {&lt;br /&gt;
      // Stop the default save button behaviour which is to close the modal.&lt;br /&gt;
      e.preventDefault();&lt;br /&gt;
      // Do your form validation here.&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= How do you write a new type of modal? =&lt;br /&gt;
If you&#039;d like to write a new type of modal to be re-used throughout your code you can extend the default modal implementation and make any customisations you require. In order to create a new modal type you&#039;ll need to create a new AMD module and import the core/modal module to extend. You can also optionally create a new modal template that builds upon the core/modal template.&lt;br /&gt;
&lt;br /&gt;
For example, let&#039;s create a modal that opens a login form:&lt;br /&gt;
First we can create the HTML for out modal by including and extending the core modal template. All we need to do is override the block defined in that template with our new title, body and footer content.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume the file is &amp;lt;your_module&amp;gt;/templates/modal_login.mustache&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
{{&amp;lt; core/modal }}&lt;br /&gt;
    {{$title}}{{#str}} login {{/str}}{{/title}}&lt;br /&gt;
    {{$body}}&lt;br /&gt;
        &amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;form&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;form-group row&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;label for=&amp;quot;inputEmail&amp;quot; class=&amp;quot;col-sm-2 col-form-label&amp;quot;&amp;gt;{{#str}} email {{/str}}&amp;lt;/label&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;col-sm-10&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;input type=&amp;quot;email&amp;quot; class=&amp;quot;form-control&amp;quot; id=&amp;quot;inputEmail&amp;quot; placeholder=&amp;quot;{{#str}} email {{/str}}&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;form-group row&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;label for=&amp;quot;inputPassword&amp;quot; class=&amp;quot;col-sm-2 col-form-label&amp;quot;&amp;gt;{{#str}} password {{/str}}&amp;lt;/label&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;col-sm-10&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;input type=&amp;quot;password&amp;quot; class=&amp;quot;form-control&amp;quot; id=&amp;quot;inputPassword&amp;quot; placeholder=&amp;quot;{{#str}} password {{/str}}&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/form&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    {{/body}}&lt;br /&gt;
    {{$footer}}&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;btn btn-primary&amp;quot; data-action=&amp;quot;login&amp;quot;&amp;gt;{{#str}} login {{/str}}&amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot; data-action=&amp;quot;cancel&amp;quot;&amp;gt;{{#str}} cancel {{/str}}&amp;lt;/button&amp;gt;&lt;br /&gt;
    {{/footer}}&lt;br /&gt;
{{/ core/modal }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next we can create the new AMD module for the login modal. You can extend the existing modal module which will give you all of the core modal functionality for free allowing you to focus on writing only the specific logic you need. In this example we would only need to write the logic for handling the login.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume the file is &amp;lt;your_module&amp;gt;/amd/src/modal_login.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;, &#039;core/notification&#039;, &#039;core/custom_interaction_events&#039;, &#039;core/modal&#039;],&lt;br /&gt;
        function($, Notification, CustomEvents, Modal) {&lt;br /&gt;
&lt;br /&gt;
    var SELECTORS = {&lt;br /&gt;
        LOGIN_BUTTON: &#039;[data-action=&amp;quot;login&amp;quot;]&#039;,&lt;br /&gt;
        CANCEL_BUTTON: &#039;[data-action=&amp;quot;cancel&amp;quot;]&#039;,&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Constructor for the Modal.&lt;br /&gt;
     *&lt;br /&gt;
     * @param {object} root The root jQuery element for the modal&lt;br /&gt;
     */&lt;br /&gt;
    var ModalLogin = function(root) {&lt;br /&gt;
        Modal.call(this, root);&lt;br /&gt;
&lt;br /&gt;
        if (!this.getFooter().find(SELECTORS.LOGIN_BUTTON).length) {&lt;br /&gt;
            Notification.exception({message: &#039;No login button found&#039;});&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!this.getFooter().find(SELECTORS.CANCEL_BUTTON).length) {&lt;br /&gt;
            Notification.exception({message: &#039;No cancel button found&#039;});&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    ModalLogin.prototype = Object.create(Modal.prototype);&lt;br /&gt;
    ModalLogin.prototype.constructor = ModalLogin;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Set up all of the event handling for the modal.&lt;br /&gt;
     *&lt;br /&gt;
     * @method registerEventListeners&lt;br /&gt;
     */&lt;br /&gt;
    ModalLogin.prototype.registerEventListeners = function() {&lt;br /&gt;
        // Apply parent event listeners.&lt;br /&gt;
        Modal.prototype.registerEventListeners.call(this);&lt;br /&gt;
&lt;br /&gt;
        this.getModal().on(CustomEvents.events.activate, SELECTORS.LOGIN_BUTTON, function(e, data) {&lt;br /&gt;
            // Add your logic for when the login button is clicked. This could include the form validation,&lt;br /&gt;
            // loading animations, error handling etc.&lt;br /&gt;
        }.bind(this));&lt;br /&gt;
&lt;br /&gt;
        this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, function(e, data) {&lt;br /&gt;
            // Add your logic for when the cancel button is clicked.&lt;br /&gt;
        }.bind(this));&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    return ModalLogin;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once you have both your template and javascript ready to go then all you need to do is tie them into where ever you&#039;d like to launch the modal. For the purpose of this example let&#039;s assume that we&#039;ve got a page with a login button with id=&amp;quot;login&amp;quot; then you might add this javascript to the page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/templates&#039;, &#039;&amp;lt;your_module&amp;gt;/modal_login&#039;], function($, Templates, ModalLogin) {&lt;br /&gt;
    var button = $(&#039;#login&#039;);&lt;br /&gt;
    var modal = null;&lt;br /&gt;
&lt;br /&gt;
    // Load the HTML from your login modal.&lt;br /&gt;
    Templates.render(&#039;&amp;lt;your_module&amp;gt;/modal_login&#039;).done(function(html) {&lt;br /&gt;
        // Create the modal with the HTML.&lt;br /&gt;
        modal = new ModalLogin(html);&lt;br /&gt;
    }); &lt;br /&gt;
&lt;br /&gt;
    // Show the modal when the login button is clicked.&lt;br /&gt;
    button.click(function() {&lt;br /&gt;
        modal.show();&lt;br /&gt;
    }); &lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=AMD_Modal&amp;diff=51304</id>
		<title>AMD Modal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=AMD_Modal&amp;diff=51304"/>
		<updated>2016-12-01T04:36:05Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: Created page with &amp;quot;= Why should you use it? = The AMD modal modules provide a simple interface for creating a modal within Moodle. The module will ensure all accessibility requirements are met i...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Why should you use it? =&lt;br /&gt;
The AMD modal modules provide a simple interface for creating a modal within Moodle. The module will ensure all accessibility requirements are met including applying the correct aria roles, focus control, aria hiding background elements and locking keyboard navigation.&lt;br /&gt;
&lt;br /&gt;
The modals will fire events for common actions that occur within the modal, e.g. show / hide, for other code to listen to and react accordingly.&lt;br /&gt;
&lt;br /&gt;
Moodle ships with a couple of standard modal types for you to re-use including a simple cancel modal, a confirm (yes/no) modal and a save/cancel modal. Hopefully with more to come!&lt;br /&gt;
&lt;br /&gt;
= How do you create a basic modal? =&lt;br /&gt;
If you&#039;d simply like to display a modal with some simple content then all you&#039;ll need is the modal factory. The factory provides a create function that accepts some configuration for your modal that the factory will use to create the modal and optionally a trigger element (the element that will open the modal when activated). The create function will return a promise that is resolved with the created modal.&lt;br /&gt;
&lt;br /&gt;
The configuration is provided as an object with key/value pairs. The options are:&lt;br /&gt;
title - the title to display in the modal header - note: this wont render HTML&lt;br /&gt;
body - the main content to be rendered in the modal body&lt;br /&gt;
footer - the content to be rendered in the modal footer&lt;br /&gt;
type - one of the modal types registered with the factory&lt;br /&gt;
large - a boolean to indicate if the modal should be wider than the default size&lt;br /&gt;
&lt;br /&gt;
Example 1&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;], function($, ModalFactory) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    title: &#039;test title&#039;,&lt;br /&gt;
    body: &#039;&amp;lt;p&amp;gt;test body content&amp;lt;/p&amp;gt;&#039;,&lt;br /&gt;
    footer: &#039;test footer content&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your new modal.&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The modals will also accept a promise for the body and footer content. It is expected that the promise will be resolved with two strings, the html content and any associated javascript. This allows the modal module to work natively with the templates module, such as in the example below.&lt;br /&gt;
&lt;br /&gt;
Example 2&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;, &#039;core/templates&#039;], function($, ModalFactory, Templates) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    title: &#039;test title&#039;,&lt;br /&gt;
    // Can include JS which is run when modal is attached to DOM.&lt;br /&gt;
    body: Templates.render(&#039;core/modal_test_3&#039;, {}),&lt;br /&gt;
    footer: &#039;test footer content&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your modal.&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since the modals aren&#039;t actually added to the DOM until they are made visible any javascript resolved with the promise is cached and only run after all of the elements are added to the DOM,  so you don&#039;t have to worry about any special handling in the javascript that is being loaded from the template.&lt;br /&gt;
&lt;br /&gt;
= How do you create a different type of modal? =&lt;br /&gt;
Moodle comes with a few specialised types of modals for common use cases. These can be created using the factory, similar to the examples above, by specifying the type of modal in the configuration provided to the create function. Each of the modal types may have different configuration options, for example the save/cancel modal doesn&#039;t allow you to set the footer content.&lt;br /&gt;
&lt;br /&gt;
Example 3&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;, &#039;core/templates&#039;], function($, ModalFactory, Templates) {&lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    type: ModalFactory.types.SAVE_CANCEL,&lt;br /&gt;
    title: &#039;Modal save cancel&#039;,&lt;br /&gt;
    body: &#039;This modal is a save/cancel modal&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    // Do what you want with your modal.&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each type of modal may fire additional events to allow your code to handle the new functionality being offered. See the modal_events.js module for a list of events that can be fired. For example, if you wanted to have a save/cancel modal that you did some form validation on before saving you could do something like the example below.&lt;br /&gt;
&lt;br /&gt;
Example 4&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/modal_factory&#039;, &#039;core/modal_events&#039;, &#039;core/templates&#039;],&lt;br /&gt;
        function($, ModalFactory, ModalEvents, Templates) {&lt;br /&gt;
  &lt;br /&gt;
  var trigger = $(&#039;#create-modal&#039;);&lt;br /&gt;
  ModalFactory.create({&lt;br /&gt;
    type: ModalFactory.types.SAVE_CANCEL,&lt;br /&gt;
    title: &#039;Modal save cancel&#039;,&lt;br /&gt;
    body: &#039;This modal is a save/cancel modal&#039;,&lt;br /&gt;
  }, trigger)&lt;br /&gt;
  .done(function(modal) {&lt;br /&gt;
    modal.getRoot().on(ModalEvents.save, function(e) {&lt;br /&gt;
      // Stop the default save button behaviour which is to close the modal.&lt;br /&gt;
      e.preventDefault();&lt;br /&gt;
      // Do your form validation here.&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= How do you write a new type of modal? =&lt;br /&gt;
If you&#039;d like to write a new type of modal to be re-used throughout your code you can extend the default modal implementation and make any customisations you require. In order to create a new modal type you&#039;ll need to create a new AMD module and import the core/modal module to extend. You can also optionally create a new modal template that builds upon the core/modal template.&lt;br /&gt;
&lt;br /&gt;
For example, let&#039;s create a modal that opens a login form:&lt;br /&gt;
First we can create the HTML for out modal by including and extending the core modal template. All we need to do is override the block defined in that template with our new title, body and footer content.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume the file is &amp;lt;your_module&amp;gt;/templates/modal_login.mustache&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
{{&amp;lt; core/modal }}&lt;br /&gt;
    {{$title}}{{#str}} login {{/str}}{{/title}}&lt;br /&gt;
    {{$body}}&lt;br /&gt;
        &amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;form&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;form-group row&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;label for=&amp;quot;inputEmail&amp;quot; class=&amp;quot;col-sm-2 col-form-label&amp;quot;&amp;gt;{{#str}} email {{/str}}&amp;lt;/label&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;col-sm-10&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;input type=&amp;quot;email&amp;quot; class=&amp;quot;form-control&amp;quot; id=&amp;quot;inputEmail&amp;quot; placeholder=&amp;quot;{{#str}} email {{/str}}&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;form-group row&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;label for=&amp;quot;inputPassword&amp;quot; class=&amp;quot;col-sm-2 col-form-label&amp;quot;&amp;gt;{{#str}} password {{/str}}&amp;lt;/label&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;col-sm-10&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;input type=&amp;quot;password&amp;quot; class=&amp;quot;form-control&amp;quot; id=&amp;quot;inputPassword&amp;quot; placeholder=&amp;quot;{{#str}} password {{/str}}&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/form&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    {{/body}}&lt;br /&gt;
    {{$footer}}&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;btn btn-primary&amp;quot; data-action=&amp;quot;login&amp;quot;&amp;gt;{{#str}} login {{/str}}&amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;button type=&amp;quot;button&amp;quot; class=&amp;quot;btn btn-secondary&amp;quot; data-action=&amp;quot;cancel&amp;quot;&amp;gt;{{#str}} cancel {{/str}}&amp;lt;/button&amp;gt;&lt;br /&gt;
    {{/footer}}&lt;br /&gt;
{{/ core/modal }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next we can create the new AMD module for the login modal. You can extend the existing modal module which will give you all of the core modal functionality for free allowing you to focus on writing only the specific logic you need. In this example we would only need to write the logic for handling the login.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume the file is &amp;lt;your_module&amp;gt;/amd/src/modal_login.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;, &#039;core/notification&#039;, &#039;core/custom_interaction_events&#039;, &#039;core/modal&#039;],&lt;br /&gt;
        function($, Notification, CustomEvents, Modal) {&lt;br /&gt;
&lt;br /&gt;
    var SELECTORS = {&lt;br /&gt;
        LOGIN_BUTTON: &#039;[data-action=&amp;quot;login&amp;quot;]&#039;,&lt;br /&gt;
        CANCEL_BUTTON: &#039;[data-action=&amp;quot;cancel&amp;quot;]&#039;,&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Constructor for the Modal.&lt;br /&gt;
     *&lt;br /&gt;
     * @param {object} root The root jQuery element for the modal&lt;br /&gt;
     */&lt;br /&gt;
    var ModalLogin = function(root) {&lt;br /&gt;
        Modal.call(this, root);&lt;br /&gt;
&lt;br /&gt;
        if (!this.getFooter().find(SELECTORS.LOGIN_BUTTON).length) {&lt;br /&gt;
            Notification.exception({message: &#039;No login button found&#039;});&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (!this.getFooter().find(SELECTORS.CANCEL_BUTTON).length) {&lt;br /&gt;
            Notification.exception({message: &#039;No cancel button found&#039;});&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    ModalLogin.prototype = Object.create(Modal.prototype);&lt;br /&gt;
    ModalLogin.prototype.constructor = ModalLogin;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Set up all of the event handling for the modal.&lt;br /&gt;
     *&lt;br /&gt;
     * @method registerEventListeners&lt;br /&gt;
     */&lt;br /&gt;
    ModalLogin.prototype.registerEventListeners = function() {&lt;br /&gt;
        // Apply parent event listeners.&lt;br /&gt;
        Modal.prototype.registerEventListeners.call(this);&lt;br /&gt;
&lt;br /&gt;
        this.getModal().on(CustomEvents.events.activate, SELECTORS.LOGIN_BUTTON, function(e, data) {&lt;br /&gt;
            // Add your logic for when the login button is clicked. This could include the form validation,&lt;br /&gt;
            // loading animations, error handling etc.&lt;br /&gt;
        }.bind(this));&lt;br /&gt;
&lt;br /&gt;
        this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, function(e, data) {&lt;br /&gt;
            // Add your logic for when the cancel button is clicked.&lt;br /&gt;
        }.bind(this));&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    return ModalLogin;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once you have both your template and javascript ready to go then all you need to do is tie them into where ever you&#039;d like to launch the modal. For the purpose of this example let&#039;s assume that we&#039;ve got a page with a login button with id=&amp;quot;login&amp;quot; then you might add this javascript to the page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;jquery&#039;, &#039;core/templates&#039;, &#039;&amp;lt;your_module&amp;gt;/modal_login&#039;], function($, Templates, ModalLogin) {&lt;br /&gt;
    var button = $(&#039;#login&#039;);&lt;br /&gt;
    var modal = null;&lt;br /&gt;
&lt;br /&gt;
    // Load the HTML from your login modal.&lt;br /&gt;
    Templates.render(&#039;&amp;lt;your_module&amp;gt;/modal_login&#039;).done(function(html) {&lt;br /&gt;
        // Create the modal with the HTML.&lt;br /&gt;
        modal = new ModalLogin(html);&lt;br /&gt;
    }); &lt;br /&gt;
&lt;br /&gt;
    // Show the modal when the login button is clicked.&lt;br /&gt;
    button.click(function() {&lt;br /&gt;
        modal.show();&lt;br /&gt;
    }); &lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=48493</id>
		<title>Templates</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=48493"/>
		<updated>2015-09-08T05:36:34Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
= Templates =&lt;br /&gt;
&lt;br /&gt;
== What is a template? ==&lt;br /&gt;
A template is an alternative to writing blocks of html directly in javascript / php by concatenating strings. The end result is the same, but templates have a number of advantages:&lt;br /&gt;
* It is easier to see the final result of the template because the code for a template is very close to what the final HTML will look like&lt;br /&gt;
* Because the templating language is intentionally limited, it is hard to introduce complex logic into a template. This make it far easier for a theme designer to override a template, without breaking the logic&lt;br /&gt;
* Templates can be rendered from javascript. This allows ajax operations to re-render a portion of the page.&lt;br /&gt;
&lt;br /&gt;
== How do I write a template? ==&lt;br /&gt;
Templates are written in a language called &amp;quot;[http://mustache.github.io/mustache.5.html Mustache]&amp;quot;. Mustache is written as HTML with additional tags used to format the display of the data. Mustache tags are made of 2 opening and closing curly braces &amp;quot;{{tag}}&amp;quot;. There are a few variations of these tags that behave differently.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{raiden}}&amp;lt;/code&amp;gt; This is a simple variable substitution. The variable named &amp;quot;variable&amp;quot; will be searched for in the current context (and any parent contexts) and when a value is found, the entire tag will be replaced by the variable (html escaped).&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{{galaga}}}&amp;lt;/code&amp;gt; This is an unescaped variable substitution. Instead of escaping the variable before replacing it in the template, the variable is included raw. This is useful when the variable contains a block of HTML (for example).&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{#lemmings}} jump off cliff {{/lemmings}}&amp;lt;/code&amp;gt; These are opening and closing section tags. If the lemmings variable exists and evaluates to &amp;quot;not false&amp;quot; value, the variable is pushed on the stack, the contents of the section are parsed and included in the result. If the variable does not exist, or evaluates to false - the section will be skipped. If the variable lemmings evaluates to an array, the section will be repeated for each item in the array with the items of the array on the context. This is how to output a list.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{^lemmings}} enjoy view {{/lemmings}}&amp;lt;/code&amp;gt; Equivalent of &amp;quot;if-not&amp;quot; block, there is not &amp;quot;else&amp;quot; in mustache.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{&amp;gt; pacman }}&amp;lt;/code&amp;gt; This is a partial. Think of it like an include. Templates can include other templates using this tag.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{$blockvar}} ... {{/blockvar}}&amp;lt;/code&amp;gt; This is a block variable. It defines a section of the template that can be overridden when it&#039;s included in another template.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{&amp;lt; template_name}} ... {{/template_name}}&amp;lt;/code&amp;gt; This is similar to including a partial but specifically indicates that you&#039;d like to override one or more black variables defined within the template you&#039;re including. You can override the black variables by defining a block variable within these tags that matches the name of the block variable you&#039;d like to override in the included template.&lt;br /&gt;
&lt;br /&gt;
So - putting this all together:&lt;br /&gt;
&lt;br /&gt;
recipe.mustache&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;{{recipename}}&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;{{description}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;h4&amp;gt;Ingredients&amp;lt;/h4&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
{{#ingredients}}&lt;br /&gt;
&amp;lt;li&amp;gt;{{.}}&amp;lt;/li&amp;gt;&lt;br /&gt;
{{/ingredients}}&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;h4&amp;gt;Steps&amp;lt;/h4&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
{{#steps}}&lt;br /&gt;
&amp;lt;li&amp;gt;{{{.}}}&amp;lt;/li&amp;gt;&lt;br /&gt;
{{/steps}}&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
{{ &amp;gt; ratethisrecipe }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When given this data:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  recipename: &amp;quot;Cheese sandwich&amp;quot;,&lt;br /&gt;
  description: &amp;quot;Who doesn&#039;t like a good cheese sandwich?&amp;quot;,&lt;br /&gt;
  ingredients: [&amp;quot;bread&amp;quot;, &amp;quot;cheese&amp;quot;, &amp;quot;butter&amp;quot;],&lt;br /&gt;
  steps: [&amp;quot;&amp;lt;p&amp;gt;Step 1 is to spread the butter on the bread&amp;lt;/p&amp;gt;&amp;quot;, &amp;quot;&amp;lt;p&amp;gt;Step 2 is to put the cheese &amp;amp;quot;in&amp;amp;quot; the bread (not on top, or underneath)&amp;lt;/p&amp;gt;&amp;quot;]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gives this: &amp;lt;span style=&amp;quot;font-size:4em&amp;quot;&amp;gt;😋&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More info - there are much clearer explanations of templates on the [http://mustache.github.io/mustache.5.html Mustache] website. Try reading those pages &amp;quot;before&amp;quot; posting on stack overflow :) .&lt;br /&gt;
&lt;br /&gt;
== Where do I put my templates? ==&lt;br /&gt;
&lt;br /&gt;
Templates go in the &amp;lt;componentdir&amp;gt;/templates folder and must have a .mustache file extension. When loading templates the template name is &amp;lt;componentname&amp;gt;/&amp;lt;filename&amp;gt; (no file extension). &lt;br /&gt;
&lt;br /&gt;
So &amp;quot;mod_lesson/timer&amp;quot; would load the template at mod/lesson/templates/timer.mustache.&lt;br /&gt;
&lt;br /&gt;
Note: Do not try and put your templates in sub folders under the &amp;quot;/templates&amp;quot; directory. This is not supported and will not work.&lt;br /&gt;
&lt;br /&gt;
== How do I call a template from javascript? ==&lt;br /&gt;
&lt;br /&gt;
Rendering a template from javascript is fairly easy. There is a new AMD module that can load/cache and render a template for you. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// This is AMD code for loading the &amp;quot;core/templates&amp;quot; module. see [Javascript Modules].&lt;br /&gt;
require([&#039;core/templates&#039;], function(templates) {&lt;br /&gt;
&lt;br /&gt;
    // This will be the context for our template. So {{name}} in the template will resolve to &amp;quot;Tweety bird&amp;quot;.&lt;br /&gt;
    var context = { name: &#039;Tweety bird&#039;, intelligence: 2 };&lt;br /&gt;
&lt;br /&gt;
    // This will call the function to load and render our template. &lt;br /&gt;
    var promise = templates.render(&#039;block_looneytunes/profile&#039;, context);&lt;br /&gt;
&lt;br /&gt;
    // The promise object returned by this function means &amp;quot;I&#039;ve considered your request and will finish it later - I PROMISE!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    // How we deal with promise objects is by adding callbacks.&lt;br /&gt;
    promise.done(function(source, javascript) {&lt;br /&gt;
        // Here eventually I have my compiled template, and any javascript that it generated.&lt;br /&gt;
&lt;br /&gt;
        // I can execute the javascript (probably after adding the html to the DOM) like this:&lt;br /&gt;
        templates.runTemplateJS(js);&lt;br /&gt;
    });&lt;br /&gt;
  &lt;br /&gt;
    // Sometimes things fail&lt;br /&gt;
    promise.fail(function(ex) {&lt;br /&gt;
        // Deal with this exception (I recommend core/notify exception function for this).&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Under the hood, this did many clever things for us. It loaded the template via an ajax call if it was not cached. It found any missing lang strings in the template and loaded them in a single ajax request, it split the JS from the HTML and returned us both in easy to use way. Read on for how to nicely deal with the javascript parameter.&lt;br /&gt;
&lt;br /&gt;
Note: with some nice chaining and sugar, we can shorten the above example quite a bit:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/templates&#039;, &#039;core/notification&#039;], function(templates, notification) {&lt;br /&gt;
    var context = { name: &#039;Tweety bird&#039;, intelligence: 2 };&lt;br /&gt;
    templates.render(&#039;block_looneytunes/profile&#039;, context)&lt;br /&gt;
        .done(doneCallback)&lt;br /&gt;
        .fail(notification.exception);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What if a template contains javascript? ==&lt;br /&gt;
&lt;br /&gt;
Sometimes a template requires that some JS be run when it is added to the page in order to give it more features. In the template we can include blocks of javascript, but we should use a special section tag that has a &amp;quot;helper&amp;quot; method registered to handle javascript carefully. &lt;br /&gt;
&lt;br /&gt;
Example&lt;br /&gt;
profile.mustache&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;profile&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Name: {{name}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Intelligence: {{intelligence}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require(&#039;jquery&#039;, function($) {&lt;br /&gt;
    // Effects! Can we have &amp;quot;blink&amp;quot;?&lt;br /&gt;
    $(&#039;#profile&#039;).slideDown();&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If this template is rendered by PHP, the javascript is separated from the HTML, and is appended to a special section in the footer of the page &amp;quot;after&amp;quot; requirejs has loaded. This provides the optimal page loading speed. If the template is rendered by javascript, the javascript source will be passed to the &amp;quot;done&amp;quot; handler from the promise. Then, when the &amp;quot;done&amp;quot; handler has added the template to the DOM, it can call &lt;br /&gt;
&amp;lt;code javascript&amp;gt;templates.runTemplateJS(javascript);&amp;lt;/code&amp;gt; &lt;br /&gt;
which will run the javascript (by creating a new script tag and appending it to the page head).&lt;br /&gt;
&lt;br /&gt;
== What other helpers can I use? ==&lt;br /&gt;
There is a string helper for loading language strings.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#str}} iscool, mod_cool, David Beckham {{/str}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The first 2 parameters are the string id and the component name, the rest of the section is the content for the $a variable. So this example would call get_string(&#039;iscool&#039;, &#039;mod_cool&#039;, &#039;David Beckham&#039;);&lt;br /&gt;
&lt;br /&gt;
Variables are allowed in the text for the $a param. &lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#str}} iscool, mod_cool, {{name}} {{/str}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For strings that accept complex $a params, you can use a json object here instead:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#str}} iscool, mod_cool, { firstname: &#039;David&#039;, lastname: &#039;Beckham&#039;}{{/str}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a pix icon helper for generating pix icon tags.&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#pix}} t/edit, core, Edit David Beckham {{/pix}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The first 2 parameters are the string id and the component name, the rest is the alt text for the image.&lt;br /&gt;
&lt;br /&gt;
== How do I call a template from php? ==&lt;br /&gt;
&lt;br /&gt;
The templates in php are attached to the renderers. There is a renderer method &amp;quot;render_from_template($templatename, $context)&amp;quot; that does the trick.&lt;br /&gt;
&lt;br /&gt;
== How do templates work with renderers? ==&lt;br /&gt;
&lt;br /&gt;
Extra care must be taken to ensure that the data passed to the context parameter is useful to the templating language. The template language cannot:&lt;br /&gt;
* Call functions&lt;br /&gt;
* Perform any boolean logic&lt;br /&gt;
* Render renderables&lt;br /&gt;
* Do capability checks&lt;br /&gt;
* Make DB queries&lt;br /&gt;
&lt;br /&gt;
So - I have &amp;quot;some&amp;quot; data in my renderable and some logic and html generation in my render method for that renderable - how do I refactor this to use a template?&lt;br /&gt;
&lt;br /&gt;
The first thing to note, is that you don&#039;t have to use a template if you don&#039;t want to. It just means that themers will still have to override your render method, instead of just overriding the template. But if you DO want to use a template, you will earn &amp;quot;cred&amp;quot; with themers, and you will be able to re-render parts of your interface from javascript in response to ajax requests without reloading the whole page (that&#039;s cool).&lt;br /&gt;
&lt;br /&gt;
There is a simple pattern to use to hook a template into a render method. If you make your renderable implement templatable as well as renderable - it will have to implement a new method &amp;quot;export_for_template(renderer_base $output)&amp;quot;. This method takes the data stored in the renderable and &amp;quot;flattens it&amp;quot; so it can be used in a template. If there is some nested data in the renderable (like other renderables) and they do not support templates, they can be &amp;quot;rendered&amp;quot; into the flat data structure using the renderer parameter. It should return an stdClass with properties that are only made of simple types: int, string, bool, float, stdClass or arrays of these types. Then the render method can updated to export the data and render it with the template.&lt;br /&gt;
&lt;br /&gt;
In the renderable:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;canmanage = $this-&amp;gt;canmanage;&lt;br /&gt;
        $data-&amp;gt;things = array();&lt;br /&gt;
        foreach ($this-&amp;gt;things as $thing) {&lt;br /&gt;
            $data-&amp;gt;things[] = $thing-&amp;gt;to_record();&lt;br /&gt;
        }&lt;br /&gt;
        $data-&amp;gt;navigation = array();&lt;br /&gt;
        foreach ($this-&amp;gt;navigation as $button) {&lt;br /&gt;
            $data-&amp;gt;navigation[] = $output-&amp;gt;render($button);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the renderer class:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param mywidget $widget&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    render(mywidget $widget) {&lt;br /&gt;
        $data = $widget-&amp;gt;export_for_template($this);&lt;br /&gt;
        return $this-&amp;gt;render_from_template(&#039;mywidget&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How to I override a template in my theme? ==&lt;br /&gt;
&lt;br /&gt;
Templates can be overridden a bit easier than overriding a renderer. First - find the template that you want to change. E.g. &amp;quot;mod/wiki/templates/ratingui.mustache&amp;quot;. Now, create a sub-folder under your themes &amp;quot;templates&amp;quot; directory with the component name of the plugin you are overriding. E.g &amp;quot;theme/timtam/templates/mod_wiki&amp;quot;. Finally, copy the ratingui.mustache file into the newly created &amp;quot;theme/timtam/templates/mod_wiki&amp;quot; and edit it. You should see your changes immediately if theme designer mode is on. Note: templates are cached just like CSS, so if you are not using theme designer mode you will need to purge all caches to see the latest version of an edited template. If the template you are overriding contains a documentation comment (see next section) it is recommended to remove it, it will still show the documentation in the template library.&lt;br /&gt;
&lt;br /&gt;
== Should I document my templates? ==&lt;br /&gt;
&lt;br /&gt;
Yes!!!! Theme designers need to know the limits of what they can expect to change without breaking anything. As a further benefit - your beautiful new template can be displayed in the &amp;quot;Template Library&amp;quot; tool shipped with Moodle. In order to provide nice documentation and examples for the Template Library, you should follow these conventions when documenting your template.&lt;br /&gt;
&lt;br /&gt;
=== Add a documentation comment to your template ===&lt;br /&gt;
Mustache comments look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  {{! &lt;br /&gt;
   I am a comment.&lt;br /&gt;
   I can span multiple lines.&lt;br /&gt;
  }}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The template library will look for a mustache comment that contains this special marker as the documentation to display, and the source of an example context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
@template component/templatename&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Useful things to include in the documentation for a template ====&lt;br /&gt;
===== Classes required for JS =====&lt;br /&gt;
This is a list of classes that are used by the javascript for this template. If removing a class from an element in the template will break the javascript, list it here.&lt;br /&gt;
&lt;br /&gt;
===== Data attributes required for JS =====&lt;br /&gt;
This is a list of data attributes (e.g. data-enhance=&amp;quot;true&amp;quot;) that are used by the javascript for this template. If removing a data attribute from an element in the template will break the javascript, list it here.&lt;br /&gt;
&lt;br /&gt;
===== Context variables required for this template =====&lt;br /&gt;
This is a description of the data that may be contained in the context that is passed to the template. Be explicit and document every attribute.&lt;br /&gt;
&lt;br /&gt;
===== Example context (json) =====&lt;br /&gt;
The Template Library will look for this data in your documentation comment as it allows it to render a &amp;quot;preview&amp;quot; of the template right in the Template Library. This is useful for theme designers to test all the available templates in their new theme to make sure they look nice in a new theme. It is also useful to make sure the template responds to different screen sizes, languages and devices. The format is a json encoded object that is passed directly into the render method for this template. &lt;br /&gt;
&lt;br /&gt;
==== A full example ====&lt;br /&gt;
lib/templates/pix_icon.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  {{!                                                                                                                                 &lt;br /&gt;
    This file is part of Moodle - http://moodle.org/                                                                                &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle is free software: you can redistribute it and/or modify                                                                  &lt;br /&gt;
    it under the terms of the GNU General Public License as published by                                                            &lt;br /&gt;
    the Free Software Foundation, either version 3 of the License, or                                                               &lt;br /&gt;
    (at your option) any later version.                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle is distributed in the hope that it will be useful,                                                                       &lt;br /&gt;
    but WITHOUT ANY WARRANTY; without even the implied warranty of                                                                  &lt;br /&gt;
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                                                   &lt;br /&gt;
    GNU General Public License for more details.                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    You should have received a copy of the GNU General Public License                                                               &lt;br /&gt;
    along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.                                                                 &lt;br /&gt;
  }}                                                                                                                                  &lt;br /&gt;
  {{!                                                                                                                                 &lt;br /&gt;
    @template core/pix_icon                                                                                                         &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle pix_icon template.                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    The purpose of this template is to render a pix_icon.                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Classes required for JS:                                                                                                        &lt;br /&gt;
    * none                                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Data attributes required for JS:                                                                                                &lt;br /&gt;
    * none                                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Context variables required for this template:                                                                                   &lt;br /&gt;
    * attributes Array of name / value pairs.                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Example context (json):                                                                                                         &lt;br /&gt;
    {                                                                                                                               &lt;br /&gt;
        &amp;quot;attributes&amp;quot;: [                                                                                                             &lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;src&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;http://moodle.com/wp-content/themes/moodle/images/logo-hat2.png&amp;quot; },                          &lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;class&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;iconsmall&amp;quot; }                                                                               &lt;br /&gt;
        ]                                                                                                                           &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
  }}                                                                                                                                  &lt;br /&gt;
  &amp;lt;img {{#attributes}}{{name}}=&amp;quot;{{value}}&amp;quot; {{/attributes}}/&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Coding style for templates ==&lt;br /&gt;
This section documents some coding style guidelines to follow when writing templates. The reason for these guidelines is to promote consistency, and interoperability of the templates.&lt;br /&gt;
&lt;br /&gt;
=== Include GPL at the top of each template ===&lt;br /&gt;
&lt;br /&gt;
Templates are a form of code and it is appropriate to license them like any other code.&lt;br /&gt;
&lt;br /&gt;
===Include a documentation comment for each template===&lt;br /&gt;
&lt;br /&gt;
The exception is when you are overriding a template, if the documentation from the parent still applies, you do not need to copy it to the overridden template.&lt;br /&gt;
&lt;br /&gt;
===Use data-attributes for JS hooks===&lt;br /&gt;
&lt;br /&gt;
Data attributes are ideal for adding javascript hooks to templates because:&lt;br /&gt;
* Classes are meant for styling - theme designers should be able to change the classes at will without breaking any functionality.&lt;br /&gt;
* IDs must be unique in the page, but it is not possible to control how many times the same template might be included in the page.&lt;br /&gt;
* Data attributes can have meaningful names and can be efficiently queried with a selector&lt;br /&gt;
&lt;br /&gt;
===Avoid custom CSS for templates===&lt;br /&gt;
&lt;br /&gt;
This is not a hard rule, but a preference. We already have too much CSS in Moodle - where ever possible we should try and re-use the existing CSS instead of adding new CSS to support every new template.&lt;br /&gt;
&lt;br /&gt;
===Re-use core templates as much as possible===&lt;br /&gt;
&lt;br /&gt;
First we need to build the core set of reusable templates - but once that is in place we should always try to re-use those core templates to build interfaces. This will make Moodle more consistent, attractive and customisable.&lt;br /&gt;
&lt;br /&gt;
===Do use the CSS framework classes directly in the templates===&lt;br /&gt;
&lt;br /&gt;
We have bootstrap in core - so lets make the most of it. There is no problem using bootstrap classes in core templates, as long as the &amp;quot;base&amp;quot; theme is also tested, and an overridden template is added there if required.&lt;br /&gt;
&lt;br /&gt;
===Avoid IDs for styling or javascript===&lt;br /&gt;
&lt;br /&gt;
IDs should never evet be used for styling as they have a high CSS specificity, and so are hard to override. In addition, IDs should be unique in the page, which implies that a template could only be used once in a page. IDs are also not ideal for javascript, for the same reason (must be unique in a page).&lt;br /&gt;
&lt;br /&gt;
The only acceptable case to use an ID is you need to create a one to one connection between the JS and template. In this case use the uniqid helper to generate an ID that will not conflict with any other template on the page, and use it as part of the ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{uniqid}}-somethingspecific&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    callFunction(&#039;{{uniqid}}-somethingspecific&#039;);&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Follow CSS coding style===&lt;br /&gt;
&lt;br /&gt;
https://docs.moodle.org/dev/CSS_coding_style&lt;br /&gt;
&lt;br /&gt;
Use hyphens as word-separators for class names. &lt;br /&gt;
Use lower case class names.&lt;br /&gt;
&lt;br /&gt;
===Wrap each template in one node with a classname that matches the template name===&lt;br /&gt;
&lt;br /&gt;
Generate a class name by combining the component and template names and separating words with underscore.&lt;br /&gt;
&lt;br /&gt;
e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;core_user_header&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;br /&gt;
[[Category:Output]]&lt;br /&gt;
&lt;br /&gt;
===Iterating over php arrays in a mustache template===&lt;br /&gt;
&lt;br /&gt;
Mustache treats hashes and arrays differently because of cross language compatibility&lt;br /&gt;
In php arrays and hashes are the same, but mustache treats them differently&lt;br /&gt;
It decides a php array is a hash and will not iterate over it if it is non 0 indexed and/or has a gap in the key numbers&lt;br /&gt;
so in short&lt;br /&gt;
you need to&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$datafortemplate-&amp;gt;mylist =  array_values($myarraywithnonnumerickeys)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
you could also use &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$datafortemplate-&amp;gt;mylist = new ArrayIterator($myarraywithnonnumerickeys);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
BUT this fails when $myarraywithnonnumerickeys is empty and you try to use&lt;br /&gt;
&amp;lt;code html5&amp;gt;&lt;br /&gt;
{{#mylist}}&lt;br /&gt;
with an array iterator if mylist is empty this block will not run&lt;br /&gt;
{{/mylist}}&lt;br /&gt;
{{^mylist}}&lt;br /&gt;
with an array iterator mylist will not run this block either because it is not quite empty&lt;br /&gt;
{{/mylist}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How do I write core templates? ==&lt;br /&gt;
Core templates should ideally be simple generic components that can be used within other templates to create more complex page layouts. They should be flexible enough for developers and themers to easily use without having to replace the template. The templates should attempt to encapsulate some core structure for the element as well as key classes while allowing the content to be easily overridden. Ultimately we want to avoid having duplicate HTML copied from template to template where possible, particularly if the HTML element has some classes associated with it.&lt;br /&gt;
&lt;br /&gt;
Mustache relies on variables to substitute context data into the template but unfortunately it&#039;s very unlikely that the the names of the context data will match what the template is expecting for all the places that the template might be used. So in order to allow easy extensibility and avoid having to duplicate templates just to rename the variables we can wrap them in block variables which would allow the template that is including our template to replace that variable with one from it&#039;s own context inline.&lt;br /&gt;
&lt;br /&gt;
There are a few key points to keep in mind when writing a core template:&lt;br /&gt;
* Consider how your template will actually be used. Try writing a test page that uses your template to help discover some of the assumptions you might have in the template.&lt;br /&gt;
* The example context you provide in the template is mostly just for showing the template in the template library and is likely not how your template will actually be used. Most uses of the template will have a different context all together.&lt;br /&gt;
* Try to enforce a core structure but avoid enforcing a specific context. Content should be overridable.&lt;br /&gt;
* Use block variables to indicate sections of your template that people are likely to want to change. Typically where they will be wanting to substitute in their own content.&lt;br /&gt;
* Try to keep any javascript that accompanies the template as decoupled from the HTML / CSS structure of the template as possible. Instead of relying on the existence of certain HTML elements or CSS classes it is generally better to leverage data-attributes which can be added to any element.&lt;br /&gt;
&lt;br /&gt;
=== An example: tabs ===&lt;br /&gt;
Let&#039;s go through an example to illustrate how you might build a core template. For the example we&#039;ll be building a tabs template, since it&#039;s a fairly complex component that requires the use of block variables and javascript.&lt;br /&gt;
&lt;br /&gt;
First we can create a basic template to get the general structure down, let&#039;s call it tabs. Here&#039;s what it might look like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
		{{# tabs }}&lt;br /&gt;
			&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
					data-target=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
					data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
					aria-controls=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
					aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
				&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{{ name }}}&amp;lt;/a&amp;gt;&lt;br /&gt;
			&amp;lt;/li&amp;gt;&lt;br /&gt;
		{{/ tabs }}&lt;br /&gt;
	&amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
		{{# tabs }}&lt;br /&gt;
			&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
				class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
				id=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
				{{{ content }}}&lt;br /&gt;
			&amp;lt;/div&amp;gt;&lt;br /&gt;
		{{/ tabs }}&lt;br /&gt;
	&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The template requires a context that looks something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;tabs&amp;quot;: [&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab1&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 1&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 1 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab2&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 2&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 2 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab3&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 3&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 3 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;}&lt;br /&gt;
	]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The javascript required to power the tabs element (keyboard navigation, show / hide panels etc) is written as an AMD module and is included by the template. The javascript is a little too large to go through here, but some key points to consider when writing it are:&lt;br /&gt;
It should ideally be independent of the HTML structure, so if someone wants to completely rewrite the tabs to be different elements (e.g. buttons or a set of divs) then the same javascript can be used without needing to change it. In order to achieve this it is important to identify the key components of the template.&lt;br /&gt;
&lt;br /&gt;
In this case it is a tab list, a tab and it&#039;s content. One way to identify these components would be to inspect the structure of the DOM, for example you might say &amp;quot;find me the ul element&amp;quot; when looking for the tab list and then &amp;quot;find my the child li elements&amp;quot; to find the tabs. While this would work, it couples your javascript to the HTML structure and makes it difficult to change later. A different approach would be to use the element attributes, for example you might say &amp;quot;find my the element with the role &#039;tablist&#039;&amp;quot; to get the tab list and then &amp;quot;find me the elements with the role &#039;tab&#039;&amp;quot; to get the tabs. This allows the HTML structure to change without breaking the javascript (as long as the correct attributes are set, of course).&lt;br /&gt;
&lt;br /&gt;
Another point of consideration for this example is what class to apply to a tab when it is selected. It makes sense to just apply something like &amp;quot;active&amp;quot; in the javascript, but that once again couples it to a particular CSS framework which makes it more difficult to change without modifying the javascript. In this case I chose to add a data attribute to the element to indicate which class will be set when the tab is selected. This means the javascript doesn&#039;t have to guess what the appropriate class is, it can just get it from the template.&lt;br /&gt;
&lt;br /&gt;
Ok, so we&#039;ve got our basic template. It&#039;s time to use it! Let&#039;s say we want to create a simple user profile page that might show 2 tabs, the first tab will be the user&#039;s name and the second tab will be the user&#039;s email address (please excuse the contrived example).&lt;br /&gt;
&lt;br /&gt;
Here&#039;s what the page might look like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;lt; core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That looks pretty simple! The only problem is, how do I get my content there? I would have to supply a context like this in order to display the tabs I want:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;tabs&amp;quot;: [&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab1&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Name&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;Your name is Mr. Test User.&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab2&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Email&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;Your email is testuser@example.com&amp;quot;},&lt;br /&gt;
	]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume that the context for this page doesn&#039;t match what the tabs template is expecting though (as will be the case most of the time). Let&#039;s assume the tabs template is being rendered with this context:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;name&amp;quot;:&amp;quot;Mr. Test User&amp;quot;,&lt;br /&gt;
	&amp;quot;email&amp;quot;:&amp;quot;testuser@example.com&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unfortunately, we&#039;ll almost certainly never have complete control over all of the contexts that our template will be rendered in which means we&#039;ll be expecting people to write new webservices to supply the same data in different formats every time they want to use a template. It becomes an unmanageable problem.&lt;br /&gt;
&lt;br /&gt;
Enter blocks! We can make the template more flexible by defining sections of the template that can be overriden when they are included. Pretty neat! This will allow us to enforce a certain core structure but not enforce a context on the template that is including the tabs.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s have another go at that template, this time leverging blocks:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
	{{$ tabheader }}&lt;br /&gt;
		&amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
							data-target=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
							data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
							aria-controls=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
							aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
						&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{{ name }}}&amp;lt;/a&amp;gt;&lt;br /&gt;
					&amp;lt;/li&amp;gt;&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
		&amp;lt;/ul&amp;gt;&lt;br /&gt;
	{{/ tabheader }}&lt;br /&gt;
	{{$ tabbody }}&lt;br /&gt;
		&amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
						class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
						id=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
						{{{ content }}}&lt;br /&gt;
					&amp;lt;/div&amp;gt;&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
	{{/ tabbody }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A summary of what we&#039;ve changed:&lt;br /&gt;
* Added a $tabheader block around the tab list, in case someone wants to change the ul element to something else.&lt;br /&gt;
* Added a $tablist block around the group of tabs to allow them to be overriden on incldue.&lt;br /&gt;
* Added a $tabbody block around the content, in case someone wants to change the content elements from divs.&lt;br /&gt;
* Added a $tabcontent block around the tab variable for the content to allow the content to be overriden on inlcude.&lt;br /&gt;
&lt;br /&gt;
Now let&#039;s see what using this template looks like for your User Profile page:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;gt; core/tabs }}&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
						data-target=&amp;quot;{{ uniqid }}-tab1&amp;quot;&lt;br /&gt;
						data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
						aria-controls=&amp;quot;{{ uniqid }}-tab1&amp;quot;&lt;br /&gt;
						aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Name&amp;lt;/a&amp;gt;&lt;br /&gt;
				&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
						data-target=&amp;quot;{{ uniqid }}-tab2&amp;quot;&lt;br /&gt;
						data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
						aria-controls=&amp;quot;{{ uniqid }}-tab2&amp;quot;&lt;br /&gt;
						aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Email&amp;lt;/a&amp;gt;&lt;br /&gt;
				&amp;lt;/li&amp;gt;&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
					class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
					id=&amp;quot;{{ uniqid }}-tab1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					Your name is {{ name }}.&lt;br /&gt;
				&amp;lt;/div&amp;gt;&lt;br /&gt;
				&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
					class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
					id=&amp;quot;{{ uniqid }}-tab2&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					Your email address is {{ email }}.&lt;br /&gt;
				&amp;lt;/div&amp;gt;&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		{{/ core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That looks a bit better! Now we&#039;ve been able to use the blocks to successfully change the template to use the context available to this page, we no longer need a &amp;quot;tabs&amp;quot; array with &amp;quot;name&amp;quot; and &amp;quot;content&amp;quot;. Even the javascript will continue to work because we&#039;ve kept the correct element attributes. &lt;br /&gt;
&lt;br /&gt;
We&#039;ve still got a slight problem though... In order to change the data for the template we&#039;ve had to copy &amp;amp; paste the HTML from the original template into our blocks as we do the override. While this works fine in this example, it means we don&#039;t quite get the encapsulation we want within the templates since we&#039;re leaking internal implementation details. If we ever wanted to change the CSS framework we use for Moodle (say from bootstrap 2 to boostrap 3 or 4) we&#039;d have to find all the places in the code where this tabs template is used and make sure that the HTML is correct in their block overrides.&lt;br /&gt;
&lt;br /&gt;
With that in mind, let&#039;s take one more pass at this template and see if we can improve it slightly again. This time we&#039;re doing to split the template out into 3 templates.&lt;br /&gt;
&lt;br /&gt;
tabs.mustache:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
	{{$ tabheader }}&lt;br /&gt;
		&amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					{{&amp;lt; core/tab_header_item }}		&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
		&amp;lt;/ul&amp;gt;&lt;br /&gt;
	{{/ tabheader }}&lt;br /&gt;
	{{$ tabbody }}&lt;br /&gt;
		&amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					{{&amp;lt; core/tab_content_item }}&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
	{{/ tabbody }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tab_header_item.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
		data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
		aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{$ tabname }}{{{ name }}}{{/ tabname }}&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tab_content_item.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
	class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	{{$ tabpanelcontent }}{{{ content }}}{{/ tabpanelcontent }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A summary of the changes:&lt;br /&gt;
* Split the template into 3, moving the tab into it&#039;s own template and the content into it&#039;s own and then including them in the tabs template.&lt;br /&gt;
* Removed the ids from the tabs and content. The javascript would be updating to assign these ids at runtime so that they don&#039;t need to be provided as part of the template context.&lt;br /&gt;
* Added a $tabname block for in the tab_header_item template to make the name flexible on import.&lt;br /&gt;
* Added a $tabpanelcontant block in the tab_content_item template to make the content flexible on import.&lt;br /&gt;
&lt;br /&gt;
Cool, so let&#039;s see what that looks like in our example now:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;gt; core/tabs }}&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{&amp;gt; core/tab_header_item }}&lt;br /&gt;
					{{$ tabname }}Name{{/ tabname }}&lt;br /&gt;
				{{/ core/tab_header_item }}&lt;br /&gt;
				{{&amp;gt; core/tab_header_item }}&lt;br /&gt;
					{{$ tabname }}Email{{/ tabname }}&lt;br /&gt;
				{{/ core/tab_header_item }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{&amp;gt; core/tab_content_item }}&lt;br /&gt;
					{{$ tabpanelcontent }}Your name is {{ name }}.{{/ tabpanelcontent }}&lt;br /&gt;
				{{/ core/tab_content_item }}&lt;br /&gt;
				{{&amp;gt; core/tab_content_item }}&lt;br /&gt;
					{{$ tabpanelcontent }}Your email address is {{ email }}.{{/ tabpanelcontent }}&lt;br /&gt;
				{{/ core/tab_content_item }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		{{/ core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And we&#039;re done! After making the changes above we&#039;ve been able to keep the benefits of the previous change to allow the context changes but we&#039;ve also removed the need to copy &amp;amp; paste the HTML everywhere. Instead we&#039;re able to use the child templates with a few additional blocks defined to get the content in there.&lt;br /&gt;
&lt;br /&gt;
Now if we want to change tabs HTML or CSS frameworks we can just change the core tabs templates and this page will receive the updates for free.&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=48492</id>
		<title>Templates</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=48492"/>
		<updated>2015-09-08T05:22:09Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
= Templates =&lt;br /&gt;
&lt;br /&gt;
== What is a template? ==&lt;br /&gt;
A template is an alternative to writing blocks of html directly in javascript / php by concatenating strings. The end result is the same, but templates have a number of advantages:&lt;br /&gt;
* It is easier to see the final result of the template because the code for a template is very close to what the final HTML will look like&lt;br /&gt;
* Because the templating language is intentionally limited, it is hard to introduce complex logic into a template. This make it far easier for a theme designer to override a template, without breaking the logic&lt;br /&gt;
* Templates can be rendered from javascript. This allows ajax operations to re-render a portion of the page.&lt;br /&gt;
&lt;br /&gt;
== How do I write a template? ==&lt;br /&gt;
Templates are written in a language called &amp;quot;[http://mustache.github.io/mustache.5.html Mustache]&amp;quot;. Mustache is written as HTML with additional tags used to format the display of the data. Mustache tags are made of 2 opening and closing curly braces &amp;quot;{{tag}}&amp;quot;. There are a few variations of these tags that behave differently.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{raiden}}&amp;lt;/code&amp;gt; This is a simple variable substitution. The variable named &amp;quot;variable&amp;quot; will be searched for in the current context (and any parent contexts) and when a value is found, the entire tag will be replaced by the variable (html escaped).&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{{galaga}}}&amp;lt;/code&amp;gt; This is an unescaped variable substitution. Instead of escaping the variable before replacing it in the template, the variable is included raw. This is useful when the variable contains a block of HTML (for example).&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{#lemmings}} jump off cliff {{/lemmings}}&amp;lt;/code&amp;gt; These are opening and closing section tags. If the lemmings variable exists and evaluates to &amp;quot;not false&amp;quot; value, the variable is pushed on the stack, the contents of the section are parsed and included in the result. If the variable does not exist, or evaluates to false - the section will be skipped. If the variable lemmings evaluates to an array, the section will be repeated for each item in the array with the items of the array on the context. This is how to output a list.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{^lemmings}} enjoy view {{/lemmings}}&amp;lt;/code&amp;gt; Equivalent of &amp;quot;if-not&amp;quot; block, there is not &amp;quot;else&amp;quot; in mustache.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{&amp;gt; pacman }}&amp;lt;/code&amp;gt; This is a partial. Think of it like an include. Templates can include other templates using this tag.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{$blockvar}} ... {{/blockvar}}&amp;lt;/code&amp;gt; This is a block variable. It defines a section of the template that can be overridden when it&#039;s included in another template.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{&amp;lt; template_name}} ... {{/template_name}}&amp;lt;/code&amp;gt; This is similar to including a partial but specifically indicates that you&#039;d like to override one or more black variables defined within the template you&#039;re including. You can override the black variables by defining a block variable within these tags that matches the name of the block variable you&#039;d like to override in the included template.&lt;br /&gt;
&lt;br /&gt;
So - putting this all together:&lt;br /&gt;
&lt;br /&gt;
recipe.mustache&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;{{recipename}}&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;{{description}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;h4&amp;gt;Ingredients&amp;lt;/h4&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
{{#ingredients}}&lt;br /&gt;
&amp;lt;li&amp;gt;{{.}}&amp;lt;/li&amp;gt;&lt;br /&gt;
{{/ingredients}}&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;h4&amp;gt;Steps&amp;lt;/h4&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
{{#steps}}&lt;br /&gt;
&amp;lt;li&amp;gt;{{{.}}}&amp;lt;/li&amp;gt;&lt;br /&gt;
{{/steps}}&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
{{ &amp;gt; ratethisrecipe }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When given this data:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  recipename: &amp;quot;Cheese sandwich&amp;quot;,&lt;br /&gt;
  description: &amp;quot;Who doesn&#039;t like a good cheese sandwich?&amp;quot;,&lt;br /&gt;
  ingredients: [&amp;quot;bread&amp;quot;, &amp;quot;cheese&amp;quot;, &amp;quot;butter&amp;quot;],&lt;br /&gt;
  steps: [&amp;quot;&amp;lt;p&amp;gt;Step 1 is to spread the butter on the bread&amp;lt;/p&amp;gt;&amp;quot;, &amp;quot;&amp;lt;p&amp;gt;Step 2 is to put the cheese &amp;amp;quot;in&amp;amp;quot; the bread (not on top, or underneath)&amp;lt;/p&amp;gt;&amp;quot;]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gives this: &amp;lt;span style=&amp;quot;font-size:4em&amp;quot;&amp;gt;😋&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More info - there are much clearer explanations of templates on the [http://mustache.github.io/mustache.5.html Mustache] website. Try reading those pages &amp;quot;before&amp;quot; posting on stack overflow :) .&lt;br /&gt;
&lt;br /&gt;
== How do I write core templates? ==&lt;br /&gt;
Core templates should ideally be simple generic components that can be used within other templates to create more complex page layouts. They should be flexible enough for developers and themers to easily use without having to replace the template. The templates should attempt to encapsulate some core structure for the element as well as key classes while allowing the content to be easily overridden. Ultimately we want to avoid having duplicate HTML copied from template to template where possible, particularly if the HTML element has some classes associated with it.&lt;br /&gt;
&lt;br /&gt;
Mustache relies on variables to substitute context data into the template but unfortunately it&#039;s very unlikely that the the names of the context data will match what the template is expecting for all the places that the template might be used. So in order to allow easy extensibility and avoid having to duplicate templates just to rename the variables we can wrap them in block variables which would allow the template that is including our template to replace that variable with one from it&#039;s own context inline.&lt;br /&gt;
&lt;br /&gt;
There are a few key points to keep in mind when writing a core template:&lt;br /&gt;
* Consider how your template will actually be used. Try writing a test page that uses your template to help discover some of the assumptions you might have in the template.&lt;br /&gt;
* The example context you provide in the template is mostly just for showing the template in the template library and is likely not how your template will actually be used. Most uses of the template will have a different context all together.&lt;br /&gt;
* Try to enforce a core structure but avoid enforcing a specific context. Content should be overridable.&lt;br /&gt;
* Use block variables to indicate sections of your template that people are likely to want to change. Typically where they will be wanting to substitute in their own content.&lt;br /&gt;
* Try to keep any javascript that accompanies the template as decoupled from the HTML / CSS structure of the template as possible. Instead of relying on the existence of certain HTML elements or CSS classes it is generally better to leverage data-attributes which can be added to any element.&lt;br /&gt;
&lt;br /&gt;
=== An example: tabs ===&lt;br /&gt;
Let&#039;s go through an example to illustrate how you might build a core template. For the example we&#039;ll be building a tabs template, since it&#039;s a fairly complex component that requires the use of block variables and javascript.&lt;br /&gt;
&lt;br /&gt;
First we can create a basic template to get the general structure down, let&#039;s call it tabs. Here&#039;s what it might look like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
		{{# tabs }}&lt;br /&gt;
			&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
					data-target=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
					data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
					aria-controls=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
					aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
				&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{{ name }}}&amp;lt;/a&amp;gt;&lt;br /&gt;
			&amp;lt;/li&amp;gt;&lt;br /&gt;
		{{/ tabs }}&lt;br /&gt;
	&amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
		{{# tabs }}&lt;br /&gt;
			&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
				class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
				id=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
				{{{ content }}}&lt;br /&gt;
			&amp;lt;/div&amp;gt;&lt;br /&gt;
		{{/ tabs }}&lt;br /&gt;
	&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The template requires a context that looks something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;tabs&amp;quot;: [&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab1&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 1&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 1 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab2&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 2&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 2 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab3&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Tab 3&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;This is tab 3 content &amp;lt;a href=\&amp;quot;#\&amp;quot;&amp;gt;test&amp;lt;/a&amp;gt;&amp;quot;}&lt;br /&gt;
	]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The javascript required to power the tabs element (keyboard navigation, show / hide panels etc) is written as an AMD module and is included by the template. The javascript is a little too large to go through here, but some key points to consider when writing it are:&lt;br /&gt;
It should ideally be independent of the HTML structure, so if someone wants to completely rewrite the tabs to be different elements (e.g. buttons or a set of divs) then the same javascript can be used without needing to change it. In order to achieve this it is important to identify the key components of the template.&lt;br /&gt;
&lt;br /&gt;
In this case it is a tab list, a tab and it&#039;s content. One way to identify these components would be to inspect the structure of the DOM, for example you might say &amp;quot;find me the ul element&amp;quot; when looking for the tab list and then &amp;quot;find my the child li elements&amp;quot; to find the tabs. While this would work, it couples your javascript to the HTML structure and makes it difficult to change later. A different approach would be to use the element attributes, for example you might say &amp;quot;find my the element with the role &#039;tablist&#039;&amp;quot; to get the tab list and then &amp;quot;find me the elements with the role &#039;tab&#039;&amp;quot; to get the tabs. This allows the HTML structure to change without breaking the javascript (as long as the correct attributes are set, of course).&lt;br /&gt;
&lt;br /&gt;
Another point of consideration for this example is what class to apply to a tab when it is selected. It makes sense to just apply something like &amp;quot;active&amp;quot; in the javascript, but that once again couples it to a particular CSS framework which makes it more difficult to change without modifying the javascript. In this case I chose to add a data attribute to the element to indicate which class will be set when the tab is selected. This means the javascript doesn&#039;t have to guess what the appropriate class is, it can just get it from the template.&lt;br /&gt;
&lt;br /&gt;
Ok, so we&#039;ve got our basic template. It&#039;s time to use it! Let&#039;s say we want to create a simple user profile page that might show 2 tabs, the first tab will be the user&#039;s name and the second tab will be the user&#039;s email address (please excuse the contrived example).&lt;br /&gt;
&lt;br /&gt;
Here&#039;s what the page might look like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;lt; core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That looks pretty simple! The only problem is, how do I get my content there? I would have to supply a context like this in order to display the tabs I want:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;tabs&amp;quot;: [&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab1&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Name&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;Your name is Mr. Test User.&amp;quot;},&lt;br /&gt;
		{&amp;quot;id&amp;quot;:&amp;quot;tab2&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Email&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;Your email is testuser@example.com&amp;quot;},&lt;br /&gt;
	]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume that the context for this page doesn&#039;t match what the tabs template is expecting though (as will be the case most of the time). Let&#039;s assume the tabs template is being rendered with this context:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;name&amp;quot;:&amp;quot;Mr. Test User&amp;quot;,&lt;br /&gt;
	&amp;quot;email&amp;quot;:&amp;quot;testuser@example.com&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unfortunately, we&#039;ll almost certainly never have complete control over all of the contexts that our template will be rendered in which means we&#039;ll be expecting people to write new webservices to supply the same data in different formats every time they want to use a template. It becomes an unmanageable problem.&lt;br /&gt;
&lt;br /&gt;
Enter blocks! We can make the template more flexible by defining sections of the template that can be overriden when they are included. Pretty neat! This will allow us to enforce a certain core structure but not enforce a context on the template that is including the tabs.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s have another go at that template, this time leverging blocks:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
	{{$ tabheader }}&lt;br /&gt;
		&amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
							data-target=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
							data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
							aria-controls=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&lt;br /&gt;
							aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
						&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{{ name }}}&amp;lt;/a&amp;gt;&lt;br /&gt;
					&amp;lt;/li&amp;gt;&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
		&amp;lt;/ul&amp;gt;&lt;br /&gt;
	{{/ tabheader }}&lt;br /&gt;
	{{$ tabbody }}&lt;br /&gt;
		&amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
						class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
						id=&amp;quot;{{ uniqid }}-{{ id }}&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
						{{{ content }}}&lt;br /&gt;
					&amp;lt;/div&amp;gt;&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
	{{/ tabbody }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A summary of what we&#039;ve changed:&lt;br /&gt;
* Added a $tabheader block around the tab list, in case someone wants to change the ul element to something else.&lt;br /&gt;
* Added a $tablist block around the group of tabs to allow them to be overriden on incldue.&lt;br /&gt;
* Added a $tabbody block around the content, in case someone wants to change the content elements from divs.&lt;br /&gt;
* Added a $tabcontent block around the tab variable for the content to allow the content to be overriden on inlcude.&lt;br /&gt;
&lt;br /&gt;
Now let&#039;s see what using this template looks like for your User Profile page:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;gt; core/tabs }}&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
						data-target=&amp;quot;{{ uniqid }}-tab1&amp;quot;&lt;br /&gt;
						data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
						aria-controls=&amp;quot;{{ uniqid }}-tab1&amp;quot;&lt;br /&gt;
						aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Name&amp;lt;/a&amp;gt;&lt;br /&gt;
				&amp;lt;/li&amp;gt;&lt;br /&gt;
				&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
						data-target=&amp;quot;{{ uniqid }}-tab2&amp;quot;&lt;br /&gt;
						data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
						aria-controls=&amp;quot;{{ uniqid }}-tab2&amp;quot;&lt;br /&gt;
						aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Email&amp;lt;/a&amp;gt;&lt;br /&gt;
				&amp;lt;/li&amp;gt;&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
					class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
					id=&amp;quot;{{ uniqid }}-tab1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					Your name is {{ name }}.&lt;br /&gt;
				&amp;lt;/div&amp;gt;&lt;br /&gt;
				&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
					class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
					id=&amp;quot;{{ uniqid }}-tab2&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
					Your email address is {{ email }}.&lt;br /&gt;
				&amp;lt;/div&amp;gt;&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		{{/ core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That looks a bit better! Now we&#039;ve been able to use the blocks to successfully change the template to use the context available to this page, we no longer need a &amp;quot;tabs&amp;quot; array with &amp;quot;name&amp;quot; and &amp;quot;content&amp;quot;. Even the javascript will continue to work because we&#039;ve kept the correct element attributes. &lt;br /&gt;
&lt;br /&gt;
We&#039;ve still got a slight problem though... In order to change the data for the template we&#039;ve had to copy &amp;amp; paste the HTML from the original template into our blocks as we do the override. While this works fine in this example, it means we don&#039;t quite get the encapsulation we want within the templates since we&#039;re leaking internal implementation details. If we ever wanted to change the CSS framework we use for Moodle (say from bootstrap 2 to boostrap 3 or 4) we&#039;d have to find all the places in the code where this tabs template is used and make sure that the HTML is correct in their block overrides.&lt;br /&gt;
&lt;br /&gt;
With that in mind, let&#039;s take one more pass at this template and see if we can improve it slightly again. This time we&#039;re doing to split the template out into 3 templates.&lt;br /&gt;
&lt;br /&gt;
tabs.mustache:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{ uniqid }}-tab-container&amp;quot;&amp;gt;&lt;br /&gt;
	{{$ tabheader }}&lt;br /&gt;
		&amp;lt;ul role=&amp;quot;tablist&amp;quot; class=&amp;quot;nav nav-tabs&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					{{&amp;lt; core/tab_header_item }}		&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
		&amp;lt;/ul&amp;gt;&lt;br /&gt;
	{{/ tabheader }}&lt;br /&gt;
	{{$ tabbody }}&lt;br /&gt;
		&amp;lt;div class=&amp;quot;tab-content&amp;quot;&amp;gt;&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{# tabs }}&lt;br /&gt;
					{{&amp;lt; core/tab_content_item }}&lt;br /&gt;
				{{/ tabs }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
	{{/ tabbody }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    require([&#039;jquery&#039;,&#039;core/tabs&#039;], function($, tabs) {&lt;br /&gt;
&lt;br /&gt;
        var container = $(&amp;quot;#{{ uniqid }}-tab-container&amp;quot;);&lt;br /&gt;
        tabs.create(container);&lt;br /&gt;
    });&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tab_header_item.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;li role=&amp;quot;tab&amp;quot;&lt;br /&gt;
		data-selected-class=&amp;quot;active&amp;quot;&lt;br /&gt;
		aria-selected=&amp;quot;false&amp;quot; tabindex=&amp;quot;-1&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;{{$ tabname }}{{{ name }}}{{/ tabname }}&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tab_content_item.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div role=&amp;quot;tabpanel&amp;quot;&lt;br /&gt;
	class=&amp;quot;tab-pane&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	{{$ tabpanelcontent }}{{{ content }}}{{/ tabpanelcontent }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A summary of the changes:&lt;br /&gt;
* Split the template into 3, moving the tab into it&#039;s own template and the content into it&#039;s own and then including them in the tabs template.&lt;br /&gt;
* Removed the ids from the tabs and content. The javascript would be updating to assign these ids at runtime so that they don&#039;t need to be provided as part of the template context.&lt;br /&gt;
* Added a $tabname block for in the tab_header_item template to make the name flexible on import.&lt;br /&gt;
* Added a $tabpanelcontant block in the tab_content_item template to make the content flexible on import.&lt;br /&gt;
&lt;br /&gt;
Cool, so let&#039;s see what that looks like in our example now:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
    &amp;lt;header&amp;gt;&amp;lt;title&amp;gt;User Profile&amp;lt;/title&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        {{&amp;gt; core/tabs }}&lt;br /&gt;
			{{$ tablist }}&lt;br /&gt;
				{{&amp;gt; core/tab_header_item }}&lt;br /&gt;
					{{$ tabname }}Name{{/ tabname }}&lt;br /&gt;
				{{/ core/tab_header_item }}&lt;br /&gt;
				{{&amp;gt; core/tab_header_item }}&lt;br /&gt;
					{{$ tabname }}Email{{/ tabname }}&lt;br /&gt;
				{{/ core/tab_header_item }}&lt;br /&gt;
			{{/ tablist }}&lt;br /&gt;
			{{$ tabcontent }}&lt;br /&gt;
				{{&amp;gt; core/tab_content_item }}&lt;br /&gt;
					{{$ tabpanelcontent }}Your name is {{ name }}.{{/ tabpanelcontent }}&lt;br /&gt;
				{{/ core/tab_content_item }}&lt;br /&gt;
				{{&amp;gt; core/tab_content_item }}&lt;br /&gt;
					{{$ tabpanelcontent }}Your email address is {{ email }}.{{/ tabpanelcontent }}&lt;br /&gt;
				{{/ core/tab_content_item }}&lt;br /&gt;
			{{/ tabcontent }}&lt;br /&gt;
		{{/ core/tabs }}&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And we&#039;re done! After making the changes above we&#039;ve been able to keep the benefits of the previous change to allow the context changes but we&#039;ve also removed the need to copy &amp;amp; paste the HTML everywhere. Instead we&#039;re able to use the child templates with a few additional blocks defined to get the content in there.&lt;br /&gt;
&lt;br /&gt;
Now if we want to change tabs HTML or CSS frameworks we can just change the core tabs templates and this page will receive the updates for free.&lt;br /&gt;
&lt;br /&gt;
== Where do I put my templates? ==&lt;br /&gt;
&lt;br /&gt;
Templates go in the &amp;lt;componentdir&amp;gt;/templates folder and must have a .mustache file extension. When loading templates the template name is &amp;lt;componentname&amp;gt;/&amp;lt;filename&amp;gt; (no file extension). &lt;br /&gt;
&lt;br /&gt;
So &amp;quot;mod_lesson/timer&amp;quot; would load the template at mod/lesson/templates/timer.mustache.&lt;br /&gt;
&lt;br /&gt;
Note: Do not try and put your templates in sub folders under the &amp;quot;/templates&amp;quot; directory. This is not supported and will not work.&lt;br /&gt;
&lt;br /&gt;
== How do I call a template from javascript? ==&lt;br /&gt;
&lt;br /&gt;
Rendering a template from javascript is fairly easy. There is a new AMD module that can load/cache and render a template for you. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// This is AMD code for loading the &amp;quot;core/templates&amp;quot; module. see [Javascript Modules].&lt;br /&gt;
require([&#039;core/templates&#039;], function(templates) {&lt;br /&gt;
&lt;br /&gt;
    // This will be the context for our template. So {{name}} in the template will resolve to &amp;quot;Tweety bird&amp;quot;.&lt;br /&gt;
    var context = { name: &#039;Tweety bird&#039;, intelligence: 2 };&lt;br /&gt;
&lt;br /&gt;
    // This will call the function to load and render our template. &lt;br /&gt;
    var promise = templates.render(&#039;block_looneytunes/profile&#039;, context);&lt;br /&gt;
&lt;br /&gt;
    // The promise object returned by this function means &amp;quot;I&#039;ve considered your request and will finish it later - I PROMISE!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    // How we deal with promise objects is by adding callbacks.&lt;br /&gt;
    promise.done(function(source, javascript) {&lt;br /&gt;
        // Here eventually I have my compiled template, and any javascript that it generated.&lt;br /&gt;
&lt;br /&gt;
        // I can execute the javascript (probably after adding the html to the DOM) like this:&lt;br /&gt;
        templates.runTemplateJS(js);&lt;br /&gt;
    });&lt;br /&gt;
  &lt;br /&gt;
    // Sometimes things fail&lt;br /&gt;
    promise.fail(function(ex) {&lt;br /&gt;
        // Deal with this exception (I recommend core/notify exception function for this).&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Under the hood, this did many clever things for us. It loaded the template via an ajax call if it was not cached. It found any missing lang strings in the template and loaded them in a single ajax request, it split the JS from the HTML and returned us both in easy to use way. Read on for how to nicely deal with the javascript parameter.&lt;br /&gt;
&lt;br /&gt;
Note: with some nice chaining and sugar, we can shorten the above example quite a bit:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/templates&#039;, &#039;core/notification&#039;], function(templates, notification) {&lt;br /&gt;
    var context = { name: &#039;Tweety bird&#039;, intelligence: 2 };&lt;br /&gt;
    templates.render(&#039;block_looneytunes/profile&#039;, context)&lt;br /&gt;
        .done(doneCallback)&lt;br /&gt;
        .fail(notification.exception);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What if a template contains javascript? ==&lt;br /&gt;
&lt;br /&gt;
Sometimes a template requires that some JS be run when it is added to the page in order to give it more features. In the template we can include blocks of javascript, but we should use a special section tag that has a &amp;quot;helper&amp;quot; method registered to handle javascript carefully. &lt;br /&gt;
&lt;br /&gt;
Example&lt;br /&gt;
profile.mustache&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;profile&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Name: {{name}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Intelligence: {{intelligence}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require(&#039;jquery&#039;, function($) {&lt;br /&gt;
    // Effects! Can we have &amp;quot;blink&amp;quot;?&lt;br /&gt;
    $(&#039;#profile&#039;).slideDown();&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If this template is rendered by PHP, the javascript is separated from the HTML, and is appended to a special section in the footer of the page &amp;quot;after&amp;quot; requirejs has loaded. This provides the optimal page loading speed. If the template is rendered by javascript, the javascript source will be passed to the &amp;quot;done&amp;quot; handler from the promise. Then, when the &amp;quot;done&amp;quot; handler has added the template to the DOM, it can call &lt;br /&gt;
&amp;lt;code javascript&amp;gt;templates.runTemplateJS(javascript);&amp;lt;/code&amp;gt; &lt;br /&gt;
which will run the javascript (by creating a new script tag and appending it to the page head).&lt;br /&gt;
&lt;br /&gt;
== What other helpers can I use? ==&lt;br /&gt;
There is a string helper for loading language strings.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#str}} iscool, mod_cool, David Beckham {{/str}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The first 2 parameters are the string id and the component name, the rest of the section is the content for the $a variable. So this example would call get_string(&#039;iscool&#039;, &#039;mod_cool&#039;, &#039;David Beckham&#039;);&lt;br /&gt;
&lt;br /&gt;
Variables are allowed in the text for the $a param. &lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#str}} iscool, mod_cool, {{name}} {{/str}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For strings that accept complex $a params, you can use a json object here instead:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#str}} iscool, mod_cool, { firstname: &#039;David&#039;, lastname: &#039;Beckham&#039;}{{/str}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a pix icon helper for generating pix icon tags.&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#pix}} t/edit, core, Edit David Beckham {{/pix}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The first 2 parameters are the string id and the component name, the rest is the alt text for the image.&lt;br /&gt;
&lt;br /&gt;
== How do I call a template from php? ==&lt;br /&gt;
&lt;br /&gt;
The templates in php are attached to the renderers. There is a renderer method &amp;quot;render_from_template($templatename, $context)&amp;quot; that does the trick.&lt;br /&gt;
&lt;br /&gt;
== How do templates work with renderers? ==&lt;br /&gt;
&lt;br /&gt;
Extra care must be taken to ensure that the data passed to the context parameter is useful to the templating language. The template language cannot:&lt;br /&gt;
* Call functions&lt;br /&gt;
* Perform any boolean logic&lt;br /&gt;
* Render renderables&lt;br /&gt;
* Do capability checks&lt;br /&gt;
* Make DB queries&lt;br /&gt;
&lt;br /&gt;
So - I have &amp;quot;some&amp;quot; data in my renderable and some logic and html generation in my render method for that renderable - how do I refactor this to use a template?&lt;br /&gt;
&lt;br /&gt;
The first thing to note, is that you don&#039;t have to use a template if you don&#039;t want to. It just means that themers will still have to override your render method, instead of just overriding the template. But if you DO want to use a template, you will earn &amp;quot;cred&amp;quot; with themers, and you will be able to re-render parts of your interface from javascript in response to ajax requests without reloading the whole page (that&#039;s cool).&lt;br /&gt;
&lt;br /&gt;
There is a simple pattern to use to hook a template into a render method. If you make your renderable implement templatable as well as renderable - it will have to implement a new method &amp;quot;export_for_template(renderer_base $output)&amp;quot;. This method takes the data stored in the renderable and &amp;quot;flattens it&amp;quot; so it can be used in a template. If there is some nested data in the renderable (like other renderables) and they do not support templates, they can be &amp;quot;rendered&amp;quot; into the flat data structure using the renderer parameter. It should return an stdClass with properties that are only made of simple types: int, string, bool, float, stdClass or arrays of these types. Then the render method can updated to export the data and render it with the template.&lt;br /&gt;
&lt;br /&gt;
In the renderable:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;canmanage = $this-&amp;gt;canmanage;&lt;br /&gt;
        $data-&amp;gt;things = array();&lt;br /&gt;
        foreach ($this-&amp;gt;things as $thing) {&lt;br /&gt;
            $data-&amp;gt;things[] = $thing-&amp;gt;to_record();&lt;br /&gt;
        }&lt;br /&gt;
        $data-&amp;gt;navigation = array();&lt;br /&gt;
        foreach ($this-&amp;gt;navigation as $button) {&lt;br /&gt;
            $data-&amp;gt;navigation[] = $output-&amp;gt;render($button);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the renderer class:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param mywidget $widget&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    render(mywidget $widget) {&lt;br /&gt;
        $data = $widget-&amp;gt;export_for_template($this);&lt;br /&gt;
        return $this-&amp;gt;render_from_template(&#039;mywidget&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How to I override a template in my theme? ==&lt;br /&gt;
&lt;br /&gt;
Templates can be overridden a bit easier than overriding a renderer. First - find the template that you want to change. E.g. &amp;quot;mod/wiki/templates/ratingui.mustache&amp;quot;. Now, create a sub-folder under your themes &amp;quot;templates&amp;quot; directory with the component name of the plugin you are overriding. E.g &amp;quot;theme/timtam/templates/mod_wiki&amp;quot;. Finally, copy the ratingui.mustache file into the newly created &amp;quot;theme/timtam/templates/mod_wiki&amp;quot; and edit it. You should see your changes immediately if theme designer mode is on. Note: templates are cached just like CSS, so if you are not using theme designer mode you will need to purge all caches to see the latest version of an edited template. If the template you are overriding contains a documentation comment (see next section) it is recommended to remove it, it will still show the documentation in the template library.&lt;br /&gt;
&lt;br /&gt;
== Should I document my templates? ==&lt;br /&gt;
&lt;br /&gt;
Yes!!!! Theme designers need to know the limits of what they can expect to change without breaking anything. As a further benefit - your beautiful new template can be displayed in the &amp;quot;Template Library&amp;quot; tool shipped with Moodle. In order to provide nice documentation and examples for the Template Library, you should follow these conventions when documenting your template.&lt;br /&gt;
&lt;br /&gt;
=== Add a documentation comment to your template ===&lt;br /&gt;
Mustache comments look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  {{! &lt;br /&gt;
   I am a comment.&lt;br /&gt;
   I can span multiple lines.&lt;br /&gt;
  }}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The template library will look for a mustache comment that contains this special marker as the documentation to display, and the source of an example context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
@template component/templatename&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Useful things to include in the documentation for a template ====&lt;br /&gt;
===== Classes required for JS =====&lt;br /&gt;
This is a list of classes that are used by the javascript for this template. If removing a class from an element in the template will break the javascript, list it here.&lt;br /&gt;
&lt;br /&gt;
===== Data attributes required for JS =====&lt;br /&gt;
This is a list of data attributes (e.g. data-enhance=&amp;quot;true&amp;quot;) that are used by the javascript for this template. If removing a data attribute from an element in the template will break the javascript, list it here.&lt;br /&gt;
&lt;br /&gt;
===== Context variables required for this template =====&lt;br /&gt;
This is a description of the data that may be contained in the context that is passed to the template. Be explicit and document every attribute.&lt;br /&gt;
&lt;br /&gt;
===== Example context (json) =====&lt;br /&gt;
The Template Library will look for this data in your documentation comment as it allows it to render a &amp;quot;preview&amp;quot; of the template right in the Template Library. This is useful for theme designers to test all the available templates in their new theme to make sure they look nice in a new theme. It is also useful to make sure the template responds to different screen sizes, languages and devices. The format is a json encoded object that is passed directly into the render method for this template. &lt;br /&gt;
&lt;br /&gt;
==== A full example ====&lt;br /&gt;
lib/templates/pix_icon.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  {{!                                                                                                                                 &lt;br /&gt;
    This file is part of Moodle - http://moodle.org/                                                                                &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle is free software: you can redistribute it and/or modify                                                                  &lt;br /&gt;
    it under the terms of the GNU General Public License as published by                                                            &lt;br /&gt;
    the Free Software Foundation, either version 3 of the License, or                                                               &lt;br /&gt;
    (at your option) any later version.                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle is distributed in the hope that it will be useful,                                                                       &lt;br /&gt;
    but WITHOUT ANY WARRANTY; without even the implied warranty of                                                                  &lt;br /&gt;
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                                                   &lt;br /&gt;
    GNU General Public License for more details.                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    You should have received a copy of the GNU General Public License                                                               &lt;br /&gt;
    along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.                                                                 &lt;br /&gt;
  }}                                                                                                                                  &lt;br /&gt;
  {{!                                                                                                                                 &lt;br /&gt;
    @template core/pix_icon                                                                                                         &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle pix_icon template.                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    The purpose of this template is to render a pix_icon.                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Classes required for JS:                                                                                                        &lt;br /&gt;
    * none                                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Data attributes required for JS:                                                                                                &lt;br /&gt;
    * none                                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Context variables required for this template:                                                                                   &lt;br /&gt;
    * attributes Array of name / value pairs.                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Example context (json):                                                                                                         &lt;br /&gt;
    {                                                                                                                               &lt;br /&gt;
        &amp;quot;attributes&amp;quot;: [                                                                                                             &lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;src&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;http://moodle.com/wp-content/themes/moodle/images/logo-hat2.png&amp;quot; },                          &lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;class&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;iconsmall&amp;quot; }                                                                               &lt;br /&gt;
        ]                                                                                                                           &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
  }}                                                                                                                                  &lt;br /&gt;
  &amp;lt;img {{#attributes}}{{name}}=&amp;quot;{{value}}&amp;quot; {{/attributes}}/&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Coding style for templates ==&lt;br /&gt;
This section documents some coding style guidelines to follow when writing templates. The reason for these guidelines is to promote consistency, and interoperability of the templates.&lt;br /&gt;
&lt;br /&gt;
=== Include GPL at the top of each template ===&lt;br /&gt;
&lt;br /&gt;
Templates are a form of code and it is appropriate to license them like any other code.&lt;br /&gt;
&lt;br /&gt;
===Include a documentation comment for each template===&lt;br /&gt;
&lt;br /&gt;
The exception is when you are overriding a template, if the documentation from the parent still applies, you do not need to copy it to the overridden template.&lt;br /&gt;
&lt;br /&gt;
===Use data-attributes for JS hooks===&lt;br /&gt;
&lt;br /&gt;
Data attributes are ideal for adding javascript hooks to templates because:&lt;br /&gt;
* Classes are meant for styling - theme designers should be able to change the classes at will without breaking any functionality.&lt;br /&gt;
* IDs must be unique in the page, but it is not possible to control how many times the same template might be included in the page.&lt;br /&gt;
* Data attributes can have meaningful names and can be efficiently queried with a selector&lt;br /&gt;
&lt;br /&gt;
===Avoid custom CSS for templates===&lt;br /&gt;
&lt;br /&gt;
This is not a hard rule, but a preference. We already have too much CSS in Moodle - where ever possible we should try and re-use the existing CSS instead of adding new CSS to support every new template.&lt;br /&gt;
&lt;br /&gt;
===Re-use core templates as much as possible===&lt;br /&gt;
&lt;br /&gt;
First we need to build the core set of reusable templates - but once that is in place we should always try to re-use those core templates to build interfaces. This will make Moodle more consistent, attractive and customisable.&lt;br /&gt;
&lt;br /&gt;
===Do use the CSS framework classes directly in the templates===&lt;br /&gt;
&lt;br /&gt;
We have bootstrap in core - so lets make the most of it. There is no problem using bootstrap classes in core templates, as long as the &amp;quot;base&amp;quot; theme is also tested, and an overridden template is added there if required.&lt;br /&gt;
&lt;br /&gt;
===Avoid IDs for styling or javascript===&lt;br /&gt;
&lt;br /&gt;
IDs should never evet be used for styling as they have a high CSS specificity, and so are hard to override. In addition, IDs should be unique in the page, which implies that a template could only be used once in a page. IDs are also not ideal for javascript, for the same reason (must be unique in a page).&lt;br /&gt;
&lt;br /&gt;
The only acceptable case to use an ID is you need to create a one to one connection between the JS and template. In this case use the uniqid helper to generate an ID that will not conflict with any other template on the page, and use it as part of the ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{uniqid}}-somethingspecific&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    callFunction(&#039;{{uniqid}}-somethingspecific&#039;);&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Follow CSS coding style===&lt;br /&gt;
&lt;br /&gt;
https://docs.moodle.org/dev/CSS_coding_style&lt;br /&gt;
&lt;br /&gt;
Use hyphens as word-separators for class names. &lt;br /&gt;
Use lower case class names.&lt;br /&gt;
&lt;br /&gt;
===Wrap each template in one node with a classname that matches the template name===&lt;br /&gt;
&lt;br /&gt;
Generate a class name by combining the component and template names and separating words with underscore.&lt;br /&gt;
&lt;br /&gt;
e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;core_user_header&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;br /&gt;
[[Category:Output]]&lt;br /&gt;
&lt;br /&gt;
===Iterating over php arrays in a mustache template===&lt;br /&gt;
&lt;br /&gt;
Mustache treats hashes and arrays differently because of cross language compatibility&lt;br /&gt;
In php arrays and hashes are the same, but mustache treats them differently&lt;br /&gt;
It decides a php array is a hash and will not iterate over it if it is non 0 indexed and/or has a gap in the key numbers&lt;br /&gt;
so in short&lt;br /&gt;
you need to&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$datafortemplate-&amp;gt;mylist =  array_values($myarraywithnonnumerickeys)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
you could also use &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$datafortemplate-&amp;gt;mylist = new ArrayIterator($myarraywithnonnumerickeys);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
BUT this fails when $myarraywithnonnumerickeys is empty and you try to use&lt;br /&gt;
&amp;lt;code html5&amp;gt;&lt;br /&gt;
{{#mylist}}&lt;br /&gt;
with an array iterator if mylist is empty this block will not run&lt;br /&gt;
{{/mylist}}&lt;br /&gt;
{{^mylist}}&lt;br /&gt;
with an array iterator mylist will not run this block either because it is not quite empty&lt;br /&gt;
{{/mylist}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=48472</id>
		<title>Templates</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=48472"/>
		<updated>2015-08-28T08:54:16Z</updated>

		<summary type="html">&lt;p&gt;Ryanwyllie: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
= Templates =&lt;br /&gt;
&lt;br /&gt;
== What is a template? ==&lt;br /&gt;
A template is an alternative to writing blocks of html directly in javascript / php by concatenating strings. The end result is the same, but templates have a number of advantages:&lt;br /&gt;
* It is easier to see the final result of the template because the code for a template is very close to what the final HTML will look like&lt;br /&gt;
* Because the templating language is intentionally limited, it is hard to introduce complex logic into a template. This make it far easier for a theme designer to override a template, without breaking the logic&lt;br /&gt;
* Templates can be rendered from javascript. This allows ajax operations to re-render a portion of the page.&lt;br /&gt;
&lt;br /&gt;
== How do I write a template? ==&lt;br /&gt;
Templates are written in a language called &amp;quot;[http://mustache.github.io/mustache.5.html Mustache]&amp;quot;. Mustache is written as HTML with additional tags used to format the display of the data. Mustache tags are made of 2 opening and closing curly braces &amp;quot;{{tag}}&amp;quot;. There are a few variations of these tags that behave differently.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{raiden}}&amp;lt;/code&amp;gt; This is a simple variable substitution. The variable named &amp;quot;variable&amp;quot; will be searched for in the current context (and any parent contexts) and when a value is found, the entire tag will be replaced by the variable (html escaped).&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{{galaga}}}&amp;lt;/code&amp;gt; This is an unescaped variable substitution. Instead of escaping the variable before replacing it in the template, the variable is included raw. This is useful when the variable contains a block of HTML (for example).&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{#lemmings}} jump off cliff {{/lemmings}}&amp;lt;/code&amp;gt; These are opening and closing section tags. If the lemmings variable exists and evaluates to &amp;quot;not false&amp;quot; value, the variable is pushed on the stack, the contents of the section are parsed and included in the result. If the variable does not exist, or evaluates to false - the section will be skipped. If the variable lemmings evaluates to an array, the section will be repeated for each item in the array with the items of the array on the context. This is how to output a list.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{^lemmings}} enjoy view {{/lemmings}}&amp;lt;/code&amp;gt; Equivalent of &amp;quot;if-not&amp;quot; block, there is not &amp;quot;else&amp;quot; in mustache.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{&amp;gt; pacman }}&amp;lt;/code&amp;gt; This is a partial. Think of it like an include. Templates can include other templates using this tag.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{$blockvar}} ... {{/blockvar}}&amp;lt;/code&amp;gt; This is a block variable. It defines a section of the template that can be overridden when it&#039;s included in another template.&lt;br /&gt;
* &amp;lt;code xml&amp;gt;{{&amp;lt; template_name}} ... {{/template_name}}&amp;lt;/code&amp;gt; This is similar to including a partial but specifically indicates that you&#039;d like to override one or more black variables defined within the template you&#039;re including. You can override the black variables by defining a block variable within these tags that matches the name of the block variable you&#039;d like to override in the included template.&lt;br /&gt;
&lt;br /&gt;
So - putting this all together:&lt;br /&gt;
&lt;br /&gt;
recipe.mustache&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;{{recipename}}&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;{{description}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;h4&amp;gt;Ingredients&amp;lt;/h4&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
{{#ingredients}}&lt;br /&gt;
&amp;lt;li&amp;gt;{{.}}&amp;lt;/li&amp;gt;&lt;br /&gt;
{{/ingredients}}&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;h4&amp;gt;Steps&amp;lt;/h4&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
{{#steps}}&lt;br /&gt;
&amp;lt;li&amp;gt;{{{.}}}&amp;lt;/li&amp;gt;&lt;br /&gt;
{{/steps}}&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
{{ &amp;gt; ratethisrecipe }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When given this data:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  recipename: &amp;quot;Cheese sandwich&amp;quot;,&lt;br /&gt;
  description: &amp;quot;Who doesn&#039;t like a good cheese sandwich?&amp;quot;,&lt;br /&gt;
  ingredients: [&amp;quot;bread&amp;quot;, &amp;quot;cheese&amp;quot;, &amp;quot;butter&amp;quot;],&lt;br /&gt;
  steps: [&amp;quot;&amp;lt;p&amp;gt;Step 1 is to spread the butter on the bread&amp;lt;/p&amp;gt;&amp;quot;, &amp;quot;&amp;lt;p&amp;gt;Step 2 is to put the cheese &amp;amp;quot;in&amp;amp;quot; the bread (not on top, or underneath)&amp;lt;/p&amp;gt;&amp;quot;]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gives this: &amp;lt;span style=&amp;quot;font-size:4em&amp;quot;&amp;gt;😋&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More info - there are much clearer explanations of templates on the [http://mustache.github.io/mustache.5.html Mustache] website. Try reading those pages &amp;quot;before&amp;quot; posting on stack overflow :) .&lt;br /&gt;
&lt;br /&gt;
== Where do I put my templates? ==&lt;br /&gt;
&lt;br /&gt;
Templates go in the &amp;lt;componentdir&amp;gt;/templates folder and must have a .mustache file extension. When loading templates the template name is &amp;lt;componentname&amp;gt;/&amp;lt;filename&amp;gt; (no file extension). &lt;br /&gt;
&lt;br /&gt;
So &amp;quot;mod_lesson/timer&amp;quot; would load the template at mod/lesson/templates/timer.mustache.&lt;br /&gt;
&lt;br /&gt;
Note: Do not try and put your templates in sub folders under the &amp;quot;/templates&amp;quot; directory. This is not supported and will not work.&lt;br /&gt;
&lt;br /&gt;
== How do I call a template from javascript? ==&lt;br /&gt;
&lt;br /&gt;
Rendering a template from javascript is fairly easy. There is a new AMD module that can load/cache and render a template for you. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// This is AMD code for loading the &amp;quot;core/templates&amp;quot; module. see [Javascript Modules].&lt;br /&gt;
require([&#039;core/templates&#039;], function(templates) {&lt;br /&gt;
&lt;br /&gt;
    // This will be the context for our template. So {{name}} in the template will resolve to &amp;quot;Tweety bird&amp;quot;.&lt;br /&gt;
    var context = { name: &#039;Tweety bird&#039;, intelligence: 2 };&lt;br /&gt;
&lt;br /&gt;
    // This will call the function to load and render our template. &lt;br /&gt;
    var promise = templates.render(&#039;block_looneytunes/profile&#039;, context);&lt;br /&gt;
&lt;br /&gt;
    // The promise object returned by this function means &amp;quot;I&#039;ve considered your request and will finish it later - I PROMISE!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    // How we deal with promise objects is by adding callbacks.&lt;br /&gt;
    promise.done(function(source, javascript) {&lt;br /&gt;
        // Here eventually I have my compiled template, and any javascript that it generated.&lt;br /&gt;
&lt;br /&gt;
        // I can execute the javascript (probably after adding the html to the DOM) like this:&lt;br /&gt;
        templates.runTemplateJS(js);&lt;br /&gt;
    });&lt;br /&gt;
  &lt;br /&gt;
    // Sometimes things fail&lt;br /&gt;
    promise.fail(function(ex) {&lt;br /&gt;
        // Deal with this exception (I recommend core/notify exception function for this).&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Under the hood, this did many clever things for us. It loaded the template via an ajax call if it was not cached. It found any missing lang strings in the template and loaded them in a single ajax request, it split the JS from the HTML and returned us both in easy to use way. Read on for how to nicely deal with the javascript parameter.&lt;br /&gt;
&lt;br /&gt;
Note: with some nice chaining and sugar, we can shorten the above example quite a bit:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/templates&#039;, &#039;core/notification&#039;], function(templates, notification) {&lt;br /&gt;
    var context = { name: &#039;Tweety bird&#039;, intelligence: 2 };&lt;br /&gt;
    templates.render(&#039;block_looneytunes/profile&#039;, context)&lt;br /&gt;
        .done(doneCallback)&lt;br /&gt;
        .fail(notification.exception);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What if a template contains javascript? ==&lt;br /&gt;
&lt;br /&gt;
Sometimes a template requires that some JS be run when it is added to the page in order to give it more features. In the template we can include blocks of javascript, but we should use a special section tag that has a &amp;quot;helper&amp;quot; method registered to handle javascript carefully. &lt;br /&gt;
&lt;br /&gt;
Example&lt;br /&gt;
profile.mustache&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;profile&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Name: {{name}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Intelligence: {{intelligence}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require(&#039;jquery&#039;, function($) {&lt;br /&gt;
    // Effects! Can we have &amp;quot;blink&amp;quot;?&lt;br /&gt;
    $(&#039;#profile&#039;).slideDown();&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If this template is rendered by PHP, the javascript is separated from the HTML, and is appended to a special section in the footer of the page &amp;quot;after&amp;quot; requirejs has loaded. This provides the optimal page loading speed. If the template is rendered by javascript, the javascript source will be passed to the &amp;quot;done&amp;quot; handler from the promise. Then, when the &amp;quot;done&amp;quot; handler has added the template to the DOM, it can call &lt;br /&gt;
&amp;lt;code javascript&amp;gt;templates.runTemplateJS(javascript);&amp;lt;/code&amp;gt; &lt;br /&gt;
which will run the javascript (by creating a new script tag and appending it to the page head).&lt;br /&gt;
&lt;br /&gt;
== What other helpers can I use? ==&lt;br /&gt;
There is a string helper for loading language strings.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#str}} iscool, mod_cool, David Beckham {{/str}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The first 2 parameters are the string id and the component name, the rest of the section is the content for the $a variable. So this example would call get_string(&#039;iscool&#039;, &#039;mod_cool&#039;, &#039;David Beckham&#039;);&lt;br /&gt;
&lt;br /&gt;
Variables are allowed in the text for the $a param. &lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#str}} iscool, mod_cool, {{name}} {{/str}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For strings that accept complex $a params, you can use a json object here instead:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#str}} iscool, mod_cool, { firstname: &#039;David&#039;, lastname: &#039;Beckham&#039;}{{/str}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a pix icon helper for generating pix icon tags.&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{#pix}} t/edit, core, Edit David Beckham {{/pix}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The first 2 parameters are the string id and the component name, the rest is the alt text for the image.&lt;br /&gt;
&lt;br /&gt;
== How do I call a template from php? ==&lt;br /&gt;
&lt;br /&gt;
The templates in php are attached to the renderers. There is a renderer method &amp;quot;render_from_template($templatename, $context)&amp;quot; that does the trick.&lt;br /&gt;
&lt;br /&gt;
== How do templates work with renderers? ==&lt;br /&gt;
&lt;br /&gt;
Extra care must be taken to ensure that the data passed to the context parameter is useful to the templating language. The template language cannot:&lt;br /&gt;
* Call functions&lt;br /&gt;
* Perform any boolean logic&lt;br /&gt;
* Render renderables&lt;br /&gt;
* Do capability checks&lt;br /&gt;
* Make DB queries&lt;br /&gt;
&lt;br /&gt;
So - I have &amp;quot;some&amp;quot; data in my renderable and some logic and html generation in my render method for that renderable - how do I refactor this to use a template?&lt;br /&gt;
&lt;br /&gt;
The first thing to note, is that you don&#039;t have to use a template if you don&#039;t want to. It just means that themers will still have to override your render method, instead of just overriding the template. But if you DO want to use a template, you will earn &amp;quot;cred&amp;quot; with themers, and you will be able to re-render parts of your interface from javascript in response to ajax requests without reloading the whole page (that&#039;s cool).&lt;br /&gt;
&lt;br /&gt;
There is a simple pattern to use to hook a template into a render method. If you make your renderable implement templatable as well as renderable - it will have to implement a new method &amp;quot;export_for_template(renderer_base $output)&amp;quot;. This method takes the data stored in the renderable and &amp;quot;flattens it&amp;quot; so it can be used in a template. If there is some nested data in the renderable (like other renderables) and they do not support templates, they can be &amp;quot;rendered&amp;quot; into the flat data structure using the renderer parameter. It should return an stdClass with properties that are only made of simple types: int, string, bool, float, stdClass or arrays of these types. Then the render method can updated to export the data and render it with the template.&lt;br /&gt;
&lt;br /&gt;
In the renderable:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;canmanage = $this-&amp;gt;canmanage;&lt;br /&gt;
        $data-&amp;gt;things = array();&lt;br /&gt;
        foreach ($this-&amp;gt;things as $thing) {&lt;br /&gt;
            $data-&amp;gt;things[] = $thing-&amp;gt;to_record();&lt;br /&gt;
        }&lt;br /&gt;
        $data-&amp;gt;navigation = array();&lt;br /&gt;
        foreach ($this-&amp;gt;navigation as $button) {&lt;br /&gt;
            $data-&amp;gt;navigation[] = $output-&amp;gt;render($button);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the renderer class:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param mywidget $widget&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    render(mywidget $widget) {&lt;br /&gt;
        $data = $widget-&amp;gt;export_for_template($this);&lt;br /&gt;
        return $this-&amp;gt;render_from_template(&#039;mywidget&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How to I override a template in my theme? ==&lt;br /&gt;
&lt;br /&gt;
Templates can be overridden a bit easier than overriding a renderer. First - find the template that you want to change. E.g. &amp;quot;mod/wiki/templates/ratingui.mustache&amp;quot;. Now, create a sub-folder under your themes &amp;quot;templates&amp;quot; directory with the component name of the plugin you are overriding. E.g &amp;quot;theme/timtam/templates/mod_wiki&amp;quot;. Finally, copy the ratingui.mustache file into the newly created &amp;quot;theme/timtam/templates/mod_wiki&amp;quot; and edit it. You should see your changes immediately if theme designer mode is on. Note: templates are cached just like CSS, so if you are not using theme designer mode you will need to purge all caches to see the latest version of an edited template. If the template you are overriding contains a documentation comment (see next section) it is recommended to remove it, it will still show the documentation in the template library.&lt;br /&gt;
&lt;br /&gt;
== Should I document my templates? ==&lt;br /&gt;
&lt;br /&gt;
Yes!!!! Theme designers need to know the limits of what they can expect to change without breaking anything. As a further benefit - your beautiful new template can be displayed in the &amp;quot;Template Library&amp;quot; tool shipped with Moodle. In order to provide nice documentation and examples for the Template Library, you should follow these conventions when documenting your template.&lt;br /&gt;
&lt;br /&gt;
=== Add a documentation comment to your template ===&lt;br /&gt;
Mustache comments look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  {{! &lt;br /&gt;
   I am a comment.&lt;br /&gt;
   I can span multiple lines.&lt;br /&gt;
  }}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The template library will look for a mustache comment that contains this special marker as the documentation to display, and the source of an example context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
@template component/templatename&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Useful things to include in the documentation for a template ====&lt;br /&gt;
===== Classes required for JS =====&lt;br /&gt;
This is a list of classes that are used by the javascript for this template. If removing a class from an element in the template will break the javascript, list it here.&lt;br /&gt;
&lt;br /&gt;
===== Data attributes required for JS =====&lt;br /&gt;
This is a list of data attributes (e.g. data-enhance=&amp;quot;true&amp;quot;) that are used by the javascript for this template. If removing a data attribute from an element in the template will break the javascript, list it here.&lt;br /&gt;
&lt;br /&gt;
===== Context variables required for this template =====&lt;br /&gt;
This is a description of the data that may be contained in the context that is passed to the template. Be explicit and document every attribute.&lt;br /&gt;
&lt;br /&gt;
===== Example context (json) =====&lt;br /&gt;
The Template Library will look for this data in your documentation comment as it allows it to render a &amp;quot;preview&amp;quot; of the template right in the Template Library. This is useful for theme designers to test all the available templates in their new theme to make sure they look nice in a new theme. It is also useful to make sure the template responds to different screen sizes, languages and devices. The format is a json encoded object that is passed directly into the render method for this template. &lt;br /&gt;
&lt;br /&gt;
==== A full example ====&lt;br /&gt;
lib/templates/pix_icon.mustache&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  {{!                                                                                                                                 &lt;br /&gt;
    This file is part of Moodle - http://moodle.org/                                                                                &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle is free software: you can redistribute it and/or modify                                                                  &lt;br /&gt;
    it under the terms of the GNU General Public License as published by                                                            &lt;br /&gt;
    the Free Software Foundation, either version 3 of the License, or                                                               &lt;br /&gt;
    (at your option) any later version.                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle is distributed in the hope that it will be useful,                                                                       &lt;br /&gt;
    but WITHOUT ANY WARRANTY; without even the implied warranty of                                                                  &lt;br /&gt;
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                                                   &lt;br /&gt;
    GNU General Public License for more details.                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    You should have received a copy of the GNU General Public License                                                               &lt;br /&gt;
    along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.                                                                 &lt;br /&gt;
  }}                                                                                                                                  &lt;br /&gt;
  {{!                                                                                                                                 &lt;br /&gt;
    @template core/pix_icon                                                                                                         &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Moodle pix_icon template.                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    The purpose of this template is to render a pix_icon.                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Classes required for JS:                                                                                                        &lt;br /&gt;
    * none                                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Data attributes required for JS:                                                                                                &lt;br /&gt;
    * none                                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Context variables required for this template:                                                                                   &lt;br /&gt;
    * attributes Array of name / value pairs.                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    Example context (json):                                                                                                         &lt;br /&gt;
    {                                                                                                                               &lt;br /&gt;
        &amp;quot;attributes&amp;quot;: [                                                                                                             &lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;src&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;http://moodle.com/wp-content/themes/moodle/images/logo-hat2.png&amp;quot; },                          &lt;br /&gt;
            { &amp;quot;name&amp;quot;: &amp;quot;class&amp;quot;, &amp;quot;value&amp;quot;: &amp;quot;iconsmall&amp;quot; }                                                                               &lt;br /&gt;
        ]                                                                                                                           &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
  }}                                                                                                                                  &lt;br /&gt;
  &amp;lt;img {{#attributes}}{{name}}=&amp;quot;{{value}}&amp;quot; {{/attributes}}/&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Coding style for templates ==&lt;br /&gt;
This section documents some coding style guidelines to follow when writing templates. The reason for these guidelines is to promote consistency, and interoperability of the templates.&lt;br /&gt;
&lt;br /&gt;
=== Include GPL at the top of each template ===&lt;br /&gt;
&lt;br /&gt;
Templates are a form of code and it is appropriate to license them like any other code.&lt;br /&gt;
&lt;br /&gt;
===Include a documentation comment for each template===&lt;br /&gt;
&lt;br /&gt;
The exception is when you are overriding a template, if the documentation from the parent still applies, you do not need to copy it to the overridden template.&lt;br /&gt;
&lt;br /&gt;
===Use data-attributes for JS hooks===&lt;br /&gt;
&lt;br /&gt;
Data attributes are ideal for adding javascript hooks to templates because:&lt;br /&gt;
* Classes are meant for styling - theme designers should be able to change the classes at will without breaking any functionality.&lt;br /&gt;
* IDs must be unique in the page, but it is not possible to control how many times the same template might be included in the page.&lt;br /&gt;
* Data attributes can have meaningful names and can be efficiently queried with a selector&lt;br /&gt;
&lt;br /&gt;
===Avoid custom CSS for templates===&lt;br /&gt;
&lt;br /&gt;
This is not a hard rule, but a preference. We already have too much CSS in Moodle - where ever possible we should try and re-use the existing CSS instead of adding new CSS to support every new template.&lt;br /&gt;
&lt;br /&gt;
===Re-use core templates as much as possible===&lt;br /&gt;
&lt;br /&gt;
First we need to build the core set of reusable templates - but once that is in place we should always try to re-use those core templates to build interfaces. This will make Moodle more consistent, attractive and customisable.&lt;br /&gt;
&lt;br /&gt;
===Do use the CSS framework classes directly in the templates===&lt;br /&gt;
&lt;br /&gt;
We have bootstrap in core - so lets make the most of it. There is no problem using bootstrap classes in core templates, as long as the &amp;quot;base&amp;quot; theme is also tested, and an overridden template is added there if required.&lt;br /&gt;
&lt;br /&gt;
===Avoid IDs for styling or javascript===&lt;br /&gt;
&lt;br /&gt;
IDs should never evet be used for styling as they have a high CSS specificity, and so are hard to override. In addition, IDs should be unique in the page, which implies that a template could only be used once in a page. IDs are also not ideal for javascript, for the same reason (must be unique in a page).&lt;br /&gt;
&lt;br /&gt;
The only acceptable case to use an ID is you need to create a one to one connection between the JS and template. In this case use the uniqid helper to generate an ID that will not conflict with any other template on the page, and use it as part of the ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;{{uniqid}}-somethingspecific&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
    callFunction(&#039;{{uniqid}}-somethingspecific&#039;);&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Follow CSS coding style===&lt;br /&gt;
&lt;br /&gt;
https://docs.moodle.org/dev/CSS_coding_style&lt;br /&gt;
&lt;br /&gt;
Use hyphens as word-separators for class names. &lt;br /&gt;
Use lower case class names.&lt;br /&gt;
&lt;br /&gt;
===Wrap each template in one node with a classname that matches the template name===&lt;br /&gt;
&lt;br /&gt;
Generate a class name by combining the component and template names and separating words with underscore.&lt;br /&gt;
&lt;br /&gt;
e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;core_user_header&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;br /&gt;
[[Category:Output]]&lt;/div&gt;</summary>
		<author><name>Ryanwyllie</name></author>
	</entry>
</feed>