diff --git a/question/type/ordering/amd/build/drag_reorder.min.js b/question/type/ordering/amd/build/drag_reorder.min.js index 4db721a7b5f..4edaec785ec 100644 --- a/question/type/ordering/amd/build/drag_reorder.min.js +++ b/question/type/ordering/amd/build/drag_reorder.min.js @@ -1,3 +1,3 @@ -define("qtype_ordering/drag_reorder",["exports","jquery","core/dragdrop","core/key_codes","core/templates","core/notification"],(function(_exports,_jquery,_dragdrop,_key_codes,_templates,_notification){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_jquery=_interopRequireDefault(_jquery),_dragdrop=_interopRequireDefault(_dragdrop),_key_codes=_interopRequireDefault(_key_codes),_templates=_interopRequireDefault(_templates),_notification=_interopRequireDefault(_notification);class DragReorder{constructor(config){_defineProperty(this,"config",{reorderStart:void 0,reorderEnd:void 0}),_defineProperty(this,"dragStart",null),_defineProperty(this,"originalOrder",null),_defineProperty(this,"orderList",null),_defineProperty(this,"itemDragging",null),_defineProperty(this,"proxy",null),this.config=config,this.orderList=document.querySelector(this.config.list),this.startListeners(),(0,_jquery.default)(this.combineSelectors(config.list,config.item)).attr("tabindex","0")}startListeners(){const pointerHandle=e=>{if(e.target.closest(this.config.item)&&!e.target.closest(this.config.actionButton)){this.itemDragging=(0,_jquery.default)(e.target.closest(this.config.item));const details=_dragdrop.default.prepare(e);details.start&&this.startDrag(e,details)}};this.orderList.addEventListener("mousedown",pointerHandle),this.orderList.addEventListener("touchstart",pointerHandle),this.orderList.addEventListener("keydown",this.itemMovedByKeyboard.bind(this)),this.orderList.addEventListener("click",this.itemMovedByClick.bind(this))}startDrag(e,details){this.dragStart={time:(new Date).getTime(),x:details.x,y:details.y},void 0!==this.config.reorderStart&&this.config.reorderStart(this.itemDragging.closest(this.config.list),this.itemDragging),this.originalOrder=this.getCurrentOrder(),_templates.default.renderForPromise("qtype_ordering/proxyhtml",{itemHtml:this.itemDragging.html(),itemClassName:this.itemDragging.attr("class"),listClassName:this.orderList.classList.toString(),proxyStyles:["width: ".concat(this.itemDragging.outerWidth(),"px;"),"height: ".concat(this.itemDragging.outerHeight(),"px;")].join(" ")}).then((_ref=>{let{html:html,js:js}=_ref;this.proxy=(0,_jquery.default)(_templates.default.appendNodeContents(document.body,html,js)[0]),this.proxy.css(this.itemDragging.offset()),this.itemDragging.addClass(this.config.itemMovingClass),this.updateProxy(),_dragdrop.default.start(e,this.proxy,this.dragMove.bind(this),this.dragEnd.bind(this))})).catch(_notification.default.exception)}dragMove(){let closestItem=null,closestDistance=null;if(this.orderList.querySelectorAll(this.config.item).forEach((element=>{const distance=this.distanceBetweenElements(element);(null===closestItem||distance{inner.split(",").forEach((secondSelector=>{combined.push(firstSelector.trim()+" "+secondSelector.trim())}))})),combined.join(", ")}midX(node){return node.offset().left+node.outerWidth()/2}midY(node){return node.offset().top+node.outerHeight()/2}distanceBetweenElements(element){const[e1,e2]=[(0,_jquery.default)(element),(0,_jquery.default)(this.proxy)],[dx,dy]=[this.midX(e1)-this.midX(e2),this.midY(e1)-this.midY(e2)];return Math.sqrt(dx*dx+dy*dy)}getCurrentOrder(){return this.itemDragging.closest(this.config.list).find(this.config.item).map(((index,item)=>this.config.idGetter(item))).get()}arrayEquals(a1,a2){return a1.length===a2.length&&a1.every(((v,i)=>v===a2[i]))}static init(sortableid,responseid){new DragReorder({actionButton:"[data-action]",list:"ul#"+sortableid,item:"li.sortableitem",itemMovingClass:"current-drop",idGetter:item=>item.id,reorderDone:(list,item,newOrder)=>{(0,_jquery.default)("input#"+responseid)[0].value=newOrder.join(",")}})}}return _exports.default=DragReorder,_exports.default})); +define("qtype_ordering/drag_reorder",["exports","jquery","core/dragdrop","core/templates","core/notification"],(function(_exports,_jquery,_dragdrop,_templates,_notification){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_jquery=_interopRequireDefault(_jquery),_dragdrop=_interopRequireDefault(_dragdrop),_templates=_interopRequireDefault(_templates),_notification=_interopRequireDefault(_notification);class DragReorder{constructor(config){_defineProperty(this,"config",{reorderStart:void 0,reorderEnd:void 0}),_defineProperty(this,"dragStart",null),_defineProperty(this,"originalOrder",null),_defineProperty(this,"orderList",null),_defineProperty(this,"itemDragging",null),_defineProperty(this,"proxy",null),this.config=config,this.orderList=document.querySelector(this.config.list),this.startListeners()}startListeners(){const pointerHandle=e=>{if(e.target.closest(this.config.item)&&!e.target.closest(this.config.actionButton)){this.itemDragging=(0,_jquery.default)(e.target.closest(this.config.item));const details=_dragdrop.default.prepare(e);details.start&&this.startDrag(e,details)}};this.orderList.addEventListener("mousedown",pointerHandle),this.orderList.addEventListener("touchstart",pointerHandle),this.orderList.addEventListener("click",this.itemMovedByClick.bind(this))}startDrag(e,details){this.dragStart={time:(new Date).getTime(),x:details.x,y:details.y},void 0!==this.config.reorderStart&&this.config.reorderStart(this.itemDragging.closest(this.config.list),this.itemDragging),this.originalOrder=this.getCurrentOrder(),_templates.default.renderForPromise("qtype_ordering/proxyhtml",{itemHtml:this.itemDragging.html(),itemClassName:this.itemDragging.attr("class"),listClassName:this.orderList.classList.toString(),proxyStyles:["width: ".concat(this.itemDragging.outerWidth(),"px;"),"height: ".concat(this.itemDragging.outerHeight(),"px;")].join(" ")}).then((_ref=>{let{html:html,js:js}=_ref;this.proxy=(0,_jquery.default)(_templates.default.appendNodeContents(document.body,html,js)[0]),this.proxy.css(this.itemDragging.offset()),this.itemDragging.addClass(this.config.itemMovingClass),this.updateProxy(),_dragdrop.default.start(e,this.proxy,this.dragMove.bind(this),this.dragEnd.bind(this))})).catch(_notification.default.exception)}dragMove(){let closestItem=null,closestDistance=null;if(this.orderList.querySelectorAll(this.config.item).forEach((element=>{const distance=this.distanceBetweenElements(element);(null===closestItem||distancethis.config.idGetter(item))).get()}arrayEquals(a1,a2){return a1.length===a2.length&&a1.every(((v,i)=>v===a2[i]))}static init(sortableid,responseid){new DragReorder({actionButton:"[data-action]",list:"ul#"+sortableid,item:"li.sortableitem",itemMovingClass:"current-drop",idGetter:item=>item.id,reorderDone:(list,item,newOrder)=>{(0,_jquery.default)("input#"+responseid)[0].value=newOrder.join(",")}})}}return _exports.default=DragReorder,_exports.default})); //# sourceMappingURL=drag_reorder.min.js.map \ No newline at end of file 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 ceaa2c9bc30..c95f8f33737 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 * 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) && !e.target.closest(this.config.actionButton)) {\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 this.orderList.addEventListener('click', this.itemMovedByClick.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.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 * Handles the movement of an item by click.\n *\n * @param {MouseEvent} e The pointer event.\n */\n itemMovedByClick(e) {\n const actionButton = e.target.closest(this.config.actionButton);\n if (actionButton) {\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 (actionButton.dataset.action) {\n case 'move-backward':\n e.preventDefault();\n e.stopPropagation();\n if (this.itemDragging.prev().length) {\n this.itemDragging.prev().insertAfter(this.itemDragging);\n }\n break;\n case 'move-forward':\n e.preventDefault();\n e.stopPropagation();\n if (this.itemDragging.next().length) {\n this.itemDragging.next().insertBefore(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 // When moving an item to the first or last position, the button that was clicked will be hidden.\n // In this case, we need to focus the other button.\n if (!this.itemDragging.prev().length) {\n // Focus the 'next' action button.\n this.itemDragging.find('[data-action=\"move-forward\"]').focus();\n } else if (!this.itemDragging.next().length) {\n // Focus the 'previous' action button.\n this.itemDragging.find('[data-action=\"move-backward\"]').focus();\n }\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 actionButton: '[data-action]',\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","actionButton","itemDragging","details","drag","prepare","start","startDrag","addEventListener","itemMovedByKeyboard","bind","itemMovedByClick","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","arrowRight","arrowDown","preventDefault","stopPropagation","next","arrowLeft","arrowUp","prev","dataset","action","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 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\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) && !e.target.closest(this.config.actionButton)) {\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('click', this.itemMovedByClick.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 dragEnd() {\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 }\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 * Handles the movement of an item by click.\n *\n * @param {MouseEvent} e The pointer event.\n */\n itemMovedByClick(e) {\n const actionButton = e.target.closest(this.config.actionButton);\n if (actionButton) {\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 (actionButton.dataset.action) {\n case 'move-backward':\n e.preventDefault();\n e.stopPropagation();\n if (this.itemDragging.prev().length) {\n this.itemDragging.prev().insertAfter(this.itemDragging);\n }\n break;\n case 'move-forward':\n e.preventDefault();\n e.stopPropagation();\n if (this.itemDragging.next().length) {\n this.itemDragging.next().insertBefore(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 // When moving an item to the first or last position, the button that was clicked will be hidden.\n // In this case, we need to focus the other button.\n if (!this.itemDragging.prev().length) {\n // Focus the 'next' action button.\n this.itemDragging.find('[data-action=\"move-forward\"]').focus();\n } else if (!this.itemDragging.next().length) {\n // Focus the 'previous' action button.\n this.itemDragging.find('[data-action=\"move-backward\"]').focus();\n }\n }\n }\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 actionButton: '[data-action]',\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","pointerHandle","e","target","closest","item","actionButton","itemDragging","details","drag","prepare","start","startDrag","addEventListener","itemMovedByClick","bind","dragStart","time","Date","getTime","x","y","originalOrder","getCurrentOrder","renderForPromise","itemHtml","html","itemClassName","attr","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","reorderDone","remove","removeClass","dataset","action","preventDefault","stopPropagation","prev","next","focus","midX","node","left","top","e1","e2","dx","dy","Math","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 b2a39dae261..d4ab6278fd2 100644 --- a/question/type/ordering/amd/src/drag_reorder.js +++ b/question/type/ordering/amd/src/drag_reorder.js @@ -26,7 +26,6 @@ import $ from 'jquery'; import drag from 'core/dragdrop'; -import keys from 'core/key_codes'; import Templates from 'core/templates'; import Notification from 'core/notification'; @@ -101,10 +100,6 @@ export default class DragReorder { this.orderList = document.querySelector(this.config.list); this.startListeners(); - - // Make the items tabbable. - // TODO: This can be removed once we move to templates and add the tabindex there. - $(this.combineSelectors(config.list, config.item)).attr('tabindex', '0'); } /** @@ -128,7 +123,6 @@ export default class DragReorder { // Set up the list listeners for moving list items around. this.orderList.addEventListener('mousedown', pointerHandle); this.orderList.addEventListener('touchstart', pointerHandle); - this.orderList.addEventListener('keydown', this.itemMovedByKeyboard.bind(this)); this.orderList.addEventListener('click', this.itemMovedByClick.bind(this)); } @@ -214,11 +208,8 @@ export default class DragReorder { /** * End dragging. - * - * @param {number} x X co-ordinate - * @param {number} y Y co-ordinate */ - dragEnd(x, y) { + dragEnd() { if (typeof this.config.reorderEnd !== 'undefined') { this.config.reorderEnd(this.itemDragging.closest(this.config.list), this.itemDragging); } @@ -227,10 +218,6 @@ export default class DragReorder { // Order has changed, call the callback. this.config.reorderDone(this.itemDragging.closest(this.config.list), this.itemDragging, this.getCurrentOrder()); - } else if (new Date().getTime() - this.dragStart.time < 500 && - Math.abs(this.dragStart.x - x) < 10 && Math.abs(this.dragStart.y - y) < 10) { - // This was really a click. Set the focus on the current item. - this.itemDragging[0].focus(); } // Clean up after the drag is finished. @@ -241,49 +228,6 @@ export default class DragReorder { this.dragStart = null; } - /** - * Items can be moved and placed using certain keys. - * Tab for tabbing though and choose the item to be moved - * space, arrow-right arrow-down for moving current element forwards. - * arrow-right arrow-down for moving the current element backwards. - * - * @param {Event} e The keyboard event. - */ - itemMovedByKeyboard(e) { - if (e.target.closest(this.config.item)) { - this.itemDragging = $(e.target.closest(this.config.item)); - - // Store the current state of the list. - this.originalOrder = this.getCurrentOrder(); - - switch (e.keyCode) { - case keys.arrowRight: - case keys.arrowDown: - e.preventDefault(); - e.stopPropagation(); - if (this.itemDragging.next().length) { - this.itemDragging.next().insertBefore(this.itemDragging); - } - break; - - case keys.arrowLeft: - case keys.arrowUp: - e.preventDefault(); - e.stopPropagation(); - if (this.itemDragging.prev().length) { - this.itemDragging.prev().insertAfter(this.itemDragging); - } - break; - } - - // After we have potentially moved the item, we need to check if the order has changed. - if (!this.arrayEquals(this.originalOrder, this.getCurrentOrder())) { - // Order has changed, call the callback. - this.config.reorderDone(this.itemDragging.closest(this.config.list), this.itemDragging, this.getCurrentOrder()); - } - } - } - /** * Handles the movement of an item by click. * @@ -332,26 +276,6 @@ export default class DragReorder { } } - /** - * TODO: Once the tabindex is added to the template, this can be removed. - * Our outer and inner are two CSS selectors, which may contain commas. - * We want to combine them safely. So for instance combineSelectors('a, b', 'c, d') - * gives 'a c, a d, b c, b d'. - * - * @param {String} outer The selector for the outer element. - * @param {String} inner The selector for the inner element. - * @returns {String} The combined selector used to listen to the list item. - */ - combineSelectors(outer, inner) { - let combined = []; - outer.split(',').forEach(firstSelector => { - inner.split(',').forEach(secondSelector => { - combined.push(firstSelector.trim() + ' ' + secondSelector.trim()); - }); - }); - return combined.join(', '); - } - /** * Get the x-position of the middle of the DOM node represented by the given jQuery object. * diff --git a/question/type/ordering/styles.css b/question/type/ordering/styles.css index d1f157a83b7..f44a8267d86 100644 --- a/question/type/ordering/styles.css +++ b/question/type/ordering/styles.css @@ -32,10 +32,6 @@ cursor: move; margin-left: 26px; /* The margin is needed for the list-style-type in numberingxxx classes */ } -.que.ordering .sortablelist li.sortableitem:focus { - border-color: #0a0; - box-shadow: 0 0 5px 5px rgba(255, 255, 150, 1); -} .que.ordering .sortablelist li.sortableitem:first-of-type [data-action="move-backward"], .que.ordering .sortablelist li.sortableitem:last-of-type [data-action="move-forward"] {