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 *