From 94de1567c3848088fbcec3d21ab2ecb25161c1fb Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Wed, 20 Sep 2023 11:01:34 +0800 Subject: [PATCH] MDL-74054 qbank_columnsortorder: Move away from ModalFactory --- .../columnsortorder/amd/build/user_actions.min.js | 4 ++-- .../amd/build/user_actions.min.js.map | 2 +- .../bank/columnsortorder/amd/src/user_actions.js | 14 ++++++-------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/question/bank/columnsortorder/amd/build/user_actions.min.js b/question/bank/columnsortorder/amd/build/user_actions.min.js index 11a3626de08..4228e27cc9f 100644 --- a/question/bank/columnsortorder/amd/build/user_actions.min.js +++ b/question/bank/columnsortorder/amd/build/user_actions.min.js @@ -1,4 +1,4 @@ -define("qbank_columnsortorder/user_actions",["exports","qbank_columnsortorder/actions","qbank_columnsortorder/repository","core/str","core/modal_events","core/modal_factory","core/notification","core/sortable_list","core/templates"],(function(_exports,actions,repository,_str,_modal_events,_modal_factory,_notification,_sortable_list,_templates){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj} +define("qbank_columnsortorder/user_actions",["exports","qbank_columnsortorder/actions","qbank_columnsortorder/repository","core/str","core/modal_events","core/modal_save_cancel","core/notification","core/sortable_list","core/templates"],(function(_exports,actions,repository,_str,_modal_events,_modal_save_cancel,_notification,_sortable_list,_templates){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj} /** * Javascript for customising the user's view of the question bank * @@ -6,6 +6,6 @@ define("qbank_columnsortorder/user_actions",["exports","qbank_columnsortorder/ac * @copyright 2021 Catalyst IT Australia Pty Ltd * @author Ghaly Marc-Alexandre * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,actions=_interopRequireWildcard(actions),repository=_interopRequireWildcard(repository),_modal_events=_interopRequireDefault(_modal_events),_modal_factory=_interopRequireDefault(_modal_factory),_notification=_interopRequireDefault(_notification),_sortable_list=_interopRequireDefault(_sortable_list),_templates=_interopRequireDefault(_templates);const SELECTORS_uiRoot=".questionbankwindow",SELECTORS_moveAction=".menu-action[data-action=move]",SELECTORS_resizeAction=".menu-action[data-action=resize]",SELECTORS_resizeHandle=".qbank_columnsortorder-action-handle.resize",SELECTORS_handleContainer=".handle-container",SELECTORS_headerContainer=".header-container",SELECTORS_tableColumn=identifier=>'td[data-columnid="'.concat(identifier.replace(/["\\]/g,"\\$&"),'"]');let currentHeader,currentX,suspendShowHideHandles=!1;const serialiseColumnSizes=uiRoot=>{const columnSizes=[];return uiRoot.querySelectorAll("th").forEach((header=>{const width=parseInt(header.style.width);width&&!isNaN(width)&&columnSizes.push({column:header.dataset.columnid,width:width})})),JSON.stringify(columnSizes)},showResizeModal=async(currentHeader,uiRoot)=>{const initialWidth=currentHeader.offsetWidth,modal=await _modal_factory.default.create({title:(0,_str.get_string)("resizecolumn","qbank_columnsortorder",currentHeader.textContent),type:_modal_factory.default.types.SAVE_CANCEL,body:_templates.default.render("qbank_columnsortorder/resize_modal",{})}),root=modal.getRoot();root.on(_modal_events.default.cancel,(()=>{currentHeader.style.width=initialWidth+"px"})),root.on(_modal_events.default.save,(()=>{repository.setColumnSize(serialiseColumnSizes(uiRoot)).catch(_notification.default.exception)})),modal.show();const input=(await modal.bodyPromise).get(0).querySelector("input");input.value=initialWidth,input.addEventListener("change",(e=>{const newWidth=e.target.value;currentHeader.style.width=newWidth+"px"}))},reorderColumns=event=>{const header=event.target,insertAfter=header.previousElementSibling;document.querySelector(SELECTORS_uiRoot).querySelectorAll(SELECTORS_tableColumn(header.dataset.columnid)).forEach((column=>{const row=column.parentElement;if(insertAfter){row.querySelector(SELECTORS_tableColumn(insertAfter.dataset.columnid)).after(column)}else row.insertBefore(column,row.firstChild)}))};_exports.init=async()=>{const uiRoot=document.getElementById("questionscontainer");await(uiRoot=>new Promise((resolve=>{const headerContainers=uiRoot.querySelectorAll(SELECTORS_headerContainer);_templates.default.renderForPromise("qbank_columnsortorder/handle_container",{}).then((_ref=>{let{html:html,js:js}=_ref;return headerContainers.forEach((container=>{_templates.default.prependNodeContents(container,html,js)})),resolve(),headerContainers})).catch(_notification.default.exception)})))(uiRoot),uiRoot.querySelectorAll(SELECTORS_moveAction).forEach((moveAction=>{const header=moveAction.closest("th");header.classList.add("qbank-sortable-column");const handleContainer=header.querySelector(SELECTORS_handleContainer),context={action:"move",dragtype:"move",target:"",title:moveAction.title,pixicon:"i/dragdrop",pixcomponent:"core",popup:!0};return _templates.default.renderForPromise("qbank_columnsortorder/action_handle",context).then((_ref2=>{let{html:html,js:js}=_ref2;return _templates.default.prependNodeContents(handleContainer,html,js),handleContainer})).catch(_notification.default.exception)})),(uiRoot=>{uiRoot.querySelectorAll(SELECTORS_resizeAction).forEach((resizeAction=>{const handleContainer=resizeAction.closest(SELECTORS_headerContainer).querySelector(SELECTORS_handleContainer),context={action:"resize",target:"",title:resizeAction.title,pixicon:"i/twoway",pixcomponent:"core",popup:!0};return _templates.default.renderForPromise("qbank_columnsortorder/action_handle",context).then((_ref3=>{let{html:html,js:js}=_ref3;return _templates.default.appendNodeContents(handleContainer,html,js),handleContainer})).catch(_notification.default.exception)}));let moveTracker=!1,currentResizeHandle=null;uiRoot.addEventListener("mousedown",(e=>{currentResizeHandle=e.target.closest(SELECTORS_resizeHandle),currentResizeHandle&&(currentX=e.pageX,currentHeader=e.target.closest(actions.SELECTORS.sortableColumn),moveTracker=!1,suspendShowHideHandles=!0)})),document.addEventListener("mousemove",(e=>{if(!currentHeader||!currentResizeHandle||0===currentX)return;document.getSelection().removeAllRanges();const offset=e.pageX-currentX;currentX=e.pageX;const newWidth=currentHeader.offsetWidth+offset;currentHeader.style.width=newWidth+"px",moveTracker=!0})),document.addEventListener("mouseup",(()=>{currentHeader&¤tResizeHandle&&0!==currentX&&(moveTracker?repository.setColumnSize(serialiseColumnSizes(uiRoot)).catch(_notification.default.exception):showResizeModal(currentHeader,uiRoot),currentHeader=null,currentResizeHandle=null,currentX=0,moveTracker=!1,suspendShowHideHandles=!1)}))})(uiRoot),(uiRoot=>{let shownHeader=null,tableHead=uiRoot.querySelector("thead");uiRoot.addEventListener("mouseover",(e=>{if(suspendShowHideHandles)return;const header=e.target.closest(actions.SELECTORS.sortableColumn);var _tableHead$querySelec;(header||shownHeader)&&(header&&header===shownHeader||(null===(_tableHead$querySelec=tableHead.querySelector(".show-handles"))||void 0===_tableHead$querySelec||_tableHead$querySelec.classList.remove("show-handles"),shownHeader=header,header&&header.classList.add("show-handles")))}))})(uiRoot);const sortableColumns=actions.setupSortableLists(uiRoot.querySelector(actions.SELECTORS.columnList));sortableColumns.on(_sortable_list.default.EVENTS.DROP,reorderColumns),sortableColumns.on(_sortable_list.default.EVENTS.DRAGSTART,(()=>{suspendShowHideHandles=!0})),sortableColumns.on(_sortable_list.default.EVENTS.DRAGEND,(()=>{suspendShowHideHandles=!1})),(uiRoot=>{uiRoot.addEventListener("click",(e=>{const moveAction=e.target.closest(SELECTORS_moveAction);moveAction&&(e.preventDefault(),moveAction.closest(actions.SELECTORS.sortableColumn).querySelector(actions.SELECTORS.moveHandler).click())}))})(uiRoot),(uiRoot=>{uiRoot.addEventListener("click",(e=>{const resizeAction=e.target.closest(SELECTORS_resizeAction);if(resizeAction){e.preventDefault();const currentHeader=resizeAction.closest("th");showResizeModal(currentHeader,uiRoot)}}))})(uiRoot),actions.setupActionButtons(uiRoot)}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,actions=_interopRequireWildcard(actions),repository=_interopRequireWildcard(repository),_modal_events=_interopRequireDefault(_modal_events),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_notification=_interopRequireDefault(_notification),_sortable_list=_interopRequireDefault(_sortable_list),_templates=_interopRequireDefault(_templates);const SELECTORS_uiRoot=".questionbankwindow",SELECTORS_moveAction=".menu-action[data-action=move]",SELECTORS_resizeAction=".menu-action[data-action=resize]",SELECTORS_resizeHandle=".qbank_columnsortorder-action-handle.resize",SELECTORS_handleContainer=".handle-container",SELECTORS_headerContainer=".header-container",SELECTORS_tableColumn=identifier=>'td[data-columnid="'.concat(identifier.replace(/["\\]/g,"\\$&"),'"]');let currentHeader,currentX,suspendShowHideHandles=!1;const serialiseColumnSizes=uiRoot=>{const columnSizes=[];return uiRoot.querySelectorAll("th").forEach((header=>{const width=parseInt(header.style.width);width&&!isNaN(width)&&columnSizes.push({column:header.dataset.columnid,width:width})})),JSON.stringify(columnSizes)},showResizeModal=async(currentHeader,uiRoot)=>{const initialWidth=currentHeader.offsetWidth,modal=await _modal_save_cancel.default.create({title:(0,_str.get_string)("resizecolumn","qbank_columnsortorder",currentHeader.textContent),body:_templates.default.render("qbank_columnsortorder/resize_modal",{}),show:!0}),root=modal.getRoot();root.on(_modal_events.default.cancel,(()=>{currentHeader.style.width="".concat(initialWidth,"px")})),root.on(_modal_events.default.save,(()=>{repository.setColumnSize(serialiseColumnSizes(uiRoot)).catch(_notification.default.exception)}));const input=(await modal.bodyPromise).get(0).querySelector("input");input.value=initialWidth,input.addEventListener("change",(e=>{const newWidth=e.target.value;currentHeader.style.width="".concat(newWidth,"px")}))},reorderColumns=event=>{const header=event.target,insertAfter=header.previousElementSibling;document.querySelector(SELECTORS_uiRoot).querySelectorAll(SELECTORS_tableColumn(header.dataset.columnid)).forEach((column=>{const row=column.parentElement;if(insertAfter){row.querySelector(SELECTORS_tableColumn(insertAfter.dataset.columnid)).after(column)}else row.insertBefore(column,row.firstChild)}))};_exports.init=async()=>{const uiRoot=document.getElementById("questionscontainer");await(uiRoot=>new Promise((resolve=>{const headerContainers=uiRoot.querySelectorAll(SELECTORS_headerContainer);_templates.default.renderForPromise("qbank_columnsortorder/handle_container",{}).then((_ref=>{let{html:html,js:js}=_ref;return headerContainers.forEach((container=>{_templates.default.prependNodeContents(container,html,js)})),resolve(),headerContainers})).catch(_notification.default.exception)})))(uiRoot),uiRoot.querySelectorAll(SELECTORS_moveAction).forEach((moveAction=>{const header=moveAction.closest("th");header.classList.add("qbank-sortable-column");const handleContainer=header.querySelector(SELECTORS_handleContainer),context={action:"move",dragtype:"move",target:"",title:moveAction.title,pixicon:"i/dragdrop",pixcomponent:"core",popup:!0};return _templates.default.renderForPromise("qbank_columnsortorder/action_handle",context).then((_ref2=>{let{html:html,js:js}=_ref2;return _templates.default.prependNodeContents(handleContainer,html,js),handleContainer})).catch(_notification.default.exception)})),(uiRoot=>{uiRoot.querySelectorAll(SELECTORS_resizeAction).forEach((resizeAction=>{const handleContainer=resizeAction.closest(SELECTORS_headerContainer).querySelector(SELECTORS_handleContainer),context={action:"resize",target:"",title:resizeAction.title,pixicon:"i/twoway",pixcomponent:"core",popup:!0};return _templates.default.renderForPromise("qbank_columnsortorder/action_handle",context).then((_ref3=>{let{html:html,js:js}=_ref3;return _templates.default.appendNodeContents(handleContainer,html,js),handleContainer})).catch(_notification.default.exception)}));let moveTracker=!1,currentResizeHandle=null;uiRoot.addEventListener("mousedown",(e=>{currentResizeHandle=e.target.closest(SELECTORS_resizeHandle),currentResizeHandle&&(currentX=e.pageX,currentHeader=e.target.closest(actions.SELECTORS.sortableColumn),moveTracker=!1,suspendShowHideHandles=!0)})),document.addEventListener("mousemove",(e=>{if(!currentHeader||!currentResizeHandle||0===currentX)return;document.getSelection().removeAllRanges();const offset=e.pageX-currentX;currentX=e.pageX;const newWidth=currentHeader.offsetWidth+offset;currentHeader.style.width=newWidth+"px",moveTracker=!0})),document.addEventListener("mouseup",(()=>{currentHeader&¤tResizeHandle&&0!==currentX&&(moveTracker?repository.setColumnSize(serialiseColumnSizes(uiRoot)).catch(_notification.default.exception):showResizeModal(currentHeader,uiRoot),currentHeader=null,currentResizeHandle=null,currentX=0,moveTracker=!1,suspendShowHideHandles=!1)}))})(uiRoot),(uiRoot=>{let shownHeader=null,tableHead=uiRoot.querySelector("thead");uiRoot.addEventListener("mouseover",(e=>{if(suspendShowHideHandles)return;const header=e.target.closest(actions.SELECTORS.sortableColumn);var _tableHead$querySelec;(header||shownHeader)&&(header&&header===shownHeader||(null===(_tableHead$querySelec=tableHead.querySelector(".show-handles"))||void 0===_tableHead$querySelec||_tableHead$querySelec.classList.remove("show-handles"),shownHeader=header,header&&header.classList.add("show-handles")))}))})(uiRoot);const sortableColumns=actions.setupSortableLists(uiRoot.querySelector(actions.SELECTORS.columnList));sortableColumns.on(_sortable_list.default.EVENTS.DROP,reorderColumns),sortableColumns.on(_sortable_list.default.EVENTS.DRAGSTART,(()=>{suspendShowHideHandles=!0})),sortableColumns.on(_sortable_list.default.EVENTS.DRAGEND,(()=>{suspendShowHideHandles=!1})),(uiRoot=>{uiRoot.addEventListener("click",(e=>{const moveAction=e.target.closest(SELECTORS_moveAction);moveAction&&(e.preventDefault(),moveAction.closest(actions.SELECTORS.sortableColumn).querySelector(actions.SELECTORS.moveHandler).click())}))})(uiRoot),(uiRoot=>{uiRoot.addEventListener("click",(e=>{const resizeAction=e.target.closest(SELECTORS_resizeAction);if(resizeAction){e.preventDefault();const currentHeader=resizeAction.closest("th");showResizeModal(currentHeader,uiRoot)}}))})(uiRoot),actions.setupActionButtons(uiRoot)}})); //# sourceMappingURL=user_actions.min.js.map \ No newline at end of file diff --git a/question/bank/columnsortorder/amd/build/user_actions.min.js.map b/question/bank/columnsortorder/amd/build/user_actions.min.js.map index 855d6778285..322d868ff7b 100644 --- a/question/bank/columnsortorder/amd/build/user_actions.min.js.map +++ b/question/bank/columnsortorder/amd/build/user_actions.min.js.map @@ -1 +1 @@ -{"version":3,"file":"user_actions.min.js","sources":["../src/user_actions.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 * Javascript for customising the user's view of the question bank\n *\n * @module qbank_columnsortorder/user_actions\n * @copyright 2021 Catalyst IT Australia Pty Ltd\n * @author Ghaly Marc-Alexandre \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as actions from 'qbank_columnsortorder/actions';\nimport * as repository from 'qbank_columnsortorder/repository';\nimport {get_string as getString} from 'core/str';\nimport ModalEvents from 'core/modal_events';\nimport ModalFactory from 'core/modal_factory';\nimport Notification from \"core/notification\";\nimport SortableList from 'core/sortable_list';\nimport Templates from \"core/templates\";\n\n\nconst SELECTORS = {\n uiRoot: '.questionbankwindow',\n moveAction: '.menu-action[data-action=move]',\n resizeAction: '.menu-action[data-action=resize]',\n resizeHandle: '.qbank_columnsortorder-action-handle.resize',\n handleContainer: '.handle-container',\n headerContainer: '.header-container',\n tableColumn: identifier => `td[data-columnid=\"${identifier.replace(/[\"\\\\]/g, '\\\\$&')}\"]`,\n};\n\n/** To track mouse event on a table header */\nlet currentHeader;\n\n/** Current mouse x postion, to track mouse event on a table header */\nlet currentX;\n\n/**\n * Flag to temporarily prevent move and resize handles from being shown or hidden.\n *\n * @type {boolean}\n */\nlet suspendShowHideHandles = false;\n\n/**\n * Add handle containers for move and resize handles.\n *\n * @param {Element} uiRoot The root element of the quesiton bank UI.\n * @return {Promise} Resolved after the containers have been added to each column header.\n */\nconst addHandleContainers = uiRoot => {\n return new Promise((resolve) => {\n const headerContainers = uiRoot.querySelectorAll(SELECTORS.headerContainer);\n Templates.renderForPromise('qbank_columnsortorder/handle_container', {})\n .then(({html, js}) => {\n headerContainers.forEach(container => {\n Templates.prependNodeContents(container, html, js);\n });\n resolve();\n return headerContainers;\n }).catch(Notification.exception);\n });\n};\n\n/**\n * Render move handles in each container.\n *\n * This takes a list of the move actions rendered in each column header, and creates a corresponding drag handle for each.\n *\n * @param {NodeList} moveActions Menu actions for moving columns.\n */\nconst setUpMoveHandles = moveActions => {\n moveActions.forEach(moveAction => {\n const header = moveAction.closest('th');\n header.classList.add('qbank-sortable-column');\n const handleContainer = header.querySelector(SELECTORS.handleContainer);\n const context = {\n action: \"move\",\n dragtype: \"move\",\n target: '',\n title: moveAction.title,\n pixicon: \"i/dragdrop\",\n pixcomponent: \"core\",\n popup: true\n };\n return Templates.renderForPromise('qbank_columnsortorder/action_handle', context)\n .then(({html, js}) => {\n Templates.prependNodeContents(handleContainer, html, js);\n return handleContainer;\n }).catch(Notification.exception);\n });\n};\n\n/**\n * Serialise the current column sizes.\n *\n * This finds the current width set in each column header's style property, and returns them encoded as a JSON string.\n *\n * @param {Element} uiRoot The root element of the quesiton bank UI.\n * @return {String} JSON array containing a list of objects with column and width properties.\n */\nconst serialiseColumnSizes = (uiRoot) => {\n const columnSizes = [];\n const tableHeaders = uiRoot.querySelectorAll('th');\n tableHeaders.forEach(header => {\n // Only get the width set via style attribute (set by move action).\n const width = parseInt(header.style.width);\n if (!width || isNaN(width)) {\n return;\n }\n columnSizes.push({\n column: header.dataset.columnid,\n width: width\n });\n });\n return JSON.stringify(columnSizes);\n};\n\n/**\n * Render resize handles in each container.\n *\n * This takes a list of the resize actions rendered in each column header, and creates a corresponding drag handle for each.\n * It also initialises the event handlers for the drag handles and resize modal.\n *\n * @param {Element} uiRoot Question bank UI root element.\n */\nconst setUpResizeHandles = (uiRoot) => {\n const resizeActions = uiRoot.querySelectorAll(SELECTORS.resizeAction);\n resizeActions.forEach(resizeAction => {\n const headerContainer = resizeAction.closest(SELECTORS.headerContainer);\n const handleContainer = headerContainer.querySelector(SELECTORS.handleContainer);\n const context = {\n action: \"resize\",\n target: '',\n title: resizeAction.title,\n pixicon: 'i/twoway',\n pixcomponent: 'core',\n popup: true\n };\n return Templates.renderForPromise('qbank_columnsortorder/action_handle', context)\n .then(({html, js}) => {\n Templates.appendNodeContents(handleContainer, html, js);\n return handleContainer;\n }).catch(Notification.exception);\n });\n\n let moveTracker = false;\n let currentResizeHandle = null;\n // Start mouse event on headers.\n uiRoot.addEventListener('mousedown', e => {\n currentResizeHandle = e.target.closest(SELECTORS.resizeHandle);\n // Return if it is not ' resize' button.\n if (!currentResizeHandle) {\n return;\n }\n // Save current position.\n currentX = e.pageX;\n // Find the header.\n currentHeader = e.target.closest(actions.SELECTORS.sortableColumn);\n moveTracker = false;\n suspendShowHideHandles = true;\n });\n\n // Resize column as the mouse move.\n document.addEventListener('mousemove', e => {\n if (!currentHeader || !currentResizeHandle || currentX === 0) {\n return;\n }\n\n // Prevent text selection as the handle is dragged.\n document.getSelection().removeAllRanges();\n\n // Adjust the column width according the amount the handle was dragged.\n const offset = e.pageX - currentX;\n currentX = e.pageX;\n const newWidth = currentHeader.offsetWidth + offset;\n currentHeader.style.width = newWidth + 'px';\n moveTracker = true;\n });\n\n // Set new size when mouse is up.\n document.addEventListener('mouseup', () => {\n if (!currentHeader || !currentResizeHandle || currentX === 0) {\n return;\n }\n if (moveTracker) {\n // If the mouse moved, we are changing the size by drag, so save the change.\n repository.setColumnSize(serialiseColumnSizes(uiRoot)).catch(Notification.exception);\n } else {\n // If the mouse didn't move, display a modal to change the size using a form.\n showResizeModal(currentHeader, uiRoot);\n }\n currentHeader = null;\n currentResizeHandle = null;\n currentX = 0;\n moveTracker = false;\n suspendShowHideHandles = false;\n });\n};\n\n/**\n * Event handler for resize actions in each column header.\n *\n * This will listen for a click on any resize action, and activate the corresponding resize modal.\n *\n * @param {Element} uiRoot Question bank UI root element.\n */\nconst setUpResizeActions = uiRoot => {\n uiRoot.addEventListener('click', (e) => {\n const resizeAction = e.target.closest(SELECTORS.resizeAction);\n if (resizeAction) {\n e.preventDefault();\n const currentHeader = resizeAction.closest('th');\n showResizeModal(currentHeader, uiRoot);\n }\n });\n};\n\n/**\n * Show a modal containing a number input for changing a column width without click-and-drag.\n *\n * @param {Element} currentHeader The header element that is being resized.\n * @param {Element} uiRoot The question bank UI root element.\n * @returns {Promise}\n */\nconst showResizeModal = async(currentHeader, uiRoot) => {\n\n const initialWidth = currentHeader.offsetWidth;\n\n const modal = await ModalFactory.create({\n title: getString('resizecolumn', 'qbank_columnsortorder', currentHeader.textContent),\n type: ModalFactory.types.SAVE_CANCEL,\n body: Templates.render('qbank_columnsortorder/resize_modal', {})\n });\n const root = modal.getRoot();\n root.on(ModalEvents.cancel, () => {\n currentHeader.style.width = initialWidth + 'px';\n });\n root.on(ModalEvents.save, () => {\n repository.setColumnSize(serialiseColumnSizes(uiRoot)).catch(Notification.exception);\n });\n modal.show();\n\n const body = await modal.bodyPromise;\n const input = body.get(0).querySelector('input');\n input.value = initialWidth;\n\n input.addEventListener('change', e => {\n const newWidth = e.target.value;\n currentHeader.style.width = newWidth + 'px';\n });\n};\n\n/**\n * Event handler for move actions in each column header.\n *\n * This will listen for a click on any move action, pass the click to the corresponding move handle, causing its modal to be shown.\n *\n * @param {Element} uiRoot Question bank UI root element.\n */\nconst setUpMoveActions = uiRoot => {\n uiRoot.addEventListener('click', e => {\n const moveAction = e.target.closest(SELECTORS.moveAction);\n if (moveAction) {\n e.preventDefault();\n const sortableColumn = moveAction.closest(actions.SELECTORS.sortableColumn);\n const moveHandle = sortableColumn.querySelector(actions.SELECTORS.moveHandler);\n moveHandle.click();\n }\n });\n};\n\n/**\n * Event handler for showing and hiding handles when the mouse is over a column header.\n *\n * Implementing this behaviour using the :hover CSS pseudoclass is not sufficient, as the mouse may move over the neighbouring\n * header while dragging, leading to some odd behaviour. This allows us to suspend the show/hide behaviour while a handle is being\n * dragged, and so keep the active handle visible until the drag is finished.\n *\n * @param {Element} uiRoot Question bank UI root element.\n */\nconst setupShowHideHandles = uiRoot => {\n let shownHeader = null;\n let tableHead = uiRoot.querySelector('thead');\n uiRoot.addEventListener('mouseover', e => {\n if (suspendShowHideHandles) {\n return;\n }\n const header = e.target.closest(actions.SELECTORS.sortableColumn);\n if (!header && !shownHeader) {\n return;\n }\n if (!header || header !== shownHeader) {\n tableHead.querySelector('.show-handles')?.classList.remove('show-handles');\n shownHeader = header;\n if (header) {\n header.classList.add('show-handles');\n }\n }\n });\n};\n\n/**\n * Event handler for sortable list DROP event.\n *\n * Find all table cells corresponding to the column of the dropped header, and move them to the new position.\n *\n * @param {Event} event\n */\nconst reorderColumns = event => {\n // Current header.\n const header = event.target;\n // Find the previous sibling of the header, which will be used when moving columns.\n const insertAfter = header.previousElementSibling;\n // Move columns.\n const uiRoot = document.querySelector(SELECTORS.uiRoot);\n const columns = uiRoot.querySelectorAll(SELECTORS.tableColumn(header.dataset.columnid));\n columns.forEach(column => {\n const row = column.parentElement;\n if (insertAfter) {\n // Find the column to insert after.\n const insertAfterColumn = row.querySelector(SELECTORS.tableColumn(insertAfter.dataset.columnid));\n // Insert the column.\n insertAfterColumn.after(column);\n } else {\n // Insert as the first child (first column in the table).\n row.insertBefore(column, row.firstChild);\n }\n });\n};\n\n/**\n * Initialize module\n *\n * Add containers for the drag handles to each column header, then render handles, enable show/hide behaviour, set up drag/drop\n * column sorting, then enable the move and resize modals to be triggered from menu actions.\n */\nexport const init = async() => {\n const uiRoot = document.getElementById('questionscontainer');\n await addHandleContainers(uiRoot);\n setUpMoveHandles(uiRoot.querySelectorAll(SELECTORS.moveAction));\n setUpResizeHandles(uiRoot);\n setupShowHideHandles(uiRoot);\n const sortableColumns = actions.setupSortableLists(uiRoot.querySelector(actions.SELECTORS.columnList));\n sortableColumns.on(SortableList.EVENTS.DROP, reorderColumns);\n sortableColumns.on(SortableList.EVENTS.DRAGSTART, () => {\n suspendShowHideHandles = true;\n });\n sortableColumns.on(SortableList.EVENTS.DRAGEND, () => {\n suspendShowHideHandles = false;\n });\n setUpMoveActions(uiRoot);\n setUpResizeActions(uiRoot);\n actions.setupActionButtons(uiRoot);\n};\n"],"names":["SELECTORS","identifier","replace","currentHeader","currentX","suspendShowHideHandles","serialiseColumnSizes","uiRoot","columnSizes","querySelectorAll","forEach","header","width","parseInt","style","isNaN","push","column","dataset","columnid","JSON","stringify","showResizeModal","async","initialWidth","offsetWidth","modal","ModalFactory","create","title","textContent","type","types","SAVE_CANCEL","body","Templates","render","root","getRoot","on","ModalEvents","cancel","save","repository","setColumnSize","catch","Notification","exception","show","input","bodyPromise","get","querySelector","value","addEventListener","e","newWidth","target","reorderColumns","event","insertAfter","previousElementSibling","document","row","parentElement","after","insertBefore","firstChild","getElementById","Promise","resolve","headerContainers","renderForPromise","then","_ref","html","js","container","prependNodeContents","addHandleContainers","moveAction","closest","classList","add","handleContainer","context","action","dragtype","pixicon","pixcomponent","popup","_ref2","resizeAction","_ref3","appendNodeContents","moveTracker","currentResizeHandle","pageX","actions","sortableColumn","getSelection","removeAllRanges","offset","setUpResizeHandles","shownHeader","tableHead","remove","setupShowHideHandles","sortableColumns","setupSortableLists","columnList","SortableList","EVENTS","DROP","DRAGSTART","DRAGEND","preventDefault","moveHandler","click","setUpMoveActions","setUpResizeActions","setupActionButtons"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"user_actions.min.js","sources":["../src/user_actions.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 * Javascript for customising the user's view of the question bank\n *\n * @module qbank_columnsortorder/user_actions\n * @copyright 2021 Catalyst IT Australia Pty Ltd\n * @author Ghaly Marc-Alexandre \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as actions from 'qbank_columnsortorder/actions';\nimport * as repository from 'qbank_columnsortorder/repository';\nimport {get_string as getString} from 'core/str';\nimport ModalEvents from 'core/modal_events';\nimport ModalSaveCancel from 'core/modal_save_cancel';\nimport Notification from \"core/notification\";\nimport SortableList from 'core/sortable_list';\nimport Templates from \"core/templates\";\n\n\nconst SELECTORS = {\n uiRoot: '.questionbankwindow',\n moveAction: '.menu-action[data-action=move]',\n resizeAction: '.menu-action[data-action=resize]',\n resizeHandle: '.qbank_columnsortorder-action-handle.resize',\n handleContainer: '.handle-container',\n headerContainer: '.header-container',\n tableColumn: identifier => `td[data-columnid=\"${identifier.replace(/[\"\\\\]/g, '\\\\$&')}\"]`,\n};\n\n/** To track mouse event on a table header */\nlet currentHeader;\n\n/** Current mouse x postion, to track mouse event on a table header */\nlet currentX;\n\n/**\n * Flag to temporarily prevent move and resize handles from being shown or hidden.\n *\n * @type {boolean}\n */\nlet suspendShowHideHandles = false;\n\n/**\n * Add handle containers for move and resize handles.\n *\n * @param {Element} uiRoot The root element of the quesiton bank UI.\n * @return {Promise} Resolved after the containers have been added to each column header.\n */\nconst addHandleContainers = uiRoot => {\n return new Promise((resolve) => {\n const headerContainers = uiRoot.querySelectorAll(SELECTORS.headerContainer);\n Templates.renderForPromise('qbank_columnsortorder/handle_container', {})\n .then(({html, js}) => {\n headerContainers.forEach(container => {\n Templates.prependNodeContents(container, html, js);\n });\n resolve();\n return headerContainers;\n }).catch(Notification.exception);\n });\n};\n\n/**\n * Render move handles in each container.\n *\n * This takes a list of the move actions rendered in each column header, and creates a corresponding drag handle for each.\n *\n * @param {NodeList} moveActions Menu actions for moving columns.\n */\nconst setUpMoveHandles = moveActions => {\n moveActions.forEach(moveAction => {\n const header = moveAction.closest('th');\n header.classList.add('qbank-sortable-column');\n const handleContainer = header.querySelector(SELECTORS.handleContainer);\n const context = {\n action: \"move\",\n dragtype: \"move\",\n target: '',\n title: moveAction.title,\n pixicon: \"i/dragdrop\",\n pixcomponent: \"core\",\n popup: true\n };\n return Templates.renderForPromise('qbank_columnsortorder/action_handle', context)\n .then(({html, js}) => {\n Templates.prependNodeContents(handleContainer, html, js);\n return handleContainer;\n }).catch(Notification.exception);\n });\n};\n\n/**\n * Serialise the current column sizes.\n *\n * This finds the current width set in each column header's style property, and returns them encoded as a JSON string.\n *\n * @param {Element} uiRoot The root element of the quesiton bank UI.\n * @return {String} JSON array containing a list of objects with column and width properties.\n */\nconst serialiseColumnSizes = (uiRoot) => {\n const columnSizes = [];\n const tableHeaders = uiRoot.querySelectorAll('th');\n tableHeaders.forEach(header => {\n // Only get the width set via style attribute (set by move action).\n const width = parseInt(header.style.width);\n if (!width || isNaN(width)) {\n return;\n }\n columnSizes.push({\n column: header.dataset.columnid,\n width: width\n });\n });\n return JSON.stringify(columnSizes);\n};\n\n/**\n * Render resize handles in each container.\n *\n * This takes a list of the resize actions rendered in each column header, and creates a corresponding drag handle for each.\n * It also initialises the event handlers for the drag handles and resize modal.\n *\n * @param {Element} uiRoot Question bank UI root element.\n */\nconst setUpResizeHandles = (uiRoot) => {\n const resizeActions = uiRoot.querySelectorAll(SELECTORS.resizeAction);\n resizeActions.forEach(resizeAction => {\n const headerContainer = resizeAction.closest(SELECTORS.headerContainer);\n const handleContainer = headerContainer.querySelector(SELECTORS.handleContainer);\n const context = {\n action: \"resize\",\n target: '',\n title: resizeAction.title,\n pixicon: 'i/twoway',\n pixcomponent: 'core',\n popup: true\n };\n return Templates.renderForPromise('qbank_columnsortorder/action_handle', context)\n .then(({html, js}) => {\n Templates.appendNodeContents(handleContainer, html, js);\n return handleContainer;\n }).catch(Notification.exception);\n });\n\n let moveTracker = false;\n let currentResizeHandle = null;\n // Start mouse event on headers.\n uiRoot.addEventListener('mousedown', e => {\n currentResizeHandle = e.target.closest(SELECTORS.resizeHandle);\n // Return if it is not ' resize' button.\n if (!currentResizeHandle) {\n return;\n }\n // Save current position.\n currentX = e.pageX;\n // Find the header.\n currentHeader = e.target.closest(actions.SELECTORS.sortableColumn);\n moveTracker = false;\n suspendShowHideHandles = true;\n });\n\n // Resize column as the mouse move.\n document.addEventListener('mousemove', e => {\n if (!currentHeader || !currentResizeHandle || currentX === 0) {\n return;\n }\n\n // Prevent text selection as the handle is dragged.\n document.getSelection().removeAllRanges();\n\n // Adjust the column width according the amount the handle was dragged.\n const offset = e.pageX - currentX;\n currentX = e.pageX;\n const newWidth = currentHeader.offsetWidth + offset;\n currentHeader.style.width = newWidth + 'px';\n moveTracker = true;\n });\n\n // Set new size when mouse is up.\n document.addEventListener('mouseup', () => {\n if (!currentHeader || !currentResizeHandle || currentX === 0) {\n return;\n }\n if (moveTracker) {\n // If the mouse moved, we are changing the size by drag, so save the change.\n repository.setColumnSize(serialiseColumnSizes(uiRoot)).catch(Notification.exception);\n } else {\n // If the mouse didn't move, display a modal to change the size using a form.\n showResizeModal(currentHeader, uiRoot);\n }\n currentHeader = null;\n currentResizeHandle = null;\n currentX = 0;\n moveTracker = false;\n suspendShowHideHandles = false;\n });\n};\n\n/**\n * Event handler for resize actions in each column header.\n *\n * This will listen for a click on any resize action, and activate the corresponding resize modal.\n *\n * @param {Element} uiRoot Question bank UI root element.\n */\nconst setUpResizeActions = uiRoot => {\n uiRoot.addEventListener('click', (e) => {\n const resizeAction = e.target.closest(SELECTORS.resizeAction);\n if (resizeAction) {\n e.preventDefault();\n const currentHeader = resizeAction.closest('th');\n showResizeModal(currentHeader, uiRoot);\n }\n });\n};\n\n/**\n * Show a modal containing a number input for changing a column width without click-and-drag.\n *\n * @param {Element} currentHeader The header element that is being resized.\n * @param {Element} uiRoot The question bank UI root element.\n * @returns {Promise}\n */\nconst showResizeModal = async(currentHeader, uiRoot) => {\n const initialWidth = currentHeader.offsetWidth;\n\n const modal = await ModalSaveCancel.create({\n title: getString('resizecolumn', 'qbank_columnsortorder', currentHeader.textContent),\n body: Templates.render('qbank_columnsortorder/resize_modal', {}),\n show: true,\n });\n const root = modal.getRoot();\n root.on(ModalEvents.cancel, () => {\n currentHeader.style.width = `${initialWidth}px`;\n });\n root.on(ModalEvents.save, () => {\n repository.setColumnSize(serialiseColumnSizes(uiRoot)).catch(Notification.exception);\n });\n\n const body = await modal.bodyPromise;\n const input = body.get(0).querySelector('input');\n input.value = initialWidth;\n\n input.addEventListener('change', e => {\n const newWidth = e.target.value;\n currentHeader.style.width = `${newWidth}px`;\n });\n};\n\n/**\n * Event handler for move actions in each column header.\n *\n * This will listen for a click on any move action, pass the click to the corresponding move handle, causing its modal to be shown.\n *\n * @param {Element} uiRoot Question bank UI root element.\n */\nconst setUpMoveActions = uiRoot => {\n uiRoot.addEventListener('click', e => {\n const moveAction = e.target.closest(SELECTORS.moveAction);\n if (moveAction) {\n e.preventDefault();\n const sortableColumn = moveAction.closest(actions.SELECTORS.sortableColumn);\n const moveHandle = sortableColumn.querySelector(actions.SELECTORS.moveHandler);\n moveHandle.click();\n }\n });\n};\n\n/**\n * Event handler for showing and hiding handles when the mouse is over a column header.\n *\n * Implementing this behaviour using the :hover CSS pseudoclass is not sufficient, as the mouse may move over the neighbouring\n * header while dragging, leading to some odd behaviour. This allows us to suspend the show/hide behaviour while a handle is being\n * dragged, and so keep the active handle visible until the drag is finished.\n *\n * @param {Element} uiRoot Question bank UI root element.\n */\nconst setupShowHideHandles = uiRoot => {\n let shownHeader = null;\n let tableHead = uiRoot.querySelector('thead');\n uiRoot.addEventListener('mouseover', e => {\n if (suspendShowHideHandles) {\n return;\n }\n const header = e.target.closest(actions.SELECTORS.sortableColumn);\n if (!header && !shownHeader) {\n return;\n }\n if (!header || header !== shownHeader) {\n tableHead.querySelector('.show-handles')?.classList.remove('show-handles');\n shownHeader = header;\n if (header) {\n header.classList.add('show-handles');\n }\n }\n });\n};\n\n/**\n * Event handler for sortable list DROP event.\n *\n * Find all table cells corresponding to the column of the dropped header, and move them to the new position.\n *\n * @param {Event} event\n */\nconst reorderColumns = event => {\n // Current header.\n const header = event.target;\n // Find the previous sibling of the header, which will be used when moving columns.\n const insertAfter = header.previousElementSibling;\n // Move columns.\n const uiRoot = document.querySelector(SELECTORS.uiRoot);\n const columns = uiRoot.querySelectorAll(SELECTORS.tableColumn(header.dataset.columnid));\n columns.forEach(column => {\n const row = column.parentElement;\n if (insertAfter) {\n // Find the column to insert after.\n const insertAfterColumn = row.querySelector(SELECTORS.tableColumn(insertAfter.dataset.columnid));\n // Insert the column.\n insertAfterColumn.after(column);\n } else {\n // Insert as the first child (first column in the table).\n row.insertBefore(column, row.firstChild);\n }\n });\n};\n\n/**\n * Initialize module\n *\n * Add containers for the drag handles to each column header, then render handles, enable show/hide behaviour, set up drag/drop\n * column sorting, then enable the move and resize modals to be triggered from menu actions.\n */\nexport const init = async() => {\n const uiRoot = document.getElementById('questionscontainer');\n await addHandleContainers(uiRoot);\n setUpMoveHandles(uiRoot.querySelectorAll(SELECTORS.moveAction));\n setUpResizeHandles(uiRoot);\n setupShowHideHandles(uiRoot);\n const sortableColumns = actions.setupSortableLists(uiRoot.querySelector(actions.SELECTORS.columnList));\n sortableColumns.on(SortableList.EVENTS.DROP, reorderColumns);\n sortableColumns.on(SortableList.EVENTS.DRAGSTART, () => {\n suspendShowHideHandles = true;\n });\n sortableColumns.on(SortableList.EVENTS.DRAGEND, () => {\n suspendShowHideHandles = false;\n });\n setUpMoveActions(uiRoot);\n setUpResizeActions(uiRoot);\n actions.setupActionButtons(uiRoot);\n};\n"],"names":["SELECTORS","identifier","replace","currentHeader","currentX","suspendShowHideHandles","serialiseColumnSizes","uiRoot","columnSizes","querySelectorAll","forEach","header","width","parseInt","style","isNaN","push","column","dataset","columnid","JSON","stringify","showResizeModal","async","initialWidth","offsetWidth","modal","ModalSaveCancel","create","title","textContent","body","Templates","render","show","root","getRoot","on","ModalEvents","cancel","save","repository","setColumnSize","catch","Notification","exception","input","bodyPromise","get","querySelector","value","addEventListener","e","newWidth","target","reorderColumns","event","insertAfter","previousElementSibling","document","row","parentElement","after","insertBefore","firstChild","getElementById","Promise","resolve","headerContainers","renderForPromise","then","_ref","html","js","container","prependNodeContents","addHandleContainers","moveAction","closest","classList","add","handleContainer","context","action","dragtype","pixicon","pixcomponent","popup","_ref2","resizeAction","_ref3","appendNodeContents","moveTracker","currentResizeHandle","pageX","actions","sortableColumn","getSelection","removeAllRanges","offset","setUpResizeHandles","shownHeader","tableHead","remove","setupShowHideHandles","sortableColumns","setupSortableLists","columnList","SortableList","EVENTS","DROP","DRAGSTART","DRAGEND","preventDefault","moveHandler","click","setUpMoveActions","setUpResizeActions","setupActionButtons"],"mappings":"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"} \ No newline at end of file diff --git a/question/bank/columnsortorder/amd/src/user_actions.js b/question/bank/columnsortorder/amd/src/user_actions.js index 4966cbebd62..0dbefc6b252 100644 --- a/question/bank/columnsortorder/amd/src/user_actions.js +++ b/question/bank/columnsortorder/amd/src/user_actions.js @@ -26,7 +26,7 @@ import * as actions from 'qbank_columnsortorder/actions'; import * as repository from 'qbank_columnsortorder/repository'; import {get_string as getString} from 'core/str'; import ModalEvents from 'core/modal_events'; -import ModalFactory from 'core/modal_factory'; +import ModalSaveCancel from 'core/modal_save_cancel'; import Notification from "core/notification"; import SortableList from 'core/sortable_list'; import Templates from "core/templates"; @@ -237,22 +237,20 @@ const setUpResizeActions = uiRoot => { * @returns {Promise} */ const showResizeModal = async(currentHeader, uiRoot) => { - const initialWidth = currentHeader.offsetWidth; - const modal = await ModalFactory.create({ + const modal = await ModalSaveCancel.create({ title: getString('resizecolumn', 'qbank_columnsortorder', currentHeader.textContent), - type: ModalFactory.types.SAVE_CANCEL, - body: Templates.render('qbank_columnsortorder/resize_modal', {}) + body: Templates.render('qbank_columnsortorder/resize_modal', {}), + show: true, }); const root = modal.getRoot(); root.on(ModalEvents.cancel, () => { - currentHeader.style.width = initialWidth + 'px'; + currentHeader.style.width = `${initialWidth}px`; }); root.on(ModalEvents.save, () => { repository.setColumnSize(serialiseColumnSizes(uiRoot)).catch(Notification.exception); }); - modal.show(); const body = await modal.bodyPromise; const input = body.get(0).querySelector('input'); @@ -260,7 +258,7 @@ const showResizeModal = async(currentHeader, uiRoot) => { input.addEventListener('change', e => { const newWidth = e.target.value; - currentHeader.style.width = newWidth + 'px'; + currentHeader.style.width = `${newWidth}px`; }); };