<?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=Tim%2BHunt</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=Tim%2BHunt"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Tim%2BHunt"/>
	<updated>2026-06-07T23:14:47Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Template:Migrated&amp;diff=63589</id>
		<title>Template:Migrated</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Template:Migrated&amp;diff=63589"/>
		<updated>2022-08-15T13:31:22Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: Fix missing / in URLs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| class=&amp;quot;alert alert-info&amp;quot;&lt;br /&gt;
|style=&amp;quot;padding: 0.7em 0.5em 0.5em;&amp;quot; | &#039;&#039;&#039;Important:&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
This content of this page has been updated and migrated to the new [https://moodledev.io/{{{newDocId}}} Moodle Developer Resources]. The information contained on the page should no longer be seen up-to-date.&lt;br /&gt;
&lt;br /&gt;
Why not [https://moodledev.io/{{{newDocId}}} view this page on the new site] and [https://moodledev.io/general/documentation/contributing help us to migrate more content to the new site]!&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;includeonly&amp;gt;[[Category:DevDocs Migration]]&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
This template will categorise any documentation which has been moved into to new Developer Resources site. [[:Category:DevDocs Migration]].&lt;br /&gt;
&lt;br /&gt;
This template takes the following parameters:&lt;br /&gt;
* newDocId: [string] - For example /docs/apis/access&lt;br /&gt;
&lt;br /&gt;
Please note that this is a work-in-progress and we are currently assessing options. There is nothing to announce yet, but we want to be able to track which pages have been moved into our sample sites so that if we adopt one of these options we can track more easily what we have migrated.&lt;br /&gt;
&lt;br /&gt;
At the moment this template deliberately has no content. This will be added when we have something to announce and we start to formally use any new system that we adopt.&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_4.0_developer_update&amp;diff=62386</id>
		<title>Moodle 4.0 developer update</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_4.0_developer_update&amp;diff=62386"/>
		<updated>2022-05-16T16:58:35Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: /* Question type plugins */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page highlights the important changes that are coming in Moodle 4.0 for developers. Including how the UX improvements impact custom themes, relevant API changes, and what you can do as developer to prepare for the 4.0 release.&lt;br /&gt;
== Navigation changes ==&lt;br /&gt;
The core Navigation API has been left mostly untouched. The callbacks to all navigation callbacks remain unchanged and will be called as part of the regular &#039;navigation&#039; and &#039;settingsnav&#039; initialisation. Some new core classes have been created and exist within a new namespace &#039;core/navigation&#039; and serve as conduit to rearrange, cherry-pick existing navigation nodes from the navigation/settingsnav trees and display within the respective navigation type. As such, it is highly recommended to provide unique keys for custom navigation nodes as this helps in the cherry-picking / rearranging process within the new classes.&lt;br /&gt;
=== Primary navigation ===&lt;br /&gt;
The primary navigation(the navbar) apart from the existing content will now display links to the Dashboard, My Courses, Site Admin and Course search, by default. You can still add items to the navbar via the &#039;custom menu&#039; option. This will be displayed within the &#039;More&#039; menu. We have transitioned the menus to be rendered via templates - refer user_menu.mustache. The lang menu has been moved to reside within the user menu.&lt;br /&gt;
==== Customising the primary navigation ====&lt;br /&gt;
Not yet implemented but we are looking at allowing the full addition and removal of any of the primary navigation tabs in the boost theme config file.&lt;br /&gt;
=== Secondary navigation ===&lt;br /&gt;
The main content area shows tabs for secondary navigation with a maximum of 5 items being rendered in this ‘more’ menu. A new UI component has been created to render menus like this. Files:&lt;br /&gt;
 /lib/templates/moremenu.mustache&lt;br /&gt;
==== Adding items to the navigation ====&lt;br /&gt;
The secondary navigation pulls information mainly from the settings navigation node from each context. Any plugin that implements the existing navigation hooks will have their items added to the secondary navigation.&lt;br /&gt;
Existing navigation hooks:&lt;br /&gt;
* {module}_extend_navigation&lt;br /&gt;
* {local}_extend_navigation&lt;br /&gt;
* {report}_report_extend_navigation&lt;br /&gt;
* {plugin}_extend_navigation_course&lt;br /&gt;
* {plugin}_extend_navigation_category_settings&lt;br /&gt;
==== Changing the order of tabs ====&lt;br /&gt;
Apart from the previously mentioned functions, you can also create a custom secondary class as mentioned earlier. This will automatically be picked by getter and used to render the secondary nav within the activity. E.g. mod_assign/local/views/secondary. Note: This is currently only possible on an activity and block level.&lt;br /&gt;
=== Tertiary navigation ===&lt;br /&gt;
We&#039;ve moved action buttons to the top of the page. We would encourage you to do the same.&lt;br /&gt;
If you have any buttons on an activity page that go to another page, or open a form (or similar), then we encourage you to move them from the body of your activity page to the top. All of the core activities have been updated to follow this pattern. Please take a look to see how you can format your activity in a similar fashion. There is no API here. You are welcome to create the buttons and display them as you wish in this top area.&lt;br /&gt;
=== New API functions ===&lt;br /&gt;
==== Page API ====&lt;br /&gt;
* Magic getters to fetch the primary and secondary navs and the primary output.&lt;br /&gt;
* The secondarynav magic getter also checks whether a custom secondary class has been defined within the module&#039;s local\views directory. Use this if you want to deviate from the standard secondary nav structure/order.&lt;br /&gt;
&lt;br /&gt;
* set_secondarynav - Force override the secondary navigation class&lt;br /&gt;
&lt;br /&gt;
* set_secondary_navigation - Sets the ‘_hassecondarynavigation’ and optionally the ‘_hastablistsecondarynavigation’ to indicate whether a page should render the secondary navigation, and if the secondary navigation should be rendered and behave with a tablist ARIA role (as opposed to its default which is being rendered with a menubar ARIA role).&lt;br /&gt;
==== Navigationlib ====&lt;br /&gt;
* set_show_in_secondary_navigation - whether or not a node should be displayed in the secondary nav. Accepts a single boolean argument&lt;br /&gt;
* set_force_into_more_menu- whether or not to force a node into the &#039;More&#039; menu. Accepts a single boolean argument&lt;br /&gt;
==== The activity header class ====&lt;br /&gt;
There is a new activity header class that handles the display of information common to activities. 3rd party activities are not required to explicitly output this information as part of rendering individual pages.&lt;br /&gt;
&lt;br /&gt;
The common information that are currently handled by the class are:&lt;br /&gt;
* title&lt;br /&gt;
* description&lt;br /&gt;
* completion information&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As part of the update it was required that the initial information to be displayed by the class be toggable at a theme and layout level. Taking this into account the following theme level configurable exists:&lt;br /&gt;
* activityheaderconfig =&amp;gt; An array that currently only enforces &#039;notitle&#039; but can be expanded in the future NOTE: Boost has this set as true by default &#039;options&#039;&lt;br /&gt;
The following layout level options that can be defined:&lt;br /&gt;
* noactivityheader - to remove the header in this specific layout.&lt;br /&gt;
* activityheader - An array that enforces the following options:&lt;br /&gt;
** notitle&lt;br /&gt;
** nocompletion&lt;br /&gt;
** nodescription&lt;br /&gt;
The class has a page level getter which you can use to fetch the current version of the class. The base state is initialised within the constructor with the completion information only fetched when data is exported for the template.&lt;br /&gt;
&lt;br /&gt;
The class has setters for the following variables which can be leveraged to modify the header for a particular page in the format set_{variable_name}:&lt;br /&gt;
* hidecompletion&lt;br /&gt;
* description&lt;br /&gt;
* title&lt;br /&gt;
Alternately, bulk operations can also be done by passing the above variables in an array to &#039;set_attrs&#039; which in turn calls the setters.&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note: Any updates to the activityheader needs to be performed before the call to $OUTPUT-&amp;gt;header&#039;&#039;&#039;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
===== Theme updates =====&lt;br /&gt;
With the changes in boost to incorporate the primary and secondary navigation, 3rd party themes would need to account for the following in their templates:&lt;br /&gt;
* To leverage the activity_header, it&#039;s data needs to be exported and included into the base template :&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
{{#headercontent}}&lt;br /&gt;
   {{&amp;gt; core/activity_header}}&lt;br /&gt;
{{#headercontent}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;** headercontent being the array element that contains the exported activity_header data&lt;br /&gt;
* It is recommended to transition towards the secondary/tertiary navigation hierarchy to reduce user cognitive load and with a logical separation of components&lt;br /&gt;
** Secondary navigation can be added to the templates by following the example https://github.com/moodle/moodle/blob/master/theme/boost/templates/columns2.mustache#L64-L68 This leverages the secondary navigation class to generate it&#039;s content.&lt;br /&gt;
* Flat navigation classes have been marked for deprecation. Themes that leverage the flat_navigation will need to make the following changes in their plugins in order to use it&lt;br /&gt;
** Account for the additional changes [[Moodle 4.0 developer update#Theme changes]]&lt;br /&gt;
** Indicate that they do not implement secondary navigation via the page&#039;s &amp;quot;set_secondary_navigation&amp;quot; function. It is recommended to set this within the root layout file e.g. columns2&lt;br /&gt;
** Initialise the flat navigation by introducing the following in the root layout file(if not existent)&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$nav = $PAGE-&amp;gt;flatnav;&lt;br /&gt;
$templatecontext[&#039;firstcollectionlabel&#039;] = $nav-&amp;gt;get_collectionlabel();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* In order to reintroduce the settings cog in the templates, you can introduce the following: &amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;region-main-settings-menu&amp;quot; class=&amp;quot;d-print-none {{#hasblocks}}has-blocks{{/hasblocks}}&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div&amp;gt; {{{ output.region_main_settings_menu }}} &amp;lt;/div&amp;gt;            &lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===== Accessibility notes =====&lt;br /&gt;
The jump to ‘maincontent’ div is now rendered within the activity header when within an activity context&lt;br /&gt;
== Component library ==&lt;br /&gt;
Each Moodle installation now ships with a Moodle User Interface (UI) Component library, a documentation system used to describe all the Bootstrap components and the custom Moodle components. The component Library is a helper tool for developers when creating user interfaces, a testing tool for theme developers and a documentation tool for core developers. The ultimate goal of having a component library is to encourage developers to create consistent user interfaces to improve Moodle’s overall user experience.&lt;br /&gt;
&lt;br /&gt;
The library contains pages with documentation about User Interface components. It contains details on how to use the component, what variations are available and the JavaScript events / options are associated with the component.&lt;br /&gt;
&lt;br /&gt;
When writing on these pages it is possible to render core mustache templates using some custom syntax like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{&amp;lt; mustache template=&amp;quot;core/notification_error&amp;quot; &amp;gt;}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{&amp;lt; /mustache &amp;gt;}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
You can also call core JavaScript or use HTML examples where the html code and the rendered result are visible in the Component Library. For more info visit the [http://componentlibrary.moodle.com/admin/tool/componentlibrary/docspage.php/library/moodle-templates/ Moodle templates] page or the [http://componentlibrary.moodle.com/admin/tool/componentlibrary/docspage.php/library/moodle-javascript/ Moodle JavaScript] page.&lt;br /&gt;
&lt;br /&gt;
Each page in the library uses the current css from the default theme in your Moodle installation, if you have multiple themes installed and enabled the setting &amp;quot;Allow theme changes on url&amp;quot;, the component library will have a theme selector option.&lt;br /&gt;
&lt;br /&gt;
A hosted version of the Component Library can be found here. http://componentlibrary.moodle.com&lt;br /&gt;
=== Enabling the Component Library ===&lt;br /&gt;
Component library pages are written in the markdown language. These pages need to be compiled to HTML pages before the Component Library is visible. To compile the pages the server running Moodle needs to have the [[Javascript Modules#Install%20NVM%20and%20Node|JavaScript developer tools installed]] (nodeJs and Grunt)&lt;br /&gt;
&lt;br /&gt;
If your server meets all requirements you can enable the library running&lt;br /&gt;
 $ npm install&lt;br /&gt;
 $ grunt componentlibrary&lt;br /&gt;
Further installation instructions can be found in the Component Library itself.&lt;br /&gt;
=== Documenting new UI Components ===&lt;br /&gt;
There are no set rules for adding new pages in the component library yet. These rules will need to be written and adopted in the integration process for Moodle code.&lt;br /&gt;
&lt;br /&gt;
As a guideline for making this rules consideration are:&lt;br /&gt;
&lt;br /&gt;
The component library is not about single use components, for example the Moodle grade book (a huge component with many custom features). Or about very common components like buttons, these are already covered by the Bootstrap section of the component library.&lt;br /&gt;
&lt;br /&gt;
New features should be build keeping in mind the UI part needs to be customisable and if possible (and making sense) reusable. And example would be the new page drawers that we are introducing for the Navigation project. Or the custom primary navigation menus where overflowing items are pushed into a More section.&lt;br /&gt;
== Theme changes ==&lt;br /&gt;
=== Edit switch ===&lt;br /&gt;
On theme boost the “Turn editing on” and “Customise this page” buttons have been replaced by an edit switch in the top navbar. Theme Classic will keep using the old buttons. Child themes can choose to use the edit switch if the theme config.php is using this variable&lt;br /&gt;
 $THEME-&amp;gt;haseditswitch = true;&lt;br /&gt;
The languague menu, which used to be rendered in place of the custom menu has moved to the user dropdown when the user is logged in. If not logged in it will be placed next to the search / notification / messaging icon in the top navbar.&lt;br /&gt;
=== Login page ===&lt;br /&gt;
The login page has been redesigned and allows the admin to configure a background image for the login page only in the theme settings page. This change is available in both Boost and Classic. The login page still has all the features with an improved layout. &lt;br /&gt;
=== The page footer ===&lt;br /&gt;
In large screens, the page footer button is only visible when clicking a help button at the bottom right of the screen.&lt;br /&gt;
=== User initials as profile picture placeholder ===&lt;br /&gt;
If users do not upload a profile picture the user initials are displayed on a rounded gray background as a placeholder picture in the top navbar or any other page using a placeholder image. This change will be available in both Boost and Classic. &lt;br /&gt;
&lt;br /&gt;
With the introduction of this placeholder image the full username will no longer be displayed in the top navbar.&lt;br /&gt;
=== Removal of back to top link ===&lt;br /&gt;
The &amp;quot;back to top&amp;quot; link will be removed for theme boost since the new course index reduced the dependence on page scrolling. Also, the new footer is positioned where this component used to be.&lt;br /&gt;
=== Styling changes ===&lt;br /&gt;
By default rounded edges will be used for UI components, for the page header and main content area the borders will be removed. &lt;br /&gt;
=== New layout page ===&lt;br /&gt;
Theme boost now uses the drawers.php layout for the course index and blocks.&lt;br /&gt;
== Question bank changes ==&lt;br /&gt;
There was a big project to deliver [[Question bank improvements for Moodle 4.0]] which added a new plugin type for adding features to the question banks, tracking the version history for each question as it is edited (question table has been split into &amp;lt;code&amp;gt;question&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;question_versions&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;question_bank_entries&amp;lt;/code&amp;gt;), and tracking where each question is going to be used, with new tables &amp;lt;code&amp;gt;question_references&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;question_set_references&amp;lt;/code&amp;gt;. This work was done in Epic MDL-70329 if you want to track down the details of any of the core changes.&lt;br /&gt;
=== Question type plugins ===&lt;br /&gt;
Amazingly, we (Safat and colleagues at Catalyst AU) managed to implement this without breaking most question type plugins, with one important exception if your questions do shuffling like multiple choice does. See MDL-74752. There is a new method called update_attempt_state_date_from_old_version which you may need to implement.&lt;br /&gt;
&lt;br /&gt;
However, the changes to the question bank, and the other Moodle 4.0 changes, probably broke the Behat tests for your plugin. To help with fixing that, MDL-74130 adds navigation to key question type pages (Preview and Edit for a question, and standard question bank pages like the bank itself, import and export) which should let you fix your test efficiently, and in a way that will work in all Moodle versions since 3.9.&lt;br /&gt;
&lt;br /&gt;
The &#039;most&#039; in the first paragraph here is becuase more advance question types may require more effort to fix. (For example qtype_combined which creates multi-part qusetions like the core qtype_multianswer; or qtype_pmatch or qtype_stack, which store additional data - questions tests - alongside the question itseld. How should that work with versionning?) But, if you have not done weird things like that, you are probably safe. If you find anything else that causes problems, please list it here.&lt;br /&gt;
&lt;br /&gt;
The same thing should apply to question behaviour and question import/export format plugings: no significant changes required (probably just fixing the Behat tests because of the navigation changes).&lt;br /&gt;
=== New plugin type: qbank plugins ===&lt;br /&gt;
This is not something that will cause problems for people upgrading from 3.x. Rather, it is an exciting possibility you can explore once you have survived process of upgrading to 4.0. There is a whole new plugin type which you can create to add new features to the question bank. For example extra columns, new actions and bulk actions, and so on. See [[Question_bank_plugins]].&lt;br /&gt;
=== Activities that use questions ===&lt;br /&gt;
The probable bad news is if you have an activity module which uses questions. So far, the only activity which has been fixed is mod_quiz in Moodle core, so we don&#039;t yet have a good picture of what fixes will be necessary in other activities. Work is about to start fixing [https://github.com/studentquiz/moodle-mod_studentquiz mod_studentquiz], so watching that should give more clues. As we do that, we will try to update this section of this page. Other help writing the information required here would also be greatly appreciated.&lt;br /&gt;
== The course format system ==&lt;br /&gt;
Most of the logic for rendering and editing a course has been moved to a new subsystem called courseformat. The subsystem is located in &amp;quot;course/format&amp;quot; folder so it includes all the format plugins inside. The methods and modules which are distributed between the course and the course/format folders are now rearranged or refactored to be aligned with the current Moodle coding style.&lt;br /&gt;
=== Mandatory renderer in course formats ===&lt;br /&gt;
Now format plugins renderer is not optional anymore. Legacy formats without a renderer will get a deprecation message but it will continue working however, they should create a new renderer as soon as possible. The section-based format can do it by extending the provided core_courseformat\output\section_renderer class which includes all the necessary methods.&lt;br /&gt;
=== New format base class ===&lt;br /&gt;
The old base_format class (which all plugins extend) is now renamed as core_courseformat\base. The new class provides all the functionally of the previous base_format but it has been refactored to be used as a centralized source of truth for the course rendering. Legacy formats should extend the new class to avoid the deprecation message.&lt;br /&gt;
&lt;br /&gt;
Now, the plugin format class provides information such as:&lt;br /&gt;
* If the page is displaying a single or multiple section&lt;br /&gt;
* Give access to other related format objects like the modinfo, the course record, maximum number of sections...&lt;br /&gt;
* If the format is compatible with features like course index, reactive components, ajax...&lt;br /&gt;
* Other format specifics like the page title, the default section name, default blocks...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The format instance is now the main object output components will use to render a course (see next section for more information).&lt;br /&gt;
=== New course output classes and mustache files ===&lt;br /&gt;
Traditionally, section-based course formats uses print_single_section_page and print_multiple_section_page to render the course content. In Moodle 4.0 most of the course rendering methods are migrated to output components and mustache templates. The old methods will get deprecation messages if they use the old renderer methods.&lt;br /&gt;
&lt;br /&gt;
This is an example of a format rendering a course:&amp;lt;syntaxhighlight lang=&amp;quot;php-brief&amp;quot;&amp;gt;&lt;br /&gt;
// Get the course format instance.&lt;br /&gt;
$format = course_get_format($course);&lt;br /&gt;
&lt;br /&gt;
// Get the specific format renderer.&lt;br /&gt;
$renderer = $format-&amp;gt;get_renderer($PAGE);&lt;br /&gt;
&lt;br /&gt;
if (!empty($displaysection)) {&lt;br /&gt;
    // Setup the format instance to display a single section.&lt;br /&gt;
    $format-&amp;gt;set_section_number($displaysection);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Create the ouptut instance and render it.&lt;br /&gt;
$outputclass = $format-&amp;gt;get_output_classname(&#039;content&#039;);&lt;br /&gt;
$widget = new $outputclass($format);&lt;br /&gt;
&lt;br /&gt;
echo $renderer-&amp;gt;render($widget);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Format plugins are free to use its own output classes to render a course, or they could override the existing output classes by providing their own implementation. For example, the default output for &amp;quot;content&amp;quot; (as in the previous example) is &amp;quot;core_courseformat\output\local\|content&amp;quot;, however, if the plugin has a &amp;quot;format_XXX\output\courseformat\content&amp;quot; class, the $format-&amp;gt;class the get_output_class will return the overridden one.&lt;br /&gt;
Another important update on course rendering is that now all course structure is rendered using mustache templates instead of the original html_writer methods. Now themes are able to override the course format by providing alternative versions of the mustache files. All core course templates are located in &amp;quot;course/format/templates&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
All course format output classes implements the new named_templatable interface, which allows the class to define its own template path using the &amp;quot;get_template_name&amp;quot; method. This new interface in combination with [[Templates#Blocks|mustache blocks]] allows the format plugins to provide alternative templates to render the course.&lt;br /&gt;
&lt;br /&gt;
All the new output classes and a guide on how to migrate the current third-party plugins will be available soon.&lt;br /&gt;
=== Course editor javascript modules and frontend components ===&lt;br /&gt;
The majority of the javascript logic related to the course editing is replaced by AMD modules. Because this is a major change in the way courses are edited and rendered, by default format plugins will continue using the previous YUI modules for now. However, formats can start using the new libraries overriding the &amp;quot;$format-&amp;gt;supports_components()&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Some Moodle 4.0 new features are only available for courses using the new editor library:&lt;br /&gt;
* Edit the course via the course index&lt;br /&gt;
* Creating sections without reloading the course page&lt;br /&gt;
* The new move section/activity modal&lt;br /&gt;
* Native browser drag&amp;amp;drop implementation&lt;br /&gt;
The new course editor uses a component-based reactive pattern to keep track of the course changes. The pattern highlights are:&lt;br /&gt;
* The main AMD module &amp;quot;core_crouseformat\courseeditor&amp;quot; maintains a data structure called state.&lt;br /&gt;
* Each UI element is implemented as a Component that observes the course state data and reacts to any data change&lt;br /&gt;
* When any reactive component needs to modify the course, it asks the course editor to execute a mutation. Mutations encapsulate all web services calls and alter the course state data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reactive library documentation, as well as the format plugin migration guide, will be available soon.&lt;br /&gt;
=== Other course related 4.0 changes ===&lt;br /&gt;
Two new web services have been added:&lt;br /&gt;
* core_courseformat_get_state: user by the new javascript course editor to get the current course state data (containing the list of sections, activities, and other course-related data)&lt;br /&gt;
* core_courseformat_update_course: to alter the current course content. Each call returns the parts of the course state altered by the action&lt;br /&gt;
== Behat changes ==&lt;br /&gt;
=== New steps ===&lt;br /&gt;
Moodle 4.0 introduces some new behat steps.&lt;br /&gt;
&lt;br /&gt;
Sometimes you want to create a bulk number of activities. In that case you can use:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
:count :entitytype exist with the following data:&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
Given 100 &amp;quot;mod_lti &amp;gt; tool types&amp;quot; exist with the following data:&lt;br /&gt;
  |name        |Test tool [count]                  |&lt;br /&gt;
  |description |Example description [count]        |&lt;br /&gt;
  |baseurl     |https://www.example.com/tool[count]|&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dynamic (AJAX) tabs is a new feature contributed to Moodle 4.0 by the Workplace team (MDL-71943). You can use the following step to navigate between the tabs.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I click on the &amp;quot;tab title&amp;quot; dynamic tab&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make sure that edit mode is (or is not) available on the current page, the following steps can be used.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And edit mode should be available on the current page&lt;br /&gt;
And edit mode should not be available on the current page&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are new aliases for the existing steps &amp;lt;code&amp;gt;I turn editing mode on&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;I turn editing mode off&amp;lt;/code&amp;gt;.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I switch editing mode on&lt;br /&gt;
And I switch editing mode off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In addition to the existing step to go to a course with editing mode on, we now have the following step to do the same but with editing mode being off.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I am on &amp;quot;course full name&amp;quot; course homepage with editing mode off&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following step is similar to the old &amp;lt;code&amp;gt;following &amp;quot;link string&amp;quot; should download between &amp;quot;min bytes&amp;quot; and &amp;quot;max bytes&amp;quot; bytes&amp;lt;/code&amp;gt; step, with more flexibility.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And following &amp;quot;element string&amp;quot; &amp;quot;element type&amp;quot; in the &amp;quot;container string&amp;quot; &amp;quot;container type&amp;quot; should download between &amp;quot;min bytes&amp;quot; and &amp;quot;max bytes&amp;quot; bytes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And following &amp;quot;Download&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Starter&amp;quot; &amp;quot;table_row&amp;quot; should download between &amp;quot;0&amp;quot; and &amp;quot;5000&amp;quot; bytes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following step can be used to hover the mouse over the trigger area.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I hover over the &amp;quot;element string&amp;quot; &amp;quot;element type&amp;quot; in the &amp;quot;container string&amp;quot; &amp;quot;container type&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following step enables an installed plugin.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I enable &amp;quot;plugin name&amp;quot; &amp;quot;plugin type&amp;quot; plugin&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I enable &amp;quot;course_summary&amp;quot; &amp;quot;block&amp;quot; plugin&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following is a special variation of &#039;I click on &amp;quot;&amp;lt;page name&amp;gt;&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;page&amp;quot; &amp;quot;region&amp;quot;&#039;. It first checks to see if we are on the given page via the breadcrumb. If not we then attempt to follow the link name given.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I follow the breadcrumb &amp;quot;page name&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can use the following step to ensure a node is active in the navbar.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I should see &amp;quot;Node&amp;quot; is active in navigation&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I should see &amp;quot;My courses&amp;quot; is active in navigation&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following step can be used to navigate to a given node in the primary navigation.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I select &amp;quot;Node&amp;quot; from primary navigation&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following steps are to check whether an item exists in the user menu or not.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And &amp;quot;item text&amp;quot; &amp;quot;selector type&amp;quot; should exist in the user menu&lt;br /&gt;
And &amp;quot;item text&amp;quot; &amp;quot;selector type&amp;quot; should not exist in the user menu&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And &amp;quot;Language&amp;quot; &amp;quot;link&amp;quot; should exist in the user menu&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following steps are to check if a submenu of the user menu is shown, and if an item exists or does not exist in a given user submenu.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I should see &amp;quot;submenu name&amp;quot; user submenu&lt;br /&gt;
And &amp;quot;item text&amp;quot; &amp;quot;selector type&amp;quot; should exist in the &amp;quot;submenu name&amp;quot; user submenu&lt;br /&gt;
And &amp;quot;item text&amp;quot; &amp;quot;selector type&amp;quot; should not exist in the &amp;quot;submenu name&amp;quot; user submenu&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
When I follow &amp;quot;Language&amp;quot; in the user menu&lt;br /&gt;
Then I should see &amp;quot;Language selector&amp;quot; user submenu&lt;br /&gt;
And &amp;quot;English &amp;amp;lrm;(en)&amp;amp;lrm;&amp;quot; &amp;quot;link&amp;quot; should exist in the &amp;quot;Language selector&amp;quot; user submenu&lt;br /&gt;
And &amp;quot;English (pirate) &amp;amp;lrm;(en_ar)&amp;amp;lrm;&amp;quot; &amp;quot;link&amp;quot; should not exist in the &amp;quot;Language selector&amp;quot; user submenu&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To add enrolment methods to courses you can use the following new step. The data that you provide in the next lines are used to fill the enrolment method form.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I add &amp;quot;enrolment method&amp;quot; in &amp;quot;course identifier&amp;quot; with:&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
When I add &amp;quot;Self enrolment&amp;quot; enrolment method in &amp;quot;Course 1&amp;quot; with:&lt;br /&gt;
  | Custom instance name     | Test student enrolment |&lt;br /&gt;
  | Enrolment key            | moodle_rules           |&lt;br /&gt;
  | Use group enrolment keys | Yes                    |&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are 3 new steps specific to the calendar component. These steps can be used to hover over a day in the mini-calendar or the full calendar.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I hover over day &amp;quot;day of month&amp;quot; of this month in the full calendar page&lt;br /&gt;
And I hover over day &amp;quot;day of month&amp;quot; of this month in the mini-calendar block&lt;br /&gt;
And I hover over today in the mini-calendar block&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Some new steps are added to question bank to be able to add comment to questions, verify the existence of a comment, and deleting comments form questions. Please note that the steps for adding comments only write the comment text in the comment field. You still need to click on the &amp;quot;Add comment&amp;quot; button to save the comment.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I add &amp;quot;comment text&amp;quot; comment to question&lt;br /&gt;
And I add &amp;quot;comment text&amp;quot; comment to question preview&lt;br /&gt;
And I delete &amp;quot;comment text&amp;quot; comment from question&lt;br /&gt;
And I delete &amp;quot;comment text&amp;quot; comment from question preview&lt;br /&gt;
And I should see &amp;quot;number of comments&amp;quot; on the comments column&lt;br /&gt;
And I click &amp;quot;number of comments&amp;quot; on the row on the comments column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I navigate to &amp;quot;Question bank&amp;quot; in current page administration&lt;br /&gt;
And I should see &amp;quot;0&amp;quot; on the comments column&lt;br /&gt;
And I click &amp;quot;0&amp;quot; on the row on the comments column&lt;br /&gt;
And I add &amp;quot;test comment 01&amp;quot; comment to question&lt;br /&gt;
And I click on &amp;quot;Add comment&amp;quot; &amp;quot;button&amp;quot; in the &amp;quot;.modal-dialog&amp;quot; &amp;quot;css_element&amp;quot;&lt;br /&gt;
And I click on &amp;quot;Close&amp;quot; &amp;quot;button&amp;quot; in the &amp;quot;.modal-dialog&amp;quot; &amp;quot;css_element&amp;quot;&lt;br /&gt;
And I should see &amp;quot;1&amp;quot; on the comments column&lt;br /&gt;
And I click &amp;quot;1&amp;quot; on the row on the comments column&lt;br /&gt;
And I delete &amp;quot;test comment 01&amp;quot; comment from question&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Similar to the steps for comments, the following steps are to verify the number of a question&#039;s usage and to click on it in order to open the question usage modal.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I should see &amp;quot;usage count&amp;quot; on the usage column&lt;br /&gt;
And I click &amp;quot;usage count&amp;quot; on the usage column&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following new steps are related to bulk actions in the question bank UI.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I click on question bulk action &amp;quot;action&amp;quot;&lt;br /&gt;
And I should see question bulk action &amp;quot;action&amp;quot;&lt;br /&gt;
And I should not see question bulk action &amp;quot;action&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I click on &amp;quot;First question&amp;quot; &amp;quot;checkbox&amp;quot;&lt;br /&gt;
And I click on &amp;quot;Second question&amp;quot; &amp;quot;checkbox&amp;quot;&lt;br /&gt;
And I click on &amp;quot;With selected&amp;quot; &amp;quot;button&amp;quot;&lt;br /&gt;
And I should see question bulk action &amp;quot;deleteselected&amp;quot;&lt;br /&gt;
And I click on question bulk action &amp;quot;deleteselected&amp;quot;&lt;br /&gt;
And I click on &amp;quot;Delete&amp;quot; &amp;quot;button&amp;quot; in the &amp;quot;Confirm&amp;quot; &amp;quot;dialogue&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/en/Report_builder Report builder] is a new feature contributed to Moodle 4.0 by the Workplace team. The following new step is added to Moodle 4.0 to select an action from the action menu in the list of custom reports table.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I press &amp;quot;action&amp;quot; action in the &amp;quot;report name&amp;quot; report row&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There&#039;s another step related to the report builder to set a column&#039;s aggregation in the report editor.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I set the &amp;quot;column title&amp;quot; column aggregation to &amp;quot;aggregation method&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I set the &amp;quot;First name&amp;quot; column aggregation to &amp;quot;Comma separated values&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following step needs to be used in scenarios that involve testing BigBlueButton. For this to work, you need to have a [https://github.com/moodlehq/bigbluebutton_mock BigBlueButton Mock API Server] and set &amp;lt;code&amp;gt;TEST_MOD_BIGBLUEBUTTONBN_MOCK_SERVER&amp;lt;/code&amp;gt; to point to that in config.php.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And a BigBlueButton mock server is configured&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following step replicates receiving a callback from the BigBlueButton server indicating the recordings for meetings are ready for viewing.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And the BigBlueButtonBN server has sent recording ready notifications&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following steps are specific to the lesson activity. Note that in 4.0, some links (such as the &amp;quot;edit&amp;quot; and the &amp;quot;grade essays&amp;quot; links) are replaced by buttons, so you need to update your old steps with the new ones.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I edit the lesson&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;A new step is added to be used in lesson activities to edit them. This step navigates the user to the lesson edit page.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I grade lesson essays&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;It&#039;s a new step to go to the &amp;quot;Grade essays&amp;quot; page of the lesson we are currently in.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I select edit type &amp;quot;edit type&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Select the lesson edit type when we are in the the lesson&#039;s edit page. &amp;quot;edit type&amp;quot; can either be &amp;quot;Collapsed&amp;quot; or &amp;quot;Expanded&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following new step can be used to navigate to the exports page in the course gradebook and select the specified export type from the grade exports navigation selector.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I navigate to &amp;quot;export option&amp;quot; export page in the course gradebook&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I navigate to &amp;quot;XML file&amp;quot; export page in the course gradebook&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Similarly, there&#039;s a new step to navigate to the imports page in the course gradebook and select the specified import type from the grade imports navigation selector.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I navigate to &amp;quot;import option&amp;quot; import page in the course gradebook&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Boost steps ===&lt;br /&gt;
In addition to the steps listed in the previous section, there are also some Boost specific steps coming with Moodle 4.0. These steps only work in Boost or Boost child themes, so you need to make sure they are not used in scenarios that may be run by non-Boost themes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following step checks whether a node is active in the secondary navigation.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I should see :name is active in secondary navigation&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The Boost theme shows the language selector menu in the primary navigation when not logged in, and within the user menu when logged in. The following steps are to check if the primary navigation includes the language selector menu.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And language selector menu should exist in the navbar&lt;br /&gt;
And language selector menu should not exist in the navbar&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And the following steps can be used to check whether an item exists in the language selector menu in the Boost theme.&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And &amp;quot;item text&amp;quot; &amp;quot;selector type&amp;quot; should exist in the language selector menu&lt;br /&gt;
And &amp;quot;item text&amp;quot; &amp;quot;selector type&amp;quot; should not exist in the language selector menu&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And &amp;quot;English &amp;amp;lrm;(en)&amp;amp;lrm;&amp;quot; &amp;quot;link&amp;quot; should exist in the language selector menu&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Modified steps ===&lt;br /&gt;
The step &amp;lt;code&amp;gt;I change the (window|viewport) size to &amp;quot;size&amp;quot;&amp;lt;/code&amp;gt; now supports 2 new values for the size argument. The size argument now accepts &amp;lt;code&amp;gt;mobile&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tablet&amp;lt;/code&amp;gt; values in addition to &amp;lt;code&amp;gt;small&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;medium&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;large&amp;lt;/code&amp;gt;.&lt;br /&gt;
=== Removed steps ===&lt;br /&gt;
Some behat steps are removed or replaced with new steps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As a result of some design changes, hidden or restricted activities are no longer dimmed. Therefore the step&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And &amp;quot;Activity or resource name&amp;quot; activity should be dimmed&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;is now removed.&lt;br /&gt;
Depending on what you were using that step for, you may be able to use these steps:&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And &amp;quot;Label name&amp;quot; label should be hidden&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And &amp;quot;Activity or resource name&amp;quot; activity should be hidden&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;&lt;br /&gt;
And I should see &amp;quot;Activity or resource name&amp;quot;&lt;br /&gt;
And &amp;quot;Activity or resource name&amp;quot; &amp;quot;link&amp;quot; should not exist in the &amp;quot;region-main&amp;quot; &amp;quot;region&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Other things to consider ===&lt;br /&gt;
To make behat tests more readable and easy to maintain, it is recommended to use the most direct steps to get what the test needs. It is highly recommended to use&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page &lt;br /&gt;
or&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page logged in as &amp;quot;user&amp;quot;&lt;br /&gt;
instead of navigating to the activity via&lt;br /&gt;
 I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 I follow &amp;quot;Activity name&amp;quot;&lt;br /&gt;
Now that [https://docs.moodle.org/dev/Prototypes#Course_creation_improvements Course index] is integrated these behat steps&lt;br /&gt;
 I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 I follow &amp;quot;Activity name&amp;quot;&lt;br /&gt;
will fail using Boost theme.&lt;br /&gt;
&lt;br /&gt;
The reason for it is that the drawer used in Boost is hiding the course index. So when the test is trying to follow an &amp;quot;Activity name&amp;quot; link, it finds two different links:&lt;br /&gt;
* one in the course index&lt;br /&gt;
* another one in the course main content.&lt;br /&gt;
But the first one, the one in the course index, is hidden by the drawer, and the test fails.&lt;br /&gt;
&lt;br /&gt;
However the recommended behat steps&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page &lt;br /&gt;
or&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page logged in as &amp;quot;user&amp;quot;&lt;br /&gt;
Old behat steps that may now fail can be updated to the new steps.&lt;br /&gt;
For example:&lt;br /&gt;
 And I am on the &amp;quot;Test assignment name&amp;quot; &amp;quot;assign activity&amp;quot; page logged in as teacher1&lt;br /&gt;
instead of:&lt;br /&gt;
 When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
 And I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 And I follow &amp;quot;Test assignment name&amp;quot;&lt;br /&gt;
Or for settings, instead of:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;And I follow &amp;quot;Test choice name&amp;quot;&lt;br /&gt;
And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;gherkin&amp;quot;&amp;gt;And I am on the &amp;quot;Test choice name&amp;quot; &amp;quot;choice activity editing&amp;quot; page&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are also similar stream-lined navigation steps for accessing question bank pages. See MDL-74130.&lt;br /&gt;
== Other ==&lt;br /&gt;
=== Core plugins review ===&lt;br /&gt;
A few plugins from core Moodle LMS which are no longer or hardly used have been removed and, if appropriate, added to the Moodle plugins directory.&lt;br /&gt;
&lt;br /&gt;
More information about this project, the list of plugins to be removed and the process to follow for keeping them before upgrading to 4.0 can be found in the [[Core plugins review]] page.&lt;br /&gt;
=== Core blocks cleanup ===&lt;br /&gt;
In the &amp;quot;Add a block&amp;quot; menu, the list of blocks was really long. A few changes have been done to reduce this list.&lt;br /&gt;
&lt;br /&gt;
More information about this project can be found in the [[Add a block cleanup]] page.&lt;br /&gt;
=== Site admin presets plugin ===&lt;br /&gt;
The third-party plugin [https://moodle.org/plugins/block_admin_presets Admin presets], created by David Monllaó and maintained by developers from [https://pimenko.com/ Pimenko] has been adapted and integrated into Moodle 4.0. It stores settings and plugins status (enabled/disabled) in what&#039;s called &amp;quot;presets&amp;quot; to let admins quickly switch between different configurations.&lt;br /&gt;
&lt;br /&gt;
More information about this project can be found in the [[Site admin presets|Site admin presets plugin]] page.&lt;br /&gt;
=== JavaScript browser support changes ===&lt;br /&gt;
From Moodle 4.0, Internet Explorer is no longer supported. See MDL-73915 and MDLSITE-6109 for further information on this change.&lt;br /&gt;
&lt;br /&gt;
This change means that changes built on 4.0 onwards (including the master branch) will be different to older versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
For plugin developers supporting multiple versions of Moodle using a single plugin version, the compiled javascript files are backwards compatible and will _work_ on all supported versions, however if you run the `grunt` command on multiple versions you will see unbuilt changes. Running grunt on all versions of Moodle is not necessary and this check can be safely disabled for Moodle versions 3.9 - 4.0, as long as only at least you run `grunt` against at least one version of Moodle.&lt;br /&gt;
&lt;br /&gt;
If you need to support Internet Explorer and do not wish to fork your plugin for Moodle 4.0 onwards, then it is recommended that you run `grunt` on an older version of Moodle.&lt;br /&gt;
=== The course index element ===&lt;br /&gt;
The new course index feature can be themed using a set of scss variables. Use them to change the look and feel instead of adding custom css&lt;br /&gt;
 /theme/boost/scss/moodle/courseindex.scss&lt;br /&gt;
With the introduction of the course index component, the previous and next links shown underneath each activity are no longer needed and they will be removed.&lt;br /&gt;
=== Activity icons ===&lt;br /&gt;
The icons used for activities have been redesigned and updated for all core moodle activities.&lt;br /&gt;
&lt;br /&gt;
When viewing the new icons in a file manager, for example for the quiz activity, you will see a simple black monochrome icon with a transparent background.&lt;br /&gt;
&lt;br /&gt;
On the course page, or in the activity chooser, the icon will display as a white icon on a coloured background. Styling of the icons on the coursepage is controlled by the css in theme/boost/scss/moodle/icons.scss.&lt;br /&gt;
&lt;br /&gt;
The background colour for activity icons is set using a new variable in function [modname]_supports(). The quiz activity is of type assessment, so in function quiz_supports() there is a new line defining the purpose:&lt;br /&gt;
 case FEATURE_MOD_PURPOSE: return MOD_PURPOSE_ASSESSMENT;&lt;br /&gt;
Available purposes are:&lt;br /&gt;
* MOD_PURPOSE_COMMUNICATION&lt;br /&gt;
* MOD_PURPOSE_ASSESSMENT&lt;br /&gt;
* MOD_PURPOSE_COLLABORATION&lt;br /&gt;
* MOD_PURPOSE_CONTENT&lt;br /&gt;
* MOD_PURPOSE_ADMINISTRATION&lt;br /&gt;
* MOD_PURPOSE_INTERFACE&lt;br /&gt;
The background colours linked to these purposes are set in theme/boost/scss/moodle/variables.scss&lt;br /&gt;
 $activity-icon-colors: map-merge(&lt;br /&gt;
     (&lt;br /&gt;
         &amp;quot;administration&amp;quot;: #5d63f6,&lt;br /&gt;
         &amp;quot;assessment&amp;quot;: #eb66a2,&lt;br /&gt;
         &amp;quot;collaboration&amp;quot;: #f7634d,&lt;br /&gt;
         &amp;quot;communication&amp;quot;: #11a676,&lt;br /&gt;
         &amp;quot;content&amp;quot;: #399be2,&lt;br /&gt;
         &amp;quot;interface&amp;quot;: #a378ff&lt;br /&gt;
     ),&lt;br /&gt;
     $activity-icon-colors&lt;br /&gt;
 );&lt;br /&gt;
If activity plugins do not define FEATURE_MOD_PURPOSE the activity icon will be rendered against a light grey background. There is no requirement to define the purpose of activity plugins, it will only affect the icon styling.&lt;br /&gt;
&lt;br /&gt;
Plugins implementing the variable FEATURE_MOD_PURPOSE are only supported on Moodle 4.0 and newer.&lt;br /&gt;
&lt;br /&gt;
Customising the activity icon can be done in an alternative way. For example using the styles.css in mod/[pluginname/styles.css&lt;br /&gt;
&lt;br /&gt;
In the example below the activity plugin developer chooses to keep the coloured icon for the activity and render it as large as the coloured background on the core activities&lt;br /&gt;
 .modicon_subcourse.activityiconcontainer {&lt;br /&gt;
     background-color: transparent;&lt;br /&gt;
     padding: 0;&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 .modicon_subcourse.activityiconcontainer img {&lt;br /&gt;
     width: 50px;&lt;br /&gt;
     height: 50px;&lt;br /&gt;
 }&lt;br /&gt;
To customize all icon colours use this scss array and add it to the ‘Raw initial SCSS’ in the theme Boost advanced settings page. The complete array of icon background colours can be overridden using the ‘Raw initial SCSS’ in the theme settings page. The example below changes the colours of each activity type.&lt;br /&gt;
 $activity-icon-colors: (&lt;br /&gt;
     &amp;quot;administration&amp;quot;: #5D63F6,&lt;br /&gt;
     &amp;quot;assessment&amp;quot;: #11A676,&lt;br /&gt;
     &amp;quot;collaboration&amp;quot;: #EB66A2,&lt;br /&gt;
     &amp;quot;communication&amp;quot;: #F7634D,&lt;br /&gt;
     &amp;quot;content&amp;quot;: #399BE2,&lt;br /&gt;
     &amp;quot;interface&amp;quot;: #A378FF&lt;br /&gt;
 )&lt;br /&gt;
== I&#039;m a developer, what do I need to know? ==&lt;br /&gt;
This section is a quick checklist of the areas in this document that you should consult when updating your plugin.&lt;br /&gt;
=== Modules ===&lt;br /&gt;
If you are a module developer (activity / resources) then you need to review the following updates and changes:&lt;br /&gt;
* If using settings, reformat to work with the secondary navigation. We have significantly changed the way that settings are shown. Settings added to the course and activity administration branch of the navigation are now by default shown in the secondary navigation. You will most likely find them in the more section of the secondary navigation. Please avoid creating settings in containers (a parent navigation node with children). These settings will still be shown, but this goes against the pattern that we are trying to establish for navigation around the site. If you have a lot of settings, consider creating a specific page to handle your additional settings.&lt;br /&gt;
** The order of the items in the secondary navigation may not be to your liking. This can be changed. See [[Moodle_4.0_developer_update#Changing_the_order_of_tabs|changing the order of tabs]]&lt;br /&gt;
* Update my behat tests to use new steps for site navigation. See [[Moodle_4.0_developer_update#Behat_changes|new behat steps]].&lt;br /&gt;
* Update my module to use the new activity_header API. See [[Moodle_4.0_developer_update#The_activity_header_class|the activity header]].&lt;br /&gt;
* Update my pages to make it work with the general format of the tertiary navigation. See [[Moodle_4.0_developer_update#Tertiary_navigation|the tertiary navigation]].&lt;br /&gt;
* Update my activity icon to use the API and set a purpose. See [[Moodle_4.0_developer_update#Activity_icons|activity icons]].&lt;br /&gt;
=== Themes ===&lt;br /&gt;
If you are a theme developer then you may want to consider the following:&lt;br /&gt;
* Take a look at the [[Moodle_4.0_developer_update#Navigation_changes|new navigation]] and decide if you want to incorporate this into your theme.&lt;br /&gt;
** A new layout ([[Moodle_4.0_developer_update#New_layout_page|drawers]])&lt;br /&gt;
** An [[Moodle_4.0_developer_update#Edit_switch|edit switch]]&lt;br /&gt;
** The [[Moodle_4.0_developer_update#The_course_index_element|course index]]&lt;br /&gt;
* Use of the flat nav&lt;br /&gt;
* New Site administration page and layout&lt;br /&gt;
* Course settings and how they are displayed&lt;br /&gt;
=== Course format ===&lt;br /&gt;
There have been a lot of changes made to the course format. Most in the process of moving the course format away from using the old rendering system and towards templates.&lt;br /&gt;
We recommend the following sections be read carefully:&lt;br /&gt;
# [[Moodle_4.0_developer_update#The_course_format_system|The course format]]. There have been a lot of deprecations and reading this section is critical in understanding the changes made.&lt;br /&gt;
# Consider moving the rendering of your content over to the [[Templates|template system]].&lt;br /&gt;
=== Other plugins ===&lt;br /&gt;
# Are you adding settings? See the [[Moodle_4.0_developer_update#Adding_items_to_the_navigation|secondary nav]] for adding items to this navigation bar.&lt;br /&gt;
# Have a look at [[Moodle_4.0_developer_update#Secondary_navigation|secondary]] and [[Moodle_4.0_developer_update#Tertiary_navigation|tertiary]] navigation changes in general if you have a plugin that has multiple pages to navigate around.&lt;br /&gt;
# Do you have behat tests? Check the new [[Moodle_4.0_developer_update#Behat_changes|behat changes]].&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=61887</id>
		<title>Templates</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Templates&amp;diff=61887"/>
		<updated>2022-03-22T11:16:23Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: Info about how to do help icons.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
Templates in Moodle are used for rendering the output such as HTML or email messages bodies. Templates are defined as a text with placeholder tags. Placeholder tags are replaced with actual values during the rendering. Templates can be rendered both on the server side in PHP as well as on the client side in JavaScript. Themes can override the default templates. Moodle uses [https://mustache.github.io/mustache.5.html Mustache template system].&lt;br /&gt;
== Simple example ==&lt;br /&gt;
Given the template is defined as:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;alert alert-info&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;strong&amp;gt;Hello {{name}}!&amp;lt;/strong&amp;gt; Your grade is: &amp;lt;strong&amp;gt;{{grade}}&amp;lt;/strong&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And the values for the placeholder tags &amp;lt;var&amp;gt;name&amp;lt;/var&amp;gt; and &amp;lt;var&amp;gt;grade&amp;lt;/var&amp;gt; are provided as a JSON object, referred to as &#039;&#039;rendering context&#039;&#039; (note the &#039;&#039;context&#039;&#039; here has nothing to do with Moodle [[Roles#Context|permission contexts]]. In Mustache, the term basically represents the data passed to the template).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Bobby&amp;quot;,&lt;br /&gt;
    &amp;quot;grade&amp;quot;: 10&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then the rendered result will look like:&lt;br /&gt;
&amp;lt;div class=&amp;quot;alert alert-info&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Hello Bobby!&amp;lt;/strong&amp;gt; Your grade is: &amp;lt;strong&amp;gt;10&amp;lt;/strong&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
The following page provides information about the Mustache templates syntax and how to use them in Moodle.&lt;br /&gt;
== Syntax ==&lt;br /&gt;
Mustache tags are made of two opening and closing curly braces. Their shape looks like a [https://en.wikipedia.org/wiki/Moustache moustache], thence the name.&lt;br /&gt;
=== Variables ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{name}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Bobby&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The value of the key &amp;lt;var&amp;gt;name&amp;lt;/var&amp;gt; will be searched for in the current rendering context (and any parent contexts) and when a value is found, the entire tag will be replaced by the value (HTML escaped).&lt;br /&gt;
=== Raw unescaped variable ===&lt;br /&gt;
All variables are HTML escaped by default. If you want to render raw unescaped HTML, use the triple mustache:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{{description}}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;&amp;lt;h1&amp;gt;Hello!&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;In this course you will learn about ...&amp;lt;/p&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Beware of the security implications of outputting raw HTML and make sure that the value of the variable has been processed by &amp;lt;tt&amp;gt;format_text()&amp;lt;/tt&amp;gt; or another adequate way.&lt;br /&gt;
=== Sections ===&lt;br /&gt;
Sections render blocks of text zero, one or more times, depending on the value of the key in the current context. The opening tag has a hash (pound) sign and the closing tag has a slash, followed by the key.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;False values and empty lists&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When the key is false or an empty list, the HTML between the opening and closing tag will not be displayed. This can be effectively used to conditionally control the rendering of a section.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{#hasdata}}&lt;br /&gt;
    This will not be shown if &#039;hasdata&#039; is empty.&lt;br /&gt;
{{/hasdata}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;hasdata&amp;quot;: false&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Non-empty lists&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When the value is a non-empty list, the text in the block will be displayed once for each item in the list. The context of the block will be set to the current item for each iteration. In this way we can loop over collections.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
    {{#grades}}&lt;br /&gt;
    &amp;lt;li&amp;gt;&lt;br /&gt;
        &amp;lt;em&amp;gt;{{course}}&amp;lt;/em&amp;gt; - {{grade}}&lt;br /&gt;
    &amp;lt;/li&amp;gt;&lt;br /&gt;
    {{/grades}}&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;grades&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;course&amp;quot;: &amp;quot;Arithmetic&amp;quot;,&lt;br /&gt;
            &amp;quot;grade&amp;quot;: &amp;quot;8/10&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;course&amp;quot;: &amp;quot;Geometry&amp;quot;,&lt;br /&gt;
            &amp;quot;grade&amp;quot;: &amp;quot;10/10&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Lambdas&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When the value is a callable, it will be invoked and returned value used as the section value. In Moodle plugins, this can be used to call the &amp;lt;tt&amp;gt;core_renderer&amp;lt;/tt&amp;gt; methods via the &amp;lt;tt&amp;gt;output&amp;lt;/tt&amp;gt; context variable:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{#output.should_display_navbar_logo}}&lt;br /&gt;
    &amp;lt;img src=&amp;quot;{{output.get_compact_logo_url}}&amp;quot;&amp;gt;&lt;br /&gt;
{{/output.should_display_navbar_logo}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Inverted sections&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Inverted sections will be rendered if the key does not exist, is false, or is an empty list. An inverted section begins with a caret (hat) and ends with a slash.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{#hasgrade}}&lt;br /&gt;
    Your grade is: &amp;lt;strong&amp;gt;{{grade}}&amp;lt;/strong&amp;gt;&lt;br /&gt;
{{/hasgrade}}&lt;br /&gt;
&lt;br /&gt;
{{^hasgrade}}&lt;br /&gt;
    Your work has not been graded yet.&lt;br /&gt;
{{/hasgrade}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;hasgrade&amp;quot;: false,&lt;br /&gt;
    &amp;quot;grade&amp;quot;: null&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Comments ===&lt;br /&gt;
Comments begin with an exclamation mark. The whole section is ignored. Comments are used for boilerplate documentation. They can also be used to avoid having extra break-lines in the generated output.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    This is a comment and will not be present in the rendered result.&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Partials ===&lt;br /&gt;
Templates can include other templates using the partial tag. Partials begin with a greater than sign. Partials are rendered at runtime and allow to split complex templates into smaller, potentially re-usable units. Moodle core provides with many templates that can be included this way.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{! Show the loading icon. }}&lt;br /&gt;
&amp;lt;div class=&amp;quot;p-5&amp;quot;&amp;gt;&lt;br /&gt;
    {{&amp;gt; core/loading }}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The included template uses the same rendering context as its parent template.&lt;br /&gt;
=== Blocks ===&lt;br /&gt;
{{Moodle 3.0}}&lt;br /&gt;
Mustache template system can be extended via so called [https://github.com/bobthecow/mustache.php/wiki/Pragmas Mustache pragmas]. Pragmas are non-standard extensions to the Mustache spec. Moodle 3.0 and higher has [https://github.com/bobthecow/mustache.php/wiki/BLOCKS-pragma BLOCKS pragma] installed and enabled.&lt;br /&gt;
&lt;br /&gt;
The extension allows you to define a parent template with replaceable blocks. Blocks look like sections that use dollar sign in the opening tag. The following parent template defines two blocks &amp;lt;var&amp;gt;heading&amp;lt;/var&amp;gt; and &amp;lt;var&amp;gt;content&amp;lt;/var&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    @template tool_demo/section&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;section&amp;gt;&lt;br /&gt;
    &amp;lt;h1&amp;gt;&lt;br /&gt;
        {{$heading}} Default section heading {{/heading}}&lt;br /&gt;
    &amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;div&amp;gt;&lt;br /&gt;
        {{$content}} Default section content {{/content}}&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Particular child templates can now extend / inherit from this parent template and override the default block values.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    @template tool_demo/latestnews&lt;br /&gt;
}}&lt;br /&gt;
{{&amp;lt; tool_demo/section }}&lt;br /&gt;
    {{$heading}} Latest news {{/heading}}&lt;br /&gt;
    {{$content}} Today I learned how to use blocks in Mustache! {{/content}}&lt;br /&gt;
{{/ tool_demo/section}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Blocks are particularly useful for building a library of re-usable components.&lt;br /&gt;
== Helpers ==&lt;br /&gt;
Moodle providers several Mustache helpers. Helpers tags look like sections eventually containing zero or more parameters.&lt;br /&gt;
=== str ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;{{#str}}&amp;lt;/tt&amp;gt; is a string helper for loading text strings from language packs. It effectively represents Mustache variant of &amp;lt;code&amp;gt;get_string()&amp;lt;/code&amp;gt; calls.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{#str}} helloworld, mod_greeting {{/str}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The first two parameters are the string identifier and the component name. The optional third parameter defines the value for the string&#039;s &amp;lt;code&amp;gt;$a&amp;lt;/code&amp;gt; placeholder. Literals as well as variable tags are allowed to define the value.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{#str}} backto, core, Moodle.org {{/str}}&lt;br /&gt;
&lt;br /&gt;
{{#str}} backto, core, {{name}} {{/str}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For strings that accept non-scalar placeholders, see the following section.&lt;br /&gt;
&lt;br /&gt;
Note: if you want to do a &#039;&#039;&#039;help icon&#039;&#039;&#039;, and wondering &amp;quot;where is the helper for that?&amp;quot; then acutally, it is not a helper. You need to use &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{&amp;gt;core/help_icon}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; as a partial.&lt;br /&gt;
=== quote ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;{{#quote}}&amp;lt;/tt&amp;gt; is used to quote non-scalar &amp;lt;tt&amp;gt;{{#str}}&amp;lt;/tt&amp;gt; arguments.&lt;br /&gt;
&lt;br /&gt;
Some strings accept complex non-scalar 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;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{#str}} counteditems, core, { &amp;quot;count&amp;quot;: &amp;quot;42&amp;quot;, &amp;quot;items&amp;quot;: &amp;quot;courses&amp;quot; } {{/str}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If you wanted to use the context values instead of literal values, you might intuitively use something like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{! DO NOT DO THIS !}}&lt;br /&gt;
{{#str}} counteditems, core, { &amp;quot;count&amp;quot;: {{count}}, &amp;quot;items&amp;quot;: {{itemname}} } {{/str}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
There is a potential problem though. If the variable tag &amp;lt;var&amp;gt;itemname&amp;lt;/var&amp;gt; evaluates to a string containing double quotes, it will break the JSON syntax. We need to escape certain characters potentially appearing in the variable tags. For this, we use the &amp;lt;tt&amp;gt;{{#quote}}&amp;lt;/tt&amp;gt; helper.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{#str}} counteditems, core, { &amp;quot;count&amp;quot;: {{count}}, &amp;quot;items&amp;quot;: {{#quote}} {{itemname}} {{/quote}} } {{/str}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== pix ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;{{#pix}}&amp;lt;/tt&amp;gt; is a icon picture helper for generating pix icon tags.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{#pix}} t/edit, core, Edit this section {{/pix}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The first two parameters are the icon identifier and the component name. The rest is the alt text for the icon.&lt;br /&gt;
&lt;br /&gt;
See [[Using images in a theme]] and [[Moodle_icons]] for some background information about pix icons in Moodle.&lt;br /&gt;
=== userdate ===&lt;br /&gt;
{{Moodle 3.3}}&lt;br /&gt;
The &amp;lt;tt&amp;gt;{{#userdate}}&amp;lt;/tt&amp;gt; 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;
It is recommended to use the string helper to get one of the core Moodle formats.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;time&amp;quot;: 1628871929&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{#userdate}} {{time}}, {{#str}} strftimedate, core_langconfig {{/str}} {{/userdate}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&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; in case of English) to format the user date. So the resulting formatted timestamp from the userdate helper would be like &amp;quot;13 August 2021&amp;quot;.&lt;br /&gt;
=== shortentext ===&lt;br /&gt;
{{Moodle 3.3}}&lt;br /&gt;
The &amp;lt;tt&amp;gt;{{#shortentext}} &amp;lt;/tt&amp;gt; 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;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur lacinia pretium nulla gravida interdum.&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{#shortentext}} 15, {{{description}}} {{/shortentext}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== Template files ==&lt;br /&gt;
Templates are saved in &amp;lt;tt&amp;gt;templates/*.mustache&amp;lt;/tt&amp;gt; files within core components and plugins folders. When loading them, templates are identified by their [[Frankenstyle|full component name]] followed by slash and the filename without the file extension. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039; A &amp;lt;tt&amp;gt;timer&amp;lt;/tt&amp;gt; template provided by the &amp;lt;tt&amp;gt;mod_lesson&amp;lt;/tt&amp;gt; module would be referred to as &amp;lt;tt&amp;gt;mod_lesson/timer&amp;lt;/tt&amp;gt; and it would be located in &amp;lt;tt&amp;gt;mod/lesson/templates/timer.mustache&amp;lt;/tt&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
Since Moodle 3.8 it is possible to use sub-directories under the &amp;lt;tt&amp;gt;templates&amp;lt;/tt&amp;gt; directory. The first sub-directory name must meet [[Coding style#Rules for level2|certain naming rules]] (same as for class namespaces).&lt;br /&gt;
=== Mustache file boilerplate ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    This file is part of Moodle - https://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 plugintype_pluginname/template_name&lt;br /&gt;
&lt;br /&gt;
    Template purpose and description.&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;
    * none&lt;br /&gt;
&lt;br /&gt;
    Example context (json):&lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Rendering in PHP ==&lt;br /&gt;
Use the &amp;lt;code&amp;gt;render_from_template()&amp;lt;/code&amp;gt; method to render the given context data with the template.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$data = [&lt;br /&gt;
    &#039;name&#039; =&amp;gt; &#039;Lorem ipsum&#039;,&lt;br /&gt;
    &#039;description&#039; =&amp;gt; format_text($description, FORMAT_HTML),&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
echo $OUTPUT-&amp;gt;render_from_template($templatename, $data);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Renderers ===&lt;br /&gt;
Templates can be effectively used in [[Renderer|renderers]] to generate the HTML representing the given &amp;lt;code&amp;gt;renderable&amp;lt;/code&amp;gt; object. Make your &amp;lt;code&amp;gt;renderable&amp;lt;/code&amp;gt; class also implement &amp;lt;code&amp;gt;templatable&amp;lt;/code&amp;gt; interface. It will have to implement a new method &amp;lt;code&amp;gt;export_for_template(renderer_base $output)&amp;lt;/code&amp;gt;. The method should return a JSON-serialisable object (containing only objects, arrays and scalars) that will be passed as the rendering context data to a template.&lt;br /&gt;
&lt;br /&gt;
In the simplest case where you have a renderable, templatable object with a class name matching the name of the template that will render it, you do not need to add any renderer code explicity. Passing your widget directly to &amp;lt;code&amp;gt;$OUTPUT-&amp;gt;render()&amp;lt;/code&amp;gt; will infer the name of your template, call &amp;lt;code&amp;gt;export_for_template()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;render_from_template()&amp;lt;/code&amp;gt;, then return the result.&lt;br /&gt;
&lt;br /&gt;
Example of the method added to the renderable mywidget:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Describe the renderable widget so it can be renderer by a mustache template.&lt;br /&gt;
 *&lt;br /&gt;
 * @param renderer_base $output&lt;br /&gt;
 * @return stdClass&lt;br /&gt;
 */&lt;br /&gt;
public function export_for_template(renderer_base $output) {&lt;br /&gt;
&lt;br /&gt;
    $data = new stdClass();&lt;br /&gt;
    $data-&amp;gt;canmanage = $this-&amp;gt;canmanage;&lt;br /&gt;
    $data-&amp;gt;things = [];&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 = [];&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
The rendering method can now use templates to render the object:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Render mywidget via a template.&lt;br /&gt;
 *&lt;br /&gt;
 * @param mywidget $widget&lt;br /&gt;
 *&lt;br /&gt;
 * @return string HTML&lt;br /&gt;
 */&lt;br /&gt;
protected function render_mywidget(mywidget $widget) {&lt;br /&gt;
    $data = $widget-&amp;gt;export_for_template($this);&lt;br /&gt;
    return $this-&amp;gt;render_from_template(&#039;tool_myplugin/mywidget&#039;, $data);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In your page:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;tool_myplugin&#039;);&lt;br /&gt;
echo $output-&amp;gt;render($widget);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
== Rendering in JavaScript ==&lt;br /&gt;
Rendering a template from JavaScript is fairly easy. There is a [[Javascript Modules|JavaScript module]] that can load (and cache) a template and then use it for rendering the given data.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import {exception as displayException} from &#039;core/notification&#039;;&lt;br /&gt;
import Templates from &#039;core/templates&#039;;&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;
const context = {&lt;br /&gt;
    name: &#039;Tweety bird&#039;,&lt;br /&gt;
    intelligence: 2,&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// This will call the function to load and render our template.&lt;br /&gt;
Templates.renderForPromise(&#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(({html, js}) =&amp;gt; {&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;, html, js);&lt;br /&gt;
    })&lt;br /&gt;
&lt;br /&gt;
    // Deal with this exception (Using core/notify exception function is recommended).&lt;br /&gt;
    .catch(ex =&amp;gt; displayException(ex));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Under the hood, this does a few clever things for us. It loads the template via an AJAX call if it was not cached. It finds any missing lang strings in the template and loads them in a single AJAX request. It split the JS from the HTML and returns us both in easy to use way. Read on for how to nicely deal with that &amp;lt;code&amp;gt;js&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
== Template requires JavaScript ==&lt;br /&gt;
Sometimes a template requires that some JavaScript runs 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;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!-- HTML here --&amp;gt;&amp;gt;&lt;br /&gt;
{{^element.frozen}}&lt;br /&gt;
{{#js}}&lt;br /&gt;
require([&#039;theme_boost/form-display-errors&#039;], function(module) {&lt;br /&gt;
    module.enhance({{#quote}}{{element.id}}{{/quote}});&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
{{/element.frozen}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
templates.runTemplateJS(javascript);&lt;br /&gt;
&amp;lt;/syntaxhighlight&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;
Note: It is recommended that the JavaScript present be kept to a minimum - preferably just the inclusion of a module designed to do the actual work. This allows for a template to be overridden by a renderer without the JavaScript having to be copied. It also enforces appropriate linting and minification of the code.&lt;br /&gt;
== Overriding templates in a theme ==&lt;br /&gt;
Templates can be overridden by a theme.&lt;br /&gt;
# Find the template that you want to change - e.g. &amp;lt;tt&amp;gt;mod/wiki/templates/ratingui.mustache&amp;lt;/tt&amp;gt;&lt;br /&gt;
# 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;lt;tt&amp;gt;theme/timtam/templates/mod_wiki&amp;lt;/tt&amp;gt;&lt;br /&gt;
# Copy the &amp;lt;tt&amp;gt;ratingui.mustache&amp;lt;/tt&amp;gt; file into the newly created &amp;lt;tt&amp;gt;theme/timtam/templates/mod_wiki&amp;lt;/tt&amp;gt; and edit it.&lt;br /&gt;
You should see your changes immediately if theme designer mode is on. 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 it is recommended to remove it. It will still show the documentation in the template library.&lt;br /&gt;
== Documenting the templates ==&lt;br /&gt;
Theme designers need to know the limits of what they can expect to change without breaking anything. Also, correctly documented templates can be previewed in the &amp;quot;Template library&amp;quot; tool shipped with Moodle.&lt;br /&gt;
* &#039;&#039;&#039;Classes required for JS&#039;&#039;&#039; - 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;
* &#039;&#039;&#039;Data attributes required for JS&#039;&#039;&#039; - 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;
* &#039;&#039;&#039;Context variables required for this template&#039;&#039;&#039; - 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;
* &#039;&#039;&#039;Example context (JSON)&#039;&#039;&#039; - 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;
== Coding style ==&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;
&#039;&#039;&#039;Include GPL at the top of each template&#039;&#039;&#039;. Templates are a form of code and it is appropriate to license them like any other code.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Include a documentation comment for each template.&#039;&#039;&#039; 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;
&#039;&#039;&#039;Use data-attributes for JS hooks&#039;&#039;&#039;. 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;
&lt;br /&gt;
&#039;&#039;&#039;Avoid custom CSS for templates&#039;&#039;&#039;. 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;
&#039;&#039;&#039;Re-use core templates as much as possible&#039;&#039;&#039; - 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;
&#039;&#039;&#039;Do use the CSS framework classes directly in the templates&#039;&#039;&#039; - 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;
&#039;&#039;&#039;Avoid IDs for styling or javascript&#039;&#039;&#039; - 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;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Follow CSS coding style&#039;&#039;&#039; - See [[CSS coding style]]. Use hyphens as word-separators for class names. Use lower case class names.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Wrap each template in one node with a classname that matches the template name&#039;&#039;&#039;. 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;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
== Notes ==&lt;br /&gt;
=== Iterating over PHP arrays in Mustache templates ===&lt;br /&gt;
In PHP, both lists and hashes are implemented as arrays. But Mustache must treat them as different structures because of cross language compatibility. If the PHP array does not have the &amp;lt;code&amp;gt;[0]&amp;lt;/code&amp;gt; key, or there are gaps in the keys sequence, Mustache will interpret that array as a hash and will not iterate over it.&lt;br /&gt;
&lt;br /&gt;
So you need to make sure the elements in the list are properly indexed:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$datafortemplate-&amp;gt;mylist = array_values($myarraywithnonnumerickeys)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Test for non-empty array in Mustache templates ===&lt;br /&gt;
Short answer: you can&#039;t.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{! This will work in PHP but not in JavaScript. }}&lt;br /&gt;
{{#users.0}} ... {{/users.0}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{! This will work in JavaScript but not in PHP. }}&lt;br /&gt;
{{#users.length}} ... {{/users.length}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As a workaround, include a specific property in the context like &amp;quot;hasusers&amp;quot;.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;hasusers&amp;quot;: false,&lt;br /&gt;
    &amp;quot;users&amp;quot;: []&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
{{#hasusers}}&lt;br /&gt;
    {{#users}}&lt;br /&gt;
    ....&lt;br /&gt;
    {{/users}}&lt;br /&gt;
{{#hasusers}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Squash whitespace in a template ===&lt;br /&gt;
Sometimes whitespace is significant, for example inside a link it will show with an underline. If you need two Mustache tags from separate lines to be rendered with no whitespace between them you can use Mustache comments to squash the whitespace.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;blah&amp;quot;&amp;gt;{{!&lt;br /&gt;
}}{{icon}}{{!&lt;br /&gt;
}}{{name}}&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Access to globals ===&lt;br /&gt;
In PHP you have access to $CFG object to allow access to properties. Mustache rendering also exposes a globals object automatically during rendering. For example:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;{{globals.config.wwwroot}}/login/logout.php?sesskey={{globals.config.sesskey}}&amp;quot;&amp;gt;{{#str}}&amp;lt;/nowiki&amp;gt; logout, core &amp;lt;nowiki&amp;gt;{{/str}}&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
The properties available on the &amp;lt;code&amp;gt;globals.config&amp;lt;/code&amp;gt; object are the same as normally exposed for javascript; these are gathered from &amp;lt;code&amp;gt;get_config_for_javascript()&amp;lt;/code&amp;gt; function in &#039;&#039;/lib/outputrequirementslib.php&#039;&#039;.&lt;br /&gt;
== 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;
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;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
The template requires a context that looks something like:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&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;/syntaxhighlight&amp;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: 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;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&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;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;json&amp;quot;&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;/syntaxhighlight&amp;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. Let&#039;s assume the tabs template is being rendered with this context:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&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;/syntaxhighlight&amp;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 leveraging blocks:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&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;/syntaxhighlight&amp;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;
Now let&#039;s see what using this template looks like for your User Profile page:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&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;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&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;gt; 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;gt; 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;/syntaxhighlight&amp;gt;&lt;br /&gt;
tab_header_item.mustache&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
tab_content_item.mustache&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&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;/syntaxhighlight&amp;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;
Cool, so let&#039;s see what that looks like in our example now:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html+handlebars&amp;quot;&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; core/tab_header_item }}&lt;br /&gt;
					{{$ tabname }}Name{{/ tabname }}&lt;br /&gt;
				{{/ core/tab_header_item }}&lt;br /&gt;
				{{&amp;lt; 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;lt; core/tab_content_item }}&lt;br /&gt;
					{{$ tabpanelcontent }}Your name is {{ name }}.{{/ tabpanelcontent }}&lt;br /&gt;
				{{/ core/tab_content_item }}&lt;br /&gt;
				{{&amp;lt; 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;/syntaxhighlight&amp;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;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;br /&gt;
[[Category:Output]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_4.0_developer_update&amp;diff=61786</id>
		<title>Moodle 4.0 developer update</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_4.0_developer_update&amp;diff=61786"/>
		<updated>2022-03-09T21:17:02Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: Notes about what needs to be done because of the question bank changes.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 4.0}}This page highlights the important changes that are coming in Moodle 4.0 for developers. Including how the UX improvements impact custom themes, relevant API changes, and what you can do as developer to prepare for the 4.0 release.&lt;br /&gt;
== Navigation changes ==&lt;br /&gt;
The core Navigation API has been left mostly untouched. The callbacks to all navigation callbacks remains unchanged and will be called as part of the regular &#039;navigation&#039; and &#039;settingsnav&#039; initialisation. Some new core classes have been created and exist within a new namespace &#039;core/navigation&#039; and serves as conduit to rearrange, cherry-pick existing navigation nodes from the navigation/settingsnav trees and display within the respective navigation type. As such, it is highly recommended to provide unique keys for custom navigation nodes as this helps in the cherry-picking / rearranging process within the new classes.&lt;br /&gt;
=== Primary navigation ===&lt;br /&gt;
The primary navigation(the navbar) apart from the existing content will now display links to the Dashboard, My Courses, Site Admin and Course search, by default. You can still add items to the navbar via the &#039;custom menu&#039; option. This will be displayed within the &#039;More&#039; menu. We have transitioned the menus to be rendered via templates - refer user_menu.mustache. The lang menu has been moved to reside within the user menu.&lt;br /&gt;
==== Customising the primary navigation ====&lt;br /&gt;
Not yet implemented but we are looking at allowing the full addition and removal of any of the primary navigation tabs in the boost theme config file.&lt;br /&gt;
=== Secondary navigation ===&lt;br /&gt;
The main content area shows tabs for secondary navigation with a maximum of 5 items being rendered in this ‘more’ menu. A new UI component has been created to render menus like this. Files:&lt;br /&gt;
 /lib/templates/moremenu.mustache&lt;br /&gt;
==== Changing the order of tabs ====&lt;br /&gt;
Apart from the previously mentioned functions, you can also create a custom secondary class as mentioned earlier. This will automatically be picked by getter and used to render the secondary nav within the activity. E.g. mod_assign/local/views/secondary. Note: This is currently only possible on an activity and block level. &lt;br /&gt;
=== Tertiary navigation ===&lt;br /&gt;
=== New API functions ===&lt;br /&gt;
==== Page API ====&lt;br /&gt;
* Magic getters to fetch the primary and secondary navs and the primary output.&lt;br /&gt;
* The secondarynav magic getter also checks whether a custom secondary class has been defined within the module&#039;s local\views directory. Use this if you want to deviate from the standard secondary nav structure/order.&lt;br /&gt;
&lt;br /&gt;
* set_secondary_nav - Force override the secondary navigation class&lt;br /&gt;
&lt;br /&gt;
* has_secondary_navigation_setter - Sets the ‘_hassecondarynavigation’ to indicate whether a page should render the secondary navigation&lt;br /&gt;
==== Navigationlib ====&lt;br /&gt;
* set_show_in_secondary_navigation - whether or not a node should be displayed in the secondary nav. Accepts a single boolean argument&lt;br /&gt;
* set_force_into_more_menu- whether or not to force a node into the &#039;More&#039; menu. Accepts a single boolean argument&lt;br /&gt;
==== The activity header class ====&lt;br /&gt;
There is a new activity header class that handles the display of information common to activities. 3rd party activities are not required to explicitly output this information as part of rendering individual pages.&lt;br /&gt;
&lt;br /&gt;
The common information that are currently handled by the class are:&lt;br /&gt;
* title&lt;br /&gt;
* description&lt;br /&gt;
* completion information&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As part of the update it was required that the initial information to be displayed by the class be toggable at a theme and layout level. Taking this into account the following theme level configurable exists:&lt;br /&gt;
* activityheaderconfig =&amp;gt; An array that currently only enforces &#039;notitle&#039; but can be expanded in the future NOTE: Boost has this set as true by default &#039;options&#039;&lt;br /&gt;
The following layout level options that can be defined:&lt;br /&gt;
* noactivityheader - to remove the header in this specific layout.&lt;br /&gt;
* activityheader - An array that enforces the following options:&lt;br /&gt;
** notitle&lt;br /&gt;
** nocompletion&lt;br /&gt;
** nodescription&lt;br /&gt;
The class has a page level getter which you can use to fetch the current version of the class. The base state is initialised within the constructor with the completion information only fetched when data is exported for the template.&lt;br /&gt;
&lt;br /&gt;
The class has setters for the following variables which can be leveraged to modify the header for a particular page in the format set_{variable_name}:&lt;br /&gt;
* hidecompletion&lt;br /&gt;
* description&lt;br /&gt;
* title&lt;br /&gt;
Alternately, bulk operations can also be done by passing the above variables in an array to &#039;set_attrs&#039; which in turn calls the setters.&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note: Any updates to the activityheader needs to be performed before the call to $OUTPUT-&amp;gt;header&#039;&#039;&#039;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
===== Theme updates: =====&lt;br /&gt;
In order for 3rd party themes to use the class they need to export the activity_header and include the following into their base template :&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
{{#headercontent}}&lt;br /&gt;
   {{&amp;gt; core/activity_header}}&lt;br /&gt;
{{#headercontent}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;** headercontent being the array element that contains the exported activity_header data &lt;br /&gt;
===== Accessibility notes: =====&lt;br /&gt;
The jump to ‘maincontent’ div is now rendered within the activity header when within an activity context&lt;br /&gt;
== Component library ==&lt;br /&gt;
Each Moodle installation now ships with a Moodle User Interface (UI) Component library, a documentation system used to describe all the Bootstrap components and the custom Moodle components. The component Library is a helper tool for developers when creating user interfaces, a testing tool for theme developers and a documentation tool for core developers. The ultimate goal of having a component library is to encourage developers to create consistent user interfaces to improve Moodle’s overall user experience.&lt;br /&gt;
&lt;br /&gt;
The library contains pages with documentation about User Interface components. It contains details on how to use the component, what variations are available and the JavaScript events / options are associated with the component.&lt;br /&gt;
&lt;br /&gt;
When writing on these pages it is possible to render core mustache templates using some custom syntax like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{&amp;lt; mustache template=&amp;quot;core/notification_error&amp;quot; &amp;gt;}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{&amp;lt; /mustache &amp;gt;}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
You can also call core JavaScript or use HTML examples where the html code and the rendered result are visible in the Component Library. For more info visit the [http://componentlibrary.moodle.com/admin/tool/componentlibrary/docspage.php/library/moodle-templates/ Moodle templates] page or the [http://componentlibrary.moodle.com/admin/tool/componentlibrary/docspage.php/library/moodle-javascript/ Moodle JavaScript] page.&lt;br /&gt;
&lt;br /&gt;
Each page in the library uses the current css from the default theme in your Moodle installation, if you have multiple themes installed and enabled the setting &amp;quot;Allow theme changes on url&amp;quot;, the component library will have a theme selector option.&lt;br /&gt;
&lt;br /&gt;
A hosted version of the Component Library can be found here. http://componentlibrary.moodle.com&lt;br /&gt;
=== Enabling the Component Library ===&lt;br /&gt;
Component library pages are written in the markdown language. These pages need to be compiled to HTML pages before the Component Library is visible. To compile the pages the server running Moodle needs to have the [[Javascript Modules#Install%20NVM%20and%20Node|JavaScript developer tools installed]] (nodeJs and Grunt)&lt;br /&gt;
&lt;br /&gt;
If your server meets all requirements you can enable the library running&lt;br /&gt;
 $ npm install&lt;br /&gt;
 $ grunt componentlibrary&lt;br /&gt;
Further installation instructions can be found in the Component Library itself.&lt;br /&gt;
=== Documenting new UI Components ===&lt;br /&gt;
There are no set rules for adding new pages in the component library yet. These rules will need to be written and adopted in the integration process for Moodle code.&lt;br /&gt;
&lt;br /&gt;
As a guideline for making this rules consideration are:&lt;br /&gt;
&lt;br /&gt;
The component library is not about single use components, for example the Moodle grade book (a huge component with many custom features). Or about very common components like buttons, these are already covered by the Bootstrap section of the component library.&lt;br /&gt;
&lt;br /&gt;
New features should be build keeping in mind the UI part needs to be customisable and if possible (and making sense) reusable. And example would be the new page drawers that we are introducing for the Navigation project. Or the custom primary navigation menus where overflowing items are pushed into a More section.&lt;br /&gt;
== Theme changes ==&lt;br /&gt;
=== Edit switch ===&lt;br /&gt;
On theme boost the “Turn editing on” and “Customise this page” buttons have been replaced by an edit switch in the top navbar. Theme Classic will keep using the old buttons. Child themes can choose to use the edit switch if the theme config.php is using this variable&lt;br /&gt;
 $THEME-&amp;gt;haseditswitch = true;&lt;br /&gt;
The languague menu, which used to be rendered in place of the custom menu has moved to the user dropdown when the user is logged in. If not logged in it will be placed next to the search / notification / messaging icon in the top navbar.&lt;br /&gt;
=== Login page ===&lt;br /&gt;
The login page has been redesigned and allows the admin to configure a background image for the login page only in the theme settings page. This change is available in both Boost and Classic. The login page still has all the features with an improved layout. &lt;br /&gt;
=== The page footer ===&lt;br /&gt;
In large screens, the page footer button is only visible when clicking a help button at the bottom right of the screen.&lt;br /&gt;
=== User initials as profile picture placeholder ===&lt;br /&gt;
If users do not upload a profile picture the user initials are displayed on a rounded gray background as a placeholder picture in the top navbar or any other page using a placeholder image. This change will be available in both Boost and Classic. &lt;br /&gt;
&lt;br /&gt;
With the introduction of this placeholder image the full username will no longer be displayed in the top navbar.&lt;br /&gt;
=== Removal of back to top link ===&lt;br /&gt;
The &amp;quot;back to top&amp;quot; link will be removed for theme boost since the new course index reduced the dependence on page scrolling. Also, the new footer is positioned where this component used to be.&lt;br /&gt;
=== Styling changes ===&lt;br /&gt;
By default rounded edges will be used for UI components, for the page header and main content area the borders will be removed. &lt;br /&gt;
=== New layout page ===&lt;br /&gt;
Theme boost now uses the drawers.php layout for the course index and blocks.&lt;br /&gt;
&lt;br /&gt;
== Question bank changes ==&lt;br /&gt;
There was a big project to deliver [[Question bank improvements for Moodle 4.0]] which added a new plugin type for adding features to the question banks, tracking the version history for each question as it is edited (question table has been split into &amp;lt;code&amp;gt;question&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;question_versions&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;question_bank_entries&amp;lt;/code&amp;gt;), and tracking where each question is going to be used, with new tables &amp;lt;code&amp;gt;question_references&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;question_set_references&amp;lt;/code&amp;gt;. This work was done in Epic MDL-70329 if you want to track down the details of any of the core changes.&lt;br /&gt;
&lt;br /&gt;
=== Question type plugins ===&lt;br /&gt;
Amazingly, we (Safat and colleagues at Catalyst AU) managed to implement this without breaking most question type plugins.&lt;br /&gt;
&lt;br /&gt;
However, the changes to the question bank, and the other Moodle 4.0 changes, probably broke the Behat tests for your plugin. To help with fixing that, MDL-74130 adds navigation to key question type pages (Preview and Edit for a question, and standard question bank pages like the bank itself, import and export) which should let you fix your test efficiently, and in a way that will work in all Moodle versions since 3.9.&lt;br /&gt;
&lt;br /&gt;
The &#039;most&#039; in the first paragraph here is becuase more advance question types may require more effort to fix. (For example qtype_combined which creates multi-part qusetions like the core qtype_multianswer; or qtype_pmatch or qtype_stack, which store additional data - questions tests - alongside the question itseld. How should that work with versionning?) But, if you have not done weird things like that, you are probably safe. If you find anything else that causes problems, please list it here.&lt;br /&gt;
&lt;br /&gt;
The same thing should apply to question behaviour and question import/export format plugings: no significant changes required (probably just fixing the Behat tests because of the navigation changes).&lt;br /&gt;
&lt;br /&gt;
=== New plugin type: qbank plugins ===&lt;br /&gt;
This is not something that will cause problems for people upgrading from 3.x. Rather, it is an exciting possibility you can explore once you have survived process of upgrading to 4.0. There is a whole new plugin type which you can create to add new features to the question bank. For example extra columns, new actions and bulk actions, and so on. See [[Question_bank_plugins]].&lt;br /&gt;
&lt;br /&gt;
=== Activies that use questions ===&lt;br /&gt;
The probable bad news is if you have an activity module which uses questions. So far, the only activity which has been fixed is mod_quiz in Moodle core, so we don&#039;t yet have a good picture of what fixes will be necessary in other activities. Work is about to start fixing [https://github.com/studentquiz/moodle-mod_studentquiz mod_studentquiz], so watching that should give more clues. As we do that, we will try to update this section of this page. Other help writing the information required here would also be greatly appreciated.&lt;br /&gt;
&lt;br /&gt;
== The course format system ==&lt;br /&gt;
Most of the logic for rendering and editing a course has been moved to a new subsystem called courseformat. The subsystem is located in &amp;quot;course/format&amp;quot; folder so it includes all the format plugins inside. The methods and modules which are distributed between the course and the course/format folders are now rearranged or refactored to be aligned with the current Moodle coding style.&lt;br /&gt;
=== Mandatory renderer in course formats ===&lt;br /&gt;
Now format plugins renderer is not optional anymore. Legacy formats without a renderer will get a deprecation message but it will continue working however, they should create a new renderer as soon as possible. The section-based format can do it by extending the provided core_courseformat\output\section_renderer class which includes all the necessary methods.&lt;br /&gt;
=== New format base class ===&lt;br /&gt;
The old base_format class (which all plugins extend) is now renamed as core_courseformat\base. The new class provides all the functionally of the previous base_format but it has been refactored to be used as a centralized source of truth for the course rendering. Legacy formats should extend the new class to avoid the deprecation message.&lt;br /&gt;
&lt;br /&gt;
Now, the plugin format class provides information such as:&lt;br /&gt;
* If the page is displaying a single or multiple section&lt;br /&gt;
* Give access to other related format objects like the modinfo, the course record, maximum number of sections...&lt;br /&gt;
* If the format is compatible with features like course index, reactive components, ajax...&lt;br /&gt;
* Other format specifics like the page title, the default section name, default blocks...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The format instance is now the main object output components will use to render a course (see next section for more information).&lt;br /&gt;
=== New course output classes and mustache files ===&lt;br /&gt;
Traditionally, section-based course formats uses print_single_section_page and print_multiple_section_page to render the course content. In Moodle 4.0 most of the course rendering methods are migrated to output components and mustache templates. The old methods will get deprecation messages if they use the old renderer methods.&lt;br /&gt;
&lt;br /&gt;
This is an example of a format rendering a course:&amp;lt;syntaxhighlight lang=&amp;quot;php-brief&amp;quot;&amp;gt;&lt;br /&gt;
// Get the course format instance.&lt;br /&gt;
$format = course_get_format($course);&lt;br /&gt;
&lt;br /&gt;
// Get the specific format renderer.&lt;br /&gt;
$renderer = $format-&amp;gt;get_renderer($PAGE);&lt;br /&gt;
&lt;br /&gt;
if (!empty($displaysection)) {&lt;br /&gt;
    // Setup the format instance to display a single section.&lt;br /&gt;
    $format-&amp;gt;set_section_number($displaysection);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Create the ouptut instance and render it.&lt;br /&gt;
$outputclass = $format-&amp;gt;get_output_classname(&#039;content&#039;);&lt;br /&gt;
$widget = new $outputclass($format);&lt;br /&gt;
&lt;br /&gt;
echo $renderer-&amp;gt;render($widget);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Format plugins are free to use its own output classes to render a course, or they could override the existing output classes by providing their own implementation. For example, the default output for &amp;quot;content&amp;quot; (as in the previous example) is &amp;quot;core_courseformat\output\local\|content&amp;quot;, however, if the plugin has a &amp;quot;format_XXX\output\courseformat\content&amp;quot; class, the $format-&amp;gt;class the get_output_class will return the overridden one.&lt;br /&gt;
Another important update on course rendering is that now all course structure is rendered using mustache templates instead of the original html_writer methods. Now themes are able to override the course format by providing alternative versions of the mustache files. All core course templates are located in &amp;quot;course/format/templates&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
All the new output classes and a guide on how to migrate the current third-party plugins will be available soon.&lt;br /&gt;
=== Course editor javascript modules and frontend components ===&lt;br /&gt;
The majority of the javascript logic related to the course editing is replaced by AMD modules. Because this is a major change in the way courses are edited and rendered, by default format plugins will continue using the previous YUI modules for now. However, formats can start using the new libraries overriding the &amp;quot;$format-&amp;gt;supports_components()&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Some Moodle 4.0 new features are only available for courses using the new editor library:&lt;br /&gt;
* Edit the course via the course index&lt;br /&gt;
* Creating sections without reloading the course page&lt;br /&gt;
* The new move section/activity modal&lt;br /&gt;
* Native browser drag&amp;amp;drop implementation&lt;br /&gt;
The new course editor uses a component-based reactive pattern to keep track of the course changes. The pattern highlights are:&lt;br /&gt;
* The main AMD module &amp;quot;core_crouseformat\courseeditor&amp;quot; maintains a data structure called state.&lt;br /&gt;
* Each UI element is implemented as a Component that observes the course state data and reacts to any data change&lt;br /&gt;
* When any reactive component needs to modify the course, it asks the course editor to execute a mutation. Mutations encapsulate all web services calls and alter the course state data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reactive library documentation, as well as the format plugin migration guide, will be available soon.&lt;br /&gt;
=== Other course related 4.0 changes ===&lt;br /&gt;
Two new web services have been added:&lt;br /&gt;
* core_courseformat_get_state: user by the new javascript course editor to get the current course state data (containing the list of sections, activities, and other course-related data)&lt;br /&gt;
* core_courseformat_update_course: to alter the current course content. Each call returns the parts of the course state altered by the action&lt;br /&gt;
== Behat changes ==&lt;br /&gt;
To make behat tests more readable and easy to maintain, it is recommended to use the most direct steps to get what the test needs. It is highly recommended to use&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page &lt;br /&gt;
or&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page logged in as &amp;quot;user&amp;quot;&lt;br /&gt;
instead of navigating to the activity via&lt;br /&gt;
 I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 I follow &amp;quot;Activity name&amp;quot;&lt;br /&gt;
Now that [https://docs.moodle.org/dev/Prototypes#Course_creation_improvements Course index] is integrated these behat steps&lt;br /&gt;
 I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 I follow &amp;quot;Activity name&amp;quot;&lt;br /&gt;
will fail using Boost theme.&lt;br /&gt;
&lt;br /&gt;
The reason for it is that the drawer used in Boost is hiding the course index. So when the test is trying to follow an &amp;quot;Activity name&amp;quot; link, it finds two different links:&lt;br /&gt;
* one in the course index&lt;br /&gt;
* another one in the course main content.&lt;br /&gt;
But the first one, the one in the course index, is hidden by the drawer, and the test fails.&lt;br /&gt;
&lt;br /&gt;
However the recommended behat steps&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page &lt;br /&gt;
or&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page logged in as &amp;quot;user&amp;quot;&lt;br /&gt;
Old behat steps that may now fail can be updated to the new steps.&lt;br /&gt;
For example:&lt;br /&gt;
 And I am on the &amp;quot;Test assignment name&amp;quot; &amp;quot;assign activity&amp;quot; page logged in as teacher1&lt;br /&gt;
instead of:&lt;br /&gt;
 When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
 And I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 And I follow &amp;quot;Test assignment name&amp;quot;&lt;br /&gt;
There are also similar stream-lined navigation steps for accessing question bank pages. See MDL-74130.&lt;br /&gt;
&lt;br /&gt;
== Other ==&lt;br /&gt;
=== Core plugins review ===&lt;br /&gt;
A few plugins from core Moodle LMS which are no longer or hardly used have been removed and, if appropriate, added to the Moodle plugins directory.&lt;br /&gt;
&lt;br /&gt;
More information about this project, the list of plugins to be removed and the process to follow for keeping them before upgrading to 4.0 can be found in the [[Core plugins review]] page.&lt;br /&gt;
=== Site admin presets plugin ===&lt;br /&gt;
The third-party plugin [https://moodle.org/plugins/block_admin_presets Admin presets], created by David Monllaó and maintained by developers from [https://pimenko.com/ Pimenko] has been adapted and integrated into Moodle 4.0. It stores settings and plugins status (enabled/disabled) in what&#039;s called &amp;quot;presets&amp;quot; to let admins quickly switch between different configurations.&lt;br /&gt;
&lt;br /&gt;
More information about this project can be found in the [[Site admin presets|Site admin presets plugin]] page.&lt;br /&gt;
=== JavaScript browser support changes ===&lt;br /&gt;
From Moodle 4.0, Internet Explorer is no longer supported. See MDL-73915 and MDLSITE-6109 for further information on this change.&lt;br /&gt;
&lt;br /&gt;
This change means that changes built on 4.0 onwards (including the master branch) will be different to older versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
For plugin developers supporting multiple versions of Moodle using a single plugin version, the compiled javascript files are backwards compatible and will _work_ on all supported versions, however if you run the `grunt` command on multiple versions you will see unbuilt changes. Running grunt on all versions of Moodle is not necessary and this check can be safely disabled for Moodle versions 3.9 - 4.0, as long as only at least you run `grunt` against at least one version of Moodle.&lt;br /&gt;
&lt;br /&gt;
If you need to support Internet Explorer and do not wish to fork your plugin for Moodle 4.0 onwards, then it is recommended that you run `grunt` on an older version of Moodle.&lt;br /&gt;
=== The course index element ===&lt;br /&gt;
The new course index feature can be themed using a set of scss variables. Use them to change the look and feel instead of adding custom css&lt;br /&gt;
 /theme/boost/scss/moodle/courseindex.scss&lt;br /&gt;
With the introduction of the course index component, the previous and next links shown underneath each activity are no longer needed and they will be removed.&lt;br /&gt;
=== Activity icons ===&lt;br /&gt;
The icons used for activities have been redesigned and updated for all core moodle activities.&lt;br /&gt;
&lt;br /&gt;
When viewing the new icons in a file manager, for example for the quiz activity, you will see a simple black monochrome icon with a transparent background.&lt;br /&gt;
&lt;br /&gt;
On the course page, or in the activity chooser, the icon will display as a white icon on a coloured background. Styling of the icons on the coursepage is controlled by the css in theme/boost/scss/moodle/icons.scss.&lt;br /&gt;
&lt;br /&gt;
The background colour for activity icons is set using a new variable in function [modname]_supports(). The quiz activity is of type assessment, so in function quiz_supports() there is a new line defining the purpose:&lt;br /&gt;
 case FEATURE_MOD_PURPOSE: return MOD_PURPOSE_ASSESSMENT;&lt;br /&gt;
Available purposes are:&lt;br /&gt;
* MOD_PURPOSE_COMMUNICATION&lt;br /&gt;
* MOD_PURPOSE_ASSESSMENT&lt;br /&gt;
* MOD_PURPOSE_COLLABORATION&lt;br /&gt;
* MOD_PURPOSE_CONTENT&lt;br /&gt;
* MOD_PURPOSE_ADMINISTRATION&lt;br /&gt;
* MOD_PURPOSE_INTERFACE&lt;br /&gt;
The background colours linked to these purposes are set in theme/boost/scss/moodle/variables.scss&lt;br /&gt;
 $activity-icon-colors: map-merge(&lt;br /&gt;
     (&lt;br /&gt;
         &amp;quot;administration&amp;quot;: #5d63f6,&lt;br /&gt;
         &amp;quot;assessment&amp;quot;: #eb66a2,&lt;br /&gt;
         &amp;quot;collaboration&amp;quot;: #f7634d,&lt;br /&gt;
         &amp;quot;communication&amp;quot;: #11a676,&lt;br /&gt;
         &amp;quot;content&amp;quot;: #399be2,&lt;br /&gt;
         &amp;quot;interface&amp;quot;: #a378ff&lt;br /&gt;
     ),&lt;br /&gt;
     $activity-icon-colors&lt;br /&gt;
 );&lt;br /&gt;
If activity plugins do not define FEATURE_MOD_PURPOSE the activity icon will be rendered against a light grey background. There is no requirement to define the purpose of activity plugins, it will only affect the icon styling.&lt;br /&gt;
&lt;br /&gt;
Plugins implementing the variable FEATURE_MOD_PURPOSE are only supported on Moodle 4.0 and newer.&lt;br /&gt;
&lt;br /&gt;
Customising the activity icon can be done in an alternative way. For example using the styles.css in mod/[pluginname/styles.css&lt;br /&gt;
&lt;br /&gt;
In the example below the activity plugin developer chooses to keep the coloured icon for the activity and render it as large as the coloured background on the core activities&lt;br /&gt;
 .modicon_subcourse.activityiconcontainer {&lt;br /&gt;
     background-color: transparent;&lt;br /&gt;
     padding: 0;&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 .modicon_subcourse.activityiconcontainer img {&lt;br /&gt;
     width: 50px;&lt;br /&gt;
     height: 50px;&lt;br /&gt;
 }&lt;br /&gt;
To customize all icon colours use this scss array and add it to the ‘Raw initial SCSS’ in the theme Boost advanced settings page. The complete array of icon background colours can be overridden using the ‘Raw initial SCSS’ in the theme settings page. The example below changes the colours of each activity type.&lt;br /&gt;
 $activity-icon-colors: (&lt;br /&gt;
     &amp;quot;administration&amp;quot;: #5D63F6,&lt;br /&gt;
     &amp;quot;assessment&amp;quot;: #11A676,&lt;br /&gt;
     &amp;quot;collaboration&amp;quot;: #EB66A2,&lt;br /&gt;
     &amp;quot;communication&amp;quot;: #F7634D,&lt;br /&gt;
     &amp;quot;content&amp;quot;: #399BE2,&lt;br /&gt;
     &amp;quot;interface&amp;quot;: #A378FF&lt;br /&gt;
 )&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=61758</id>
		<title>Javascript Modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=61758"/>
		<updated>2022-03-02T09:43:50Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: /* Install grunt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
= Javascript Modules =&lt;br /&gt;
== What is a Javascript module and why do I care? ==&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;
== Why should I package my code as a module? ==&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;
= How do I write a Javascript module in Moodle? =&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;
Note that, for Moodle 3.10 and up (see MDLSITE-6130), any new Javascript module &#039;&#039;&#039;must&#039;&#039;&#039; be written on ES6.&lt;br /&gt;
== Install NVM and Node ==&lt;br /&gt;
The recommended way of installing NodeJS is via the [https://github.com/nvm-sh/nvm Node Version Manager], or NVM. NVM allows you to have several different versions of NodeJS installed at and in-use at any once on your computer. Supported versions of Moodle all use version {{NodeJSExactVersion}} of NodeJS.&lt;br /&gt;
&lt;br /&gt;
For Linux and Mac, follow https://github.com/nvm-sh/nvm#installing-and-updating&lt;br /&gt;
&lt;br /&gt;
For Windows, use https://github.com/coreybutler/nvm-windows/releases -- Note! NVM 1.1.7 for Windows has bugs. You should upgrade to at least 1.1.9.)&lt;br /&gt;
&lt;br /&gt;
Confirm it is working (version below in on Linux, and probably not current):&lt;br /&gt;
 $ nvm --version&lt;br /&gt;
 0.35.3&lt;br /&gt;
After you have installed &#039;&#039;&#039;nvm&#039;&#039;&#039;, you should install the correct version of NodeJS by running the following commands from your Moodle directory:&lt;br /&gt;
 nvm install&lt;br /&gt;
 nvm use&lt;br /&gt;
If your primary use of NodeJS is for Moodle then we recommend that you set NodeJS version {{NodeJSExactVersion}} as your default version. You can do this by running:&lt;br /&gt;
 nvm alias default {{NodeJSExactVersion}}&lt;br /&gt;
== Install grunt ==&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;
Once this is done, you can run the the following commands from your Moodle directory:&lt;br /&gt;
 npm install&lt;br /&gt;
&#039;&#039;&#039;This may mention vulnerabilities, that&#039;s fine and doesn&#039;t apply.&#039;&#039;&#039;&lt;br /&gt;
 npm install -g grunt-cli&lt;br /&gt;
Troubleshooting: on Mac, if you get weird errors, try running &amp;lt;code&amp;gt;sudo xcode-select --reset&amp;lt;/code&amp;gt;. And, this probably means that you need to have Xcode or simlar build tools installed and resonably up to date.&lt;br /&gt;
== Development mode (Moodle v2.9 to v3.7)  ==&lt;br /&gt;
To avoid having to constantly run grunt, make sure you set the following in your config.php&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
== Development mode (Moodle v3.8 and above)  ==&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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
== Development mode (Moodle v3.10 and above)  ==&lt;br /&gt;
All the above for Moodle 3.8 and up applies, plus (see MDLSITE-6130), any new Javascript module must be written on ES6.&lt;br /&gt;
== Running grunt ==&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;
 /usr/bin/env: node: No such file or directory&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;
 sudo ln -fs /usr/bin/nodejs /usr/local/bin/node&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;
== ES6 Modules (Moodle v3.8 and above) ==&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;
Note that, for Moodle 3.10 and up (see MDLSITE-6130), any new Javascript module must be written on ES6.&lt;br /&gt;
&lt;br /&gt;
The call from a PHP file takes the same format&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;myplugin/myfile&#039;,&#039;init&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And a minimal ES6 file will work with &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
export const init = () =&amp;gt; {&lt;br /&gt;
    window.console.log(&#039;we have been started&#039;);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
=== 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;
== Minimum (getting started) module for plugins ==&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;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&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;
export const init = () =&amp;gt; {&lt;br /&gt;
    document.addEventListener(&#039;change&#039;, e =&amp;gt; {&lt;br /&gt;
        const someNode = e.target.closest(&#039;.someclass&#039;);&lt;br /&gt;
        if (someNode) {&lt;br /&gt;
            alert(&#039;It changed!&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For older versions of Moodle prior to 3.8, you will need to use the legacy ES5 format instead:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define([], function() {&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
            document.addEventListener(&#039;change&#039;, function(e) {&lt;br /&gt;
                var someNode = e.target.closest(&#039;.someclass&#039;);&lt;br /&gt;
                if (someNode) {&lt;br /&gt;
                    alert(&#039;It changed!&#039;);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import jQuery from &#039;jquery&#039;; // We recommend that you strongly consider whether you really need jQuery. It is typically not needed in modern code.&lt;br /&gt;
import * as Str from &#039;core/str&#039;;&lt;br /&gt;
import Ajax from &#039;core/ajax&#039;;&lt;br /&gt;
&lt;br /&gt;
export const init = config =&amp;gt; {&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&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;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
...calls&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
export const init = (first, last) {&lt;br /&gt;
    window.console.log(`The first name was &#039;${first}&#039; and the last name was &#039;${last}&#039;`);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A more comprehensive explanation follows...&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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Standard license block omitted.&lt;br /&gt;
/*&lt;br /&gt;
 * @module     block_overview/helloworld&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;
import * as Str from &#039;core/str&#039;;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Reveal all of the hidden notes.&lt;br /&gt;
 */&lt;br /&gt;
const showAllNotes = () =&amp;gt; {&lt;br /&gt;
    document.querySelectorAll(&#039;.note.hidden&#039;).map(note =&amp;gt; note.removeClass(&#039;hidden&#039;));&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Hide all of the notes.&lt;br /&gt;
 */&lt;br /&gt;
const hideAllNotes = () =&amp;gt; document.querySelectorAll(&#039;.note&#039;).map(note =&amp;gt; note.addClass(&#039;hidden&#039;));&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Return a personalised, formal, greeting.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   {String} name The name of the person to greet&lt;br /&gt;
 * @returns {Promise}&lt;br /&gt;
 */&lt;br /&gt;
export const formal = name =&amp;gt; Str.get_string(&#039;formallygreet&#039;, &#039;block_overview&#039;, name);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Return a personalised, informal, greeting.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   {String} name The name of the person to greet&lt;br /&gt;
 * @returns {Promise}&lt;br /&gt;
 */&lt;br /&gt;
export const informal = name =&amp;gt; {&lt;br /&gt;
    return Str.get_string(&#039;informallygreet&#039;, &#039;block_overview&#039;, name);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
It&#039;s important to note tha tonly functions which are exported will be callable from outside the module. These are part of the public API.&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? In a limited number of situations you may not know the modules that you need until you call them. You can make use of dynamic imports to import them when you know what they are. Note: This is not the recommended approach in most cases.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
export const showTheThing = thingToShow =&amp;gt; {&lt;br /&gt;
    // Load the module for this thing.&lt;br /&gt;
    import(`local_examples/local/types/type_${thingToShow.modname}`)&lt;br /&gt;
    .then(thingModule =&amp;gt; {&lt;br /&gt;
        window.console.log(`The ${thingToShow.modname} is now available under thingModule within this scope`);&lt;br /&gt;
&lt;br /&gt;
        return thingModule;&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// DO NOT DO THIS - IT DOES NOT WORK IN MOODLE&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;/syntaxhighlight&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;
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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;theme_mytheme/countdowntimer&#039;, &#039;init&#039;, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Javascript module:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// /theme/mytheme/amd/src/countdowntimer.js&lt;br /&gt;
import Countdown from &#039;theme_mytheme/jquery.countdown&#039;);&lt;br /&gt;
import $ from &#039;jquery&#039;;&lt;br /&gt;
&lt;br /&gt;
export const init = params =&amp;gt; {&lt;br /&gt;
    $(&#039;#clock&#039;).countdown(params.targetItem, event =&amp;gt; {&lt;br /&gt;
             $(event.target).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Call your Javascript module from your template:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// /theme/mytheme/templates/countdowntimer.mustache&lt;br /&gt;
&amp;lt;span id=&amp;quot;theme_mytheme-clock-{{uniqid}}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require([&#039;theme_mytheme/countdowntimer&#039;], function(myModule) {&lt;br /&gt;
    myModule.init({&lt;br /&gt;
        targetItem: &#039;theme_mytheme-clock-{{uniqid}}&#039;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note: If you feel that you need to work around MDL-62468, then you should probably be putting the data into the DOM in your template via data Attributes, or loading it via a Web Service.&lt;br /&gt;
&lt;br /&gt;
Another example of adding a 3rd-party library to a Moodle plugin (by Ruslan Kabalin)&lt;br /&gt;
&lt;br /&gt;
If you want use https://github.com/R-TEK/colr_pickr in your plugin but this module isn&#039;t RequireJS-compatible.&lt;br /&gt;
&lt;br /&gt;
You need to configure requirejs in your plugin to use third-party library:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$config = [&#039;paths&#039; =&amp;gt; [&#039;colorpicker&#039; =&amp;gt; &#039;CDN or local path...&#039;]];&lt;br /&gt;
$requirejs = &#039;require.config(&#039; . json_encode($config) . &#039;)&#039;;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_amd_inline($requirejs);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then in your JS module in the plugin:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define([colorpicker], function(ColorPicker) {&lt;br /&gt;
    const button = document.getElementById(&#039;my_picker&#039;);&lt;br /&gt;
    let picker = new ColorPicker(button, &#039;#ff0000&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And another example of using https://github.com/itsjavi/bootstrap-colorpicker (that has a [[jQuery]] dependency) with native ES6 JS:&lt;br /&gt;
 NOTE: It is advised to move away from [[jQuery]] related plugins, as Moodle core is moving away from jQuery.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import ColourPicker from &#039;local_myplugin/bootstrap-colorpicker&#039;;&lt;br /&gt;
&lt;br /&gt;
const myElement = document.querySelector(&#039;.myelement&#039;);&lt;br /&gt;
const picker = new ColourPicker(myElement);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd($modulename, $functionname, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
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;
== Troubleshooting ==&lt;br /&gt;
=== npm-shrinkwrap.json sha1 / sha512 changes ===&lt;br /&gt;
If grunt changes all the hashes in npm-shrinkwrap.json then try this:&lt;br /&gt;
 rm -rf node_modules &amp;amp;&amp;amp; npm i&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;
== 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;
*MDL-67327 JavaScript issues when not following the official documentation, since Moodle 3.8&lt;br /&gt;
*[https://moodle.org/mod/forum/discuss.php?d=405829 Error from grunt watch - Moodle 3.9] Forum Discussion&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=61757</id>
		<title>Javascript Modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=61757"/>
		<updated>2022-03-02T09:32:47Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: /* Install grunt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
= Javascript Modules =&lt;br /&gt;
== What is a Javascript module and why do I care? ==&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;
== Why should I package my code as a module? ==&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;
= How do I write a Javascript module in Moodle? =&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;
Note that, for Moodle 3.10 and up (see MDLSITE-6130), any new Javascript module &#039;&#039;&#039;must&#039;&#039;&#039; be written on ES6.&lt;br /&gt;
== Install NVM and Node ==&lt;br /&gt;
The recommended way of installing NodeJS is via the [https://github.com/nvm-sh/nvm Node Version Manager], or NVM. NVM allows you to have several different versions of NodeJS installed at and in-use at any once on your computer. Supported versions of Moodle all use version {{NodeJSExactVersion}} of NodeJS.&lt;br /&gt;
&lt;br /&gt;
For Linux and Mac, follow https://github.com/nvm-sh/nvm#installing-and-updating&lt;br /&gt;
&lt;br /&gt;
For Windows, use https://github.com/coreybutler/nvm-windows/releases -- Note! NVM 1.1.7 for Windows has bugs. You should upgrade to at least 1.1.9.)&lt;br /&gt;
&lt;br /&gt;
Confirm it is working (version below in on Linux, and probably not current):&lt;br /&gt;
 $ nvm --version&lt;br /&gt;
 0.35.3&lt;br /&gt;
After you have installed &#039;&#039;&#039;nvm&#039;&#039;&#039;, you should install the correct version of NodeJS by running the following commands from your Moodle directory:&lt;br /&gt;
 nvm install&lt;br /&gt;
 nvm use&lt;br /&gt;
If your primary use of NodeJS is for Moodle then we recommend that you set NodeJS version {{NodeJSExactVersion}} as your default version. You can do this by running:&lt;br /&gt;
 nvm alias default {{NodeJSExactVersion}}&lt;br /&gt;
== Install grunt ==&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;
Once this is done, you can run the the following commands from your Moodle directory:&lt;br /&gt;
 npm install&lt;br /&gt;
&#039;&#039;&#039;This may mention vulnerabilities, that&#039;s fine and doesn&#039;t apply.&#039;&#039;&#039;&lt;br /&gt;
 npm install -g grunt-cli&lt;br /&gt;
Troubleshooting: on Mac, if you get weird errors, try running &amp;lt;code&amp;gt;sudo xcode-select --reset&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Development mode (Moodle v2.9 to v3.7)  ==&lt;br /&gt;
To avoid having to constantly run grunt, make sure you set the following in your config.php&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
== Development mode (Moodle v3.8 and above)  ==&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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
== Development mode (Moodle v3.10 and above)  ==&lt;br /&gt;
All the above for Moodle 3.8 and up applies, plus (see MDLSITE-6130), any new Javascript module must be written on ES6.&lt;br /&gt;
== Running grunt ==&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;
 /usr/bin/env: node: No such file or directory&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;
 sudo ln -fs /usr/bin/nodejs /usr/local/bin/node&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;
== ES6 Modules (Moodle v3.8 and above) ==&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;
Note that, for Moodle 3.10 and up (see MDLSITE-6130), any new Javascript module must be written on ES6.&lt;br /&gt;
&lt;br /&gt;
The call from a PHP file takes the same format&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;myplugin/myfile&#039;,&#039;init&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And a minimal ES6 file will work with &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
export const init = () =&amp;gt; {&lt;br /&gt;
    window.console.log(&#039;we have been started&#039;);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
=== 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;
== Minimum (getting started) module for plugins ==&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;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&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;
export const init = () =&amp;gt; {&lt;br /&gt;
    document.addEventListener(&#039;change&#039;, e =&amp;gt; {&lt;br /&gt;
        const someNode = e.target.closest(&#039;.someclass&#039;);&lt;br /&gt;
        if (someNode) {&lt;br /&gt;
            alert(&#039;It changed!&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For older versions of Moodle prior to 3.8, you will need to use the legacy ES5 format instead:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define([], function() {&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
            document.addEventListener(&#039;change&#039;, function(e) {&lt;br /&gt;
                var someNode = e.target.closest(&#039;.someclass&#039;);&lt;br /&gt;
                if (someNode) {&lt;br /&gt;
                    alert(&#039;It changed!&#039;);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import jQuery from &#039;jquery&#039;; // We recommend that you strongly consider whether you really need jQuery. It is typically not needed in modern code.&lt;br /&gt;
import * as Str from &#039;core/str&#039;;&lt;br /&gt;
import Ajax from &#039;core/ajax&#039;;&lt;br /&gt;
&lt;br /&gt;
export const init = config =&amp;gt; {&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&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;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
...calls&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
export const init = (first, last) {&lt;br /&gt;
    window.console.log(`The first name was &#039;${first}&#039; and the last name was &#039;${last}&#039;`);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A more comprehensive explanation follows...&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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Standard license block omitted.&lt;br /&gt;
/*&lt;br /&gt;
 * @module     block_overview/helloworld&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;
import * as Str from &#039;core/str&#039;;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Reveal all of the hidden notes.&lt;br /&gt;
 */&lt;br /&gt;
const showAllNotes = () =&amp;gt; {&lt;br /&gt;
    document.querySelectorAll(&#039;.note.hidden&#039;).map(note =&amp;gt; note.removeClass(&#039;hidden&#039;));&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Hide all of the notes.&lt;br /&gt;
 */&lt;br /&gt;
const hideAllNotes = () =&amp;gt; document.querySelectorAll(&#039;.note&#039;).map(note =&amp;gt; note.addClass(&#039;hidden&#039;));&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Return a personalised, formal, greeting.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   {String} name The name of the person to greet&lt;br /&gt;
 * @returns {Promise}&lt;br /&gt;
 */&lt;br /&gt;
export const formal = name =&amp;gt; Str.get_string(&#039;formallygreet&#039;, &#039;block_overview&#039;, name);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Return a personalised, informal, greeting.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   {String} name The name of the person to greet&lt;br /&gt;
 * @returns {Promise}&lt;br /&gt;
 */&lt;br /&gt;
export const informal = name =&amp;gt; {&lt;br /&gt;
    return Str.get_string(&#039;informallygreet&#039;, &#039;block_overview&#039;, name);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
It&#039;s important to note tha tonly functions which are exported will be callable from outside the module. These are part of the public API.&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? In a limited number of situations you may not know the modules that you need until you call them. You can make use of dynamic imports to import them when you know what they are. Note: This is not the recommended approach in most cases.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
export const showTheThing = thingToShow =&amp;gt; {&lt;br /&gt;
    // Load the module for this thing.&lt;br /&gt;
    import(`local_examples/local/types/type_${thingToShow.modname}`)&lt;br /&gt;
    .then(thingModule =&amp;gt; {&lt;br /&gt;
        window.console.log(`The ${thingToShow.modname} is now available under thingModule within this scope`);&lt;br /&gt;
&lt;br /&gt;
        return thingModule;&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// DO NOT DO THIS - IT DOES NOT WORK IN MOODLE&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;/syntaxhighlight&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;
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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;theme_mytheme/countdowntimer&#039;, &#039;init&#039;, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Javascript module:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// /theme/mytheme/amd/src/countdowntimer.js&lt;br /&gt;
import Countdown from &#039;theme_mytheme/jquery.countdown&#039;);&lt;br /&gt;
import $ from &#039;jquery&#039;;&lt;br /&gt;
&lt;br /&gt;
export const init = params =&amp;gt; {&lt;br /&gt;
    $(&#039;#clock&#039;).countdown(params.targetItem, event =&amp;gt; {&lt;br /&gt;
             $(event.target).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Call your Javascript module from your template:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// /theme/mytheme/templates/countdowntimer.mustache&lt;br /&gt;
&amp;lt;span id=&amp;quot;theme_mytheme-clock-{{uniqid}}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require([&#039;theme_mytheme/countdowntimer&#039;], function(myModule) {&lt;br /&gt;
    myModule.init({&lt;br /&gt;
        targetItem: &#039;theme_mytheme-clock-{{uniqid}}&#039;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note: If you feel that you need to work around MDL-62468, then you should probably be putting the data into the DOM in your template via data Attributes, or loading it via a Web Service.&lt;br /&gt;
&lt;br /&gt;
Another example of adding a 3rd-party library to a Moodle plugin (by Ruslan Kabalin)&lt;br /&gt;
&lt;br /&gt;
If you want use https://github.com/R-TEK/colr_pickr in your plugin but this module isn&#039;t RequireJS-compatible.&lt;br /&gt;
&lt;br /&gt;
You need to configure requirejs in your plugin to use third-party library:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$config = [&#039;paths&#039; =&amp;gt; [&#039;colorpicker&#039; =&amp;gt; &#039;CDN or local path...&#039;]];&lt;br /&gt;
$requirejs = &#039;require.config(&#039; . json_encode($config) . &#039;)&#039;;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_amd_inline($requirejs);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then in your JS module in the plugin:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define([colorpicker], function(ColorPicker) {&lt;br /&gt;
    const button = document.getElementById(&#039;my_picker&#039;);&lt;br /&gt;
    let picker = new ColorPicker(button, &#039;#ff0000&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And another example of using https://github.com/itsjavi/bootstrap-colorpicker (that has a [[jQuery]] dependency) with native ES6 JS:&lt;br /&gt;
 NOTE: It is advised to move away from [[jQuery]] related plugins, as Moodle core is moving away from jQuery.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import ColourPicker from &#039;local_myplugin/bootstrap-colorpicker&#039;;&lt;br /&gt;
&lt;br /&gt;
const myElement = document.querySelector(&#039;.myelement&#039;);&lt;br /&gt;
const picker = new ColourPicker(myElement);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd($modulename, $functionname, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
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;
== Troubleshooting ==&lt;br /&gt;
=== npm-shrinkwrap.json sha1 / sha512 changes ===&lt;br /&gt;
If grunt changes all the hashes in npm-shrinkwrap.json then try this:&lt;br /&gt;
 rm -rf node_modules &amp;amp;&amp;amp; npm i&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;
== 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;
*MDL-67327 JavaScript issues when not following the official documentation, since Moodle 3.8&lt;br /&gt;
*[https://moodle.org/mod/forum/discuss.php?d=405829 Error from grunt watch - Moodle 3.9] Forum Discussion&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=61756</id>
		<title>Javascript Modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=61756"/>
		<updated>2022-03-02T09:30:22Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: /* Install NVM and Node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
= Javascript Modules =&lt;br /&gt;
== What is a Javascript module and why do I care? ==&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;
== Why should I package my code as a module? ==&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;
= How do I write a Javascript module in Moodle? =&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;
Note that, for Moodle 3.10 and up (see MDLSITE-6130), any new Javascript module &#039;&#039;&#039;must&#039;&#039;&#039; be written on ES6.&lt;br /&gt;
== Install NVM and Node ==&lt;br /&gt;
The recommended way of installing NodeJS is via the [https://github.com/nvm-sh/nvm Node Version Manager], or NVM. NVM allows you to have several different versions of NodeJS installed at and in-use at any once on your computer. Supported versions of Moodle all use version {{NodeJSExactVersion}} of NodeJS.&lt;br /&gt;
&lt;br /&gt;
For Linux and Mac, follow https://github.com/nvm-sh/nvm#installing-and-updating&lt;br /&gt;
&lt;br /&gt;
For Windows, use https://github.com/coreybutler/nvm-windows/releases -- Note! NVM 1.1.7 for Windows has bugs. You should upgrade to at least 1.1.9.)&lt;br /&gt;
&lt;br /&gt;
Confirm it is working (version below in on Linux, and probably not current):&lt;br /&gt;
 $ nvm --version&lt;br /&gt;
 0.35.3&lt;br /&gt;
After you have installed &#039;&#039;&#039;nvm&#039;&#039;&#039;, you should install the correct version of NodeJS by running the following commands from your Moodle directory:&lt;br /&gt;
 nvm install&lt;br /&gt;
 nvm use&lt;br /&gt;
If your primary use of NodeJS is for Moodle then we recommend that you set NodeJS version {{NodeJSExactVersion}} as your default version. You can do this by running:&lt;br /&gt;
 nvm alias default {{NodeJSExactVersion}}&lt;br /&gt;
&lt;br /&gt;
== Install grunt ==&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;
Once this is done, you can run the the following commands from your Moodle directory:&lt;br /&gt;
 npm install&lt;br /&gt;
&#039;&#039;&#039;This may mention vulnerabilities, that&#039;s fine and doesn&#039;t apply.&#039;&#039;&#039;&lt;br /&gt;
 npm install -g grunt-cli&lt;br /&gt;
== Development mode (Moodle v2.9 to v3.7)  ==&lt;br /&gt;
To avoid having to constantly run grunt, make sure you set the following in your config.php&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
== Development mode (Moodle v3.8 and above)  ==&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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
== Development mode (Moodle v3.10 and above)  ==&lt;br /&gt;
All the above for Moodle 3.8 and up applies, plus (see MDLSITE-6130), any new Javascript module must be written on ES6.&lt;br /&gt;
== Running grunt ==&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;
 /usr/bin/env: node: No such file or directory&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;
 sudo ln -fs /usr/bin/nodejs /usr/local/bin/node&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;
== ES6 Modules (Moodle v3.8 and above) ==&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;
Note that, for Moodle 3.10 and up (see MDLSITE-6130), any new Javascript module must be written on ES6.&lt;br /&gt;
&lt;br /&gt;
The call from a PHP file takes the same format&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;myplugin/myfile&#039;,&#039;init&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And a minimal ES6 file will work with &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
export const init = () =&amp;gt; {&lt;br /&gt;
    window.console.log(&#039;we have been started&#039;);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
=== 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;
== Minimum (getting started) module for plugins ==&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;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&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;
export const init = () =&amp;gt; {&lt;br /&gt;
    document.addEventListener(&#039;change&#039;, e =&amp;gt; {&lt;br /&gt;
        const someNode = e.target.closest(&#039;.someclass&#039;);&lt;br /&gt;
        if (someNode) {&lt;br /&gt;
            alert(&#039;It changed!&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For older versions of Moodle prior to 3.8, you will need to use the legacy ES5 format instead:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define([], function() {&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
            document.addEventListener(&#039;change&#039;, function(e) {&lt;br /&gt;
                var someNode = e.target.closest(&#039;.someclass&#039;);&lt;br /&gt;
                if (someNode) {&lt;br /&gt;
                    alert(&#039;It changed!&#039;);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import jQuery from &#039;jquery&#039;; // We recommend that you strongly consider whether you really need jQuery. It is typically not needed in modern code.&lt;br /&gt;
import * as Str from &#039;core/str&#039;;&lt;br /&gt;
import Ajax from &#039;core/ajax&#039;;&lt;br /&gt;
&lt;br /&gt;
export const init = config =&amp;gt; {&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&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;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
...calls&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
export const init = (first, last) {&lt;br /&gt;
    window.console.log(`The first name was &#039;${first}&#039; and the last name was &#039;${last}&#039;`);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A more comprehensive explanation follows...&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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Standard license block omitted.&lt;br /&gt;
/*&lt;br /&gt;
 * @module     block_overview/helloworld&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;
import * as Str from &#039;core/str&#039;;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Reveal all of the hidden notes.&lt;br /&gt;
 */&lt;br /&gt;
const showAllNotes = () =&amp;gt; {&lt;br /&gt;
    document.querySelectorAll(&#039;.note.hidden&#039;).map(note =&amp;gt; note.removeClass(&#039;hidden&#039;));&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Hide all of the notes.&lt;br /&gt;
 */&lt;br /&gt;
const hideAllNotes = () =&amp;gt; document.querySelectorAll(&#039;.note&#039;).map(note =&amp;gt; note.addClass(&#039;hidden&#039;));&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Return a personalised, formal, greeting.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   {String} name The name of the person to greet&lt;br /&gt;
 * @returns {Promise}&lt;br /&gt;
 */&lt;br /&gt;
export const formal = name =&amp;gt; Str.get_string(&#039;formallygreet&#039;, &#039;block_overview&#039;, name);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Return a personalised, informal, greeting.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   {String} name The name of the person to greet&lt;br /&gt;
 * @returns {Promise}&lt;br /&gt;
 */&lt;br /&gt;
export const informal = name =&amp;gt; {&lt;br /&gt;
    return Str.get_string(&#039;informallygreet&#039;, &#039;block_overview&#039;, name);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
It&#039;s important to note tha tonly functions which are exported will be callable from outside the module. These are part of the public API.&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? In a limited number of situations you may not know the modules that you need until you call them. You can make use of dynamic imports to import them when you know what they are. Note: This is not the recommended approach in most cases.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
export const showTheThing = thingToShow =&amp;gt; {&lt;br /&gt;
    // Load the module for this thing.&lt;br /&gt;
    import(`local_examples/local/types/type_${thingToShow.modname}`)&lt;br /&gt;
    .then(thingModule =&amp;gt; {&lt;br /&gt;
        window.console.log(`The ${thingToShow.modname} is now available under thingModule within this scope`);&lt;br /&gt;
&lt;br /&gt;
        return thingModule;&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// DO NOT DO THIS - IT DOES NOT WORK IN MOODLE&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;/syntaxhighlight&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;
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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;theme_mytheme/countdowntimer&#039;, &#039;init&#039;, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Javascript module:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// /theme/mytheme/amd/src/countdowntimer.js&lt;br /&gt;
import Countdown from &#039;theme_mytheme/jquery.countdown&#039;);&lt;br /&gt;
import $ from &#039;jquery&#039;;&lt;br /&gt;
&lt;br /&gt;
export const init = params =&amp;gt; {&lt;br /&gt;
    $(&#039;#clock&#039;).countdown(params.targetItem, event =&amp;gt; {&lt;br /&gt;
             $(event.target).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Call your Javascript module from your template:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// /theme/mytheme/templates/countdowntimer.mustache&lt;br /&gt;
&amp;lt;span id=&amp;quot;theme_mytheme-clock-{{uniqid}}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require([&#039;theme_mytheme/countdowntimer&#039;], function(myModule) {&lt;br /&gt;
    myModule.init({&lt;br /&gt;
        targetItem: &#039;theme_mytheme-clock-{{uniqid}}&#039;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note: If you feel that you need to work around MDL-62468, then you should probably be putting the data into the DOM in your template via data Attributes, or loading it via a Web Service.&lt;br /&gt;
&lt;br /&gt;
Another example of adding a 3rd-party library to a Moodle plugin (by Ruslan Kabalin)&lt;br /&gt;
&lt;br /&gt;
If you want use https://github.com/R-TEK/colr_pickr in your plugin but this module isn&#039;t RequireJS-compatible.&lt;br /&gt;
&lt;br /&gt;
You need to configure requirejs in your plugin to use third-party library:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$config = [&#039;paths&#039; =&amp;gt; [&#039;colorpicker&#039; =&amp;gt; &#039;CDN or local path...&#039;]];&lt;br /&gt;
$requirejs = &#039;require.config(&#039; . json_encode($config) . &#039;)&#039;;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_amd_inline($requirejs);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then in your JS module in the plugin:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define([colorpicker], function(ColorPicker) {&lt;br /&gt;
    const button = document.getElementById(&#039;my_picker&#039;);&lt;br /&gt;
    let picker = new ColorPicker(button, &#039;#ff0000&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And another example of using https://github.com/itsjavi/bootstrap-colorpicker (that has a [[jQuery]] dependency) with native ES6 JS:&lt;br /&gt;
 NOTE: It is advised to move away from [[jQuery]] related plugins, as Moodle core is moving away from jQuery.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import ColourPicker from &#039;local_myplugin/bootstrap-colorpicker&#039;;&lt;br /&gt;
&lt;br /&gt;
const myElement = document.querySelector(&#039;.myelement&#039;);&lt;br /&gt;
const picker = new ColourPicker(myElement);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd($modulename, $functionname, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
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;
== Troubleshooting ==&lt;br /&gt;
=== npm-shrinkwrap.json sha1 / sha512 changes ===&lt;br /&gt;
If grunt changes all the hashes in npm-shrinkwrap.json then try this:&lt;br /&gt;
 rm -rf node_modules &amp;amp;&amp;amp; npm i&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;
== 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;
*MDL-67327 JavaScript issues when not following the official documentation, since Moodle 3.8&lt;br /&gt;
*[https://moodle.org/mod/forum/discuss.php?d=405829 Error from grunt watch - Moodle 3.9] Forum Discussion&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=61755</id>
		<title>Javascript Modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=61755"/>
		<updated>2022-03-02T09:30:08Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: /* Install NVM and Node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
= Javascript Modules =&lt;br /&gt;
== What is a Javascript module and why do I care? ==&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;
== Why should I package my code as a module? ==&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;
= How do I write a Javascript module in Moodle? =&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;
Note that, for Moodle 3.10 and up (see MDLSITE-6130), any new Javascript module &#039;&#039;&#039;must&#039;&#039;&#039; be written on ES6.&lt;br /&gt;
== Install NVM and Node ==&lt;br /&gt;
The recommended way of installing NodeJS is via the [https://github.com/nvm-sh/nvm Node Version Manager], or NVM. NVM allows you to have several different versions of NodeJS installed at and in-use at any once on your computer. Supported versions of Moodle all use version {{NodeJSExactVersion}} of NodeJS.&lt;br /&gt;
&lt;br /&gt;
For Linux and Mac, follow https://github.com/nvm-sh/nvm#installing-and-updating&lt;br /&gt;
For Windows, use https://github.com/coreybutler/nvm-windows/releases -- Note! NVM 1.1.7 for Windows has bugs. You should upgrade to at least 1.1.9.)&lt;br /&gt;
&lt;br /&gt;
Confirm it is working (version below in on Linux, and probably not current):&lt;br /&gt;
 $ nvm --version&lt;br /&gt;
 0.35.3&lt;br /&gt;
After you have installed &#039;&#039;&#039;nvm&#039;&#039;&#039;, you should install the correct version of NodeJS by running the following commands from your Moodle directory:&lt;br /&gt;
 nvm install&lt;br /&gt;
 nvm use&lt;br /&gt;
If your primary use of NodeJS is for Moodle then we recommend that you set NodeJS version {{NodeJSExactVersion}} as your default version. You can do this by running:&lt;br /&gt;
 nvm alias default {{NodeJSExactVersion}}&lt;br /&gt;
&lt;br /&gt;
== Install grunt ==&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;
Once this is done, you can run the the following commands from your Moodle directory:&lt;br /&gt;
 npm install&lt;br /&gt;
&#039;&#039;&#039;This may mention vulnerabilities, that&#039;s fine and doesn&#039;t apply.&#039;&#039;&#039;&lt;br /&gt;
 npm install -g grunt-cli&lt;br /&gt;
== Development mode (Moodle v2.9 to v3.7)  ==&lt;br /&gt;
To avoid having to constantly run grunt, make sure you set the following in your config.php&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
== Development mode (Moodle v3.8 and above)  ==&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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
== Development mode (Moodle v3.10 and above)  ==&lt;br /&gt;
All the above for Moodle 3.8 and up applies, plus (see MDLSITE-6130), any new Javascript module must be written on ES6.&lt;br /&gt;
== Running grunt ==&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;
 /usr/bin/env: node: No such file or directory&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;
 sudo ln -fs /usr/bin/nodejs /usr/local/bin/node&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;
== ES6 Modules (Moodle v3.8 and above) ==&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;
Note that, for Moodle 3.10 and up (see MDLSITE-6130), any new Javascript module must be written on ES6.&lt;br /&gt;
&lt;br /&gt;
The call from a PHP file takes the same format&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;myplugin/myfile&#039;,&#039;init&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And a minimal ES6 file will work with &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
export const init = () =&amp;gt; {&lt;br /&gt;
    window.console.log(&#039;we have been started&#039;);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
=== 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;
== Minimum (getting started) module for plugins ==&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;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&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;
export const init = () =&amp;gt; {&lt;br /&gt;
    document.addEventListener(&#039;change&#039;, e =&amp;gt; {&lt;br /&gt;
        const someNode = e.target.closest(&#039;.someclass&#039;);&lt;br /&gt;
        if (someNode) {&lt;br /&gt;
            alert(&#039;It changed!&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For older versions of Moodle prior to 3.8, you will need to use the legacy ES5 format instead:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define([], function() {&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
            document.addEventListener(&#039;change&#039;, function(e) {&lt;br /&gt;
                var someNode = e.target.closest(&#039;.someclass&#039;);&lt;br /&gt;
                if (someNode) {&lt;br /&gt;
                    alert(&#039;It changed!&#039;);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import jQuery from &#039;jquery&#039;; // We recommend that you strongly consider whether you really need jQuery. It is typically not needed in modern code.&lt;br /&gt;
import * as Str from &#039;core/str&#039;;&lt;br /&gt;
import Ajax from &#039;core/ajax&#039;;&lt;br /&gt;
&lt;br /&gt;
export const init = config =&amp;gt; {&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&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;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
...calls&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
export const init = (first, last) {&lt;br /&gt;
    window.console.log(`The first name was &#039;${first}&#039; and the last name was &#039;${last}&#039;`);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A more comprehensive explanation follows...&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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Standard license block omitted.&lt;br /&gt;
/*&lt;br /&gt;
 * @module     block_overview/helloworld&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;
import * as Str from &#039;core/str&#039;;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Reveal all of the hidden notes.&lt;br /&gt;
 */&lt;br /&gt;
const showAllNotes = () =&amp;gt; {&lt;br /&gt;
    document.querySelectorAll(&#039;.note.hidden&#039;).map(note =&amp;gt; note.removeClass(&#039;hidden&#039;));&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Hide all of the notes.&lt;br /&gt;
 */&lt;br /&gt;
const hideAllNotes = () =&amp;gt; document.querySelectorAll(&#039;.note&#039;).map(note =&amp;gt; note.addClass(&#039;hidden&#039;));&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Return a personalised, formal, greeting.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   {String} name The name of the person to greet&lt;br /&gt;
 * @returns {Promise}&lt;br /&gt;
 */&lt;br /&gt;
export const formal = name =&amp;gt; Str.get_string(&#039;formallygreet&#039;, &#039;block_overview&#039;, name);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Return a personalised, informal, greeting.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   {String} name The name of the person to greet&lt;br /&gt;
 * @returns {Promise}&lt;br /&gt;
 */&lt;br /&gt;
export const informal = name =&amp;gt; {&lt;br /&gt;
    return Str.get_string(&#039;informallygreet&#039;, &#039;block_overview&#039;, name);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
It&#039;s important to note tha tonly functions which are exported will be callable from outside the module. These are part of the public API.&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? In a limited number of situations you may not know the modules that you need until you call them. You can make use of dynamic imports to import them when you know what they are. Note: This is not the recommended approach in most cases.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
export const showTheThing = thingToShow =&amp;gt; {&lt;br /&gt;
    // Load the module for this thing.&lt;br /&gt;
    import(`local_examples/local/types/type_${thingToShow.modname}`)&lt;br /&gt;
    .then(thingModule =&amp;gt; {&lt;br /&gt;
        window.console.log(`The ${thingToShow.modname} is now available under thingModule within this scope`);&lt;br /&gt;
&lt;br /&gt;
        return thingModule;&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// DO NOT DO THIS - IT DOES NOT WORK IN MOODLE&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;/syntaxhighlight&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;
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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;theme_mytheme/countdowntimer&#039;, &#039;init&#039;, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Javascript module:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// /theme/mytheme/amd/src/countdowntimer.js&lt;br /&gt;
import Countdown from &#039;theme_mytheme/jquery.countdown&#039;);&lt;br /&gt;
import $ from &#039;jquery&#039;;&lt;br /&gt;
&lt;br /&gt;
export const init = params =&amp;gt; {&lt;br /&gt;
    $(&#039;#clock&#039;).countdown(params.targetItem, event =&amp;gt; {&lt;br /&gt;
             $(event.target).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Call your Javascript module from your template:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// /theme/mytheme/templates/countdowntimer.mustache&lt;br /&gt;
&amp;lt;span id=&amp;quot;theme_mytheme-clock-{{uniqid}}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require([&#039;theme_mytheme/countdowntimer&#039;], function(myModule) {&lt;br /&gt;
    myModule.init({&lt;br /&gt;
        targetItem: &#039;theme_mytheme-clock-{{uniqid}}&#039;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note: If you feel that you need to work around MDL-62468, then you should probably be putting the data into the DOM in your template via data Attributes, or loading it via a Web Service.&lt;br /&gt;
&lt;br /&gt;
Another example of adding a 3rd-party library to a Moodle plugin (by Ruslan Kabalin)&lt;br /&gt;
&lt;br /&gt;
If you want use https://github.com/R-TEK/colr_pickr in your plugin but this module isn&#039;t RequireJS-compatible.&lt;br /&gt;
&lt;br /&gt;
You need to configure requirejs in your plugin to use third-party library:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$config = [&#039;paths&#039; =&amp;gt; [&#039;colorpicker&#039; =&amp;gt; &#039;CDN or local path...&#039;]];&lt;br /&gt;
$requirejs = &#039;require.config(&#039; . json_encode($config) . &#039;)&#039;;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_amd_inline($requirejs);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then in your JS module in the plugin:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define([colorpicker], function(ColorPicker) {&lt;br /&gt;
    const button = document.getElementById(&#039;my_picker&#039;);&lt;br /&gt;
    let picker = new ColorPicker(button, &#039;#ff0000&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And another example of using https://github.com/itsjavi/bootstrap-colorpicker (that has a [[jQuery]] dependency) with native ES6 JS:&lt;br /&gt;
 NOTE: It is advised to move away from [[jQuery]] related plugins, as Moodle core is moving away from jQuery.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import ColourPicker from &#039;local_myplugin/bootstrap-colorpicker&#039;;&lt;br /&gt;
&lt;br /&gt;
const myElement = document.querySelector(&#039;.myelement&#039;);&lt;br /&gt;
const picker = new ColourPicker(myElement);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd($modulename, $functionname, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
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;
== Troubleshooting ==&lt;br /&gt;
=== npm-shrinkwrap.json sha1 / sha512 changes ===&lt;br /&gt;
If grunt changes all the hashes in npm-shrinkwrap.json then try this:&lt;br /&gt;
 rm -rf node_modules &amp;amp;&amp;amp; npm i&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;
== 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;
*MDL-67327 JavaScript issues when not following the official documentation, since Moodle 3.8&lt;br /&gt;
*[https://moodle.org/mod/forum/discuss.php?d=405829 Error from grunt watch - Moodle 3.9] Forum Discussion&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=History_of_the_Moodle_quiz_and_question_bank&amp;diff=61734</id>
		<title>History of the Moodle quiz and question bank</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=History_of_the_Moodle_quiz_and_question_bank&amp;diff=61734"/>
		<updated>2022-02-15T15:12:59Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is edited highlights from&lt;br /&gt;
 git log --no-merges --topo-order --reverse --format=&#039;%cd %h %s [%an]&#039; --date=short --\&lt;br /&gt;
         mod/quiz question lib/questionlib.php admin/qtypes.php admin/qbehaviours.php&lt;br /&gt;
(If you prefer, substitute &amp;lt;tt&amp;gt;gitk&amp;lt;/tt&amp;gt; for &amp;lt;tt&amp;gt;git log&amp;lt;/tt&amp;gt; in that.) Particularly significant changes have be put in bold, but this is somewhat arbitrary.&lt;br /&gt;
&lt;br /&gt;
In several cases, the first commit purporting to add a feature was pretty broken, or minimal, and then more work was done to fix it up and make it actually work. In these cases, generally I have just picked out the first commit mentioning a particular feature.&lt;br /&gt;
&lt;br /&gt;
The headings mark points in time, so the things between the Moodle 1.0 and Moodle 1.1 headings are features that are new in Moodle 1.1. The funny numbers after the date are the commit hashes. They are a link to that change on github.&lt;br /&gt;
&lt;br /&gt;
The changes have been classified according to whether they are primarily P - pedagogic, A - administrative or T - technical.&lt;br /&gt;
&lt;br /&gt;
At the moment, I was inconsistent with attributing credit for features. That is just sloppiness on my part, and hopefully I will fix it some day.--[[User:Tim Hunt|Tim Hunt]] 04:33, 12 April 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Does anyone know when Gustav Delius started being quiz maintainer?&#039;&#039;&lt;br /&gt;
== Moodle 1.0 release 20 August 2002 ==&lt;br /&gt;
* 2002-10-04 [https://github.com/moodle/moodle/commit/730fd187c825ca8e71bf78a130a4d7ca4e1785bb 730fd187] (PAT) &#039;&#039;&#039;First version of quiz module added&#039;&#039;&#039; by Martin Dougiamas. The first feature that anyone was paid to write for Moodle!&lt;br /&gt;
* 2002-10-06 [https://github.com/moodle/moodle/commit/14d8c0b4099b0d331bf6e766eac046e2259e173a 14d8c0b4] (P) &#039;&#039;&#039;First three question types created, Multiple-Choice, Short answer and True/false.&#039;&#039;&#039;&lt;br /&gt;
* 2002-10-13 [https://github.com/moodle/moodle/commit/579ddad5ef181299080f8d75641f392300649441 579ddad5] (PA) &#039;&#039;&#039;first, very basic, grades report added.&#039;&#039;&#039;&lt;br /&gt;
* 2002-10-14 [https://github.com/moodle/moodle/commit/7bd1aa1d648e801bd21fb5fa3030ef9c902f33dd 7bd1aa1d] (A) first quiz editing UI&lt;br /&gt;
* 2002-10-15 [https://github.com/moodle/moodle/commit/2a2c9725bbadd1e4391e03b54eafdab23ad18ae8 2a2c9725] (A) editing UI for the first three types.&lt;br /&gt;
* 2002-10-18 [https://github.com/moodle/moodle/commit/958aafe2b419978eb03d4ea622c93224d28602c7 958aafe2] (A) tracking start and end time of attempts.&lt;br /&gt;
* 2002-10-20 [https://github.com/moodle/moodle/commit/c74a0ca5c24473ccf5dc1ba9b8a5b44dcecb2fb9 c74a0ca5] (A) question category editing UI. (Note, categories cannot be nested, but note the the ides of published categories to allow sharing between courses already exists.)&lt;br /&gt;
* 2002-10-21 [https://github.com/moodle/moodle/commit/e1c91df09b9dc71758fec06de2c4809faa9700ae e1c91df0] (A) allow questions to be deleted.&lt;br /&gt;
* 2002-10-22 [https://github.com/moodle/moodle/commit/e331eb06fdbb4adc5ebce3cbf4aacda7ce7a5ed5 e331eb06] (A) regrading implemented&lt;br /&gt;
* 2002-12-09 [https://github.com/moodle/moodle/commit/9307692fdfd9c41d8ff1799df7c87e2d8c1c8475 9307692f] (PA) JavaScript confirmation before submitting an attempt.&lt;br /&gt;
* 2003-01-01 [https://github.com/moodle/moodle/commit/8e6c87ccf3c11b9e2ca7cfd222b6e2a0c67a93db 8e6c87cc] (PA) Teachers can enable students to review, but only after the quiz close date.&lt;br /&gt;
* 2003-02-16 [https://github.com/moodle/moodle/commit/49220fa70cc90013773771727f0f36103a19f88b 49220fa7] (A) Framework for quiz import/export formats. Only one real format for now, missingword.&lt;br /&gt;
* 2003-02-24 [https://github.com/moodle/moodle/commit/95dbc030a88308873fe0f97261bb0c847c364ad7 95dbc030] (P) &#039;&#039;&#039;Random short-answer match qtype added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-03-30 [https://github.com/moodle/moodle/commit/54a67a59218c7c5242a1398e5f3d08f23c9974d2 54a67a59] (P) &#039;&#039;&#039;Matching question type added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-04-09 [https://github.com/moodle/moodle/commit/34d52ad7d29675bc1f1c6275bddf896e262145be 34d52ad7] (P) &#039;&#039;&#039;Random questions added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-04-09 [https://github.com/moodle/moodle/commit/4b85b717128765ec207048e0006cdc25c10d7ac8 4b85b717] (P) Shuffle questions and shuffle answers features added.&lt;br /&gt;
* 2003-05-02 [https://github.com/moodle/moodle/commit/c6bcd06abac61a6d15a8f9b4d4bb12090eb93bbb c6bcd06a] (A) AON and Blackboard import formats added.&lt;br /&gt;
* 2003-07-06 [https://github.com/moodle/moodle/commit/401c8de6c55a348b3de7d2e8d785d59e1d5f6712 401c8de6] (P) &#039;&#039;&#039;Description question type added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-07-09 [https://github.com/moodle/moodle/commit/d7c93ec8fa8d11f63998ab9fd78c2c2f41045568 d7c93ec8] (A) Backup and restore added to the quiz.&lt;br /&gt;
* 2003-07-10 [https://github.com/moodle/moodle/commit/361f649d7ad7ddf2d0af1932505a6dd316559fb6 361f649d] (P) &#039;&#039;&#039;Numerical qtype added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-07-24 [https://github.com/moodle/moodle/commit/29d5d0b40c31f1b589af9c91598676dae9b6444e 29d5d0b4] (T) Quiz reports made into a sort-of plugin.&lt;br /&gt;
* 2003-07-24 [https://github.com/moodle/moodle/commit/c90f563e398f20b0cf473efb55bbf9b8ffb35420 c90f563e] (PA) simplestat report added.&lt;br /&gt;
* 2003-07-28 [https://github.com/moodle/moodle/commit/250e71d96747693f40eb7db6eb40ba166b897a96 250e71d9] (A) countdown time when less than 24 hours from the close date.&lt;br /&gt;
* 2003-08-01 [https://github.com/moodle/moodle/commit/8b439f8c164c15d39c3fa1bec029b616df5281dc 8b439f8c] (P) &#039;&#039;&#039;Multi-answer question type.&#039;&#039;&#039;&lt;br /&gt;
* 2003-08-03 [https://github.com/moodle/moodle/commit/0f36ecb9ea9634c6b0732ebf06bc36707d3ecba6 0f36ecb9] (P) Each attempt builds on the last added&lt;br /&gt;
== Moodle 1.1 release 29 August 2003 ==&lt;br /&gt;
* 2003-09-10 [https://github.com/moodle/moodle/commit/ed1daaa9d7b5d7e1e8885854d7f2add117c4f24c ed1daaa9] (P) First support for ungraded quizzes.&lt;br /&gt;
* 2003-10-15 [https://github.com/moodle/moodle/commit/857e0dfdd5ee3501eea54178829c094784bbd1f2 857e0dfd] (A) Course test manager import format.&lt;br /&gt;
* 2003-11-20 [https://github.com/moodle/moodle/commit/565e970ee212aa5a355890ff85a14828b4bf735a 565e970e] (PA) fullstat report by Thomas Robb&lt;br /&gt;
* 2003-11-20 [https://github.com/moodle/moodle/commit/7c9c2a8da68f420a8fa04ae1a90493a1dbe4f633 7c9c2a8d] (P) allow negative grades for multiple-choice.&lt;br /&gt;
* 2003-12-01 [https://github.com/moodle/moodle/commit/0315927955b0877d957453ae617b527d3a70d453 03159279] (A) Aiken import format.&lt;br /&gt;
* 2003-12-12 [https://github.com/moodle/moodle/commit/43bf9fc2d71450ec1fb91cd739814a5b20dad12a 43bf9fc2] (T) Improved plug-in formation for import/export formats.&lt;br /&gt;
* 2003-12-12 [https://github.com/moodle/moodle/commit/43bf9fc2d71450ec1fb91cd739814a5b20dad12a 43bf9fc2] (A) &#039;&#039;&#039;GIFT format added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-12-29 [https://github.com/moodle/moodle/commit/0ce4aa1a8a381f2014d46e6ee5b04db1bdef8e23 0ce4aa1a] (P) Short-answer qtype enhanced to allow wild-cards.&lt;br /&gt;
* 2004-01-11 [https://github.com/moodle/moodle/commit/998ebd420ab6c71aa1ac555287ce7ffcd4db8672 998ebd42] (A) WebCT import format added.&lt;br /&gt;
* 2004-01-13 [https://github.com/moodle/moodle/commit/a9981ba6194c438aace048e9fc3f8130a3155542 a9981ba6] (A) Matching questions added to GIFT format&lt;br /&gt;
* 2004-02-14 [https://github.com/moodle/moodle/commit/831b236f2c68b252203dcf4a9ad68a7191fbfc16 831b236f] (A) Groups support added to the quiz reports.&lt;br /&gt;
* 2004-02-16 [https://github.com/moodle/moodle/commit/bbcbc0fecc7f8c7f5b71424864bdef4f1b540c17 bbcbc0fe] (P) &#039;&#039;&#039;First version of lesson module added.&#039;&#039;&#039;&lt;br /&gt;
== Moodle 1.2 release 20 March 2004 ==&lt;br /&gt;
* 2004-05-19 [https://github.com/moodle/moodle/commit/56215ed40f5f46aa0d1943585784e7327ea724e7 56215ed4] (A) Warn teachers if they are editing a quiz with attempts.&lt;br /&gt;
== Moodle 1.3 release 25 May 2004 ==&lt;br /&gt;
* 2004-06-02 [https://github.com/moodle/moodle/commit/f41e824f33414e6184611a6d1708cd3a58ec9058 f41e824f] (PA) Time limit feature added.&lt;br /&gt;
* 2004-07-07 [https://github.com/moodle/moodle/commit/88c898f590b12bbb6bcff1c7e482669e17ab5115 88c898f5] (A) Password and subnet restrictions added.&lt;br /&gt;
* 2004-07-21 [https://github.com/moodle/moodle/commit/8966a111310d0cc1c7012d68bcd137a5bafdf11f 8966a111] (T) &#039;&#039;&#039;Question types made plug-ins&#039;&#039;&#039;, although still within mod/quiz.&lt;br /&gt;
* 2004-07-30 [https://github.com/moodle/moodle/commit/8c5a95facbeff21a356396a588446ed77713cb9e 8c5a95fa] (P) &#039;&#039;&#039;Calculated question type added.&#039;&#039;&#039;&lt;br /&gt;
* 2004-07-30 [https://github.com/moodle/moodle/commit/7a82d193240ab6a3df435ac2c89821864d5d2ee4 7a82d193] (P) &#039;&#039;&#039;Units added to numerical (and calculate) question types.&#039;&#039;&#039;&lt;br /&gt;
* 2004-08-06 [https://github.com/moodle/moodle/commit/bbb4e32d3c07fa2192f54cebddf677d9938bf8b1 bbb4e32d] (A) &#039;&#039;&#039;Moodle XML export format added.&#039;&#039;&#039;&lt;br /&gt;
* 2004-08-16 [https://github.com/moodle/moodle/commit/9c8047cfd07c5da2393720063949f448cd185c07 9c8047cf] (PA) &#039;&#039;&#039;Question preview feature added.&#039;&#039;&#039;&lt;br /&gt;
== Moodle 1.4 release 31 August 2004 ==&lt;br /&gt;
* 2004-12-16 [https://github.com/moodle/moodle/commit/6c83959e33ddd8978aa2a88af4f47bfeb97af5d4 6c83959e] (A) &#039;Secure pop-up&#039; mode added.&lt;br /&gt;
* 2004-12-16 [https://github.com/moodle/moodle/commit/d6b3c7b82e9f385daf6f9d642e8112a6bc7298ce d6b3c7b8] (A) Moodle XML export added.&lt;br /&gt;
* 2004-12-23 [https://github.com/moodle/moodle/commit/a5c0990e5d5477f743dddd234312e0cf5223e22e a5c0990e] (A) Config page to allow admins to set default quiz options.&lt;br /&gt;
* 2005-01-02 [https://github.com/moodle/moodle/commit/34283aa87d2a37fd237723c24c8da2b93a5bbec2 34283aa8] (A) &#039;Show advanced&#039; button added to the quiz settings form. (Copying what is already done in the Resource module.)&lt;br /&gt;
* 2005-01-02 [https://github.com/moodle/moodle/commit/34283aa87d2a37fd237723c24c8da2b93a5bbec2 34283aa8] (PA) Start of more sophisticated review options.&lt;br /&gt;
* 2005-01-02 [https://github.com/moodle/moodle/commit/ac27e47dc48dbe82b19e24ae59e281b74e758213 ac27e47d] (A) Hierarchical question categories.&lt;br /&gt;
* 2005-01-03 [https://github.com/moodle/moodle/commit/d70ccc495ca904789940f281655b94d9a8e8637b d70ccc49] (P) Multi-page quizzes allowed&lt;br /&gt;
* 2005-01-25 [https://github.com/moodle/moodle/commit/1680925333d35cb0ed0209f3b5c27fc681c9d278 16809253] (A) Learnwise question import format&lt;br /&gt;
* 2005-02-01 [https://github.com/moodle/moodle/commit/bdfa14dd7f34ada369dc430dc1f9f82dcc93b7dc bdfa14dd] (PA) Allow blocks on the quiz view page&lt;br /&gt;
* 2005-02-14 [https://github.com/moodle/moodle/commit/72036f9305517224f9bdc67771f2bfde93c143a2 72036f93] (A) Now a teacher option for number of decimal points to show for grades.&lt;br /&gt;
* 2005-02-17 [https://github.com/moodle/moodle/commit/06e273a1c3496a67193a16485ff695d273f69523 06e273a1] (A) attempt at adding QTI 2.0 export.&lt;br /&gt;
* 2005-03-03 [https://github.com/moodle/moodle/commit/c6bfdec3fc8d2db34be464bc01e573e23e54e748 c6bfdec3] (AT) attempt at adding question versioning, that never really got anywhere.&lt;br /&gt;
* 2005-05-06 [https://github.com/moodle/moodle/commit/ee1fb969c8274130c0e7a7317dd69a8d48e0e54f ee1fb969] (P) &#039;&#039;&#039;adaptive mode added&#039;&#039;&#039; by Gustav Delius et al of the Serving Mathematics project.&lt;br /&gt;
* 2005-05-15 [https://github.com/moodle/moodle/commit/0fc5939983046b8c00a49a1ed42381da195619f6 0fc59399] (PA) &#039;&#039;&#039;Item analysis report added&#039;&#039;&#039; by Enrique Castro&lt;br /&gt;
* 2005-05-16 [https://github.com/moodle/moodle/commit/691d06114e40e1889d2dce7012272463dd60cba1 691d0611] (A) Examview import format.&lt;br /&gt;
* 2005-06-04 [https://github.com/moodle/moodle/commit/7bbe08a267f262736df50a130066a076a6c6e095 7bbe08a2] (AT) simplest and fullstat reports removed.&lt;br /&gt;
== Moodle 1.5 release 5 June 2005 ==&lt;br /&gt;
* 2005-06-26 [https://github.com/moodle/moodle/commit/ed460c8e04d08944a778587b16f4bb22aac043ac ed460c8e] (P) Essay question type by Mark Nielsen&lt;br /&gt;
* 2005-07-22 [https://github.com/moodle/moodle/commit/80ed3fe6b02b1364bf1c1f0d625e590275caa1f8 80ed3fe6] (PA) Responses report added (temporarily)&lt;br /&gt;
* 2006-02-08 [https://github.com/moodle/moodle/commit/401c3496ae9668f1f0e6f33745afa8e73e11f8e2 401c3496] (P) Option for an enforced delay between attempts.&lt;br /&gt;
* 2006-02-19 [https://github.com/moodle/moodle/commit/14afbbf0344c275e655b0d51eb01fee7cdb0ce0b 14afbbf0] (A) Tool for re-ordering all the questions in a quiz at once.&lt;br /&gt;
* 2006-02-24 [https://github.com/moodle/moodle/commit/516cf3eb59ae523f7997616502603793f38fae9a 516cf3eb] (T) &#039;&#039;&#039;Question bank code and question types moved from mod/quiz -&amp;gt; question.&#039;&#039;&#039;&lt;br /&gt;
* 2006-03-01 [https://github.com/moodle/moodle/commit/03c8c27ee00d4c5d9ab347d4dfdbf5d7a11191fa 03c8c27e] (PA) Option to show students with/without attempts in the quiz reports.&lt;br /&gt;
* 2006-03-08 [https://github.com/moodle/moodle/commit/d1c974813032984dd852ea3f4586f04d8eecb817 d1c97481] (A) Blackboard 6 question import format.&lt;br /&gt;
* 2006-03-22 [https://github.com/moodle/moodle/commit/ead293420d0baf8af94309fa0e8b0518d8f68711 ead29342] (T) Question types now a proper sort of plugin.&lt;br /&gt;
* 2006-03-24 [https://github.com/moodle/moodle/commit/4eda4eecbd1b7fd7dc64a95ed34d6e9ad97a4a48 4eda4eec] (T) &#039;Missing&#039; qtype added.&lt;br /&gt;
* 2006-03-26 [https://github.com/moodle/moodle/commit/5f9ef821df8f4bd984e11cf41931802f72efc885 5f9ef821] (AT) Responses report moved from core to contrib (undoing 80ed3fe6b).&lt;br /&gt;
* 2006-03-27 [https://github.com/moodle/moodle/commit/31e95855b85d551f249a2d7bed0d5479e159d3b3 31e95855] (T) Quiz report plugin structure improved.&lt;br /&gt;
* 2006-04-07 [https://github.com/moodle/moodle/commit/b6e907a245ddbe17a69125725717625e3ede3b72 b6e907a2] (PA) Manual grading made applicable to all qtypes, not just Essay.&lt;br /&gt;
* July 2006 &#039;&#039;&#039;Tim Hunt takes over as quiz maintainer&#039;&#039;&#039;&lt;br /&gt;
== Moodle 1.6 release 20 June 2006 ==&lt;br /&gt;
* 2006-07-04 [https://github.com/moodle/moodle/commit/a58ffe3fe2526e04f21c1d95786cd027a82f4371 a58ffe3f] (P) Allow matching questions to have extra distractors.&lt;br /&gt;
* 2006-07-12 [https://github.com/moodle/moodle/commit/1fe641f7b43b63cb5289b0ffa8b6c4e1f2ee61ff 1fe641f7] (P) Support for matching common wrong, or partially correct, responses to numeric questions, not just one right answer.&lt;br /&gt;
* 2006-08-08 [https://github.com/moodle/moodle/commit/bbbf2d401564ade2548592853586005a7bcde900 bbbf2d40] (AT) Roles and permissions system added to Moodle.&lt;br /&gt;
* 2006-08-11 [https://github.com/moodle/moodle/commit/1b8a7434e28f5508a3f7ae116192a3ac7234543d 1b8a7434] (P) &#039;&#039;&#039;General feedback added to all types. (It was initially called something else, then renamed in a4514d91d)&#039;&#039;&#039;.&lt;br /&gt;
* 2006-08-11 [https://github.com/moodle/moodle/commit/613f306d1d68aaf826d8b6ccf26cced0dc2fa928 613f306d] (T) Moodle database code changed to use XMLDB.&lt;br /&gt;
* 2006-08-22 [https://github.com/moodle/moodle/commit/212b7b8cd9af682fc32c76d1bfd6172ead62a27c 212b7b8c] (P) Quiz overall feedback added.&lt;br /&gt;
* 2006-08-24 [https://github.com/moodle/moodle/commit/307f045f0718da95d00faf38a630d4f3169f12e5 307f045f] (P) &#039;&#039;&#039;Overall feedback options added to multiple-choice questions&#039;&#039;&#039;.&lt;br /&gt;
== Moodle 1.7 release 7 November 2006 ==&lt;br /&gt;
* 2006-11-29 [https://github.com/moodle/moodle/commit/ee259d0cd1f05219547de294e60656d303462ac3 ee259d0c] (A) Support for including category information in GIFT and Moodle XML export files.&lt;br /&gt;
* 2006-12-19 [https://github.com/moodle/moodle/commit/a23f0aaf9570886bf5803459f0018dd68e835328 a23f0aaf] (T) Moodle converted to use formslib.php, rather than hand-coded forms.&lt;br /&gt;
* 2006-12-21 [https://github.com/moodle/moodle/commit/77c7f0f549e24c7a1d180967379c64af77515105 77c7f0f5] (A) Open Office format support added to quiz report downloads.&lt;br /&gt;
* 2007-02-20 [https://github.com/moodle/moodle/commit/624cbc9c26a5f4b56083b2c1321891f0af62bc82 624cbc9c] (A) Option to display the question text when browsing the question bank.&lt;br /&gt;
== Moodle 1.8 release 30 March 2007 ==&lt;br /&gt;
* 2007-04-13 [https://github.com/moodle/moodle/commit/3e0647ffaf2c81224b6f7d2ed24d5188888fcfb5 3e0647ff] (P) Options for how multiple choice choices are numbered.&lt;br /&gt;
* 2007-06-15 [https://github.com/moodle/moodle/commit/294e63eadd0c49ed829c055111c15e08ab56d789 294e63ea] (PT) First attempt to allow students to upload files during attempts. (Gets broken in the changes to 2.0, and was never completely working, e.g. backup and restore never worked.)&lt;br /&gt;
* 2007-06-19 [https://github.com/moodle/moodle/commit/7a6f4066cee03e8db752a66d667d91b9b28f9ea5 7a6f4066] (A) Course reset implemented for quizzes.&lt;br /&gt;
* 2007-06-26 [https://github.com/moodle/moodle/commit/ac48e43a896d1a6315c38e3aac5a3c5f0d327cb8 ac48e43a] (A) Email notification/confirmation of submitted quiz attempts.&lt;br /&gt;
* 2007-07-21 [https://github.com/moodle/moodle/commit/e8825e724bf6f916752a067c9be983295729ed4f e8825e72] (A) Support for essay and description qtypes added to GIFT.&lt;br /&gt;
* 2007-07-22 [https://github.com/moodle/moodle/commit/42ff9ce68b932f844a326c4b8197cdcbd74ea002 42ff9ce6] (A) &#039;&#039;&#039;Support for the new gradebook added to the quiz.&#039;&#039;&#039;&lt;br /&gt;
* 2007-07-30 [https://github.com/moodle/moodle/commit/00719c02d66fca180334d22b4e0cf781a8ef4c27 00719c02] (PA) Separate review option for quiz overall feedback.&lt;br /&gt;
* 2007-08-08 [https://github.com/moodle/moodle/commit/a41e328736f4cdd95c62277346832c19da93115a a41e3287] (T) Allow third-party qtype plugins to participate in GIFT and Moodle XML import export.&lt;br /&gt;
* 2007-08-09 [https://github.com/moodle/moodle/commit/271e6decdac9d9445c047a7d90cc98b7912cf1b6 271e6dec] (AT) &#039;&#039;&#039;New question bank&#039;&#039;&#039; by Jamie Pratt. Cleaner code. Many problems with sharing questions between courses fixed. Finer-grained capabilities.&lt;br /&gt;
* 2007-08-27 [https://github.com/moodle/moodle/commit/5ada3c8e3aa858d7e11ccf5e92cbad78f813d691 5ada3c8e] (A) Support for Groupings added to the quiz.&lt;br /&gt;
* 2007-10-11 [https://github.com/moodle/moodle/commit/14e66f3bebac8c587d08e14f92d6f8332c26161d 14e66f3b] (A) Overridden grades from the gradebook shown in the quiz UI.&lt;br /&gt;
== Moodle 1.9 release 3 March 2008 ==&lt;br /&gt;
* 2008-03-06 [https://github.com/moodle/moodle/commit/05866d85d4155a632bb988b8c5a16252df69b7a3 05866d85] (T) Code for all the different different rules about whether a student can attempt the quiz now moved into separate classes. Not yet a proper plugin type.&lt;br /&gt;
* 2008-05-07 [https://github.com/moodle/moodle/commit/8b87ab000003e7cc830fb959b72d80de79b84cd2 8b87ab00] (PA) Summary graph added to the quiz overview report. (This is the start of a set of &#039;&#039;&#039;major improvements to the quiz reports for Moodle 2.0&#039;&#039;&#039;, done by Jamie Pratt for the OU.)&lt;br /&gt;
* 2008-05-15 [https://github.com/moodle/moodle/commit/aad5b0fca94bbc278f754634134a3839267ceb36 aad5b0fc] (PA) Group and course averages added to the overview report.&lt;br /&gt;
* 2008-05-15 [https://github.com/moodle/moodle/commit/f33e1ed4ae4948e337e5fee61adc3580f81dfa80 f33e1ed4] (T) Moodle database connection changed to use the new global $DB.&lt;br /&gt;
* 2008-05-23 [https://github.com/moodle/moodle/commit/a59eb2b6a8e569ea5777f6cfa1d9aab9669bb79f a59eb2b6] (A) Groups support added to the Manual grading report.&lt;br /&gt;
* 2008-06-10 [https://github.com/moodle/moodle/commit/0c1c764e8257d6db589ed0d89371d4b49b8972d7 0c1c764e] (PA) &#039;&#039;&#039;Quiz statistics report added.&#039;&#039;&#039;&lt;br /&gt;
* 2008-06-27 [https://github.com/moodle/moodle/commit/36e413e38c5d04c923f62e2525b2d59767babfc8 36e413e3] (P) &#039;&#039;&#039;Quiz attempt UI greatly improved, with new navigation panel and summary page.&#039;&#039;&#039;&lt;br /&gt;
* 2008-07-11 [https://github.com/moodle/moodle/commit/98f38217bb6de4ffa78f79e7371b5d8f53aaf98a 98f38217] (T) Regrading UI merged into overview report. Dry run of regrades made possible, before doing it for real.&lt;br /&gt;
* 2008-07-20 [https://github.com/moodle/moodle/commit/7f29a7dbe40d21dcbc5f0d21a399c2e6f7b3c98b 7f29a7db] (PA) &#039;&#039;&#039;Responses report moved back out of contrib, and in to standard Moodle.&#039;&#039;&#039;&lt;br /&gt;
* 2008-07-24 [https://github.com/moodle/moodle/commit/17f1782c1217ab5b83de6bd55a4e7a7adb0abe5a 17f1782c] (T) cron support added to quiz reports.&lt;br /&gt;
* 2008-08-15 [https://github.com/moodle/moodle/commit/f88fb62c40249c74475de64eedeae2c3a549441c f88fb62c] (AT) rounding of quiz and question grades before they are displayed is made consistent everywhere.&lt;br /&gt;
* 2008-08-15 [https://github.com/moodle/moodle/commit/f9a2cf86a9c7a77bd0be1c17eca9260f0833f45e f9a2cf86] (T) Quiz grades are now consistently stored in the database as NUMEBER(10,5), and question grades as NUMBER(12,7).&lt;br /&gt;
* 2008-08-29 [https://github.com/moodle/moodle/commit/62e76c6766368de71e6a7f7cd9a7fc17be942265 62e76c67] (P) Let students flag questions during quiz attempts.&lt;br /&gt;
* 2008-09-09 [https://github.com/moodle/moodle/commit/8df9635465bd09d9624407289f11680bbf2c5f0e 8df96354] (AT) Admin page for managing the installed question types.&lt;br /&gt;
* 2008-09-11 [https://github.com/moodle/moodle/commit/c308138f8994c55f17858f852be40c8d69ae9733 c308138f] (AT) Item analysis report removed.&lt;br /&gt;
* 2008-11-20 [https://github.com/moodle/moodle/commit/fa583f5f6eb3b4c9f624e77df0cfb9f9e705e6c3 fa583f5f] (T) &#039;&#039;&#039;New editing UI for quizzes&#039;&#039;&#039;. Finnish Summer of Code project by Olli Savolainen.&lt;br /&gt;
* 2008-11-28 [https://github.com/moodle/moodle/commit/f24493ec9b0e46c30c5343283dd10179a0fd892e f24493ec] (P) Allow essay questions to be selected by random questions.&lt;br /&gt;
* 2009-01-07 [https://github.com/moodle/moodle/commit/a733c4b98b527ef66ea48eb4f0d11bc59ae89a56 a733c4b9] (A) Add an option to display the user&#039;s photo and name on the quiz attempt page.&lt;br /&gt;
* 2009-01-14 [https://github.com/moodle/moodle/commit/96c7d771df88fd0aa2514ba898c89f81053c6e93 96c7d771] (AT) mod/quiz:reviewmyattempts capability separated from mod/quiz:attempt.&lt;br /&gt;
* 2009-01-20 [https://github.com/moodle/moodle/commit/46795afcbdd7fe43de03afb6b2b87eb5c21ea691 46795afc] (T) refactoring of the code that displays the question bank, to eliminate duplication between the quiz editing and question bank display code.&lt;br /&gt;
* 2009-02-25 [https://github.com/moodle/moodle/commit/cd120b2344d0c9d8f8bfa20466e3abb9fe0e4c8a cd120b23] (AT) New YUI pop-up for selecting the question type when adding a new question, replacing the old select menu.&lt;br /&gt;
* 2009-05-06 [https://github.com/moodle/moodle/commit/6bf44482c651faa946fb2cf5a34475456258c708 6bf44482] (T) Moodle 2.0 $PAGE and $OUTPUT changes applied to the quiz.&lt;br /&gt;
* 2009-05-29 [https://github.com/moodle/moodle/commit/83a15d025cb163509dcff124ed914058c826966f 83a15d02] (P) &#039;&#039;&#039;New question type &#039;Simple calculated&#039; by Pierre Pichet.&#039;&#039;&#039;&lt;br /&gt;
* 2009-06-05 [https://github.com/moodle/moodle/commit/aa9c6ecf02b25e967766ad09a23b668ebff83a7e aa9c6ecf] (A) Highlight the last question you edited in the question bank like. A small, but very useful change.&lt;br /&gt;
* 2009-06-12 [https://github.com/moodle/moodle/commit/cf6155226cba2e4e62e9e1cb44dad88afacc39b4 cf615522] (T) require_js replaced by $PAGE-&amp;gt;requires everywhere.&lt;br /&gt;
* 2009-06-19 [https://github.com/moodle/moodle/commit/17da2e6f28d3477eb4ccfe5ac94c9cebb8456c8e 17da2e6f] (T) The concept of &#039;subplugins&#039; is born. Quiz report, within the quiz, are one of the early examples. (Regrettably, the prefix quiz_, not quizreport_ is chosen.)&lt;br /&gt;
* 2009-09-30 [https://github.com/moodle/moodle/commit/7d4dfc481e65a2548d32723a4726ddc833cdd1f5 7d4dfc48] (A) Integration with &#039;Safe Exam Browser&#039; added.&lt;br /&gt;
* 2010-02-07 [https://github.com/moodle/moodle/commit/2d279432b0c64c8dda20758641f529f87f14ea1f 2d279432] (P) &#039;&#039;&#039;New question type &#039;Calculated multiple choice&#039; by Pierre Pichet.&#039;&#039;&#039;&lt;br /&gt;
* 2010-03-08 [https://github.com/moodle/moodle/commit/990650f94cbe46344ced45c5fe69ebc273da1d00 990650f9] (A) Different open and close dates, etc., for different groups or individuals. Implemented by Matt Petro of the University of Wisconsin - Madison Engineering School.&lt;br /&gt;
* 2010-05-20 [https://github.com/moodle/moodle/commit/9df209c1226b1859a0c3d534f026306d2dfc13f9 9df209c1] (T) Moodle events now triggered for starting and finishing quiz attempts.&lt;br /&gt;
* 2010-05-21 [https://github.com/moodle/moodle/commit/56ed242b51909666b9e757f1a94fb2c105928b5e 56ed242b] (PA) New quiz option &#039;Show blocks during quiz attempts&#039; by Sam Hemelryk.&lt;br /&gt;
* 2010-08-06 [https://github.com/moodle/moodle/commit/d39ba35c34d4272d5092b5f80bacd2be6e7fc50f d39ba35c] (A) Make it clearer in the quiz grades report when essay questions need to be graded.&lt;br /&gt;
* 2010-08-10 [https://github.com/moodle/moodle/commit/fe6ce2348945f267b3d90ed74442a221c0a9808d fe6ce234] (T) Quiz and question bank converted to the Moodle 2.0 Files API.&lt;br /&gt;
* 2010-10-24 [https://github.com/moodle/moodle/commit/41941110fdecb6313637a6ad77c6e6e26aa79833 41941110] (T) Quiz and question bank converted to the Moodle 2.0 Backup and restore system.&lt;br /&gt;
* 2010-10-30 [https://github.com/moodle/moodle/commit/92b360057504ecfb2b3f8174d06a32d7564314bf 92b36005] (P) Grading of units in numerical and calculated questions changed to work the way people would expect.&lt;br /&gt;
== Moodle 2.0 release 24 November 2010 ==&lt;br /&gt;
* 2010-12-20 [https://github.com/moodle/moodle/commit/d1b7e03d5d507243d9f8adb9465161f3702f4a12 d1b7e03d] (PT) &#039;&#039;&#039;New moodle question engine, a major development by Tim Hunt, introduces the concept of Question behaviour, to handle the difference between adaptive, deferred feedback, and manually graded questions&#039;&#039;&#039;.&lt;br /&gt;
* 2010-12-20 [https://github.com/moodle/moodle/commit/d1b7e03d5d507243d9f8adb9465161f3702f4a12 d1b7e03d] (P) &#039;&#039;&#039;This also allows new behaviours like Certainty based marking, Immediate feedback, and Interactive with multiple tries.&#039;&#039;&#039;&lt;br /&gt;
* 2010-12-20 [https://github.com/moodle/moodle/commit/d1b7e03d5d507243d9f8adb9465161f3702f4a12 d1b7e03d] (T) Also in this change, many more unit tests for questions, and all questions now use renderers for output.&lt;br /&gt;
* End Dec 2010 Moodle development moves from CVS to git.&lt;br /&gt;
* 2011-02-11 [https://github.com/moodle/moodle/commit/fd214b596d63d2f7f8aff0e1d6550978f8ba60c7 fd214b59] (PT) Code to preserve the scroll position when submitting a question in the quiz, or editing the quiz.&lt;br /&gt;
* 2011-03-10 [https://github.com/moodle/moodle/commit/894e8b4e93d8f3b4036ab738e2396a5eb0707c0a 894e8b4e] (P) New essay features: Use the HTML editor or not; control the size of the response area; allow attachments; and information to be shown to the person grading.&lt;br /&gt;
* 2011-03-16 [https://github.com/moodle/moodle/commit/217f9a618ccc554a3650c2f9fbb9595215fd82fb 217f9a61] (T) As part of this, handling files are part of question responses now works properly, finally doing what 294e63ead tried.&lt;br /&gt;
* 2011-04-26 [https://github.com/moodle/moodle/commit/606e07d574c649cedea92ff5bf3946f19a93e747 606e07d5] (T) Student-visible parts of the quiz converted to use a renderer, mostly thanks to Dean Lennard.&lt;br /&gt;
* 2011-05-25 [https://github.com/moodle/moodle/commit/1da821bbde1348a67326ff7f676dff49182d4247 1da821bb] (PT) Introduce the concept of &#039;question variants&#039; as a first-class concept in the question engine.&lt;br /&gt;
* 2011-06-01 [https://github.com/moodle/moodle/commit/4b2da7cee08bea3c00338c5807f874a370c1c065 4b2da7ce] (A) Ability to restore 1.9 backups added to the quiz and question bank.&lt;br /&gt;
* 2011-06-15 [https://github.com/moodle/moodle/commit/fde4560daeb9597142d9788f4e9051d36a9f67c2 fde4560d] (A) Admin page for managing the installed question behaviours.&lt;br /&gt;
* 2011-06-16 [https://github.com/moodle/moodle/commit/2a6c5c52ee258b0097895c889cef949d8ab5ce72 2a6c5c52] (PT) Ability to have images in multiple choice answers restored. (It was broken since 2.0.)&lt;br /&gt;
== Moodle 2.1 release 1 July 2011 ==&lt;br /&gt;
* 2011-10-03 [https://github.com/moodle/moodle/commit/a28a5d74af1db4eeb12e194c0c9db111522458d2 a28a5d74] (T) Make the &#039;&#039;&#039;Quiz access rules&#039;&#039;&#039; (from 05866d85d) become proper sub-plugings of the quiz.&lt;br /&gt;
* 2011-10-28 [https://github.com/moodle/moodle/commit/2dc54611f2c23e7b1686b26abc8f4fbda9c6531b 2dc54611] (AT) Unmaintained qti_two export format removed.&lt;br /&gt;
* 2011-11-02 [https://github.com/moodle/moodle/commit/75a31c9039b1f06f6d1dca7b07282117de83aa41 75a31c90] (T) Plugin API made more standard in areas like cron, languages strings, for the question-related plugins.&lt;br /&gt;
== Moodle 2.2 release 5 December 2011 ==&lt;br /&gt;
* 2011-12-07 [https://github.com/moodle/moodle/commit/c2f5e2ab816e4bc067085b0f9c59b01739d945a9 c2f5e2ab] (T) Plugin API made more standard in areas like cron, languages strings, for the quiz-related plugins.&lt;br /&gt;
* 2012-01-08 [https://github.com/moodle/moodle/commit/5db829494030a73d15dabdc8be8685497888b138 5db82949] (P) Quiz attempt tracks the page the student is currently on, and takes them back there if they leave the attempt and come back later. (By Charles Fulton)&lt;br /&gt;
* 2012-03-07 [https://github.com/moodle/moodle/commit/88eca3cd2666a7ea451ecc8862867e68563d8bb7 88eca3cd] (A) New mod:quiz/addinstance lets you control which teachers can add a quiz to a course. (The same sort of capability is added to each activity.)&lt;br /&gt;
* 2012-01-20 [https://github.com/moodle/moodle/commit/33c8d37b6f2fa380a50ef97d60103ed9a1f9c376 33c8d37b] (P) An option to force students to answer questions strictly in order, rather than letting them navigate around the quiz as they please. (By Charles Fulton)&lt;br /&gt;
* ... hopefully much more yet to come.&lt;br /&gt;
&#039;&#039;Last updated 11th April 2012. This summary currently contains 148 items, whereas the full git log command at the top of this page lists 4777 commits.&#039;&#039;&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Question API]]&lt;br /&gt;
[[Category:Questions]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=History_of_the_Moodle_quiz_and_question_bank&amp;diff=61733</id>
		<title>History of the Moodle quiz and question bank</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=History_of_the_Moodle_quiz_and_question_bank&amp;diff=61733"/>
		<updated>2022-02-15T14:52:04Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is edited highlights from&lt;br /&gt;
    git log --no-merges mod/quiz question lib/questionlib.php admin/qtypes.php admin/qbehaviours.php&lt;br /&gt;
(If you prefer, substitute &amp;lt;tt&amp;gt;gitk&amp;lt;/tt&amp;gt; for &amp;lt;tt&amp;gt;git log&amp;lt;/tt&amp;gt; in that.) Particularly significant changes have be put in bold, but this is somewhat arbitrary.&lt;br /&gt;
&lt;br /&gt;
In several cases, the first commit purporting to add a feature was pretty broken, or minimal, and then more work was done to fix it up and make it actually work. In these cases, generally I have just picked out the first commit mentioning a particular feature.&lt;br /&gt;
&lt;br /&gt;
The headings mark points in time, so the things between the Moodle 1.0 and Moodle 1.1 headings are features that are new in Moodle 1.1. The funny numbers after the date are the commit hashes. They are a link to that change on github.&lt;br /&gt;
&lt;br /&gt;
The changes have been classified according to whether they are primarily P - pedagogic, A - administrative or T - technical.&lt;br /&gt;
&lt;br /&gt;
At the moment, I was inconsistent with attributing credit for features. That is just sloppiness on my part, and hopefully I will fix it some day.--[[User:Tim Hunt|Tim Hunt]] 04:33, 12 April 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Does anyone know when Gustav Delius started being quiz maintainer?&#039;&#039;&lt;br /&gt;
== Moodle 1.0 release 20 August 2002 ==&lt;br /&gt;
* 2002-10-04 [https://github.com/moodle/moodle/commit/730fd187c825ca8e71bf78a130a4d7ca4e1785bb 730fd187] (PAT) &#039;&#039;&#039;First version of quiz module added&#039;&#039;&#039; by Martin Dougiamas. The first feature that anyone was paid to write for Moodle!&lt;br /&gt;
* 2002-10-06 [https://github.com/moodle/moodle/commit/14d8c0b4099b0d331bf6e766eac046e2259e173a 14d8c0b4] (P) &#039;&#039;&#039;First three question types created, Multiple-Choice, Short answer and True/false.&#039;&#039;&#039;&lt;br /&gt;
* 2002-10-13 [https://github.com/moodle/moodle/commit/579ddad5ef181299080f8d75641f392300649441 579ddad5] (PA) &#039;&#039;&#039;first, very basic, grades report added.&#039;&#039;&#039;&lt;br /&gt;
* 2002-10-14 [https://github.com/moodle/moodle/commit/7bd1aa1d648e801bd21fb5fa3030ef9c902f33dd 7bd1aa1d] (A) first quiz editing UI&lt;br /&gt;
* 2002-10-15 [https://github.com/moodle/moodle/commit/2a2c9725bbadd1e4391e03b54eafdab23ad18ae8 2a2c9725] (A) editing UI for the first three types.&lt;br /&gt;
* 2002-10-18 [https://github.com/moodle/moodle/commit/958aafe2b419978eb03d4ea622c93224d28602c7 958aafe2] (A) tracking start and end time of attempts.&lt;br /&gt;
* 2002-10-20 [https://github.com/moodle/moodle/commit/c74a0ca5c24473ccf5dc1ba9b8a5b44dcecb2fb9 c74a0ca5] (A) question category editing UI. (Note, categories cannot be nested, but note the the ides of published categories to allow sharing between courses already exists.)&lt;br /&gt;
* 2002-10-21 [https://github.com/moodle/moodle/commit/e1c91df09b9dc71758fec06de2c4809faa9700ae e1c91df0] (A) allow questions to be deleted.&lt;br /&gt;
* 2002-10-22 [https://github.com/moodle/moodle/commit/e331eb06fdbb4adc5ebce3cbf4aacda7ce7a5ed5 e331eb06] (A) regrading implemented&lt;br /&gt;
* 2002-12-09 [https://github.com/moodle/moodle/commit/9307692fdfd9c41d8ff1799df7c87e2d8c1c8475 9307692f] (PA) JavaScript confirmation before submitting an attempt.&lt;br /&gt;
* 2003-01-01 [https://github.com/moodle/moodle/commit/8e6c87ccf3c11b9e2ca7cfd222b6e2a0c67a93db 8e6c87cc] (PA) Teachers can enable students to review, but only after the quiz close date.&lt;br /&gt;
* 2003-02-16 [https://github.com/moodle/moodle/commit/49220fa70cc90013773771727f0f36103a19f88b 49220fa7] (A) Framework for quiz import/export formats. Only one real format for now, missingword.&lt;br /&gt;
* 2003-02-24 [https://github.com/moodle/moodle/commit/95dbc030a88308873fe0f97261bb0c847c364ad7 95dbc030] (P) &#039;&#039;&#039;Random short-answer match qtype added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-03-30 [https://github.com/moodle/moodle/commit/54a67a59218c7c5242a1398e5f3d08f23c9974d2 54a67a59] (P) &#039;&#039;&#039;Matching question type added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-04-09 [https://github.com/moodle/moodle/commit/34d52ad7d29675bc1f1c6275bddf896e262145be 34d52ad7] (P) &#039;&#039;&#039;Random questions added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-04-09 [https://github.com/moodle/moodle/commit/4b85b717128765ec207048e0006cdc25c10d7ac8 4b85b717] (P) Shuffle questions and shuffle answers features added.&lt;br /&gt;
* 2003-05-02 [https://github.com/moodle/moodle/commit/c6bcd06abac61a6d15a8f9b4d4bb12090eb93bbb c6bcd06a] (A) AON and Blackboard import formats added.&lt;br /&gt;
* 2003-07-06 [https://github.com/moodle/moodle/commit/401c8de6c55a348b3de7d2e8d785d59e1d5f6712 401c8de6] (P) &#039;&#039;&#039;Description question type added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-07-09 [https://github.com/moodle/moodle/commit/d7c93ec8fa8d11f63998ab9fd78c2c2f41045568 d7c93ec8] (A) Backup and restore added to the quiz.&lt;br /&gt;
* 2003-07-10 [https://github.com/moodle/moodle/commit/361f649d7ad7ddf2d0af1932505a6dd316559fb6 361f649d] (P) &#039;&#039;&#039;Numerical qtype added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-07-24 [https://github.com/moodle/moodle/commit/29d5d0b40c31f1b589af9c91598676dae9b6444e 29d5d0b4] (T) Quiz reports made into a sort-of plugin.&lt;br /&gt;
* 2003-07-24 [https://github.com/moodle/moodle/commit/c90f563e398f20b0cf473efb55bbf9b8ffb35420 c90f563e] (PA) simplestat report added.&lt;br /&gt;
* 2003-07-28 [https://github.com/moodle/moodle/commit/250e71d96747693f40eb7db6eb40ba166b897a96 250e71d9] (A) countdown time when less than 24 hours from the close date.&lt;br /&gt;
* 2003-08-01 [https://github.com/moodle/moodle/commit/8b439f8c164c15d39c3fa1bec029b616df5281dc 8b439f8c] (P) &#039;&#039;&#039;Multi-answer question type.&#039;&#039;&#039;&lt;br /&gt;
* 2003-08-03 [https://github.com/moodle/moodle/commit/0f36ecb9ea9634c6b0732ebf06bc36707d3ecba6 0f36ecb9] (P) Each attempt builds on the last added&lt;br /&gt;
== Moodle 1.1 release 29 August 2003 ==&lt;br /&gt;
* 2003-09-10 [https://github.com/moodle/moodle/commit/ed1daaa9d7b5d7e1e8885854d7f2add117c4f24c ed1daaa9] (P) First support for ungraded quizzes.&lt;br /&gt;
* 2003-10-15 [https://github.com/moodle/moodle/commit/857e0dfdd5ee3501eea54178829c094784bbd1f2 857e0dfd] (A) Course test manager import format.&lt;br /&gt;
* 2003-11-20 [https://github.com/moodle/moodle/commit/565e970ee212aa5a355890ff85a14828b4bf735a 565e970e] (PA) fullstat report by Thomas Robb&lt;br /&gt;
* 2003-11-20 [https://github.com/moodle/moodle/commit/7c9c2a8da68f420a8fa04ae1a90493a1dbe4f633 7c9c2a8d] (P) allow negative grades for multiple-choice.&lt;br /&gt;
* 2003-12-01 [https://github.com/moodle/moodle/commit/0315927955b0877d957453ae617b527d3a70d453 03159279] (A) Aiken import format.&lt;br /&gt;
* 2003-12-12 [https://github.com/moodle/moodle/commit/43bf9fc2d71450ec1fb91cd739814a5b20dad12a 43bf9fc2] (T) Improved plug-in formation for import/export formats.&lt;br /&gt;
* 2003-12-12 [https://github.com/moodle/moodle/commit/43bf9fc2d71450ec1fb91cd739814a5b20dad12a 43bf9fc2] (A) &#039;&#039;&#039;GIFT format added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-12-29 [https://github.com/moodle/moodle/commit/0ce4aa1a8a381f2014d46e6ee5b04db1bdef8e23 0ce4aa1a] (P) Short-answer qtype enhanced to allow wild-cards.&lt;br /&gt;
* 2004-01-11 [https://github.com/moodle/moodle/commit/998ebd420ab6c71aa1ac555287ce7ffcd4db8672 998ebd42] (A) WebCT import format added.&lt;br /&gt;
* 2004-01-13 [https://github.com/moodle/moodle/commit/a9981ba6194c438aace048e9fc3f8130a3155542 a9981ba6] (A) Matching questions added to GIFT format&lt;br /&gt;
* 2004-02-14 [https://github.com/moodle/moodle/commit/831b236f2c68b252203dcf4a9ad68a7191fbfc16 831b236f] (A) Groups support added to the quiz reports.&lt;br /&gt;
* 2004-02-16 [https://github.com/moodle/moodle/commit/bbcbc0fecc7f8c7f5b71424864bdef4f1b540c17 bbcbc0fe] (P) &#039;&#039;&#039;First version of lesson module added.&#039;&#039;&#039;&lt;br /&gt;
== Moodle 1.2 release 20 March 2004 ==&lt;br /&gt;
* 2004-05-19 [https://github.com/moodle/moodle/commit/56215ed40f5f46aa0d1943585784e7327ea724e7 56215ed4] (A) Warn teachers if they are editing a quiz with attempts.&lt;br /&gt;
== Moodle 1.3 release 25 May 2004 ==&lt;br /&gt;
* 2004-06-02 [https://github.com/moodle/moodle/commit/f41e824f33414e6184611a6d1708cd3a58ec9058 f41e824f] (PA) Time limit feature added.&lt;br /&gt;
* 2004-07-07 [https://github.com/moodle/moodle/commit/88c898f590b12bbb6bcff1c7e482669e17ab5115 88c898f5] (A) Password and subnet restrictions added.&lt;br /&gt;
* 2004-07-21 [https://github.com/moodle/moodle/commit/8966a111310d0cc1c7012d68bcd137a5bafdf11f 8966a111] (T) &#039;&#039;&#039;Question types made plug-ins&#039;&#039;&#039;, although still within mod/quiz.&lt;br /&gt;
* 2004-07-30 [https://github.com/moodle/moodle/commit/8c5a95facbeff21a356396a588446ed77713cb9e 8c5a95fa] (P) &#039;&#039;&#039;Calculated question type added.&#039;&#039;&#039;&lt;br /&gt;
* 2004-07-30 [https://github.com/moodle/moodle/commit/7a82d193240ab6a3df435ac2c89821864d5d2ee4 7a82d193] (P) &#039;&#039;&#039;Units added to numerical (and calculate) question types.&#039;&#039;&#039;&lt;br /&gt;
* 2004-08-06 [https://github.com/moodle/moodle/commit/bbb4e32d3c07fa2192f54cebddf677d9938bf8b1 bbb4e32d] (A) &#039;&#039;&#039;Moodle XML export format added.&#039;&#039;&#039;&lt;br /&gt;
* 2004-08-16 [https://github.com/moodle/moodle/commit/9c8047cfd07c5da2393720063949f448cd185c07 9c8047cf] (PA) &#039;&#039;&#039;Question preview feature added.&#039;&#039;&#039;&lt;br /&gt;
== Moodle 1.4 release 31 August 2004 ==&lt;br /&gt;
* 2004-12-16 [https://github.com/moodle/moodle/commit/6c83959e33ddd8978aa2a88af4f47bfeb97af5d4 6c83959e] (A) &#039;Secure pop-up&#039; mode added.&lt;br /&gt;
* 2004-12-16 [https://github.com/moodle/moodle/commit/d6b3c7b82e9f385daf6f9d642e8112a6bc7298ce d6b3c7b8] (A) Moodle XML export added.&lt;br /&gt;
* 2004-12-23 [https://github.com/moodle/moodle/commit/a5c0990e5d5477f743dddd234312e0cf5223e22e a5c0990e] (A) Config page to allow admins to set default quiz options.&lt;br /&gt;
* 2005-01-02 [https://github.com/moodle/moodle/commit/34283aa87d2a37fd237723c24c8da2b93a5bbec2 34283aa8] (A) &#039;Show advanced&#039; button added to the quiz settings form. (Copying what is already done in the Resource module.)&lt;br /&gt;
* 2005-01-02 [https://github.com/moodle/moodle/commit/34283aa87d2a37fd237723c24c8da2b93a5bbec2 34283aa8] (PA) Start of more sophisticated review options.&lt;br /&gt;
* 2005-01-02 [https://github.com/moodle/moodle/commit/ac27e47dc48dbe82b19e24ae59e281b74e758213 ac27e47d] (A) Hierarchical question categories.&lt;br /&gt;
* 2005-01-03 [https://github.com/moodle/moodle/commit/d70ccc495ca904789940f281655b94d9a8e8637b d70ccc49] (P) Multi-page quizzes allowed&lt;br /&gt;
* 2005-01-25 [https://github.com/moodle/moodle/commit/1680925333d35cb0ed0209f3b5c27fc681c9d278 16809253] (A) Learnwise question import format&lt;br /&gt;
* 2005-02-01 [https://github.com/moodle/moodle/commit/bdfa14dd7f34ada369dc430dc1f9f82dcc93b7dc bdfa14dd] (PA) Allow blocks on the quiz view page&lt;br /&gt;
* 2005-02-14 [https://github.com/moodle/moodle/commit/72036f9305517224f9bdc67771f2bfde93c143a2 72036f93] (A) Now a teacher option for number of decimal points to show for grades.&lt;br /&gt;
* 2005-02-17 [https://github.com/moodle/moodle/commit/06e273a1c3496a67193a16485ff695d273f69523 06e273a1] (A) attempt at adding QTI 2.0 export.&lt;br /&gt;
* 2005-03-03 [https://github.com/moodle/moodle/commit/c6bfdec3fc8d2db34be464bc01e573e23e54e748 c6bfdec3] (AT) attempt at adding question versioning, that never really got anywhere.&lt;br /&gt;
* 2005-05-06 [https://github.com/moodle/moodle/commit/ee1fb969c8274130c0e7a7317dd69a8d48e0e54f ee1fb969] (P) &#039;&#039;&#039;adaptive mode added&#039;&#039;&#039; by Gustav Delius et al of the Serving Mathematics project.&lt;br /&gt;
* 2005-05-15 [https://github.com/moodle/moodle/commit/0fc5939983046b8c00a49a1ed42381da195619f6 0fc59399] (PA) &#039;&#039;&#039;Item analysis report added&#039;&#039;&#039; by Enrique Castro&lt;br /&gt;
* 2005-05-16 [https://github.com/moodle/moodle/commit/691d06114e40e1889d2dce7012272463dd60cba1 691d0611] (A) Examview import format.&lt;br /&gt;
* 2005-06-04 [https://github.com/moodle/moodle/commit/7bbe08a267f262736df50a130066a076a6c6e095 7bbe08a2] (AT) simplest and fullstat reports removed.&lt;br /&gt;
== Moodle 1.5 release 5 June 2005 ==&lt;br /&gt;
* 2005-06-26 [https://github.com/moodle/moodle/commit/ed460c8e04d08944a778587b16f4bb22aac043ac ed460c8e] (P) Essay question type by Mark Nielsen&lt;br /&gt;
* 2005-07-22 [https://github.com/moodle/moodle/commit/80ed3fe6b02b1364bf1c1f0d625e590275caa1f8 80ed3fe6] (PA) Responses report added (temporarily)&lt;br /&gt;
* 2006-02-08 [https://github.com/moodle/moodle/commit/401c3496ae9668f1f0e6f33745afa8e73e11f8e2 401c3496] (P) Option for an enforced delay between attempts.&lt;br /&gt;
* 2006-02-19 [https://github.com/moodle/moodle/commit/14afbbf0344c275e655b0d51eb01fee7cdb0ce0b 14afbbf0] (A) Tool for re-ordering all the questions in a quiz at once.&lt;br /&gt;
* 2006-02-24 [https://github.com/moodle/moodle/commit/516cf3eb59ae523f7997616502603793f38fae9a 516cf3eb] (T) &#039;&#039;&#039;Question bank code and question types moved from mod/quiz -&amp;gt; question.&#039;&#039;&#039;&lt;br /&gt;
* 2006-03-01 [https://github.com/moodle/moodle/commit/03c8c27ee00d4c5d9ab347d4dfdbf5d7a11191fa 03c8c27e] (PA) Option to show students with/without attempts in the quiz reports.&lt;br /&gt;
* 2006-03-08 [https://github.com/moodle/moodle/commit/d1c974813032984dd852ea3f4586f04d8eecb817 d1c97481] (A) Blackboard 6 question import format.&lt;br /&gt;
* 2006-03-22 [https://github.com/moodle/moodle/commit/ead293420d0baf8af94309fa0e8b0518d8f68711 ead29342] (T) Question types now a proper sort of plugin.&lt;br /&gt;
* 2006-03-24 [https://github.com/moodle/moodle/commit/4eda4eecbd1b7fd7dc64a95ed34d6e9ad97a4a48 4eda4eec] (T) &#039;Missing&#039; qtype added.&lt;br /&gt;
* 2006-03-26 [https://github.com/moodle/moodle/commit/5f9ef821df8f4bd984e11cf41931802f72efc885 5f9ef821] (AT) Responses report moved from core to contrib (undoing 80ed3fe6b).&lt;br /&gt;
* 2006-03-27 [https://github.com/moodle/moodle/commit/31e95855b85d551f249a2d7bed0d5479e159d3b3 31e95855] (T) Quiz report plugin structure improved.&lt;br /&gt;
* 2006-04-07 [https://github.com/moodle/moodle/commit/b6e907a245ddbe17a69125725717625e3ede3b72 b6e907a2] (PA) Manual grading made applicable to all qtypes, not just Essay.&lt;br /&gt;
* July 2006 &#039;&#039;&#039;Tim Hunt takes over as quiz maintainer&#039;&#039;&#039;&lt;br /&gt;
== Moodle 1.6 release 20 June 2006 ==&lt;br /&gt;
* 2006-07-04 [https://github.com/moodle/moodle/commit/a58ffe3fe2526e04f21c1d95786cd027a82f4371 a58ffe3f] (P) Allow matching questions to have extra distractors.&lt;br /&gt;
* 2006-07-12 [https://github.com/moodle/moodle/commit/1fe641f7b43b63cb5289b0ffa8b6c4e1f2ee61ff 1fe641f7] (P) Support for matching common wrong, or partially correct, responses to numeric questions, not just one right answer.&lt;br /&gt;
* 2006-08-08 [https://github.com/moodle/moodle/commit/bbbf2d401564ade2548592853586005a7bcde900 bbbf2d40] (AT) Roles and permissions system added to Moodle.&lt;br /&gt;
* 2006-08-11 [https://github.com/moodle/moodle/commit/1b8a7434e28f5508a3f7ae116192a3ac7234543d 1b8a7434] (P) &#039;&#039;&#039;General feedback added to all types. (It was initially called something else, then renamed in a4514d91d)&#039;&#039;&#039;.&lt;br /&gt;
* 2006-08-11 [https://github.com/moodle/moodle/commit/613f306d1d68aaf826d8b6ccf26cced0dc2fa928 613f306d] (T) Moodle database code changed to use XMLDB.&lt;br /&gt;
* 2006-08-22 [https://github.com/moodle/moodle/commit/212b7b8cd9af682fc32c76d1bfd6172ead62a27c 212b7b8c] (P) Quiz overall feedback added.&lt;br /&gt;
* 2006-08-24 [https://github.com/moodle/moodle/commit/307f045f0718da95d00faf38a630d4f3169f12e5 307f045f] (P) &#039;&#039;&#039;Overall feedback options added to multiple-choice questions&#039;&#039;&#039;.&lt;br /&gt;
== Moodle 1.7 release 7 November 2006 ==&lt;br /&gt;
* 2006-11-29 [https://github.com/moodle/moodle/commit/ee259d0cd1f05219547de294e60656d303462ac3 ee259d0c] (A) Support for including category information in GIFT and Moodle XML export files.&lt;br /&gt;
* 2006-12-19 [https://github.com/moodle/moodle/commit/a23f0aaf9570886bf5803459f0018dd68e835328 a23f0aaf] (T) Moodle converted to use formslib.php, rather than hand-coded forms.&lt;br /&gt;
* 2006-12-21 [https://github.com/moodle/moodle/commit/77c7f0f549e24c7a1d180967379c64af77515105 77c7f0f5] (A) Open Office format support added to quiz report downloads.&lt;br /&gt;
* 2007-02-20 [https://github.com/moodle/moodle/commit/624cbc9c26a5f4b56083b2c1321891f0af62bc82 624cbc9c] (A) Option to display the question text when browsing the question bank.&lt;br /&gt;
== Moodle 1.8 release 30 March 2007 ==&lt;br /&gt;
* 2007-04-13 [https://github.com/moodle/moodle/commit/3e0647ffaf2c81224b6f7d2ed24d5188888fcfb5 3e0647ff] (P) Options for how multiple choice choices are numbered.&lt;br /&gt;
* 2007-06-15 [https://github.com/moodle/moodle/commit/294e63eadd0c49ed829c055111c15e08ab56d789 294e63ea] (PT) First attempt to allow students to upload files during attempts. (Gets broken in the changes to 2.0, and was never completely working, e.g. backup and restore never worked.)&lt;br /&gt;
* 2007-06-19 [https://github.com/moodle/moodle/commit/7a6f4066cee03e8db752a66d667d91b9b28f9ea5 7a6f4066] (A) Course reset implemented for quizzes.&lt;br /&gt;
* 2007-06-26 [https://github.com/moodle/moodle/commit/ac48e43a896d1a6315c38e3aac5a3c5f0d327cb8 ac48e43a] (A) Email notification/confirmation of submitted quiz attempts.&lt;br /&gt;
* 2007-07-21 [https://github.com/moodle/moodle/commit/e8825e724bf6f916752a067c9be983295729ed4f e8825e72] (A) Support for essay and description qtypes added to GIFT.&lt;br /&gt;
* 2007-07-22 [https://github.com/moodle/moodle/commit/42ff9ce68b932f844a326c4b8197cdcbd74ea002 42ff9ce6] (A) &#039;&#039;&#039;Support for the new gradebook added to the quiz.&#039;&#039;&#039;&lt;br /&gt;
* 2007-07-30 [https://github.com/moodle/moodle/commit/00719c02d66fca180334d22b4e0cf781a8ef4c27 00719c02] (PA) Separate review option for quiz overall feedback.&lt;br /&gt;
* 2007-08-08 [https://github.com/moodle/moodle/commit/a41e328736f4cdd95c62277346832c19da93115a a41e3287] (T) Allow third-party qtype plugins to participate in GIFT and Moodle XML import export.&lt;br /&gt;
* 2007-08-09 [https://github.com/moodle/moodle/commit/271e6decdac9d9445c047a7d90cc98b7912cf1b6 271e6dec] (AT) &#039;&#039;&#039;New question bank&#039;&#039;&#039; by Jamie Pratt. Cleaner code. Many problems with sharing questions between courses fixed. Finer-grained capabilities.&lt;br /&gt;
* 2007-08-27 [https://github.com/moodle/moodle/commit/5ada3c8e3aa858d7e11ccf5e92cbad78f813d691 5ada3c8e] (A) Support for Groupings added to the quiz.&lt;br /&gt;
* 2007-10-11 [https://github.com/moodle/moodle/commit/14e66f3bebac8c587d08e14f92d6f8332c26161d 14e66f3b] (A) Overridden grades from the gradebook shown in the quiz UI.&lt;br /&gt;
== Moodle 1.9 release 3 March 2008 ==&lt;br /&gt;
* 2008-03-06 [https://github.com/moodle/moodle/commit/05866d85d4155a632bb988b8c5a16252df69b7a3 05866d85] (T) Code for all the different different rules about whether a student can attempt the quiz now moved into separate classes. Not yet a proper plugin type.&lt;br /&gt;
* 2008-05-07 [https://github.com/moodle/moodle/commit/8b87ab000003e7cc830fb959b72d80de79b84cd2 8b87ab00] (PA) Summary graph added to the quiz overview report. (This is the start of a set of &#039;&#039;&#039;major improvements to the quiz reports for Moodle 2.0&#039;&#039;&#039;, done by Jamie Pratt for the OU.)&lt;br /&gt;
* 2008-05-15 [https://github.com/moodle/moodle/commit/aad5b0fca94bbc278f754634134a3839267ceb36 aad5b0fc] (PA) Group and course averages added to the overview report.&lt;br /&gt;
* 2008-05-15 [https://github.com/moodle/moodle/commit/f33e1ed4ae4948e337e5fee61adc3580f81dfa80 f33e1ed4] (T) Moodle database connection changed to use the new global $DB.&lt;br /&gt;
* 2008-05-23 [https://github.com/moodle/moodle/commit/a59eb2b6a8e569ea5777f6cfa1d9aab9669bb79f a59eb2b6] (A) Groups support added to the Manual grading report.&lt;br /&gt;
* 2008-06-10 [https://github.com/moodle/moodle/commit/0c1c764e8257d6db589ed0d89371d4b49b8972d7 0c1c764e] (PA) &#039;&#039;&#039;Quiz statistics report added.&#039;&#039;&#039;&lt;br /&gt;
* 2008-06-27 [https://github.com/moodle/moodle/commit/36e413e38c5d04c923f62e2525b2d59767babfc8 36e413e3] (P) &#039;&#039;&#039;Quiz attempt UI greatly improved, with new navigation panel and summary page.&#039;&#039;&#039;&lt;br /&gt;
* 2008-07-11 [https://github.com/moodle/moodle/commit/98f38217bb6de4ffa78f79e7371b5d8f53aaf98a 98f38217] (T) Regrading UI merged into overview report. Dry run of regrades made possible, before doing it for real.&lt;br /&gt;
* 2008-07-20 [https://github.com/moodle/moodle/commit/7f29a7dbe40d21dcbc5f0d21a399c2e6f7b3c98b 7f29a7db] (PA) &#039;&#039;&#039;Responses report moved back out of contrib, and in to standard Moodle.&#039;&#039;&#039;&lt;br /&gt;
* 2008-07-24 [https://github.com/moodle/moodle/commit/17f1782c1217ab5b83de6bd55a4e7a7adb0abe5a 17f1782c] (T) cron support added to quiz reports.&lt;br /&gt;
* 2008-08-15 [https://github.com/moodle/moodle/commit/f88fb62c40249c74475de64eedeae2c3a549441c f88fb62c] (AT) rounding of quiz and question grades before they are displayed is made consistent everywhere.&lt;br /&gt;
* 2008-08-15 [https://github.com/moodle/moodle/commit/f9a2cf86a9c7a77bd0be1c17eca9260f0833f45e f9a2cf86] (T) Quiz grades are now consistently stored in the database as NUMEBER(10,5), and question grades as NUMBER(12,7).&lt;br /&gt;
* 2008-08-29 [https://github.com/moodle/moodle/commit/62e76c6766368de71e6a7f7cd9a7fc17be942265 62e76c67] (P) Let students flag questions during quiz attempts.&lt;br /&gt;
* 2008-09-09 [https://github.com/moodle/moodle/commit/8df9635465bd09d9624407289f11680bbf2c5f0e 8df96354] (AT) Admin page for managing the installed question types.&lt;br /&gt;
* 2008-09-11 [https://github.com/moodle/moodle/commit/c308138f8994c55f17858f852be40c8d69ae9733 c308138f] (AT) Item analysis report removed.&lt;br /&gt;
* 2008-11-20 [https://github.com/moodle/moodle/commit/fa583f5f6eb3b4c9f624e77df0cfb9f9e705e6c3 fa583f5f] (T) &#039;&#039;&#039;New editing UI for quizzes&#039;&#039;&#039;. Finnish Summer of Code project by Olli Savolainen.&lt;br /&gt;
* 2008-11-28 [https://github.com/moodle/moodle/commit/f24493ec9b0e46c30c5343283dd10179a0fd892e f24493ec] (P) Allow essay questions to be selected by random questions.&lt;br /&gt;
* 2009-01-07 [https://github.com/moodle/moodle/commit/a733c4b98b527ef66ea48eb4f0d11bc59ae89a56 a733c4b9] (A) Add an option to display the user&#039;s photo and name on the quiz attempt page.&lt;br /&gt;
* 2009-01-14 [https://github.com/moodle/moodle/commit/96c7d771df88fd0aa2514ba898c89f81053c6e93 96c7d771] (AT) mod/quiz:reviewmyattempts capability separated from mod/quiz:attempt.&lt;br /&gt;
* 2009-01-20 [https://github.com/moodle/moodle/commit/46795afcbdd7fe43de03afb6b2b87eb5c21ea691 46795afc] (T) refactoring of the code that displays the question bank, to eliminate duplication between the quiz editing and question bank display code.&lt;br /&gt;
* 2009-02-25 [https://github.com/moodle/moodle/commit/cd120b2344d0c9d8f8bfa20466e3abb9fe0e4c8a cd120b23] (AT) New YUI pop-up for selecting the question type when adding a new question, replacing the old select menu.&lt;br /&gt;
* 2009-05-06 [https://github.com/moodle/moodle/commit/6bf44482c651faa946fb2cf5a34475456258c708 6bf44482] (T) Moodle 2.0 $PAGE and $OUTPUT changes applied to the quiz.&lt;br /&gt;
* 2009-05-29 [https://github.com/moodle/moodle/commit/83a15d025cb163509dcff124ed914058c826966f 83a15d02] (P) &#039;&#039;&#039;New question type &#039;Simple calculated&#039; by Pierre Pichet.&#039;&#039;&#039;&lt;br /&gt;
* 2009-06-05 [https://github.com/moodle/moodle/commit/aa9c6ecf02b25e967766ad09a23b668ebff83a7e aa9c6ecf] (A) Highlight the last question you edited in the question bank like. A small, but very useful change.&lt;br /&gt;
* 2009-06-12 [https://github.com/moodle/moodle/commit/cf6155226cba2e4e62e9e1cb44dad88afacc39b4 cf615522] (T) require_js replaced by $PAGE-&amp;gt;requires everywhere.&lt;br /&gt;
* 2009-06-19 [https://github.com/moodle/moodle/commit/17da2e6f28d3477eb4ccfe5ac94c9cebb8456c8e 17da2e6f] (T) The concept of &#039;subplugins&#039; is born. Quiz report, within the quiz, are one of the early examples. (Regrettably, the prefix quiz_, not quizreport_ is chosen.)&lt;br /&gt;
* 2009-09-30 [https://github.com/moodle/moodle/commit/7d4dfc481e65a2548d32723a4726ddc833cdd1f5 7d4dfc48] (A) Integration with &#039;Safe Exam Browser&#039; added.&lt;br /&gt;
* 2010-02-07 [https://github.com/moodle/moodle/commit/2d279432b0c64c8dda20758641f529f87f14ea1f 2d279432] (P) &#039;&#039;&#039;New question type &#039;Calculated multiple choice&#039; by Pierre Pichet.&#039;&#039;&#039;&lt;br /&gt;
* 2010-03-08 [https://github.com/moodle/moodle/commit/990650f94cbe46344ced45c5fe69ebc273da1d00 990650f9] (A) Different open and close dates, etc., for different groups or individuals. Implemented by Matt Petro of the University of Wisconsin - Madison Engineering School.&lt;br /&gt;
* 2010-05-20 [https://github.com/moodle/moodle/commit/9df209c1226b1859a0c3d534f026306d2dfc13f9 9df209c1] (T) Moodle events now triggered for starting and finishing quiz attempts.&lt;br /&gt;
* 2010-05-21 [https://github.com/moodle/moodle/commit/56ed242b51909666b9e757f1a94fb2c105928b5e 56ed242b] (PA) New quiz option &#039;Show blocks during quiz attempts&#039; by Sam Hemelryk.&lt;br /&gt;
* 2010-08-06 [https://github.com/moodle/moodle/commit/d39ba35c34d4272d5092b5f80bacd2be6e7fc50f d39ba35c] (A) Make it clearer in the quiz grades report when essay questions need to be graded.&lt;br /&gt;
* 2010-08-10 [https://github.com/moodle/moodle/commit/fe6ce2348945f267b3d90ed74442a221c0a9808d fe6ce234] (T) Quiz and question bank converted to the Moodle 2.0 Files API.&lt;br /&gt;
* 2010-10-24 [https://github.com/moodle/moodle/commit/41941110fdecb6313637a6ad77c6e6e26aa79833 41941110] (T) Quiz and question bank converted to the Moodle 2.0 Backup and restore system.&lt;br /&gt;
* 2010-10-30 [https://github.com/moodle/moodle/commit/92b360057504ecfb2b3f8174d06a32d7564314bf 92b36005] (P) Grading of units in numerical and calculated questions changed to work the way people would expect.&lt;br /&gt;
== Moodle 2.0 release 24 November 2010 ==&lt;br /&gt;
* 2010-12-20 [https://github.com/moodle/moodle/commit/d1b7e03d5d507243d9f8adb9465161f3702f4a12 d1b7e03d] (PT) &#039;&#039;&#039;New moodle question engine, a major development by Tim Hunt, introduces the concept of Question behaviour, to handle the difference between adaptive, deferred feedback, and manually graded questions&#039;&#039;&#039;.&lt;br /&gt;
* 2010-12-20 [https://github.com/moodle/moodle/commit/d1b7e03d5d507243d9f8adb9465161f3702f4a12 d1b7e03d] (P) &#039;&#039;&#039;This also allows new behaviours like Certainty based marking, Immediate feedback, and Interactive with multiple tries.&#039;&#039;&#039;&lt;br /&gt;
* 2010-12-20 [https://github.com/moodle/moodle/commit/d1b7e03d5d507243d9f8adb9465161f3702f4a12 d1b7e03d] (T) Also in this change, many more unit tests for questions, and all questions now use renderers for output.&lt;br /&gt;
* End Dec 2010 Moodle development moves from CVS to git.&lt;br /&gt;
* 2011-02-11 [https://github.com/moodle/moodle/commit/fd214b596d63d2f7f8aff0e1d6550978f8ba60c7 fd214b59] (PT) Code to preserve the scroll position when submitting a question in the quiz, or editing the quiz.&lt;br /&gt;
* 2011-03-10 [https://github.com/moodle/moodle/commit/894e8b4e93d8f3b4036ab738e2396a5eb0707c0a 894e8b4e] (P) New essay features: Use the HTML editor or not; control the size of the response area; allow attachments; and information to be shown to the person grading.&lt;br /&gt;
* 2011-03-16 [https://github.com/moodle/moodle/commit/217f9a618ccc554a3650c2f9fbb9595215fd82fb 217f9a61] (T) As part of this, handling files are part of question responses now works properly, finally doing what 294e63ead tried.&lt;br /&gt;
* 2011-04-26 [https://github.com/moodle/moodle/commit/606e07d574c649cedea92ff5bf3946f19a93e747 606e07d5] (T) Student-visible parts of the quiz converted to use a renderer, mostly thanks to Dean Lennard.&lt;br /&gt;
* 2011-05-25 [https://github.com/moodle/moodle/commit/1da821bbde1348a67326ff7f676dff49182d4247 1da821bb] (PT) Introduce the concept of &#039;question variants&#039; as a first-class concept in the question engine.&lt;br /&gt;
* 2011-06-01 [https://github.com/moodle/moodle/commit/4b2da7cee08bea3c00338c5807f874a370c1c065 4b2da7ce] (A) Ability to restore 1.9 backups added to the quiz and question bank.&lt;br /&gt;
* 2011-06-15 [https://github.com/moodle/moodle/commit/fde4560daeb9597142d9788f4e9051d36a9f67c2 fde4560d] (A) Admin page for managing the installed question behaviours.&lt;br /&gt;
* 2011-06-16 [https://github.com/moodle/moodle/commit/2a6c5c52ee258b0097895c889cef949d8ab5ce72 2a6c5c52] (PT) Ability to have images in multiple choice answers restored. (It was broken since 2.0.)&lt;br /&gt;
== Moodle 2.1 release 1 July 2011 ==&lt;br /&gt;
* 2011-10-03 [https://github.com/moodle/moodle/commit/a28a5d74af1db4eeb12e194c0c9db111522458d2 a28a5d74] (T) Make the &#039;&#039;&#039;Quiz access rules&#039;&#039;&#039; (from 05866d85d) become proper sub-plugings of the quiz.&lt;br /&gt;
* 2011-10-28 [https://github.com/moodle/moodle/commit/2dc54611f2c23e7b1686b26abc8f4fbda9c6531b 2dc54611] (AT) Unmaintained qti_two export format removed.&lt;br /&gt;
* 2011-11-02 [https://github.com/moodle/moodle/commit/75a31c9039b1f06f6d1dca7b07282117de83aa41 75a31c90] (T) Plugin API made more standard in areas like cron, languages strings, for the question-related plugins.&lt;br /&gt;
== Moodle 2.2 release 5 December 2011 ==&lt;br /&gt;
* 2011-12-07 [https://github.com/moodle/moodle/commit/c2f5e2ab816e4bc067085b0f9c59b01739d945a9 c2f5e2ab] (T) Plugin API made more standard in areas like cron, languages strings, for the quiz-related plugins.&lt;br /&gt;
* 2012-01-08 [https://github.com/moodle/moodle/commit/5db829494030a73d15dabdc8be8685497888b138 5db82949] (P) Quiz attempt tracks the page the student is currently on, and takes them back there if they leave the attempt and come back later. (By Charles Fulton)&lt;br /&gt;
* 2012-03-07 [https://github.com/moodle/moodle/commit/88eca3cd2666a7ea451ecc8862867e68563d8bb7 88eca3cd] (A) New mod:quiz/addinstance lets you control which teachers can add a quiz to a course. (The same sort of capability is added to each activity.)&lt;br /&gt;
* 2012-01-20 [https://github.com/moodle/moodle/commit/33c8d37b6f2fa380a50ef97d60103ed9a1f9c376 33c8d37b] (P) An option to force students to answer questions strictly in order, rather than letting them navigate around the quiz as they please. (By Charles Fulton)&lt;br /&gt;
* ... hopefully much more yet to come.&lt;br /&gt;
&#039;&#039;Last updated 11th April 2012. This summary currently contains 148 items, whereas the full git log command at the top of this page lists 4777 commits.&#039;&#039;&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Question API]]&lt;br /&gt;
[[Category:Questions]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=History_of_the_Moodle_quiz_and_question_bank&amp;diff=61732</id>
		<title>History of the Moodle quiz and question bank</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=History_of_the_Moodle_quiz_and_question_bank&amp;diff=61732"/>
		<updated>2022-02-15T14:41:36Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: /* Moodle 1.6 release 20 June 2006 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is edited highlights from&lt;br /&gt;
    git log mod/quiz question lib/questionlib.php admin/qtypes.php admin/qbehaviours.php&lt;br /&gt;
(If you prefer, substitute &amp;lt;tt&amp;gt;gitk&amp;lt;/tt&amp;gt; for &amp;lt;tt&amp;gt;git log&amp;lt;/tt&amp;gt; in that.) Particularly significant changes have be put in bold, but this is somewhat arbitrary.&lt;br /&gt;
&lt;br /&gt;
In several cases, the first commit purporting to add a feature was pretty broken, or minimal, and then more work was done to fix it up and make it actually work. In these cases, generally I have just picked out the first commit mentioning a particular feature.&lt;br /&gt;
&lt;br /&gt;
The headings mark points in time, so the things between the Moodle 1.0 and Moodle 1.1 headings are features that are new in Moodle 1.1. The funny numbers after the date are the commit hashes. They are a link to that change on github.&lt;br /&gt;
&lt;br /&gt;
The changes have been classified according to whether they are primarily P - pedagogic, A - administrative or T - technical.&lt;br /&gt;
&lt;br /&gt;
At the moment, I was inconsistent with attributing credit for features. That is just sloppiness on my part, and hopefully I will fix it some day.--[[User:Tim Hunt|Tim Hunt]] 04:33, 12 April 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Does anyone know when Gustav Delius started being quiz maintainer?&#039;&#039;&lt;br /&gt;
== Moodle 1.0 release 20 August 2002 ==&lt;br /&gt;
* 2002-10-04 [https://github.com/moodle/moodle/commit/730fd187c825ca8e71bf78a130a4d7ca4e1785bb 730fd187] (PAT) &#039;&#039;&#039;First version of quiz module added&#039;&#039;&#039; by Martin Dougiamas. The first feature that anyone was paid to write for Moodle!&lt;br /&gt;
* 2002-10-06 [https://github.com/moodle/moodle/commit/14d8c0b4099b0d331bf6e766eac046e2259e173a 14d8c0b4] (P) &#039;&#039;&#039;First three question types created, Multiple-Choice, Short answer and True/false.&#039;&#039;&#039;&lt;br /&gt;
* 2002-10-13 [https://github.com/moodle/moodle/commit/579ddad5ef181299080f8d75641f392300649441 579ddad5] (PA) &#039;&#039;&#039;first, very basic, grades report added.&#039;&#039;&#039;&lt;br /&gt;
* 2002-10-14 [https://github.com/moodle/moodle/commit/7bd1aa1d648e801bd21fb5fa3030ef9c902f33dd 7bd1aa1d] (A) first quiz editing UI&lt;br /&gt;
* 2002-10-15 [https://github.com/moodle/moodle/commit/2a2c9725bbadd1e4391e03b54eafdab23ad18ae8 2a2c9725] (A) editing UI for the first three types.&lt;br /&gt;
* 2002-10-18 [https://github.com/moodle/moodle/commit/958aafe2b419978eb03d4ea622c93224d28602c7 958aafe2] (A) tracking start and end time of attempts.&lt;br /&gt;
* 2002-10-20 [https://github.com/moodle/moodle/commit/c74a0ca5c24473ccf5dc1ba9b8a5b44dcecb2fb9 c74a0ca5] (A) question category editing UI. (Note, categories cannot be nested, but note the the ides of published categories to allow sharing between courses already exists.)&lt;br /&gt;
* 2002-10-21 [https://github.com/moodle/moodle/commit/e1c91df09b9dc71758fec06de2c4809faa9700ae e1c91df0] (A) allow questions to be deleted.&lt;br /&gt;
* 2002-10-22 [https://github.com/moodle/moodle/commit/e331eb06fdbb4adc5ebce3cbf4aacda7ce7a5ed5 e331eb06] (A) regrading implemented&lt;br /&gt;
* 2002-12-09 [https://github.com/moodle/moodle/commit/9307692fdfd9c41d8ff1799df7c87e2d8c1c8475 9307692f] (PA) JavaScript confirmation before submitting an attempt.&lt;br /&gt;
* 2003-01-01 [https://github.com/moodle/moodle/commit/8e6c87ccf3c11b9e2ca7cfd222b6e2a0c67a93db 8e6c87cc] (PA) Teachers can enable students to review, but only after the quiz close date.&lt;br /&gt;
* 2003-02-16 [https://github.com/moodle/moodle/commit/49220fa70cc90013773771727f0f36103a19f88b 49220fa7] (A) Framework for quiz import/export formats. Only one real format for now, missingword.&lt;br /&gt;
* 2003-02-24 [https://github.com/moodle/moodle/commit/95dbc030a88308873fe0f97261bb0c847c364ad7 95dbc030] (P) &#039;&#039;&#039;Random short-answer match qtype added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-03-30 [https://github.com/moodle/moodle/commit/54a67a59218c7c5242a1398e5f3d08f23c9974d2 54a67a59] (P) &#039;&#039;&#039;Matching question type added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-04-09 [https://github.com/moodle/moodle/commit/34d52ad7d29675bc1f1c6275bddf896e262145be 34d52ad7] (P) &#039;&#039;&#039;Random questions added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-04-09 [https://github.com/moodle/moodle/commit/4b85b717128765ec207048e0006cdc25c10d7ac8 4b85b717] (P) Shuffle questions and shuffle answers features added.&lt;br /&gt;
* 2003-05-02 [https://github.com/moodle/moodle/commit/c6bcd06abac61a6d15a8f9b4d4bb12090eb93bbb c6bcd06a] (A) AON and Blackboard import formats added.&lt;br /&gt;
* 2003-07-06 [https://github.com/moodle/moodle/commit/401c8de6c55a348b3de7d2e8d785d59e1d5f6712 401c8de6] (P) &#039;&#039;&#039;Description question type added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-07-09 [https://github.com/moodle/moodle/commit/d7c93ec8fa8d11f63998ab9fd78c2c2f41045568 d7c93ec8] (A) Backup and restore added to the quiz.&lt;br /&gt;
* 2003-07-10 [https://github.com/moodle/moodle/commit/361f649d7ad7ddf2d0af1932505a6dd316559fb6 361f649d] (P) &#039;&#039;&#039;Numerical qtype added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-07-24 [https://github.com/moodle/moodle/commit/29d5d0b40c31f1b589af9c91598676dae9b6444e 29d5d0b4] (T) Quiz reports made into a sort-of plugin.&lt;br /&gt;
* 2003-07-24 [https://github.com/moodle/moodle/commit/c90f563e398f20b0cf473efb55bbf9b8ffb35420 c90f563e] (PA) simplestat report added.&lt;br /&gt;
* 2003-07-28 [https://github.com/moodle/moodle/commit/250e71d96747693f40eb7db6eb40ba166b897a96 250e71d9] (A) countdown time when less than 24 hours from the close date.&lt;br /&gt;
* 2003-08-01 [https://github.com/moodle/moodle/commit/8b439f8c164c15d39c3fa1bec029b616df5281dc 8b439f8c] (P) &#039;&#039;&#039;Multi-answer question type.&#039;&#039;&#039;&lt;br /&gt;
* 2003-08-03 [https://github.com/moodle/moodle/commit/0f36ecb9ea9634c6b0732ebf06bc36707d3ecba6 0f36ecb9] (P) Each attempt builds on the last added&lt;br /&gt;
== Moodle 1.1 release 29 August 2003 ==&lt;br /&gt;
* 2003-09-10 [https://github.com/moodle/moodle/commit/ed1daaa9d7b5d7e1e8885854d7f2add117c4f24c ed1daaa9] (P) First support for ungraded quizzes.&lt;br /&gt;
* 2003-10-15 [https://github.com/moodle/moodle/commit/857e0dfdd5ee3501eea54178829c094784bbd1f2 857e0dfd] (A) Course test manager import format.&lt;br /&gt;
* 2003-11-20 [https://github.com/moodle/moodle/commit/565e970ee212aa5a355890ff85a14828b4bf735a 565e970e] (PA) fullstat report by Thomas Robb&lt;br /&gt;
* 2003-11-20 [https://github.com/moodle/moodle/commit/7c9c2a8da68f420a8fa04ae1a90493a1dbe4f633 7c9c2a8d] (P) allow negative grades for multiple-choice.&lt;br /&gt;
* 2003-12-01 [https://github.com/moodle/moodle/commit/0315927955b0877d957453ae617b527d3a70d453 03159279] (A) Aiken import format.&lt;br /&gt;
* 2003-12-12 [https://github.com/moodle/moodle/commit/43bf9fc2d71450ec1fb91cd739814a5b20dad12a 43bf9fc2] (T) Improved plug-in formation for import/export formats.&lt;br /&gt;
* 2003-12-12 [https://github.com/moodle/moodle/commit/43bf9fc2d71450ec1fb91cd739814a5b20dad12a 43bf9fc2] (A) &#039;&#039;&#039;GIFT format added.&#039;&#039;&#039;&lt;br /&gt;
* 2003-12-29 [https://github.com/moodle/moodle/commit/0ce4aa1a8a381f2014d46e6ee5b04db1bdef8e23 0ce4aa1a] (P) Short-answer qtype enhanced to allow wild-cards.&lt;br /&gt;
* 2004-01-11 [https://github.com/moodle/moodle/commit/998ebd420ab6c71aa1ac555287ce7ffcd4db8672 998ebd42] (A) WebCT import format added.&lt;br /&gt;
* 2004-01-13 [https://github.com/moodle/moodle/commit/a9981ba6194c438aace048e9fc3f8130a3155542 a9981ba6] (A) Matching questions added to GIFT format&lt;br /&gt;
* 2004-02-14 [https://github.com/moodle/moodle/commit/831b236f2c68b252203dcf4a9ad68a7191fbfc16 831b236f] (A) Groups support added to the quiz reports.&lt;br /&gt;
* 2004-02-16 [https://github.com/moodle/moodle/commit/bbcbc0fecc7f8c7f5b71424864bdef4f1b540c17 bbcbc0fe] (P) &#039;&#039;&#039;First version of lesson module added.&#039;&#039;&#039;&lt;br /&gt;
== Moodle 1.2 release 20 March 2004 ==&lt;br /&gt;
* 2004-05-19 [https://github.com/moodle/moodle/commit/56215ed40f5f46aa0d1943585784e7327ea724e7 56215ed4] (A) Warn teachers if they are editing a quiz with attempts.&lt;br /&gt;
== Moodle 1.3 release 25 May 2004 ==&lt;br /&gt;
* 2004-06-02 [https://github.com/moodle/moodle/commit/f41e824f33414e6184611a6d1708cd3a58ec9058 f41e824f] (PA) Time limit feature added.&lt;br /&gt;
* 2004-07-07 [https://github.com/moodle/moodle/commit/88c898f590b12bbb6bcff1c7e482669e17ab5115 88c898f5] (A) Password and subnet restrictions added.&lt;br /&gt;
* 2004-07-21 [https://github.com/moodle/moodle/commit/8966a111310d0cc1c7012d68bcd137a5bafdf11f 8966a111] (T) &#039;&#039;&#039;Question types made plug-ins&#039;&#039;&#039;, although still within mod/quiz.&lt;br /&gt;
* 2004-07-30 [https://github.com/moodle/moodle/commit/8c5a95facbeff21a356396a588446ed77713cb9e 8c5a95fa] (P) &#039;&#039;&#039;Calculated question type added.&#039;&#039;&#039;&lt;br /&gt;
* 2004-07-30 [https://github.com/moodle/moodle/commit/7a82d193240ab6a3df435ac2c89821864d5d2ee4 7a82d193] (P) &#039;&#039;&#039;Units added to numerical (and calculate) question types.&#039;&#039;&#039;&lt;br /&gt;
* 2004-08-06 [https://github.com/moodle/moodle/commit/bbb4e32d3c07fa2192f54cebddf677d9938bf8b1 bbb4e32d] (A) &#039;&#039;&#039;Moodle XML export format added.&#039;&#039;&#039;&lt;br /&gt;
* 2004-08-16 [https://github.com/moodle/moodle/commit/9c8047cfd07c5da2393720063949f448cd185c07 9c8047cf] (PA) &#039;&#039;&#039;Question preview feature added.&#039;&#039;&#039;&lt;br /&gt;
== Moodle 1.4 release 31 August 2004 ==&lt;br /&gt;
* 2004-12-16 [https://github.com/moodle/moodle/commit/6c83959e33ddd8978aa2a88af4f47bfeb97af5d4 6c83959e] (A) &#039;Secure pop-up&#039; mode added.&lt;br /&gt;
* 2004-12-16 [https://github.com/moodle/moodle/commit/d6b3c7b82e9f385daf6f9d642e8112a6bc7298ce d6b3c7b8] (A) Moodle XML export added.&lt;br /&gt;
* 2004-12-23 [https://github.com/moodle/moodle/commit/a5c0990e5d5477f743dddd234312e0cf5223e22e a5c0990e] (A) Config page to allow admins to set default quiz options.&lt;br /&gt;
* 2005-01-02 [https://github.com/moodle/moodle/commit/34283aa87d2a37fd237723c24c8da2b93a5bbec2 34283aa8] (A) &#039;Show advanced&#039; button added to the quiz settings form. (Copying what is already done in the Resource module.)&lt;br /&gt;
* 2005-01-02 [https://github.com/moodle/moodle/commit/34283aa87d2a37fd237723c24c8da2b93a5bbec2 34283aa8] (PA) Start of more sophisticated review options.&lt;br /&gt;
* 2005-01-02 [https://github.com/moodle/moodle/commit/ac27e47dc48dbe82b19e24ae59e281b74e758213 ac27e47d] (A) Hierarchical question categories.&lt;br /&gt;
* 2005-01-03 [https://github.com/moodle/moodle/commit/d70ccc495ca904789940f281655b94d9a8e8637b d70ccc49] (P) Multi-page quizzes allowed&lt;br /&gt;
* 2005-01-25 [https://github.com/moodle/moodle/commit/1680925333d35cb0ed0209f3b5c27fc681c9d278 16809253] (A) Learnwise question import format&lt;br /&gt;
* 2005-02-01 [https://github.com/moodle/moodle/commit/bdfa14dd7f34ada369dc430dc1f9f82dcc93b7dc bdfa14dd] (PA) Allow blocks on the quiz view page&lt;br /&gt;
* 2005-02-14 [https://github.com/moodle/moodle/commit/72036f9305517224f9bdc67771f2bfde93c143a2 72036f93] (A) Now a teacher option for number of decimal points to show for grades.&lt;br /&gt;
* 2005-02-17 [https://github.com/moodle/moodle/commit/06e273a1c3496a67193a16485ff695d273f69523 06e273a1] (A) attempt at adding QTI 2.0 export.&lt;br /&gt;
* 2005-03-03 [https://github.com/moodle/moodle/commit/c6bfdec3fc8d2db34be464bc01e573e23e54e748 c6bfdec3] (AT) attempt at adding question versioning, that never really got anywhere.&lt;br /&gt;
* 2005-05-06 [https://github.com/moodle/moodle/commit/ee1fb969c8274130c0e7a7317dd69a8d48e0e54f ee1fb969] (P) &#039;&#039;&#039;adaptive mode added&#039;&#039;&#039; by Gustav Delius et al of the Serving Mathematics project.&lt;br /&gt;
* 2005-05-15 [https://github.com/moodle/moodle/commit/0fc5939983046b8c00a49a1ed42381da195619f6 0fc59399] (PA) &#039;&#039;&#039;Item analysis report added&#039;&#039;&#039; by Enrique Castro&lt;br /&gt;
* 2005-05-16 [https://github.com/moodle/moodle/commit/691d06114e40e1889d2dce7012272463dd60cba1 691d0611] (A) Examview import format.&lt;br /&gt;
* 2005-06-04 [https://github.com/moodle/moodle/commit/7bbe08a267f262736df50a130066a076a6c6e095 7bbe08a2] (AT) simplest and fullstat reports removed.&lt;br /&gt;
== Moodle 1.5 release 5 June 2005 ==&lt;br /&gt;
* 2005-06-26 [https://github.com/moodle/moodle/commit/ed460c8e04d08944a778587b16f4bb22aac043ac ed460c8e] (P) Essay question type by Mark Nielsen&lt;br /&gt;
* 2005-07-22 [https://github.com/moodle/moodle/commit/80ed3fe6b02b1364bf1c1f0d625e590275caa1f8 80ed3fe6] (PA) Responses report added (temporarily)&lt;br /&gt;
* 2006-02-08 [https://github.com/moodle/moodle/commit/401c3496ae9668f1f0e6f33745afa8e73e11f8e2 401c3496] (P) Option for an enforced delay between attempts.&lt;br /&gt;
* 2006-02-19 [https://github.com/moodle/moodle/commit/14afbbf0344c275e655b0d51eb01fee7cdb0ce0b 14afbbf0] (A) Tool for re-ordering all the questions in a quiz at once.&lt;br /&gt;
* 2006-02-24 [https://github.com/moodle/moodle/commit/516cf3eb59ae523f7997616502603793f38fae9a 516cf3eb] (T) &#039;&#039;&#039;Question bank code and question types moved from mod/quiz -&amp;gt; question.&#039;&#039;&#039;&lt;br /&gt;
* 2006-03-01 [https://github.com/moodle/moodle/commit/03c8c27ee00d4c5d9ab347d4dfdbf5d7a11191fa 03c8c27e] (PA) Option to show students with/without attempts in the quiz reports.&lt;br /&gt;
* 2006-03-08 [https://github.com/moodle/moodle/commit/d1c974813032984dd852ea3f4586f04d8eecb817 d1c97481] (A) Blackboard 6 question import format.&lt;br /&gt;
* 2006-03-22 [https://github.com/moodle/moodle/commit/ead293420d0baf8af94309fa0e8b0518d8f68711 ead29342] (T) Question types now a proper sort of plugin.&lt;br /&gt;
* 2006-03-24 [https://github.com/moodle/moodle/commit/4eda4eecbd1b7fd7dc64a95ed34d6e9ad97a4a48 4eda4eec] (T) &#039;Missing&#039; qtype added.&lt;br /&gt;
* 2006-03-26 [https://github.com/moodle/moodle/commit/5f9ef821df8f4bd984e11cf41931802f72efc885 5f9ef821] (AT) Responses report moved from core to contrib (undoing 80ed3fe6b).&lt;br /&gt;
* 2006-03-27 [https://github.com/moodle/moodle/commit/31e95855b85d551f249a2d7bed0d5479e159d3b3 31e95855] (T) Quiz report plugin structure improved.&lt;br /&gt;
* 2006-04-07 [https://github.com/moodle/moodle/commit/b6e907a245ddbe17a69125725717625e3ede3b72 b6e907a2] (PA) Manual grading made applicable to all qtypes, not just Essay.&lt;br /&gt;
* July 2006 &#039;&#039;&#039;Tim Hunt takes over as quiz maintainer&#039;&#039;&#039;&lt;br /&gt;
== Moodle 1.6 release 20 June 2006 ==&lt;br /&gt;
* 2006-07-04 [https://github.com/moodle/moodle/commit/a58ffe3fe2526e04f21c1d95786cd027a82f4371 a58ffe3f] (P) Allow matching questions to have extra distractors.&lt;br /&gt;
* 2006-07-12 [https://github.com/moodle/moodle/commit/1fe641f7b43b63cb5289b0ffa8b6c4e1f2ee61ff 1fe641f7] (P) Support for matching common wrong, or partially correct, responses to numeric questions, not just one right answer.&lt;br /&gt;
* 2006-08-08 [https://github.com/moodle/moodle/commit/bbbf2d401564ade2548592853586005a7bcde900 bbbf2d40] (AT) Roles and permissions system added to Moodle.&lt;br /&gt;
* 2006-08-11 [https://github.com/moodle/moodle/commit/1b8a7434e28f5508a3f7ae116192a3ac7234543d 1b8a7434] (P) &#039;&#039;&#039;General feedback added to all types. (It was initially called something else, then renamed in a4514d91d)&#039;&#039;&#039;.&lt;br /&gt;
* 2006-08-11 [https://github.com/moodle/moodle/commit/613f306d1d68aaf826d8b6ccf26cced0dc2fa928 613f306d] (T) Moodle database code changed to use XMLDB.&lt;br /&gt;
* 2006-08-22 [https://github.com/moodle/moodle/commit/212b7b8cd9af682fc32c76d1bfd6172ead62a27c 212b7b8c] (P) Quiz overall feedback added.&lt;br /&gt;
* 2006-08-24 [https://github.com/moodle/moodle/commit/307f045f0718da95d00faf38a630d4f3169f12e5 307f045f] (P) &#039;&#039;&#039;Overall feedback options added to multiple-choice questions&#039;&#039;&#039;.&lt;br /&gt;
== Moodle 1.7 release 7 November 2006 ==&lt;br /&gt;
* 2006-11-29 [https://github.com/moodle/moodle/commit/ee259d0cd1f05219547de294e60656d303462ac3 ee259d0c] (A) Support for including category information in GIFT and Moodle XML export files.&lt;br /&gt;
* 2006-12-19 [https://github.com/moodle/moodle/commit/a23f0aaf9570886bf5803459f0018dd68e835328 a23f0aaf] (T) Moodle converted to use formslib.php, rather than hand-coded forms.&lt;br /&gt;
* 2006-12-21 [https://github.com/moodle/moodle/commit/77c7f0f549e24c7a1d180967379c64af77515105 77c7f0f5] (A) Open Office format support added to quiz report downloads.&lt;br /&gt;
* 2007-02-20 [https://github.com/moodle/moodle/commit/624cbc9c26a5f4b56083b2c1321891f0af62bc82 624cbc9c] (A) Option to display the question text when browsing the question bank.&lt;br /&gt;
== Moodle 1.8 release 30 March 2007 ==&lt;br /&gt;
* 2007-04-13 [https://github.com/moodle/moodle/commit/3e0647ffaf2c81224b6f7d2ed24d5188888fcfb5 3e0647ff] (P) Options for how multiple choice choices are numbered.&lt;br /&gt;
* 2007-06-15 [https://github.com/moodle/moodle/commit/294e63eadd0c49ed829c055111c15e08ab56d789 294e63ea] (PT) First attempt to allow students to upload files during attempts. (Gets broken in the changes to 2.0, and was never completely working, e.g. backup and restore never worked.)&lt;br /&gt;
* 2007-06-19 [https://github.com/moodle/moodle/commit/7a6f4066cee03e8db752a66d667d91b9b28f9ea5 7a6f4066] (A) Course reset implemented for quizzes.&lt;br /&gt;
* 2007-06-26 [https://github.com/moodle/moodle/commit/ac48e43a896d1a6315c38e3aac5a3c5f0d327cb8 ac48e43a] (A) Email notification/confirmation of submitted quiz attempts.&lt;br /&gt;
* 2007-07-21 [https://github.com/moodle/moodle/commit/e8825e724bf6f916752a067c9be983295729ed4f e8825e72] (A) Support for essay and description qtypes added to GIFT.&lt;br /&gt;
* 2007-07-22 [https://github.com/moodle/moodle/commit/42ff9ce68b932f844a326c4b8197cdcbd74ea002 42ff9ce6] (A) &#039;&#039;&#039;Support for the new gradebook added to the quiz.&#039;&#039;&#039;&lt;br /&gt;
* 2007-07-30 [https://github.com/moodle/moodle/commit/00719c02d66fca180334d22b4e0cf781a8ef4c27 00719c02] (PA) Separate review option for quiz overall feedback.&lt;br /&gt;
* 2007-08-08 [https://github.com/moodle/moodle/commit/a41e328736f4cdd95c62277346832c19da93115a a41e3287] (T) Allow third-party qtype plugins to participate in GIFT and Moodle XML import export.&lt;br /&gt;
* 2007-08-09 [https://github.com/moodle/moodle/commit/271e6decdac9d9445c047a7d90cc98b7912cf1b6 271e6dec] (AT) &#039;&#039;&#039;New question bank&#039;&#039;&#039; by Jamie Pratt. Cleaner code. Many problems with sharing questions between courses fixed. Finer-grained capabilities.&lt;br /&gt;
* 2007-08-27 [https://github.com/moodle/moodle/commit/5ada3c8e3aa858d7e11ccf5e92cbad78f813d691 5ada3c8e] (A) Support for Groupings added to the quiz.&lt;br /&gt;
* 2007-10-11 [https://github.com/moodle/moodle/commit/14e66f3bebac8c587d08e14f92d6f8332c26161d 14e66f3b] (A) Overridden grades from the gradebook shown in the quiz UI.&lt;br /&gt;
== Moodle 1.9 release 3 March 2008 ==&lt;br /&gt;
* 2008-03-06 [https://github.com/moodle/moodle/commit/05866d85d4155a632bb988b8c5a16252df69b7a3 05866d85] (T) Code for all the different different rules about whether a student can attempt the quiz now moved into separate classes. Not yet a proper plugin type.&lt;br /&gt;
* 2008-05-07 [https://github.com/moodle/moodle/commit/8b87ab000003e7cc830fb959b72d80de79b84cd2 8b87ab00] (PA) Summary graph added to the quiz overview report. (This is the start of a set of &#039;&#039;&#039;major improvements to the quiz reports for Moodle 2.0&#039;&#039;&#039;, done by Jamie Pratt for the OU.)&lt;br /&gt;
* 2008-05-15 [https://github.com/moodle/moodle/commit/aad5b0fca94bbc278f754634134a3839267ceb36 aad5b0fc] (PA) Group and course averages added to the overview report.&lt;br /&gt;
* 2008-05-15 [https://github.com/moodle/moodle/commit/f33e1ed4ae4948e337e5fee61adc3580f81dfa80 f33e1ed4] (T) Moodle database connection changed to use the new global $DB.&lt;br /&gt;
* 2008-05-23 [https://github.com/moodle/moodle/commit/a59eb2b6a8e569ea5777f6cfa1d9aab9669bb79f a59eb2b6] (A) Groups support added to the Manual grading report.&lt;br /&gt;
* 2008-06-10 [https://github.com/moodle/moodle/commit/0c1c764e8257d6db589ed0d89371d4b49b8972d7 0c1c764e] (PA) &#039;&#039;&#039;Quiz statistics report added.&#039;&#039;&#039;&lt;br /&gt;
* 2008-06-27 [https://github.com/moodle/moodle/commit/36e413e38c5d04c923f62e2525b2d59767babfc8 36e413e3] (P) &#039;&#039;&#039;Quiz attempt UI greatly improved, with new navigation panel and summary page.&#039;&#039;&#039;&lt;br /&gt;
* 2008-07-11 [https://github.com/moodle/moodle/commit/98f38217bb6de4ffa78f79e7371b5d8f53aaf98a 98f38217] (T) Regrading UI merged into overview report. Dry run of regrades made possible, before doing it for real.&lt;br /&gt;
* 2008-07-20 [https://github.com/moodle/moodle/commit/7f29a7dbe40d21dcbc5f0d21a399c2e6f7b3c98b 7f29a7db] (PA) &#039;&#039;&#039;Responses report moved back out of contrib, and in to standard Moodle.&#039;&#039;&#039;&lt;br /&gt;
* 2008-07-24 [https://github.com/moodle/moodle/commit/17f1782c1217ab5b83de6bd55a4e7a7adb0abe5a 17f1782c] (T) cron support added to quiz reports.&lt;br /&gt;
* 2008-08-15 [https://github.com/moodle/moodle/commit/f88fb62c40249c74475de64eedeae2c3a549441c f88fb62c] (AT) rounding of quiz and question grades before they are displayed is made consistent everywhere.&lt;br /&gt;
* 2008-08-15 [https://github.com/moodle/moodle/commit/f9a2cf86a9c7a77bd0be1c17eca9260f0833f45e f9a2cf86] (T) Quiz grades are now consistently stored in the database as NUMEBER(10,5), and question grades as NUMBER(12,7).&lt;br /&gt;
* 2008-08-29 [https://github.com/moodle/moodle/commit/62e76c6766368de71e6a7f7cd9a7fc17be942265 62e76c67] (P) Let students flag questions during quiz attempts.&lt;br /&gt;
* 2008-09-09 [https://github.com/moodle/moodle/commit/8df9635465bd09d9624407289f11680bbf2c5f0e 8df96354] (AT) Admin page for managing the installed question types.&lt;br /&gt;
* 2008-09-11 [https://github.com/moodle/moodle/commit/c308138f8994c55f17858f852be40c8d69ae9733 c308138f] (AT) Item analysis report removed.&lt;br /&gt;
* 2008-11-20 [https://github.com/moodle/moodle/commit/fa583f5f6eb3b4c9f624e77df0cfb9f9e705e6c3 fa583f5f] (T) &#039;&#039;&#039;New editing UI for quizzes&#039;&#039;&#039;. Finnish Summer of Code project by Olli Savolainen.&lt;br /&gt;
* 2008-11-28 [https://github.com/moodle/moodle/commit/f24493ec9b0e46c30c5343283dd10179a0fd892e f24493ec] (P) Allow essay questions to be selected by random questions.&lt;br /&gt;
* 2009-01-07 [https://github.com/moodle/moodle/commit/a733c4b98b527ef66ea48eb4f0d11bc59ae89a56 a733c4b9] (A) Add an option to display the user&#039;s photo and name on the quiz attempt page.&lt;br /&gt;
* 2009-01-14 [https://github.com/moodle/moodle/commit/96c7d771df88fd0aa2514ba898c89f81053c6e93 96c7d771] (AT) mod/quiz:reviewmyattempts capability separated from mod/quiz:attempt.&lt;br /&gt;
* 2009-01-20 [https://github.com/moodle/moodle/commit/46795afcbdd7fe43de03afb6b2b87eb5c21ea691 46795afc] (T) refactoring of the code that displays the question bank, to eliminate duplication between the quiz editing and question bank display code.&lt;br /&gt;
* 2009-02-25 [https://github.com/moodle/moodle/commit/cd120b2344d0c9d8f8bfa20466e3abb9fe0e4c8a cd120b23] (AT) New YUI pop-up for selecting the question type when adding a new question, replacing the old select menu.&lt;br /&gt;
* 2009-05-06 [https://github.com/moodle/moodle/commit/6bf44482c651faa946fb2cf5a34475456258c708 6bf44482] (T) Moodle 2.0 $PAGE and $OUTPUT changes applied to the quiz.&lt;br /&gt;
* 2009-05-29 [https://github.com/moodle/moodle/commit/83a15d025cb163509dcff124ed914058c826966f 83a15d02] (P) &#039;&#039;&#039;New question type &#039;Simple calculated&#039; by Pierre Pichet.&#039;&#039;&#039;&lt;br /&gt;
* 2009-06-05 [https://github.com/moodle/moodle/commit/aa9c6ecf02b25e967766ad09a23b668ebff83a7e aa9c6ecf] (A) Highlight the last question you edited in the question bank like. A small, but very useful change.&lt;br /&gt;
* 2009-06-12 [https://github.com/moodle/moodle/commit/cf6155226cba2e4e62e9e1cb44dad88afacc39b4 cf615522] (T) require_js replaced by $PAGE-&amp;gt;requires everywhere.&lt;br /&gt;
* 2009-06-19 [https://github.com/moodle/moodle/commit/17da2e6f28d3477eb4ccfe5ac94c9cebb8456c8e 17da2e6f] (T) The concept of &#039;subplugins&#039; is born. Quiz report, within the quiz, are one of the early examples. (Regrettably, the prefix quiz_, not quizreport_ is chosen.)&lt;br /&gt;
* 2009-09-30 [https://github.com/moodle/moodle/commit/7d4dfc481e65a2548d32723a4726ddc833cdd1f5 7d4dfc48] (A) Integration with &#039;Safe Exam Browser&#039; added.&lt;br /&gt;
* 2010-02-07 [https://github.com/moodle/moodle/commit/2d279432b0c64c8dda20758641f529f87f14ea1f 2d279432] (P) &#039;&#039;&#039;New question type &#039;Calculated multiple choice&#039; by Pierre Pichet.&#039;&#039;&#039;&lt;br /&gt;
* 2010-03-08 [https://github.com/moodle/moodle/commit/990650f94cbe46344ced45c5fe69ebc273da1d00 990650f9] (A) Different open and close dates, etc., for different groups or individuals. Implemented by Matt Petro of the University of Wisconsin - Madison Engineering School.&lt;br /&gt;
* 2010-05-20 [https://github.com/moodle/moodle/commit/9df209c1226b1859a0c3d534f026306d2dfc13f9 9df209c1] (T) Moodle events now triggered for starting and finishing quiz attempts.&lt;br /&gt;
* 2010-05-21 [https://github.com/moodle/moodle/commit/56ed242b51909666b9e757f1a94fb2c105928b5e 56ed242b] (PA) New quiz option &#039;Show blocks during quiz attempts&#039; by Sam Hemelryk.&lt;br /&gt;
* 2010-08-06 [https://github.com/moodle/moodle/commit/d39ba35c34d4272d5092b5f80bacd2be6e7fc50f d39ba35c] (A) Make it clearer in the quiz grades report when essay questions need to be graded.&lt;br /&gt;
* 2010-08-10 [https://github.com/moodle/moodle/commit/fe6ce2348945f267b3d90ed74442a221c0a9808d fe6ce234] (T) Quiz and question bank converted to the Moodle 2.0 Files API.&lt;br /&gt;
* 2010-10-24 [https://github.com/moodle/moodle/commit/41941110fdecb6313637a6ad77c6e6e26aa79833 41941110] (T) Quiz and question bank converted to the Moodle 2.0 Backup and restore system.&lt;br /&gt;
* 2010-10-30 [https://github.com/moodle/moodle/commit/92b360057504ecfb2b3f8174d06a32d7564314bf 92b36005] (P) Grading of units in numerical and calculated questions changed to work the way people would expect.&lt;br /&gt;
== Moodle 2.0 release 24 November 2010 ==&lt;br /&gt;
* 2010-12-20 [https://github.com/moodle/moodle/commit/d1b7e03d5d507243d9f8adb9465161f3702f4a12 d1b7e03d] (PT) &#039;&#039;&#039;New moodle question engine, a major development by Tim Hunt, introduces the concept of Question behaviour, to handle the difference between adaptive, deferred feedback, and manually graded questions&#039;&#039;&#039;.&lt;br /&gt;
* 2010-12-20 [https://github.com/moodle/moodle/commit/d1b7e03d5d507243d9f8adb9465161f3702f4a12 d1b7e03d] (P) &#039;&#039;&#039;This also allows new behaviours like Certainty based marking, Immediate feedback, and Interactive with multiple tries.&#039;&#039;&#039;&lt;br /&gt;
* 2010-12-20 [https://github.com/moodle/moodle/commit/d1b7e03d5d507243d9f8adb9465161f3702f4a12 d1b7e03d] (T) Also in this change, many more unit tests for questions, and all questions now use renderers for output.&lt;br /&gt;
* End Dec 2010 Moodle development moves from CVS to git.&lt;br /&gt;
* 2011-02-11 [https://github.com/moodle/moodle/commit/fd214b596d63d2f7f8aff0e1d6550978f8ba60c7 fd214b59] (PT) Code to preserve the scroll position when submitting a question in the quiz, or editing the quiz.&lt;br /&gt;
* 2011-03-10 [https://github.com/moodle/moodle/commit/894e8b4e93d8f3b4036ab738e2396a5eb0707c0a 894e8b4e] (P) New essay features: Use the HTML editor or not; control the size of the response area; allow attachments; and information to be shown to the person grading.&lt;br /&gt;
* 2011-03-16 [https://github.com/moodle/moodle/commit/217f9a618ccc554a3650c2f9fbb9595215fd82fb 217f9a61] (T) As part of this, handling files are part of question responses now works properly, finally doing what 294e63ead tried.&lt;br /&gt;
* 2011-04-26 [https://github.com/moodle/moodle/commit/606e07d574c649cedea92ff5bf3946f19a93e747 606e07d5] (T) Student-visible parts of the quiz converted to use a renderer, mostly thanks to Dean Lennard.&lt;br /&gt;
* 2011-05-25 [https://github.com/moodle/moodle/commit/1da821bbde1348a67326ff7f676dff49182d4247 1da821bb] (PT) Introduce the concept of &#039;question variants&#039; as a first-class concept in the question engine.&lt;br /&gt;
* 2011-06-01 [https://github.com/moodle/moodle/commit/4b2da7cee08bea3c00338c5807f874a370c1c065 4b2da7ce] (A) Ability to restore 1.9 backups added to the quiz and question bank.&lt;br /&gt;
* 2011-06-15 [https://github.com/moodle/moodle/commit/fde4560daeb9597142d9788f4e9051d36a9f67c2 fde4560d] (A) Admin page for managing the installed question behaviours.&lt;br /&gt;
* 2011-06-16 [https://github.com/moodle/moodle/commit/2a6c5c52ee258b0097895c889cef949d8ab5ce72 2a6c5c52] (PT) Ability to have images in multiple choice answers restored. (It was broken since 2.0.)&lt;br /&gt;
== Moodle 2.1 release 1 July 2011 ==&lt;br /&gt;
* 2011-10-03 [https://github.com/moodle/moodle/commit/a28a5d74af1db4eeb12e194c0c9db111522458d2 a28a5d74] (T) Make the &#039;&#039;&#039;Quiz access rules&#039;&#039;&#039; (from 05866d85d) become proper sub-plugings of the quiz.&lt;br /&gt;
* 2011-10-28 [https://github.com/moodle/moodle/commit/2dc54611f2c23e7b1686b26abc8f4fbda9c6531b 2dc54611] (AT) Unmaintained qti_two export format removed.&lt;br /&gt;
* 2011-11-02 [https://github.com/moodle/moodle/commit/75a31c9039b1f06f6d1dca7b07282117de83aa41 75a31c90] (T) Plugin API made more standard in areas like cron, languages strings, for the question-related plugins.&lt;br /&gt;
== Moodle 2.2 release 5 December 2011 ==&lt;br /&gt;
* 2011-12-07 [https://github.com/moodle/moodle/commit/c2f5e2ab816e4bc067085b0f9c59b01739d945a9 c2f5e2ab] (T) Plugin API made more standard in areas like cron, languages strings, for the quiz-related plugins.&lt;br /&gt;
* 2012-01-08 [https://github.com/moodle/moodle/commit/5db829494030a73d15dabdc8be8685497888b138 5db82949] (P) Quiz attempt tracks the page the student is currently on, and takes them back there if they leave the attempt and come back later. (By Charles Fulton)&lt;br /&gt;
* 2012-03-07 [https://github.com/moodle/moodle/commit/88eca3cd2666a7ea451ecc8862867e68563d8bb7 88eca3cd] (A) New mod:quiz/addinstance lets you control which teachers can add a quiz to a course. (The same sort of capability is added to each activity.)&lt;br /&gt;
* 2012-01-20 [https://github.com/moodle/moodle/commit/33c8d37b6f2fa380a50ef97d60103ed9a1f9c376 33c8d37b] (P) An option to force students to answer questions strictly in order, rather than letting them navigate around the quiz as they please. (By Charles Fulton)&lt;br /&gt;
* ... hopefully much more yet to come.&lt;br /&gt;
&#039;&#039;Last updated 11th April 2012. This summary currently contains 148 items, whereas the full git log command at the top of this page lists 4777 commits.&#039;&#039;&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Question API]]&lt;br /&gt;
[[Category:Questions]]&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=61656</id>
		<title>Javascript Modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=61656"/>
		<updated>2022-01-27T15:18:07Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: Update docs to match this month&amp;#039;s flavour of the month for JS&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
= Javascript Modules =&lt;br /&gt;
== What is a Javascript module and why do I care? ==&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;
== Why should I package my code as a module? ==&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;
= How do I write a Javascript module in Moodle? =&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;
Note that, for Moodle 3.10 and up (see MDLSITE-6130), any new Javascript module &#039;&#039;&#039;must&#039;&#039;&#039; be written on ES6.&lt;br /&gt;
== Install NVM and Node ==&lt;br /&gt;
The recommended way of installing NodeJS is via the [https://github.com/nvm-sh/nvm Node Version Manager], or NVM. NVM allows you to have several different versions of NodeJS installed at and in-use at any once on your computer. Supported versions of Moodle all use version {{NodeJSExactVersion}} of NodeJS.&lt;br /&gt;
&lt;br /&gt;
https://github.com/nvm-sh/nvm#installing-and-updating&lt;br /&gt;
&lt;br /&gt;
Confirm it is working:&lt;br /&gt;
 $ nvm --version&lt;br /&gt;
 0.35.3&lt;br /&gt;
After you have installed &#039;&#039;&#039;nvm&#039;&#039;&#039;, you should install the correct version of NodeJS by running the following commands from your Moodle directory:&lt;br /&gt;
 nvm install&lt;br /&gt;
 nvm use&lt;br /&gt;
If your primary use of NodeJS is for Moodle then we recommend that you set NodeJS version {{NodeJSExactVersion}} as your default version. You can do this by running:&lt;br /&gt;
 nvm alias default {{NodeJSExactVersion}}&lt;br /&gt;
== Install grunt ==&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;
Once this is done, you can run the the following commands from your Moodle directory:&lt;br /&gt;
 npm install&lt;br /&gt;
&#039;&#039;&#039;This may mention vulnerabilities, that&#039;s fine and doesn&#039;t apply.&#039;&#039;&#039;&lt;br /&gt;
 npm install -g grunt-cli&lt;br /&gt;
== Development mode (Moodle v2.9 to v3.7)  ==&lt;br /&gt;
To avoid having to constantly run grunt, make sure you set the following in your config.php&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
== Development mode (Moodle v3.8 and above)  ==&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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
== Development mode (Moodle v3.10 and above)  ==&lt;br /&gt;
All the above for Moodle 3.8 and up applies, plus (see MDLSITE-6130), any new Javascript module must be written on ES6.&lt;br /&gt;
== Running grunt ==&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;
 /usr/bin/env: node: No such file or directory&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;
 sudo ln -fs /usr/bin/nodejs /usr/local/bin/node&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;
== ES6 Modules (Moodle v3.8 and above) ==&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;
Note that, for Moodle 3.10 and up (see MDLSITE-6130), any new Javascript module must be written on ES6.&lt;br /&gt;
&lt;br /&gt;
The call from a PHP file takes the same format&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;myplugin/myfile&#039;,&#039;init&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And a minimal ES6 file will work with &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
export const init = () =&amp;gt; {&lt;br /&gt;
    window.console.log(&#039;we have been started&#039;);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
=== 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;
== Minimum (getting started) module for plugins ==&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;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&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;
export const init = () =&amp;gt; {&lt;br /&gt;
    document.addEventListener(&#039;change&#039;, e =&amp;gt; {&lt;br /&gt;
        const someNode = e.target.closest(&#039;.someclass&#039;);&lt;br /&gt;
        if (someNode) {&lt;br /&gt;
            alert(&#039;It changed!&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For older versions of Moodle prior to 3.8, you will need to use the legacy ES5 format instead:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define([], function() {&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
            document.addEventListener(&#039;change&#039;, function(e) {&lt;br /&gt;
                var someNode = e.target.closest(&#039;.someclass&#039;);&lt;br /&gt;
                if (someNode) {&lt;br /&gt;
                    alert(&#039;It changed!&#039;);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import jQuery from &#039;jquery&#039;; // We recommend that you strongly consider whether you really need jQuery. It is typically not needed in modern code.&lt;br /&gt;
import * as Str from &#039;core/str&#039;;&lt;br /&gt;
import Ajax from &#039;core/ajax&#039;;&lt;br /&gt;
&lt;br /&gt;
export const init = config =&amp;gt; {&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&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;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&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;/syntaxhighlight&amp;gt;&lt;br /&gt;
...calls&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
export const init = (first, last) {&lt;br /&gt;
    window.console.log(`The first name was &#039;${first}&#039; and the last name was &#039;${last}&#039;`);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A more comprehensive explanation follows...&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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// Standard license block omitted.&lt;br /&gt;
/*&lt;br /&gt;
 * @module     block_overview/helloworld&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;
import * as Str from &#039;core/str&#039;;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Reveal all of the hidden notes.&lt;br /&gt;
 */&lt;br /&gt;
const showAllNotes = () =&amp;gt; {&lt;br /&gt;
    document.querySelectorAll(&#039;.note.hidden&#039;).map(note =&amp;gt; note.removeClass(&#039;hidden&#039;));&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Hide all of the notes.&lt;br /&gt;
 */&lt;br /&gt;
const hideAllNotes = () =&amp;gt; document.querySelectorAll(&#039;.note&#039;).map(note =&amp;gt; note.addClass(&#039;hidden&#039;));&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Return a personalised, formal, greeting.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   {String} name The name of the person to greet&lt;br /&gt;
 * @returns {Promise}&lt;br /&gt;
 */&lt;br /&gt;
export const formal = name =&amp;gt; Str.get_string(&#039;formallygreet&#039;, &#039;block_overview&#039;, name);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Return a personalised, informal, greeting.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   {String} name The name of the person to greet&lt;br /&gt;
 * @returns {Promise}&lt;br /&gt;
 */&lt;br /&gt;
export const informal = name =&amp;gt; {&lt;br /&gt;
    return Str.get_string(&#039;informallygreet&#039;, &#039;block_overview&#039;, name);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
It&#039;s important to note tha tonly functions which are exported will be callable from outside the module. These are part of the public API.&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? In a limited number of situations you may not know the modules that you need until you call them. You can make use of dynamic imports to import them when you know what they are. Note: This is not the recommended approach in most cases.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
export const showTheThing = thingToShow =&amp;gt; {&lt;br /&gt;
    // Load the module for this thing.&lt;br /&gt;
    import(`local_examples/local/types/type_${thingToShow.modname}`)&lt;br /&gt;
    .then(thingModule =&amp;gt; {&lt;br /&gt;
        window.console.log(`The ${thingToShow.modname} is now available under thingModule within this scope`);&lt;br /&gt;
&lt;br /&gt;
        return thingModule;&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// DO NOT DO THIS - IT DOES NOT WORK IN MOODLE&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;/syntaxhighlight&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;
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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;theme_mytheme/countdowntimer&#039;, &#039;init&#039;, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Javascript module:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// /theme/mytheme/amd/src/countdowntimer.js&lt;br /&gt;
import Countdown from &#039;theme_mytheme/jquery.countdown&#039;);&lt;br /&gt;
import $ from &#039;jquery&#039;;&lt;br /&gt;
&lt;br /&gt;
export const init = params =&amp;gt; {&lt;br /&gt;
    $(&#039;#clock&#039;).countdown(params.targetItem, event =&amp;gt; {&lt;br /&gt;
             $(event.target).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
2. Call your Javascript module from your template:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
// /theme/mytheme/templates/countdowntimer.mustache&lt;br /&gt;
&amp;lt;span id=&amp;quot;theme_mytheme-clock-{{uniqid}}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require([&#039;theme_mytheme/countdowntimer&#039;], function(myModule) {&lt;br /&gt;
    myModule.init({&lt;br /&gt;
        targetItem: &#039;theme_mytheme-clock-{{uniqid}}&#039;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note: If you feel that you need to work around MDL-62468, then you should probably be putting the data into the DOM in your template via data Attributes, or loading it via a Web Service.&lt;br /&gt;
&lt;br /&gt;
Another example of adding a 3rd-party library to a Moodle plugin (by Ruslan Kabalin)&lt;br /&gt;
&lt;br /&gt;
If you want use https://github.com/R-TEK/colr_pickr in your plugin but this module isn&#039;t RequireJS-compatible.&lt;br /&gt;
&lt;br /&gt;
You need to configure requirejs in your plugin to use third-party library:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$config = [&#039;paths&#039; =&amp;gt; [&#039;colorpicker&#039; =&amp;gt; &#039;CDN or local path...&#039;]];&lt;br /&gt;
$requirejs = &#039;require.config(&#039; . json_encode($config) . &#039;)&#039;;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_amd_inline($requirejs);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then in your JS module in the plugin:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define([colorpicker], function(ColorPicker) {&lt;br /&gt;
    const button = document.getElementById(&#039;my_picker&#039;);&lt;br /&gt;
    let picker = new ColorPicker(button, &#039;#ff0000&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And another example of using https://github.com/itsjavi/bootstrap-colorpicker (that has a [[jQuery]] dependency) with native ES6 JS:&lt;br /&gt;
 NOTE: It is advised to move away from [[jQuery]] related plugins, as Moodle core is moving away from jQuery.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
import ColourPicker from &#039;local_myplugin/bootstrap-colorpicker&#039;;&lt;br /&gt;
&lt;br /&gt;
const myElement = document.querySelector(&#039;.myelement&#039;);&lt;br /&gt;
const picker = new ColourPicker(myElement);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd($modulename, $functionname, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;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;
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;
== Troubleshooting ==&lt;br /&gt;
=== npm-shrinkwrap.json sha1 / sha512 changes ===&lt;br /&gt;
If grunt changes all the hashes in npm-shrinkwrap.json then try this:&lt;br /&gt;
 rm -rf node_modules &amp;amp;&amp;amp; npm i&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;
== 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;
*MDL-67327 JavaScript issues when not following the official documentation, since Moodle 3.8&lt;br /&gt;
*[https://moodle.org/mod/forum/discuss.php?d=405829 Error from grunt watch - Moodle 3.9] Forum Discussion&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_meeting_October_2021&amp;diff=61616</id>
		<title>Developer meeting October 2021</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_meeting_October_2021&amp;diff=61616"/>
		<updated>2022-01-13T14:40:03Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Developer meetings]] &amp;gt; October 2021 meeting &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Date&lt;br /&gt;
| Tuesday 12 October 2021 at 07:00 UTC&lt;br /&gt;
|-&lt;br /&gt;
| Meeting recording&lt;br /&gt;
| [https://moodle.org/mod/bigbluebuttonbn/view.php?id=8596 Developer meetings BBB on moodle.org]&lt;br /&gt;
|-&lt;br /&gt;
| Discussion&lt;br /&gt;
| [https://moodle.org/mod/forum/discuss.php?d=426502 Developer meeting Tuesday 12 October 2021]&lt;br /&gt;
|}&lt;br /&gt;
== Agenda ==&lt;br /&gt;
# Latest #moodledev news - [https://moodle.org/user/view.php?id=2356736&amp;amp;course=5 Sander Bangma], Moodle HQ - [[:File:Community Dev Meeting - LMS Update - Oct 2021.pdf|slides PDF]] - &#039;&#039;starts at the biginning of the recording&#039;&#039;&lt;br /&gt;
# Question bank improvements in Moodle 4.0 - [https://moodle.org/user/view.php?id=1914213&amp;amp;course=5 Matt Porritt], Catalyst AU - [[:File:qbank preso 20211012.pdf|slides PDF]] - &#039;&#039;starts at about 32:00 in the recording. Demo of new features from 34:00 to 41:30.&#039;&#039;&lt;br /&gt;
----&lt;br /&gt;
If there is any topic that you would like to present or discuss at a developer meeting, please contact [https://moodle.org/user/profile.php?id=1601 David Mudrák].&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_meeting_October_2021&amp;diff=61615</id>
		<title>Developer meeting October 2021</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_meeting_October_2021&amp;diff=61615"/>
		<updated>2022-01-13T14:28:56Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: Add time info&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Developer meetings]] &amp;gt; October 2021 meeting &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Date&lt;br /&gt;
| Tuesday 12 October 2021 at 07:00 UTC&lt;br /&gt;
|-&lt;br /&gt;
| Meeting recording&lt;br /&gt;
| [https://moodle.org/mod/bigbluebuttonbn/view.php?id=8596 Developer meetings BBB on moodle.org]&lt;br /&gt;
|-&lt;br /&gt;
| Discussion&lt;br /&gt;
| [https://moodle.org/mod/forum/discuss.php?d=426502 Developer meeting Tuesday 12 October 2021]&lt;br /&gt;
|}&lt;br /&gt;
== Agenda ==&lt;br /&gt;
# Latest #moodledev news - [https://moodle.org/user/view.php?id=2356736&amp;amp;course=5 Sander Bangma], Moodle HQ - [[:File:Community Dev Meeting - LMS Update - Oct 2021.pdf|slides PDF]] - &#039;&#039;starts at the biginning of the recording&#039;&#039;&lt;br /&gt;
# Question bank improvements in Moodle 4.0 - [https://moodle.org/user/view.php?id=1914213&amp;amp;course=5 Matt Porritt], Catalyst AU - [[:File:qbank preso 20211012.pdf|slides PDF]] - &#039;&#039;starts at about 32:00 in the recording&#039;&#039;&lt;br /&gt;
----&lt;br /&gt;
If there is any topic that you would like to present or discuss at a developer meeting, please contact [https://moodle.org/user/profile.php?id=1601 David Mudrák].&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tracker_issue_labels&amp;diff=61433</id>
		<title>Tracker issue labels</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tracker_issue_labels&amp;diff=61433"/>
		<updated>2021-10-12T08:14:14Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Moodle Tracker allows issues to be &amp;quot;labelled&amp;quot; with tags. This page lists common labels that we use to flag aspects about our MDL issues (bugs and feature requests about Moodle itself).&lt;br /&gt;
&lt;br /&gt;
Note: Labels can only be added by a user with permission to edit an issue i.e. the issue reporter, members of the developers group, or members of certain other groups.&lt;br /&gt;
==Labels==&lt;br /&gt;
;triaged:This is set after a bug has been [[Bug triage|triaged]] by component lead or HQ developer. It indicates that the issue has been confirmed, with basic fields like &amp;quot;Priority&amp;quot; checked, and is now ready for a developer to look at.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20in%20(triaging_in_progress) triaging_in_progress]:  Used to flag issues that are being triaged (sometimes an ongoing process for days or weeks). When the issue has been triaged the &#039;&#039;triaging_in_progress&#039;&#039; label should be removed and a &#039;&#039;triaged&#039;&#039; label should be added or when the issue is closed.&lt;br /&gt;
;mdlqa:Used to flag that an issue is a direct result of a Moodle QA test, conducted just before major releases. The bug should also be LINKED to the original MDLQA test, so that developers/integrators can reset the original MDLQA test (for re-testing) when the MDL issue is fixed. Once all the related MDLQA tests are passing the label can be deleted.&lt;br /&gt;
;mdlqa_conversion: Used to flag MDL issues that are converting MDLQA issues to behat features. The bug should also be LINKED to the MDLQA test being converted. Useful to know what&#039;s going and exclude some issues from manual QA. Once the MDL issue has been closed and the MDLQA has been moved to MDLQA-5249 the label can be deleted.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20unit_test_required unit_test_required]: Used to flag issues that should have their own unit tests.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20acceptance_test_required acceptance_test_required]: Used to flag issues that should be regularly tested using the behat framework (https://docs.moodle.org/dev/Acceptance_testing). Before a major release these issues will be reviewed and new feature files will be added.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20qa_test_required qa_test_required]:Used to flag issues that cannot be covered by automated tests. When adding the label, please also add a comment advising exactly what needs covering in the QA test e.g. steps 6-10 in testing instructions.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20qa_identified qa_identified]: Used to flag issues identified in QA testing which we were not able to fix before the release. Hopefully such issues can be worked on shortly after release, removing the label once the issue is fixed.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20docs_required docs_required]:  Used to flag issues that have created a need for documentation work, such as new pages, changes, or even being added to upcoming release notes. Docs people will look for these issues periodically when working on documentation, removing the label once documentation has been written. For new features in the upcoming version of Moodle, please add documentation to the dev docs (adding a link to it from the tracker issue) or in a comment in the issue, then when the new version wiki is set up (3 weeks prior to release), the info can be transferred.&lt;br /&gt;
;dev_docs_required ([https://tracker.moodle.org/issues/?jql=labels%20in%20(dev_docs_required) all] | [https://tracker.moodle.org/issues/?jql=labels%20in%20(dev_docs_required)%20AND%20assignee%20%3D%20currentUser() yours]):  Used to flag issues that need to be noted in the dev docs. The responsibility of creating/updating Dev docs falls to the developer assigned to each relevant issue. When the issue is resolved, documentation should be created/updated, an appropriate URL should be added to the &#039;&#039;Documentation link&#039;&#039; field of the issue and the &#039;&#039;dev_docs_required&#039;&#039; label should be removed from the issue.&lt;br /&gt;
;integration_held: Used to flag issues already sent to integration that, for any cause, have been postponed to next cycles. Used only by integrators when there is some dependency or time-period causing one issue not being immediately integrable. Must be cleaned when the held is over.&lt;br /&gt;
;unhold_requested:Used to ask for an issue (having the &#039;&#039;integration_held &#039;&#039; label) to become unblocked, this flag must be coupled with a reasoned comment. Anybody can use it as far as repeated requests are avoided. Development managers will decide ASAP about giving the issue an integration opportunity or keeping it held. See [[Integration_Review#During_continuous_integration.2FFreeze.2FQA_period]].&lt;br /&gt;
;security_held: Used to flag security issues that have been reviewed by integrators already but held from integration repository. These issues must be cleared during point releases.&lt;br /&gt;
;security_benefit: Used to flag issues which help to improve the security of Moodle, but are not directly exploitable security bugs (and therefore do not have a security level assigned). For example, MDL-66775 and MDL-65443.&lt;br /&gt;
;partner:Moodle Partners apply this label to flag issues that are important to their clients. The Moodle HQ dev team takes this label into consideration when setting roadmap and bug fixing priorities.&lt;br /&gt;
;patch: This label indicates that a solution (patch) has been attached to the issue. However, if you can, it may be better to submit the issue for peer review, rather than using this label. This is useful to component leads and Moodle HQ when deciding what to work on next.&lt;br /&gt;
;cime: A developer can add the label &#039;cime&#039; to an issue to request that CiBot perform an [[Automated code review]].&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20performance%20AND%20project%20%3D%20MDL performance]: Used to flag any issues that developers think may affect Moodle&#039;s performance in some way (positively or negatively)&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20ui_change ui_change]: Used to identify issues that affect the interface presented to users. This label will usually be added together with the &#039;&#039;docs_required label&#039;&#039;, but the &#039;&#039;ui_change&#039;&#039; will remain permanently with the issue, while the &#039;&#039;docs_required&#039;&#039; label is removed after docs are created. This label is searched for during the preparation of release notes.&lt;br /&gt;
;api_change: Used to identify API changes. This label will usually be added together with the &#039;&#039;dev_docs_required label&#039;&#039;, but the &#039;&#039;api_change&#039;&#039; will remain permanently with the issue, while the &#039;&#039;dev_docs_required&#039;&#039; label is removed after docs are created. This label is searched for during the preparation of release notes.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20release_notes release_notes]: Used to identify all issues to be listed in the release notes (minor or major).&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20upgrade_notes upgrade_notes]: Issues that need to be mentioned in the user documentation [[:en:Upgrading|Upgrading]] under &#039;Possible issues that may affect you in Moodle 3.x&#039; (major versions).&lt;br /&gt;
;lost_functionality: Used to identify issues describing functionality which was available in an earlier version but which is no longer available in the latest version.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20%20test_server_required test_server_required]: Used to identify QA tests which can&#039;t be tested on the [http://qa.moodle.net QA testing site] such as upgrade testing.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20credentials_required credentials_required]: Used to identify QA tests which require the tester to enter credentials such as a client ID and secret for configuring OAuth 2.&lt;br /&gt;
;new: Used to identify new tests in the current QA cycle for volunteers from the community to use as a basis for exploratory testing.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20addon_candidate addon_candidate]: Used to identify suggestions for improvements/new features as possible candidates for add-on development. New and willing developers can be directed to these issues for projects.&lt;br /&gt;
;affects_mobileapp: Used to identify MDL issues that may affect the mobile app. It should be used when adding new features to functionalities supported by the app or when doing changes in existing ones. Examples are: MDL-372 and MDL-38158&lt;br /&gt;
;affects_moodlecloud: Used to identify MDL issues that may affect Moodlecloud&lt;br /&gt;
;affects_workplace: Used to identify MDL issues that may affect Moodle Workplace&lt;br /&gt;
;needs_user_stories: Used to identify issues that require further clarification of the requirements through adding user stories.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?filter=21824 ready_for_integration]: Used to identify issues that already have been peer-reviewed but the user lacks permissions (pull-requester) to send the issue to integration. Any pull-requester can, on peer-reviewer&#039;s behalf, proceed with the transition. The label is removed once the issue has been transitioned.&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Tracker]]&lt;br /&gt;
* [[Bug triage]]&lt;br /&gt;
[[Category:Tracker]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tracker_issue_labels&amp;diff=61432</id>
		<title>Tracker issue labels</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tracker_issue_labels&amp;diff=61432"/>
		<updated>2021-10-12T08:13:26Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: Add link to unhold_requested info&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Moodle Tracker allows issues to be &amp;quot;labelled&amp;quot; with tags. This page lists common labels that we use to flag aspects about our MDL issues (bugs and feature requests about Moodle itself).&lt;br /&gt;
&lt;br /&gt;
Note: Labels can only be added by a user with permission to edit an issue i.e. the issue reporter, members of the developers group, or members of certain other groups.&lt;br /&gt;
==Labels==&lt;br /&gt;
;triaged:This is set after a bug has been [[Bug triage|triaged]] by component lead or HQ developer. It indicates that the issue has been confirmed, with basic fields like &amp;quot;Priority&amp;quot; checked, and is now ready for a developer to look at.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20in%20(triaging_in_progress) triaging_in_progress]:  Used to flag issues that are being triaged (sometimes an ongoing process for days or weeks). When the issue has been triaged the &#039;&#039;triaging_in_progress&#039;&#039; label should be removed and a &#039;&#039;triaged&#039;&#039; label should be added or when the issue is closed.&lt;br /&gt;
;mdlqa:Used to flag that an issue is a direct result of a Moodle QA test, conducted just before major releases. The bug should also be LINKED to the original MDLQA test, so that developers/integrators can reset the original MDLQA test (for re-testing) when the MDL issue is fixed. Once all the related MDLQA tests are passing the label can be deleted.&lt;br /&gt;
;mdlqa_conversion: Used to flag MDL issues that are converting MDLQA issues to behat features. The bug should also be LINKED to the MDLQA test being converted. Useful to know what&#039;s going and exclude some issues from manual QA. Once the MDL issue has been closed and the MDLQA has been moved to MDLQA-5249 the label can be deleted.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20unit_test_required unit_test_required]: Used to flag issues that should have their own unit tests.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20acceptance_test_required acceptance_test_required]: Used to flag issues that should be regularly tested using the behat framework (https://docs.moodle.org/dev/Acceptance_testing). Before a major release these issues will be reviewed and new feature files will be added.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20qa_test_required qa_test_required]:Used to flag issues that cannot be covered by automated tests. When adding the label, please also add a comment advising exactly what needs covering in the QA test e.g. steps 6-10 in testing instructions.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20qa_identified qa_identified]: Used to flag issues identified in QA testing which we were not able to fix before the release. Hopefully such issues can be worked on shortly after release, removing the label once the issue is fixed.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20docs_required docs_required]:  Used to flag issues that have created a need for documentation work, such as new pages, changes, or even being added to upcoming release notes. Docs people will look for these issues periodically when working on documentation, removing the label once documentation has been written. For new features in the upcoming version of Moodle, please add documentation to the dev docs (adding a link to it from the tracker issue) or in a comment in the issue, then when the new version wiki is set up (3 weeks prior to release), the info can be transferred.&lt;br /&gt;
;dev_docs_required ([https://tracker.moodle.org/issues/?jql=labels%20in%20(dev_docs_required) all] | [https://tracker.moodle.org/issues/?jql=labels%20in%20(dev_docs_required)%20AND%20assignee%20%3D%20currentUser() yours]):  Used to flag issues that need to be noted in the dev docs. The responsibility of creating/updating Dev docs falls to the developer assigned to each relevant issue. When the issue is resolved, documentation should be created/updated, an appropriate URL should be added to the &#039;&#039;Documentation link&#039;&#039; field of the issue and the &#039;&#039;dev_docs_required&#039;&#039; label should be removed from the issue.&lt;br /&gt;
;integration_held: Used to flag issues already sent to integration that, for any cause, have been postponed to next cycles. Used only by integrators when there is some dependency or time-period causing one issue not being immediately integrable. Must be cleaned when the held is over.&lt;br /&gt;
;unhold_requested:Used to ask for an issue (having the &#039;&#039;integration_held &#039;&#039; label) to become unblocked, this flag must be coupled with a reasoned comment. Anybody can use it as far as repeated requests are avoided. Development managers will decide ASAP about giving the issue an integration opportunity or keeping it held. See &amp;lt;nowiki&amp;gt;[[Integration_Review#During_continuous_integration.2FFreeze.2FQA_period]]&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
;security_held: Used to flag security issues that have been reviewed by integrators already but held from integration repository. These issues must be cleared during point releases.&lt;br /&gt;
;security_benefit: Used to flag issues which help to improve the security of Moodle, but are not directly exploitable security bugs (and therefore do not have a security level assigned). For example, MDL-66775 and MDL-65443.&lt;br /&gt;
;partner:Moodle Partners apply this label to flag issues that are important to their clients. The Moodle HQ dev team takes this label into consideration when setting roadmap and bug fixing priorities.&lt;br /&gt;
;patch: This label indicates that a solution (patch) has been attached to the issue. However, if you can, it may be better to submit the issue for peer review, rather than using this label. This is useful to component leads and Moodle HQ when deciding what to work on next.&lt;br /&gt;
;cime: A developer can add the label &#039;cime&#039; to an issue to request that CiBot perform an [[Automated code review]].&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20performance%20AND%20project%20%3D%20MDL performance]: Used to flag any issues that developers think may affect Moodle&#039;s performance in some way (positively or negatively)&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20ui_change ui_change]: Used to identify issues that affect the interface presented to users. This label will usually be added together with the &#039;&#039;docs_required label&#039;&#039;, but the &#039;&#039;ui_change&#039;&#039; will remain permanently with the issue, while the &#039;&#039;docs_required&#039;&#039; label is removed after docs are created. This label is searched for during the preparation of release notes.&lt;br /&gt;
;api_change: Used to identify API changes. This label will usually be added together with the &#039;&#039;dev_docs_required label&#039;&#039;, but the &#039;&#039;api_change&#039;&#039; will remain permanently with the issue, while the &#039;&#039;dev_docs_required&#039;&#039; label is removed after docs are created. This label is searched for during the preparation of release notes.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20release_notes release_notes]: Used to identify all issues to be listed in the release notes (minor or major).&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20upgrade_notes upgrade_notes]: Issues that need to be mentioned in the user documentation [[:en:Upgrading|Upgrading]] under &#039;Possible issues that may affect you in Moodle 3.x&#039; (major versions).&lt;br /&gt;
;lost_functionality: Used to identify issues describing functionality which was available in an earlier version but which is no longer available in the latest version.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20%20test_server_required test_server_required]: Used to identify QA tests which can&#039;t be tested on the [http://qa.moodle.net QA testing site] such as upgrade testing.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20credentials_required credentials_required]: Used to identify QA tests which require the tester to enter credentials such as a client ID and secret for configuring OAuth 2.&lt;br /&gt;
;new: Used to identify new tests in the current QA cycle for volunteers from the community to use as a basis for exploratory testing.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?jql=labels%20%3D%20addon_candidate addon_candidate]: Used to identify suggestions for improvements/new features as possible candidates for add-on development. New and willing developers can be directed to these issues for projects.&lt;br /&gt;
;affects_mobileapp: Used to identify MDL issues that may affect the mobile app. It should be used when adding new features to functionalities supported by the app or when doing changes in existing ones. Examples are: MDL-372 and MDL-38158&lt;br /&gt;
;affects_moodlecloud: Used to identify MDL issues that may affect Moodlecloud&lt;br /&gt;
;affects_workplace: Used to identify MDL issues that may affect Moodle Workplace&lt;br /&gt;
;needs_user_stories: Used to identify issues that require further clarification of the requirements through adding user stories.&lt;br /&gt;
;[https://tracker.moodle.org/issues/?filter=21824 ready_for_integration]: Used to identify issues that already have been peer-reviewed but the user lacks permissions (pull-requester) to send the issue to integration. Any pull-requester can, on peer-reviewer&#039;s behalf, proceed with the transition. The label is removed once the issue has been transitioned.&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Tracker]]&lt;br /&gt;
* [[Bug triage]]&lt;br /&gt;
[[Category:Tracker]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.11_release_notes&amp;diff=60545</id>
		<title>Moodle 3.11 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.11_release_notes&amp;diff=60545"/>
		<updated>2021-08-06T13:35:49Z</updated>

		<summary type="html">&lt;p&gt;Tim+Hunt: Make it easier to find the PHPunit upgrade notes.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: 17 May 2021&lt;br /&gt;
&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.11%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.11].&lt;br /&gt;
&lt;br /&gt;
See our [https://docs.moodle.org/311/en/New_features New features page] in the user documentation for an introduction to Moodle 3.11 with screenshots.&lt;br /&gt;
&lt;br /&gt;
If you are upgrading from a previous version, please see [[:en:Upgrading|Upgrading]] in the user docs.&lt;br /&gt;
==Server requirements==&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software and operating systems up-to-date.&lt;br /&gt;
* Moodle upgrade: Moodle 3.6 or later&lt;br /&gt;
* PHP version: minimum PHP 7.3.0 &#039;&#039;Note: minimum PHP version has increased since Moodle 3.10&#039;&#039;. PHP 7.4.x is supported too. [[Moodle and PHP|PHP 8.0 support]] is being implemented (see MDL-70745) and &#039;&#039;&#039;not ready for production&#039;&#039;&#039; yet.&lt;br /&gt;
* PHP extension &#039;&#039;&#039;sodium&#039;&#039;&#039; is recommended. It will be required in Moodle 4.2. For further details, see [https://docs.moodle.org/311/en/Environment_-_PHP_extension_sodium Environment - PHP extension sodium].&lt;br /&gt;
* PHP setting &#039;&#039;&#039;max_input_vars&#039;&#039;&#039; is recommended to be &amp;gt;= 5000 for PHP 7.x installations. It&#039;s a requirement for PHP 8.x installations. For further details, see [https://docs.moodle.org/311/en/Environment_-_max_input_vars Environment - max input vars].&lt;br /&gt;
=== Database requirements ===&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;
{| class=&amp;quot;wikitable&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.6  &lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.7 &lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 10.2.29 &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;
| 2017 (increased since Moodle 3.10)&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;
| 11.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
==Client requirements==&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;
&#039;&#039;Note: Moodle 3.10 and above do NOT support Internet Explorer 11.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Safari 7 and below has known compatibility issues with Moodle 3.10 and above.&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date. https://www.whatsmybrowser.org/&lt;br /&gt;
==Warnings==&lt;br /&gt;
* If you have a site running on MariaDB / MySQL with many users, you may experience database issues after the upgrade step 2021042100. The upgrade attempts to drop several columns from the user table (&amp;quot;icq&amp;quot;, &amp;quot;skype&amp;quot; and others) once they were converted to new user profile fields (MDL-28452). These ALTER TABLE queries typically require copying all the rows into a new tablespace and rebuilding all indexes. Which may eventually lead to time-outs and &#039;&#039;&amp;quot;MySQL server has gone away&amp;quot;&#039;&#039; errors. It should be enough and safe to simply wait for the query to finish on the DB server (you may need to monitor currently running queries there) and then re-run the upgrade until the upgrade step 2021042100.01 finishes successfully.&lt;br /&gt;
==Major features==&lt;br /&gt;
===Improve student activity completion===&lt;br /&gt;
* MDL-71189 - Define sort ordering for completion conditions&lt;br /&gt;
* MDL-70821 - Update the course homepage to display the activity information&lt;br /&gt;
* MDL-70818 - Implement the activity dates functionality for each activity and output them in view.php&lt;br /&gt;
* MDL-70815 - Create a base class for fetching a user&#039;s activity completion details&lt;br /&gt;
* MDL-70816 - Create a base class for fetching an activity&#039;s dates that are relevant for a given user&lt;br /&gt;
* MDL-70820 - Implement the completion details functionality for each activity plugins output them in view.php - Part 1&lt;br /&gt;
* MDL-70935 - Implement the completion details functionality for each activity plugins output them in view.php - Part 2&lt;br /&gt;
* MDL-71235 - Review and update existing web services to return the new fields and exported information from activities&lt;br /&gt;
* MDL-71288 - Activity completion fallback for third party plugins&lt;br /&gt;
* MDL-71163 - Remove duplicate activity dates&lt;br /&gt;
* MDL-71144 - Deprecate the *_get_completion_state() callbacks&lt;br /&gt;
* MDL-71234 - Create user tours for the activity information output component&lt;br /&gt;
===Brickfield accessibility toolkit===&lt;br /&gt;
* MDL-69863 - Brickfield Education Labs accessibility toolkit core integration&lt;br /&gt;
===Badges===&lt;br /&gt;
* MDL-71117 - Make Moodle OBv2.1 implementation compliant &lt;br /&gt;
* MDL-70689 - Add new &amp;quot;IMS OBv2.1&amp;quot; OAuth 2 service&lt;br /&gt;
* MDL-70911 - Remove &amp;quot;Backpack settings&amp;quot; site administration page and improve UI&lt;br /&gt;
* MDL-63961 - Improve resolution of badge image sent to external backpacks and used when duplicating badges&lt;br /&gt;
===Content bank and H5P===&lt;br /&gt;
* MDL-69331 - Add ability to disable specified H5P content types&lt;br /&gt;
* MDL-66769 - Create a task to clean up unused H5P content&lt;br /&gt;
* MDL-70429 - Allow admins to set the default returntype in repository_contentbank&lt;br /&gt;
* MDL-67999 - Update content bank upload button to open file picker in a popup instead of new page&lt;br /&gt;
* MDL-69762 - Option to make a content bank item unlisted&lt;br /&gt;
* MDL-70408 - Open H5P file from H5P activity when it was added as a reference&lt;br /&gt;
* MDL-70438 - Content bank should provide info on the number of places where content is used and warn you when deleting&lt;br /&gt;
===Assignment===&lt;br /&gt;
* MDL-52420 - Assignment comments should be also saved when clicking &#039;save changes&#039; in the assignment grader page&lt;br /&gt;
* MDL-68533 - Allow mod_assign download all assignments to be streamed&lt;br /&gt;
* MDL-67702 - Assignment name filter preference should only affect current assignment&#039;s view&lt;br /&gt;
* MDL-70038 - Implement Poppler pdftoppm compatibility for faster assignment submission PDF to PNG conversion&lt;br /&gt;
* MDL-69631 - Add &#039;Draft&#039; filter to assignment grading table&lt;br /&gt;
===Quiz and questions===&lt;br /&gt;
* MDL-32226 - Add Plagiarism support to essay questions&lt;br /&gt;
* MDL-70895 - Questions: Default options when creating a question&lt;br /&gt;
* MDL-71262 - Add default options for essay question type&lt;br /&gt;
* MDL-71225 - Add default options for ddimageortext, ddmarker and match question types&lt;br /&gt;
* MDL-71181 - Display pass grade on quiz front page&lt;br /&gt;
* MDL-68597 - Add optional min/max word count limits to Essay question type&lt;br /&gt;
* MDL-69735 - Read-only view of quiz settings overrides&lt;br /&gt;
* MDL-70134 - Improve manual grading of quiz essay answers - web page format&lt;br /&gt;
* MDL-66600 - Manual grading of automatically graded questions: show computer grading&lt;br /&gt;
* MDL-71205 - Add default options for numerical question type using user-preferences&lt;br /&gt;
* MDL-70562 - In a newly created quiz, prevent &amp;quot;Edit quiz&amp;quot; and &amp;quot;Back to the course&amp;quot; buttons sticking together&lt;br /&gt;
* MDL-70266 - Quiz override screens should show user identity fields&lt;br /&gt;
* MDL-71030 - Quiz review: name the person who made each change in the question response history (if not the student)&lt;br /&gt;
===Accessibility improvements===&lt;br /&gt;
* MDL-69474 - Improve accessibility of profile images&lt;br /&gt;
* MDL-71089 - Make it possible to style toast notifications&lt;br /&gt;
===Usability improvements===&lt;br /&gt;
* MDL-70817 - Create an output component that displays an activity&#039;s information for a user&lt;br /&gt;
* MDL-48594 - More filtering options on Activity Completion Report&lt;br /&gt;
* MDL-65856 - UX Review of session expired timeout modal&lt;br /&gt;
* MDL-65135 - Add year to messaging conversation date headings, if not the current year&lt;br /&gt;
* MDL-51287 - Show confirmation when profile changes are saved&lt;br /&gt;
* MDL-70565 - Add ability to search country field on Participants page&lt;br /&gt;
* MDL-69145 - Default the participants page filtering to &amp;quot;ALL&amp;quot;&lt;br /&gt;
* MDL-57831 - Improve notification preferences on/off buttons so they fit better with non-English strings&lt;br /&gt;
* MDL-71254 - OAuth2: Display login errors on the login page&lt;br /&gt;
* MDL-67028 - LTI: Support Course dates substitution parameters&lt;br /&gt;
* MDL-70753 - Create landing page for the reports link in the secondary navigation&lt;br /&gt;
* MDL-71403 - Update message preferences of a user as admin to use consistent toggle icons&lt;br /&gt;
* MDL-71064 - Add support for keyboard hotkeys in VideoJS&lt;br /&gt;
* MDL-69878 - Always show the close button on the message drawer&lt;br /&gt;
==Other highlights==&lt;br /&gt;
===Functional changes===&lt;br /&gt;
* MDL-28452 - Convert user profile fields for messaging/networking into custom profile fields&lt;br /&gt;
* MDL-58673 - Enable playbackrates for videojs&lt;br /&gt;
* MDL-45242 - Allow user profile fields to be specified as user identity fields - New code is backwards-compatible, but report code should be updated.&lt;br /&gt;
* MDL-66431 - Remove &amp;quot;Enable activity chooser&amp;quot; user preference&lt;br /&gt;
* MDL-61768 - Update Google Drive repository to allow Shared drive files&lt;br /&gt;
* MDL-63381 - Option to not include permissions overrides when importing or restoring a backup&lt;br /&gt;
* MDL-71190 - Backup and Restore lastaccess to course&lt;br /&gt;
* MDL-48269 - Remove option to hide a group picture&lt;br /&gt;
* MDL-71118 - Differentiate between grade as a noun and grade as a verb in the UI texts&lt;br /&gt;
* MDL-71186 - Add custom user field support to group management screens&lt;br /&gt;
* MDL-69773 - Add an option to display section names in Section link block&lt;br /&gt;
===For administrators===&lt;br /&gt;
* MDL-70722 - Move Microsoft, Facebook and NextCloud OAuth2 services to new, reorganised architecture&lt;br /&gt;
* MDL-42382 - Add a &amp;quot;Replace filter&amp;quot; option on the admin browse users page&lt;br /&gt;
* MDL-65843 - Ability to force cron scheduled task definitions in config.php (schedule and disabled)&lt;br /&gt;
* MDL-70536 - Create a CLI script to reset user dashboards&lt;br /&gt;
* MDL-67748 - Improve the web services tokens management to allow searching and filtering &lt;br /&gt;
* MDL-69460 - Check for removed files before CLI upgrade&lt;br /&gt;
* MDL-70828 - Add ability to switch off session lock debugging&lt;br /&gt;
* MDL-70583 - Implement a renderer for progress_bar in cli output&lt;br /&gt;
* MDL-68010 - Allow disabled tasks to be run from the GUI&lt;br /&gt;
* MDL-71017 - Add the ability to configure OAuth2 services for login only; add login display name&lt;br /&gt;
* MDL-70269 - Update the ClamAV default behaviour when an error occurs&lt;br /&gt;
* MDL-70500 - Use Dynamic Registration to allow Tools to update to LTI Advantage&lt;br /&gt;
* MDL-70287 - Payment service consumers should be able to specify url after payment&lt;br /&gt;
* MDL-70158 - Make it easier to find a specific component in template library&lt;br /&gt;
* MDL-70632 - Allow searching of available language packs&lt;br /&gt;
* MDL-70362 - Add showdebugging and showsql options to admin/cli/uninstall_plugins.php&lt;br /&gt;
* MDL-69898 - Config change event should link to config change report&lt;br /&gt;
* MDL-70159 - Sort capabilities in capability overview tool&lt;br /&gt;
===Mobile===&lt;br /&gt;
* MDL-71273 - Add a new option in Moodle app &amp;quot;Disabled features&amp;quot; for preventing the new LTI launch in the app&lt;br /&gt;
* MDL-65983 - Include option for testing Push notifications in a site&lt;br /&gt;
===Performance===&lt;br /&gt;
* MDL-68481 - mod/folder/download_folder.php should be a streaming zip download&lt;br /&gt;
* MDL-70444 - Make my_reset_page_for_all_users for dashboards more robust&lt;br /&gt;
* MDL-68052 - Implement cleanup of analytics_indicator_calc stores table&lt;br /&gt;
* MDL-71044 - Extend the &#039;backup_cleanup_task&#039; scheduled task to remove old files&lt;br /&gt;
* MDL-66667 - Cache course image in the course_summary_exporter&lt;br /&gt;
* MDL-69121 - Allow redis session store to use zip or zStd for compression like redis MUC&lt;br /&gt;
* MDL-70107 - Running a scheduled task in the GUI should unlock the session&lt;br /&gt;
* MDL-27193 - Eliminate DB queries in mod/glossary/settings.php &lt;br /&gt;
* MDL-70608 - Update language pack installs / updates to run asynchronously to avoid timeouts when multiple are used&lt;br /&gt;
==Security improvements==&lt;br /&gt;
* MDL-65818 - Provide admin setting type for secure data (passwords/tokens)&lt;br /&gt;
* MDL-64865 - Add logging when auth config is automatically changed due to config/filesystem mismatch&lt;br /&gt;
* MDL-69333 - Reduce ability to fingerprint a server with a htaccess-dist / nginx file / docs&lt;br /&gt;
* MDL-69522 - Allow antivirus scanners to specify the message to the user&lt;br /&gt;
* MDL-67882 - Log changes to the message notifications settings&lt;br /&gt;
* MDL-70649 - Allow plugins to augment the cURL security helper via callback&lt;br /&gt;
* MDL-70735 - Reduce information disclosure from TCPDF version&lt;br /&gt;
* MDL-70766 - Log changes to auth plugin settings in config log&lt;br /&gt;
* MDL-70439 - Display user email address visibility settings on their own profile&lt;br /&gt;
==For developers==&lt;br /&gt;
The PHPUnit upgrade will almost certainly break your tests. See [[Writing PHPUnit tests#Upgrading unit tests to work with Moodle 3.11 and up .28PHPUnit 9.5.29]]&lt;br /&gt;
* MDL-52817 - New sql_group_concat db method&lt;br /&gt;
* MDL-64554 - Add module for displaying moodleform in a modal window&lt;br /&gt;
* MDL-71036 - Upgrade PHPUnit to 9.5.x&lt;br /&gt;
* MDL-68608 - Improve the readonly session debugging message&lt;br /&gt;
* MDL-71012 - HTTP 503 Service Not Available is returned by exceptions and should be 500 instead&lt;br /&gt;
* MDL-70311 - Upgrade boost to use Bootstrap latest version&lt;br /&gt;
* MDL-69202 - Restore backup: add getter method for oldmoduleid&lt;br /&gt;
* MDL-70055 - Support large number of SQL-IN parameters in Postgres&lt;br /&gt;
* MDL-70142 - Preserve form data when purging individual caches&lt;br /&gt;
* MDL-71099 - Move user_fields from core to core_user&lt;br /&gt;
===Web service additions and updates===&lt;br /&gt;
* MDL-69869 - Add ability for &amp;quot;get enrolled users&amp;quot; web service to be filtered by suspended users&lt;br /&gt;
* MDL-70128 - Create a new endpoint (script) to retrieve draft files from web services&lt;br /&gt;
* MDL-68853 - Create web service to trigger report_viewed event for H5P activities&lt;br /&gt;
* MDL-69259 - Create H5P activity web service to get the list of students that attempted an activity&lt;br /&gt;
* MDL-70387 - New web service core_files_get_unused_draft_itemid&lt;br /&gt;
* MDL-71492 - Return quiz pass grade via web services&lt;br /&gt;
* MDL-70037 - Update mod_forum_get_discussion_posts web service to return the last_modified attribute&lt;br /&gt;
* MDL-71031 - Batch create API for grade categories&lt;br /&gt;
* MDL-71169 - All new external functions implementation classes should use &amp;lt;tt&amp;gt;execute&amp;lt;/tt&amp;gt; as the method name, in which case the &amp;lt;tt&amp;gt;methodname&amp;lt;/tt&amp;gt; property should not be specified in db/services.php file&lt;br /&gt;
===Deprecations===&lt;br /&gt;
* MDL-69792 - Deprecate unused backpack js functions&lt;br /&gt;
* MDL-66138 - Deprecate get_forum_discussions_paginated webservice&lt;br /&gt;
* MDL-65319 - Phase 2 of deprecation of functions in lib/deprecatedlib.php initially deprecated in 3.7&lt;br /&gt;
* MDL-65284 - Final deprecation for analytics methods deprecated in MDL-64783&lt;br /&gt;
* MDL-65215 - Final deprecation of i_dock_block()&lt;br /&gt;
* MDL-65186 - Final deprecation of \core_analytics\manager::add_builtin_models()&lt;br /&gt;
* MDL-65086 - get_enabled_time_splitting_methods final deprecation&lt;br /&gt;
* MDL-64982 - Final deprecation of behat_base::TIMEOUT and related constants&lt;br /&gt;
* MDL-64866 - Remove message/defaultoutputs.php and final deprecation of admin_page_manageqbehaviours class&lt;br /&gt;
* MDL-64776 - Final deprecation of booktool_print_get_toc()&lt;br /&gt;
* MDL-63266 - Final deprecation of enrol/database/cli/sync.php&lt;br /&gt;
===Component API updates===&lt;br /&gt;
* admin/upgrade.txt&lt;br /&gt;
* analytics/upgrade.txt&lt;br /&gt;
* auth/shibboleth/upgrade.txt&lt;br /&gt;
* backup/upgrade.txt&lt;br /&gt;
* badges/upgrade.txt&lt;br /&gt;
* blocks/section_links/upgrade.txt&lt;br /&gt;
* blocks/tag_youtube/upgrade.txt&lt;br /&gt;
* completion/upgrade.txt&lt;br /&gt;
* contentbank/upgrade.txt&lt;br /&gt;
* course/upgrade.txt&lt;br /&gt;
* customfield/upgrade.txt&lt;br /&gt;
* enrol/database/upgrade.txt&lt;br /&gt;
* enrol/upgrade.txt&lt;br /&gt;
* group/upgrade.txt&lt;br /&gt;
* h5p/upgrade.txt&lt;br /&gt;
* lib/upgrade.txt&lt;br /&gt;
* mod/book/upgrade.txt&lt;br /&gt;
* mod/feedback/upgrade.txt&lt;br /&gt;
* mod/forum/upgrade.txt&lt;br /&gt;
* mod/h5pactivity/upgrade.txt&lt;br /&gt;
* mod/quiz/upgrade.txt&lt;br /&gt;
* payment/upgrade.txt&lt;br /&gt;
* plagiarism/upgrade.txt&lt;br /&gt;
* question/type/upgrade.txt&lt;br /&gt;
* report/upgrade.txt&lt;br /&gt;
* repository/upgrade.txt&lt;br /&gt;
* theme/upgrade.txt&lt;br /&gt;
* user/upgrade.txt&lt;br /&gt;
* webservice/upgrade.txt&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.10 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.11]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.11]]&lt;br /&gt;
[[es:Notas de Moodle 3.11]]&lt;/div&gt;</summary>
		<author><name>Tim+Hunt</name></author>
	</entry>
</feed>