diff --git a/question/type/ordering/amd/build/drag_reorder.min.js.map b/question/type/ordering/amd/build/drag_reorder.min.js.map
index c8a99360462..51696725c4b 100644
--- a/question/type/ordering/amd/build/drag_reorder.min.js.map
+++ b/question/type/ordering/amd/build/drag_reorder.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"drag_reorder.min.js","sources":["../src/drag_reorder.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/*\n * Generic library to allow things in a vertical list to be re-ordered using drag and drop.\n *\n * To make a set of things draggable, create a new instance of this object passing the\n * necessary config, as explained in the comment on the constructor.\n *\n * @package qtype_ordering\n * @copyright 2018 The Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n'use strict';\n\nimport $ from 'jquery';\nimport drag from 'core/dragdrop';\nimport keys from 'core/key_codes';\nimport Templates from 'core/templates';\nimport Notification from 'core/notification';\n\nexport default class DragReorder {\n\n // Class variables handling state.\n config = {reorderStart: undefined, reorderEnd: undefined}; // Config object with some basic definitions.\n dragStart = null; // Information about when and where the drag started.\n originalOrder = null; // Array of ids that's used to compare the state after the drag event finishes.\n\n // DOM Nodes and jQuery representations.\n orderList = null; // Order list (HTMLElement).\n itemDragging = null; // Item being moved by dragging (jQuery object).\n proxy = null; // Drag proxy (jQuery object).\n\n /**\n * Constructor.\n *\n * To make a list draggable, create a new instance of this object, passing the necessary config.\n * For example:\n * {\n * // Selector for the list (or lists) to be reordered.\n * list: 'ul.my-list',\n *\n * // Selector, relative to the list selector, for the items that can be moved.\n * item: '> li',\n *\n * // While the proxy is being dragged, this class is added to the item being moved.\n * // You can probably use \"osep-itemmoving\" here.\n * itemMovingClass: \"osep-itemmoving\",\n *\n * // This is a callback which, when called with the DOM node for an item,\n * // returns the string that uniquely identifies each item.\n * // Therefore, the result of the drag action will be represented by the array\n * // obtained by calling this method on each item in the list in order.\n * idGetter: function(item) { return node.id; },\n *\n * // Function that will be called when a re-order starts (optional, can be not set).\n * // Useful if you need to save information about the initial state.\n * // This function should have two parameters. The first will be a\n * // jQuery object for the list that was reordered, the second will\n * // be the jQuery object for the item moved - which will not yet have been moved.\n * // Note, it is quite possible for reorderStart to be called with no\n * // subsequent call to reorderDone.\n * reorderStart: function($list, $item) { ... }\n *\n * // Function that will be called when a drag has finished, and the list\n * // has been reordered. This function should have three parameters. The first will be\n * // a jQuery object for the list that was reordered, the second will be the jQuery\n * // object for the item moved, and the third will be the new order, which is\n * // an array of ids obtained by calling idGetter on each item in the list in order.\n * // This callback will only be called in the new order is actually different from the old order.\n * reorderDone: function($list, $item, newOrder) { ... }\n *\n * // Function that is always called when a re-order ends (optional, can be not set)\n * // whether the order has changed. Useful if you need to undo changes made\n * // in reorderStart, since reorderDone is only called if the new order is different\n * // from the original order.\n * reorderEnd: function($list, $item) { ... }\n * }\n *\n * There is a subtlety, If you have items in your list that do not have a drag handle,\n * they are considered to be placeholders in otherwise empty containers.\n *\n * @param {Object} config As above.\n */\n constructor(config) {\n // Bring in the config to our state.\n this.config = config;\n\n // Get the list we'll be working with this time.\n this.orderList = document.querySelector(this.config.list);\n\n this.startListeners();\n\n // Make the items tabbable.\n // TODO: This can be removed once we move to templates and add the tabindex there.\n $(this.combineSelectors(config.list, config.item)).attr('tabindex', '0');\n }\n\n /**\n * Start the listeners for the list.\n */\n startListeners() {\n /**\n * Handle mousedown or touchstart events on the list.\n *\n * @param {Event} e The event.\n */\n const pointerHandle = e => {\n if (e.target.closest(this.config.item)) {\n this.itemDragging = $(e.target.closest(this.config.item));\n const details = drag.prepare(e);\n if (details.start) {\n this.startDrag(e, details);\n }\n }\n };\n // Set up the list listeners for moving list items around.\n this.orderList.addEventListener('mousedown', pointerHandle);\n this.orderList.addEventListener('touchstart', pointerHandle);\n this.orderList.addEventListener('keydown', this.itemMovedByKeyboard.bind(this));\n }\n\n /**\n * Start dragging.\n *\n * @param {Event} e The event which is either mousedown or touchstart.\n * @param {Object} details Object with start (boolean flag) and x, y (only if flag true) values\n */\n startDrag(e, details) {\n this.dragStart = {\n time: new Date().getTime(),\n x: details.x,\n y: details.y\n };\n\n if (typeof this.config.reorderStart !== 'undefined') {\n this.config.reorderStart(this.itemDragging.closest(this.config.list), this.itemDragging);\n }\n\n this.originalOrder = this.getCurrentOrder();\n\n Templates.renderForPromise('qtype_ordering/proxyhtml', {\n itemHtml: this.itemDragging.html(),\n itemClassName: this.itemDragging.attr('class'),\n listClassName: this.orderList.classList.toString(),\n proxyStyles: [\n `width: ${this.itemDragging.outerWidth()}px;`,\n `height: ${this.itemDragging.outerHeight()}px;`,\n ].join(' '),\n }).then(({html, js}) => {\n this.proxy = $(Templates.appendNodeContents(document.body, html, js)[0]);\n this.proxy.css(this.itemDragging.offset());\n\n this.itemDragging.addClass(this.config.itemMovingClass);\n\n this.updateProxy();\n // Start drag.\n drag.start(e, this.proxy, this.dragMove.bind(this), this.dragEnd.bind(this));\n }).catch(Notification.exception);\n }\n\n /**\n * Move the proxy to the current mouse position.\n */\n dragMove() {\n let closestItem = null;\n let closestDistance = null;\n this.orderList.querySelectorAll(this.config.item).forEach(element => {\n const distance = this.distanceBetweenElements(element);\n if (closestItem === null || distance < closestDistance) {\n closestItem = $(element);\n closestDistance = distance;\n }\n });\n\n if (closestItem[0] === this.itemDragging[0]) {\n return;\n }\n\n // Set offset depending on if item is being dragged downwards/upwards.\n const offsetValue = this.midY(this.proxy) < this.midY(closestItem) ? 20 : -20;\n if (this.midY(this.proxy) + offsetValue < this.midY(closestItem)) {\n this.itemDragging.insertBefore(closestItem);\n } else {\n this.itemDragging.insertAfter(closestItem);\n }\n this.updateProxy();\n }\n\n /**\n * Update proxy's position.\n */\n updateProxy() {\n const items = [...this.orderList.querySelectorAll(this.config.item)];\n for (let i = 0; i < items.length; ++i) {\n if (this.itemDragging[0] === items[i]) {\n this.proxy.find('li').attr('value', i + 1);\n break;\n }\n }\n }\n\n /**\n * End dragging.\n *\n * @param {number} x X co-ordinate\n * @param {number} y Y co-ordinate\n */\n dragEnd(x, y) {\n if (typeof this.config.reorderEnd !== 'undefined') {\n this.config.reorderEnd(this.itemDragging.closest(this.config.list), this.itemDragging);\n }\n\n if (!this.arrayEquals(this.originalOrder, this.getCurrentOrder())) {\n // Order has changed, call the callback.\n this.config.reorderDone(this.itemDragging.closest(this.config.list), this.itemDragging, this.getCurrentOrder());\n\n } else if (new Date().getTime() - this.dragStart.time < 500 &&\n Math.abs(this.dragStart.x - x) < 10 && Math.abs(this.dragStart.y - y) < 10) {\n // This was really a click. Set the focus on the current item.\n this.itemDragging[0].focus();\n }\n\n // Clean up after the drag is finished.\n this.proxy.remove();\n this.proxy = null;\n this.itemDragging.removeClass(this.config.itemMovingClass);\n this.itemDragging = null;\n this.dragStart = null;\n }\n\n /**\n * Items can be moved and placed using certain keys.\n * Tab for tabbing though and choose the item to be moved\n * space, arrow-right arrow-down for moving current element forwards.\n * arrow-right arrow-down for moving the current element backwards.\n *\n * @param {Event} e The keyboard event.\n */\n itemMovedByKeyboard(e) {\n if (e.target.closest(this.config.item)) {\n this.itemDragging = $(e.target.closest(this.config.item));\n\n // Store the current state of the list.\n this.originalOrder = this.getCurrentOrder();\n\n switch (e.keyCode) {\n case keys.space:\n case keys.arrowRight:\n case keys.arrowDown:\n e.preventDefault();\n e.stopPropagation();\n if (this.itemDragging.next().length) {\n this.itemDragging.next().insertBefore(this.itemDragging);\n }\n break;\n\n case keys.arrowLeft:\n case keys.arrowUp:\n e.preventDefault();\n e.stopPropagation();\n if (this.itemDragging.prev().length) {\n this.itemDragging.prev().insertAfter(this.itemDragging);\n }\n break;\n }\n\n // After we have potentially moved the item, we need to check if the order has changed.\n if (!this.arrayEquals(this.originalOrder, this.getCurrentOrder())) {\n // Order has changed, call the callback.\n this.config.reorderDone(this.itemDragging.closest(this.config.list), this.itemDragging, this.getCurrentOrder());\n }\n }\n }\n\n /**\n * TODO: Once the tabindex is added to the template, this can be removed.\n * Our outer and inner are two CSS selectors, which may contain commas.\n * We want to combine them safely. So for instance combineSelectors('a, b', 'c, d')\n * gives 'a c, a d, b c, b d'.\n *\n * @param {String} outer The selector for the outer element.\n * @param {String} inner The selector for the inner element.\n * @returns {String} The combined selector used to listen to the list item.\n */\n combineSelectors(outer, inner) {\n let combined = [];\n outer.split(',').forEach(firstSelector => {\n inner.split(',').forEach(secondSelector => {\n combined.push(firstSelector.trim() + ' ' + secondSelector.trim());\n });\n });\n return combined.join(', ');\n }\n\n /**\n * Get the x-position of the middle of the DOM node represented by the given jQuery object.\n *\n * @param {jQuery} node jQuery wrapping a DOM node.\n * @returns {number} Number the x-coordinate of the middle (left plus half outerWidth).\n */\n midX(node) {\n return node.offset().left + node.outerWidth() / 2;\n }\n\n /**\n * Get the y-position of the middle of the DOM node represented by the given jQuery object.\n *\n * @param {jQuery} node jQuery wrapped DOM node.\n * @returns {number} Number the y-coordinate of the middle (top plus half outerHeight).\n */\n midY(node) {\n return node.offset().top + node.outerHeight() / 2;\n }\n\n /**\n * Calculate the distance between the centres of two elements.\n *\n * @param {HTMLLIElement} element DOM node of a list item.\n * @return {number} number the distance in pixels.\n */\n distanceBetweenElements(element) {\n const [e1, e2] = [$(element), $(this.proxy)];\n const [dx, dy] = [this.midX(e1) - this.midX(e2), this.midY(e1) - this.midY(e2)];\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n /**\n * Get the current order of the list containing itemDragging.\n *\n * @returns {Array} Array of strings, the id of each element in order.\n */\n getCurrentOrder() {\n return this.itemDragging.closest(this.config.list).find(this.config.item).map(\n (index, item) => {\n return this.config.idGetter(item);\n }).get();\n }\n\n /**\n * Compare two arrays which contain primitive types to see if they are equal.\n * @param {Array} a1 first array.\n * @param {Array} a2 second array.\n * @return {Boolean} boolean true if they both contain the same elements in the same order, else false.\n */\n arrayEquals(a1, a2) {\n return a1.length === a2.length &&\n a1.every((v, i) => {\n return v === a2[i];\n });\n }\n\n /**\n * Initialise one ordering question.\n *\n * @param {String} sortableid id of ul for this question.\n * @param {String} responseid id of hidden field for this question.\n */\n static init(sortableid, responseid) {\n new DragReorder({\n list: 'ul#' + sortableid,\n item: 'li.sortableitem',\n itemMovingClass: \"current-drop\",\n idGetter: item => {\n return item.id;\n },\n reorderDone: (list, item, newOrder) => {\n $('input#' + responseid)[0].value = newOrder.join(',');\n }\n });\n }\n}\n"],"names":["DragReorder","constructor","config","reorderStart","undefined","reorderEnd","orderList","document","querySelector","this","list","startListeners","combineSelectors","item","attr","pointerHandle","e","target","closest","itemDragging","details","drag","prepare","start","startDrag","addEventListener","itemMovedByKeyboard","bind","dragStart","time","Date","getTime","x","y","originalOrder","getCurrentOrder","renderForPromise","itemHtml","html","itemClassName","listClassName","classList","toString","proxyStyles","outerWidth","outerHeight","join","then","_ref","js","proxy","Templates","appendNodeContents","body","css","offset","addClass","itemMovingClass","updateProxy","dragMove","dragEnd","catch","Notification","exception","closestItem","closestDistance","querySelectorAll","forEach","element","distance","distanceBetweenElements","offsetValue","midY","insertBefore","insertAfter","items","i","length","find","arrayEquals","Math","abs","focus","reorderDone","remove","removeClass","keyCode","keys","space","arrowRight","arrowDown","preventDefault","stopPropagation","next","arrowLeft","arrowUp","prev","outer","inner","combined","split","firstSelector","secondSelector","push","trim","midX","node","left","top","e1","e2","dx","dy","sqrt","map","index","idGetter","get","a1","a2","every","v","sortableid","responseid","id","newOrder","value"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"drag_reorder.min.js","sources":["../src/drag_reorder.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/*\n * To make a set of things draggable, create a new instance of this object passing the\n * necessary config, as explained in the comment on the constructor.\n *\n * @package qtype_ordering\\drag_reorder\n * @copyright 2018 The Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n'use strict';\n\nimport $ from 'jquery';\nimport drag from 'core/dragdrop';\nimport keys from 'core/key_codes';\nimport Templates from 'core/templates';\nimport Notification from 'core/notification';\n\nexport default class DragReorder {\n\n // Class variables handling state.\n config = {reorderStart: undefined, reorderEnd: undefined}; // Config object with some basic definitions.\n dragStart = null; // Information about when and where the drag started.\n originalOrder = null; // Array of ids that's used to compare the state after the drag event finishes.\n\n // DOM Nodes and jQuery representations.\n orderList = null; // Order list (HTMLElement).\n itemDragging = null; // Item being moved by dragging (jQuery object).\n proxy = null; // Drag proxy (jQuery object).\n\n /**\n * Constructor.\n *\n * To make a list draggable, create a new instance of this object, passing the necessary config.\n * For example:\n * {\n * // Selector for the list (or lists) to be reordered.\n * list: 'ul.my-list',\n *\n * // Selector, relative to the list selector, for the items that can be moved.\n * item: '> li',\n *\n * // While the proxy is being dragged, this class is added to the item being moved.\n * // You can probably use \"osep-itemmoving\" here.\n * itemMovingClass: \"osep-itemmoving\",\n *\n * // This is a callback which, when called with the DOM node for an item,\n * // returns the string that uniquely identifies each item.\n * // Therefore, the result of the drag action will be represented by the array\n * // obtained by calling this method on each item in the list in order.\n * idGetter: function(item) { return node.id; },\n *\n * // Function that will be called when a re-order starts (optional, can be not set).\n * // Useful if you need to save information about the initial state.\n * // This function should have two parameters. The first will be a\n * // jQuery object for the list that was reordered, the second will\n * // be the jQuery object for the item moved - which will not yet have been moved.\n * // Note, it is quite possible for reorderStart to be called with no\n * // subsequent call to reorderDone.\n * reorderStart: function($list, $item) { ... }\n *\n * // Function that will be called when a drag has finished, and the list\n * // has been reordered. This function should have three parameters. The first will be\n * // a jQuery object for the list that was reordered, the second will be the jQuery\n * // object for the item moved, and the third will be the new order, which is\n * // an array of ids obtained by calling idGetter on each item in the list in order.\n * // This callback will only be called in the new order is actually different from the old order.\n * reorderDone: function($list, $item, newOrder) { ... }\n *\n * // Function that is always called when a re-order ends (optional, can be not set)\n * // whether the order has changed. Useful if you need to undo changes made\n * // in reorderStart, since reorderDone is only called if the new order is different\n * // from the original order.\n * reorderEnd: function($list, $item) { ... }\n * }\n *\n * There is a subtlety, If you have items in your list that do not have a drag handle,\n * they are considered to be placeholders in otherwise empty containers.\n *\n * @param {Object} config As above.\n */\n constructor(config) {\n // Bring in the config to our state.\n this.config = config;\n\n // Get the list we'll be working with this time.\n this.orderList = document.querySelector(this.config.list);\n\n this.startListeners();\n\n // Make the items tabbable.\n // TODO: This can be removed once we move to templates and add the tabindex there.\n $(this.combineSelectors(config.list, config.item)).attr('tabindex', '0');\n }\n\n /**\n * Start the listeners for the list.\n */\n startListeners() {\n /**\n * Handle mousedown or touchstart events on the list.\n *\n * @param {Event} e The event.\n */\n const pointerHandle = e => {\n if (e.target.closest(this.config.item)) {\n this.itemDragging = $(e.target.closest(this.config.item));\n const details = drag.prepare(e);\n if (details.start) {\n this.startDrag(e, details);\n }\n }\n };\n // Set up the list listeners for moving list items around.\n this.orderList.addEventListener('mousedown', pointerHandle);\n this.orderList.addEventListener('touchstart', pointerHandle);\n this.orderList.addEventListener('keydown', this.itemMovedByKeyboard.bind(this));\n }\n\n /**\n * Start dragging.\n *\n * @param {Event} e The event which is either mousedown or touchstart.\n * @param {Object} details Object with start (boolean flag) and x, y (only if flag true) values\n */\n startDrag(e, details) {\n this.dragStart = {\n time: new Date().getTime(),\n x: details.x,\n y: details.y\n };\n\n if (typeof this.config.reorderStart !== 'undefined') {\n this.config.reorderStart(this.itemDragging.closest(this.config.list), this.itemDragging);\n }\n\n this.originalOrder = this.getCurrentOrder();\n\n Templates.renderForPromise('qtype_ordering/proxyhtml', {\n itemHtml: this.itemDragging.html(),\n itemClassName: this.itemDragging.attr('class'),\n listClassName: this.orderList.classList.toString(),\n proxyStyles: [\n `width: ${this.itemDragging.outerWidth()}px;`,\n `height: ${this.itemDragging.outerHeight()}px;`,\n ].join(' '),\n }).then(({html, js}) => {\n this.proxy = $(Templates.appendNodeContents(document.body, html, js)[0]);\n this.proxy.css(this.itemDragging.offset());\n\n this.itemDragging.addClass(this.config.itemMovingClass);\n\n this.updateProxy();\n // Start drag.\n drag.start(e, this.proxy, this.dragMove.bind(this), this.dragEnd.bind(this));\n }).catch(Notification.exception);\n }\n\n /**\n * Move the proxy to the current mouse position.\n */\n dragMove() {\n let closestItem = null;\n let closestDistance = null;\n this.orderList.querySelectorAll(this.config.item).forEach(element => {\n const distance = this.distanceBetweenElements(element);\n if (closestItem === null || distance < closestDistance) {\n closestItem = $(element);\n closestDistance = distance;\n }\n });\n\n if (closestItem[0] === this.itemDragging[0]) {\n return;\n }\n\n // Set offset depending on if item is being dragged downwards/upwards.\n const offsetValue = this.midY(this.proxy) < this.midY(closestItem) ? 20 : -20;\n if (this.midY(this.proxy) + offsetValue < this.midY(closestItem)) {\n this.itemDragging.insertBefore(closestItem);\n } else {\n this.itemDragging.insertAfter(closestItem);\n }\n this.updateProxy();\n }\n\n /**\n * Update proxy's position.\n */\n updateProxy() {\n const items = [...this.orderList.querySelectorAll(this.config.item)];\n for (let i = 0; i < items.length; ++i) {\n if (this.itemDragging[0] === items[i]) {\n this.proxy.find('li').attr('value', i + 1);\n break;\n }\n }\n }\n\n /**\n * End dragging.\n *\n * @param {number} x X co-ordinate\n * @param {number} y Y co-ordinate\n */\n dragEnd(x, y) {\n if (typeof this.config.reorderEnd !== 'undefined') {\n this.config.reorderEnd(this.itemDragging.closest(this.config.list), this.itemDragging);\n }\n\n if (!this.arrayEquals(this.originalOrder, this.getCurrentOrder())) {\n // Order has changed, call the callback.\n this.config.reorderDone(this.itemDragging.closest(this.config.list), this.itemDragging, this.getCurrentOrder());\n\n } else if (new Date().getTime() - this.dragStart.time < 500 &&\n Math.abs(this.dragStart.x - x) < 10 && Math.abs(this.dragStart.y - y) < 10) {\n // This was really a click. Set the focus on the current item.\n this.itemDragging[0].focus();\n }\n\n // Clean up after the drag is finished.\n this.proxy.remove();\n this.proxy = null;\n this.itemDragging.removeClass(this.config.itemMovingClass);\n this.itemDragging = null;\n this.dragStart = null;\n }\n\n /**\n * Items can be moved and placed using certain keys.\n * Tab for tabbing though and choose the item to be moved\n * space, arrow-right arrow-down for moving current element forwards.\n * arrow-right arrow-down for moving the current element backwards.\n *\n * @param {Event} e The keyboard event.\n */\n itemMovedByKeyboard(e) {\n if (e.target.closest(this.config.item)) {\n this.itemDragging = $(e.target.closest(this.config.item));\n\n // Store the current state of the list.\n this.originalOrder = this.getCurrentOrder();\n\n switch (e.keyCode) {\n case keys.space:\n case keys.arrowRight:\n case keys.arrowDown:\n e.preventDefault();\n e.stopPropagation();\n if (this.itemDragging.next().length) {\n this.itemDragging.next().insertBefore(this.itemDragging);\n }\n break;\n\n case keys.arrowLeft:\n case keys.arrowUp:\n e.preventDefault();\n e.stopPropagation();\n if (this.itemDragging.prev().length) {\n this.itemDragging.prev().insertAfter(this.itemDragging);\n }\n break;\n }\n\n // After we have potentially moved the item, we need to check if the order has changed.\n if (!this.arrayEquals(this.originalOrder, this.getCurrentOrder())) {\n // Order has changed, call the callback.\n this.config.reorderDone(this.itemDragging.closest(this.config.list), this.itemDragging, this.getCurrentOrder());\n }\n }\n }\n\n /**\n * TODO: Once the tabindex is added to the template, this can be removed.\n * Our outer and inner are two CSS selectors, which may contain commas.\n * We want to combine them safely. So for instance combineSelectors('a, b', 'c, d')\n * gives 'a c, a d, b c, b d'.\n *\n * @param {String} outer The selector for the outer element.\n * @param {String} inner The selector for the inner element.\n * @returns {String} The combined selector used to listen to the list item.\n */\n combineSelectors(outer, inner) {\n let combined = [];\n outer.split(',').forEach(firstSelector => {\n inner.split(',').forEach(secondSelector => {\n combined.push(firstSelector.trim() + ' ' + secondSelector.trim());\n });\n });\n return combined.join(', ');\n }\n\n /**\n * Get the x-position of the middle of the DOM node represented by the given jQuery object.\n *\n * @param {jQuery} node jQuery wrapping a DOM node.\n * @returns {number} Number the x-coordinate of the middle (left plus half outerWidth).\n */\n midX(node) {\n return node.offset().left + node.outerWidth() / 2;\n }\n\n /**\n * Get the y-position of the middle of the DOM node represented by the given jQuery object.\n *\n * @param {jQuery} node jQuery wrapped DOM node.\n * @returns {number} Number the y-coordinate of the middle (top plus half outerHeight).\n */\n midY(node) {\n return node.offset().top + node.outerHeight() / 2;\n }\n\n /**\n * Calculate the distance between the centres of two elements.\n *\n * @param {HTMLLIElement} element DOM node of a list item.\n * @return {number} number the distance in pixels.\n */\n distanceBetweenElements(element) {\n const [e1, e2] = [$(element), $(this.proxy)];\n const [dx, dy] = [this.midX(e1) - this.midX(e2), this.midY(e1) - this.midY(e2)];\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n /**\n * Get the current order of the list containing itemDragging.\n *\n * @returns {Array} Array of strings, the id of each element in order.\n */\n getCurrentOrder() {\n return this.itemDragging.closest(this.config.list).find(this.config.item).map(\n (index, item) => {\n return this.config.idGetter(item);\n }).get();\n }\n\n /**\n * Compare two arrays which contain primitive types to see if they are equal.\n * @param {Array} a1 first array.\n * @param {Array} a2 second array.\n * @return {Boolean} boolean true if they both contain the same elements in the same order, else false.\n */\n arrayEquals(a1, a2) {\n return a1.length === a2.length &&\n a1.every((v, i) => {\n return v === a2[i];\n });\n }\n\n /**\n * Initialise one ordering question.\n *\n * @param {String} sortableid id of ul for this question.\n * @param {String} responseid id of hidden field for this question.\n */\n static init(sortableid, responseid) {\n new DragReorder({\n list: 'ul#' + sortableid,\n item: 'li.sortableitem',\n itemMovingClass: \"current-drop\",\n idGetter: item => {\n return item.id;\n },\n reorderDone: (list, item, newOrder) => {\n $('input#' + responseid)[0].value = newOrder.join(',');\n }\n });\n }\n}\n"],"names":["DragReorder","constructor","config","reorderStart","undefined","reorderEnd","orderList","document","querySelector","this","list","startListeners","combineSelectors","item","attr","pointerHandle","e","target","closest","itemDragging","details","drag","prepare","start","startDrag","addEventListener","itemMovedByKeyboard","bind","dragStart","time","Date","getTime","x","y","originalOrder","getCurrentOrder","renderForPromise","itemHtml","html","itemClassName","listClassName","classList","toString","proxyStyles","outerWidth","outerHeight","join","then","_ref","js","proxy","Templates","appendNodeContents","body","css","offset","addClass","itemMovingClass","updateProxy","dragMove","dragEnd","catch","Notification","exception","closestItem","closestDistance","querySelectorAll","forEach","element","distance","distanceBetweenElements","offsetValue","midY","insertBefore","insertAfter","items","i","length","find","arrayEquals","Math","abs","focus","reorderDone","remove","removeClass","keyCode","keys","space","arrowRight","arrowDown","preventDefault","stopPropagation","next","arrowLeft","arrowUp","prev","outer","inner","combined","split","firstSelector","secondSelector","push","trim","midX","node","left","top","e1","e2","dx","dy","sqrt","map","index","idGetter","get","a1","a2","every","v","sortableid","responseid","id","newOrder","value"],"mappings":"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"}
\ No newline at end of file
diff --git a/question/type/ordering/amd/src/drag_reorder.js b/question/type/ordering/amd/src/drag_reorder.js
index e4843203a0f..48a4c029834 100644
--- a/question/type/ordering/amd/src/drag_reorder.js
+++ b/question/type/ordering/amd/src/drag_reorder.js
@@ -14,12 +14,10 @@
// along with Moodle. If not, see .
/*
- * Generic library to allow things in a vertical list to be re-ordered using drag and drop.
- *
* To make a set of things draggable, create a new instance of this object passing the
* necessary config, as explained in the comment on the constructor.
*
- * @package qtype_ordering
+ * @package qtype_ordering\drag_reorder
* @copyright 2018 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
diff --git a/question/type/ordering/classes/output/correct_response.php b/question/type/ordering/classes/output/correct_response.php
index 320952692b9..95aaa0161dc 100644
--- a/question/type/ordering/classes/output/correct_response.php
+++ b/question/type/ordering/classes/output/correct_response.php
@@ -17,7 +17,7 @@
namespace qtype_ordering\output;
/**
- * Renderable class for the description of the correct response to a given question attempt.
+ * Create an array for the correct response based on the question and current step state.
*
* @package qtype_ordering
* @copyright 2023 Mihail Geshoski
@@ -26,7 +26,7 @@ namespace qtype_ordering\output;
class correct_response extends renderable_base {
/**
- * Export the data for the mustache template.
+ * Based on the question and step state, create an array for the correct response.
*
* @param \renderer_base $output renderer to be used to render the action bar elements.
* @return array
diff --git a/question/type/ordering/classes/output/feedback.php b/question/type/ordering/classes/output/feedback.php
index fadaab96d1c..759452ec4e2 100644
--- a/question/type/ordering/classes/output/feedback.php
+++ b/question/type/ordering/classes/output/feedback.php
@@ -21,7 +21,7 @@ use question_attempt;
use question_display_options;
/**
- * Renderable class for the displaying the feedback.
+ * Collate various sections of displayable feedback for render.
*
* @package qtype_ordering
* @copyright 2023 Mathew May
@@ -33,7 +33,7 @@ class feedback extends renderable_base {
protected $options;
/**
- * The class constructor.
+ * Define the feedback with options for display.
*
* @param question_attempt $qa The question attempt object.
* @param question_display_options $options Controls what should and should not be displayed
@@ -45,7 +45,7 @@ class feedback extends renderable_base {
}
/**
- * Export the data for the mustache template.
+ * Build the feedback array which is used to render the feedback.
*
* @param renderer_base $output renderer to be used to render the feedback elements.
* @return array
diff --git a/question/type/ordering/classes/output/formulation_and_controls.php b/question/type/ordering/classes/output/formulation_and_controls.php
index 51f5383bc1c..b09d76b8970 100644
--- a/question/type/ordering/classes/output/formulation_and_controls.php
+++ b/question/type/ordering/classes/output/formulation_and_controls.php
@@ -20,7 +20,7 @@ use question_attempt;
use question_display_options;
/**
- * Renderable class for the displaying the formulation and controls of the question.
+ * Create the question formulation, controls ready for output.
*
* @package qtype_ordering
* @copyright 2023 Ilya Tregubov
@@ -32,7 +32,7 @@ class formulation_and_controls extends renderable_base {
protected $options;
/**
- * The class constructor.
+ * Construct the rendarable as we also need to pass the question options.
*
* @param question_attempt $qa The question attempt object.
* @param question_display_options $options The question options.
@@ -43,7 +43,7 @@ class formulation_and_controls extends renderable_base {
}
/**
- * Export the data for the mustache template.
+ * Export the question based on the question attempt and the question display options.
*
* @param \renderer_base $output renderer to be used to render the action bar elements.
* @return array
diff --git a/question/type/ordering/classes/output/num_parts_correct.php b/question/type/ordering/classes/output/num_parts_correct.php
index fed72dcf8e0..854c534d01f 100644
--- a/question/type/ordering/classes/output/num_parts_correct.php
+++ b/question/type/ordering/classes/output/num_parts_correct.php
@@ -17,7 +17,7 @@
namespace qtype_ordering\output;
/**
- * Renderable class for the statement of how many sub-parts of the question the student got correct|partial|incorrect.
+ * Generate the number of correct, partial, and incorrect parts of the question ready for output
*
* @package qtype_ordering
* @copyright 2023 Ilya Tregubov
@@ -26,7 +26,7 @@ namespace qtype_ordering\output;
class num_parts_correct extends renderable_base {
/**
- * Export the data for the mustache template.
+ * Based on the latest step, get the number of correct, partial, and incorrect parts of the question.
*
* @param \renderer_base $output The output renderer.
* @return array
diff --git a/question/type/ordering/classes/output/specific_grade_detail_feedback.php b/question/type/ordering/classes/output/specific_grade_detail_feedback.php
index 81f27d0641b..55662f91c7a 100644
--- a/question/type/ordering/classes/output/specific_grade_detail_feedback.php
+++ b/question/type/ordering/classes/output/specific_grade_detail_feedback.php
@@ -19,7 +19,7 @@ namespace qtype_ordering\output;
use qtype_ordering_question;
/**
- * Renderable class for the displaying the grade detail of the response.
+ * Generate the grade feedback when the grading should be shown.
*
* @package qtype_ordering
* @copyright 2023 Ilya Tregubov
@@ -28,7 +28,7 @@ use qtype_ordering_question;
class specific_grade_detail_feedback extends renderable_base {
/**
- * Export the data for the mustache template.
+ * Based on the current state and the question options, generate the feedback.
*
* @param \renderer_base $output renderer to be used to render the action bar elements.
* @return array
diff --git a/question/type/ordering/edit_ordering_form.php b/question/type/ordering/edit_ordering_form.php
index 1d16b7e39df..f5e6570c35a 100644
--- a/question/type/ordering/edit_ordering_form.php
+++ b/question/type/ordering/edit_ordering_form.php
@@ -26,7 +26,6 @@ require_once($CFG->dirroot.'/question/type/ordering/question.php');
* @package qtype_ordering
* @copyright 2013 Gordon Bateson (gordon.bateson@gmail.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @codeCoverageIgnore Edit form is covered via behat and mocked in units.
*/
class qtype_ordering_edit_form extends question_edit_form {
@@ -92,7 +91,6 @@ class qtype_ordering_edit_form extends question_edit_form {
// Field for selectcount.
$name = 'selectcount';
$label = get_string($name, $plugin);
-
$mform->addElement('text', $name, $label, ['size' => 2]);
$mform->setDefault($name, qtype_ordering_question::MIN_SUBSET_ITEMS);
$mform->setType($name, PARAM_INT);
@@ -117,6 +115,7 @@ class qtype_ordering_edit_form extends question_edit_form {
$mform->addHelpButton($name, $name, $plugin);
$mform->setDefault($name, $this->get_default_value($name, 1));
+ // Field for numberingstyle.
$name = 'numberingstyle';
$label = get_string($name, $plugin);
$options = qtype_ordering_question::get_numbering_styles();
@@ -124,19 +123,18 @@ class qtype_ordering_edit_form extends question_edit_form {
$mform->addHelpButton($name, $name, $plugin);
$mform->setDefault($name, $this->get_default_value($name, qtype_ordering_question::NUMBERING_STYLE_DEFAULT));
- $elements = [];
- $options = [];
-
$mform->addElement('header', 'answersheader', get_string('draggableitems', $plugin));
$mform->setExpanded('answersheader', true);
+ // Field for the answers.
+ $elements = [];
+ $options = [];
$name = 'answer';
$elements[] = $mform->createElement('editor', $name, get_string('draggableitemno', $plugin),
$this->get_editor_attributes(), $this->get_editor_options());
$elements[] = $mform->createElement('submit', $name . 'removeeditor', get_string('removeeditor', $plugin),
['onclick' => 'skipClientValidation = true;']);
$options[$name] = ['type' => PARAM_RAW];
-
$this->add_repeat_elements($mform, $name, $elements, $options);
// Adjust HTML editor and removal buttons.
@@ -467,17 +465,6 @@ class qtype_ordering_edit_form extends question_edit_form {
return $errors;
}
- /**
- * Given a preference item name, returns the full
- * preference name of that item for this plugin
- *
- * @param string $name Item name
- * @return string full preference name
- */
- protected function get_my_preference_name(string $name): string {
- return $this->plugin_name()."_$name";
- }
-
/**
* Get array of countable item types
*
diff --git a/question/type/ordering/question.php b/question/type/ordering/question.php
index 9b1adf5ec01..2b8944be5a2 100644
--- a/question/type/ordering/question.php
+++ b/question/type/ordering/question.php
@@ -570,7 +570,7 @@ class qtype_ordering_question extends question_graded_automatically {
}
/**
- * Convert response data from mform into array
+ * Unpack the students' response into an array which updates the question currentresponse.
*
* @param array $response Form data
*/
@@ -586,6 +586,7 @@ class qtype_ordering_question extends question_graded_automatically {
}
}
}
+ // Note: TH mentions that this is a bit of a hack.
$this->currentresponse = $ids;
}
}
diff --git a/question/type/ordering/questiontype.php b/question/type/ordering/questiontype.php
index 512b1619a6e..11a1e02e3a7 100644
--- a/question/type/ordering/questiontype.php
+++ b/question/type/ordering/questiontype.php
@@ -721,9 +721,6 @@ class qtype_ordering extends question_type {
$newquestion = $format->import_headers($data);
$newquestion->qtype = $questiontype;
- // Fix empty or long question name.
- $newquestion->name = $this->fix_questionname($newquestion->name, $newquestion->questiontext);
-
// Extra fields - "selecttype" and "selectcount"
// (these fields used to be called "logical" and "studentsee").
if (isset($data['#']['selecttype'])) {
@@ -784,33 +781,6 @@ class qtype_ordering extends question_type {
return $newquestion;
}
- /**
- * Fix empty or long question name
- *
- * @param string $name The name of the question
- * @param string|null $defaultname (optional, default='') The default name of the question
- * @param int|null $maxnamelength (optional, default=42) The maximum length of the name
- * @return string Fixed name
- * @throws coding_exception
- */
- public function fix_questionname(string $name, ?string $defaultname = '', ?int $maxnamelength = 42): string {
- if (trim($name) == '') {
- if ($defaultname) {
- $name = $defaultname;
- } else {
- $name = get_string('defaultquestionname', 'qtype_ordering');
- }
- }
- if (strlen($name) > $maxnamelength) {
- $name = substr($name, 0, $maxnamelength);
- if ($pos = strrpos($name, ' ')) {
- $name = substr($name, 0, $pos);
- }
- $name .= ' ...';
- }
- return $name;
- }
-
/**
* Set layouttype, selecttype, selectcount, gradingtype, showgrading based on their textual representation
*