From 0bb0dc9de337db69066be17bfb2c0a9a8a4eb7d5 Mon Sep 17 00:00:00 2001 From: Stefan Hanauska Date: Tue, 13 Feb 2024 11:12:37 +0100 Subject: [PATCH] MBS-8586: Simplify horizontal scrolling --- amd/build/board.min.js | 2 +- amd/build/board.min.js.map | 2 +- amd/build/column.min.js.map | 2 +- amd/build/selectors.min.js | 2 +- amd/build/selectors.min.js.map | 2 +- amd/src/board.js | 59 ++++++++++++++++++++++++++++++++++ amd/src/column.js | 1 + amd/src/selectors.js | 3 ++ styles.css | 38 ++++++++++++++++++++++ templates/board.mustache | 6 ++++ 10 files changed, 112 insertions(+), 5 deletions(-) diff --git a/amd/build/board.min.js b/amd/build/board.min.js index 417a206d..ef466a31 100644 --- a/amd/build/board.min.js +++ b/amd/build/board.min.js @@ -1,3 +1,3 @@ -define("mod_kanban/board",["exports","core/reactive","mod_kanban/selectors","mod_kanban/capabilities","mod_kanban/exporter","mod_kanban/kanbancomponent","core/log","core/notification","core/str"],(function(_exports,_reactive,_selectors,_capabilities,_exporter,_kanbancomponent,_log,_notification,Str){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 _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,_selectors=_interopRequireDefault(_selectors),_capabilities=_interopRequireDefault(_capabilities),_exporter=_interopRequireDefault(_exporter),_kanbancomponent=_interopRequireDefault(_kanbancomponent),_log=_interopRequireDefault(_log),Str=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Str);class _default extends _kanbancomponent.default{constructor(){super(...arguments),_defineProperty(this,"LOCKED_COLUMNS",1),_defineProperty(this,"LOCKED_COMPLETE",2)}static init(target){return new this({element:document.getElementById(target)})}create(){this.cmid=this.element.dataset.cmid,this.id=this.element.dataset.id}getWatchers(){return[{watch:"board:updated",handler:this._boardUpdated},{watch:"columns:created",handler:this._columnCreated},{watch:"board:deleted",handler:this._reload},{watch:"common:updated",handler:this._commonUpdated}]}async stateReady(state){this.addEventListener(this.getElement(_selectors.default.ADDCOLUMNFIRST),"click",this._addColumn),1==state.capabilities.get(_capabilities.default.MANAGEBOARD).value&&(this.addEventListener(this.getElement(_selectors.default.LOCKBOARDCOLUMNS),"click",this._lockColumns),this.addEventListener(this.getElement(_selectors.default.UNLOCKBOARDCOLUMNS),"click",this._unlockColumns),this.addEventListener(this.getElement(_selectors.default.SAVEASTEMPLATE),"click",this._templateConfirm),this.addEventListener(this.getElement(_selectors.default.SHOWTEMPLATE),"click",this._showTemplate),this.addEventListener(this.getElement(_selectors.default.DELETETEMPLATE),"click",this._deleteTemplateConfirm)),this.addEventListener(this.getElement(_selectors.default.DELETEBOARD),"click",this._deleteConfirm),this.dragdrop=new _reactive.DragDrop(this),state.common.liveupdate>0&&this._continuousUpdate(state.common.liveupdate),this.toggleClass("ontouchstart"in document.documentElement,"mod_kanban_touch")}_showTemplate(){window.location.href=M.cfg.wwwroot+"/mod/kanban/view.php?id="+this.reactive.state.common.id+"&boardid="+this.reactive.state.common.template}_reload(){window.location.replace(M.cfg.wwwroot+"/mod/kanban/view.php?id="+this.reactive.state.common.id+"&userid="+this.reactive.state.common.userid)}_continuousUpdate(){setInterval((()=>{this.reactive.dispatch("getUpdates")}),1e3*(arguments.length>0&&void 0!==arguments[0]?arguments[0]:10))}_commonUpdated(_ref){let{element:element}=_ref;this.toggleClass(0!=element.template,"mod_kanban_hastemplate")}destroy(){void 0!==this.dragdrop&&this.dragdrop.unregister(),this._reload()}_templateConfirm(){Str.get_strings([{key:"saveastemplate",component:"mod_kanban"},{key:"saveastemplateconfirm",component:"mod_kanban"},{key:"save",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._saveAsTemplate()})))).catch((error=>_log.default.debug(error)))}_saveAsTemplate(){this.reactive.dispatch("saveAsTemplate")}_deleteConfirm(){Str.get_strings([{key:"deleteboard",component:"mod_kanban"},{key:"deleteboardconfirm",component:"mod_kanban"},{key:"delete",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._deleteBoard()})))).catch((error=>_log.default.debug(error)))}_deleteTemplateConfirm(){Str.get_strings([{key:"deletetemplate",component:"mod_kanban"},{key:"deletetemplateconfirm",component:"mod_kanban"},{key:"delete",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._deleteBoard()})))).catch((error=>_log.default.debug(error)))}_deleteBoard(){this.reactive.dispatch("deleteBoard")}_boardUpdated(_ref2){let{element:element}=_ref2;const colcontainer=this.getElement(_selectors.default.COLUMNCONTAINER);if(void 0!==element.sequence){let sequence=element.sequence.split(",");[...colcontainer.children].forEach((node=>{node.classList.contains("mod_kanban_column")&&!sequence.includes(node.dataset.id)&&colcontainer.removeChild(node)})),[...colcontainer.children].sort(((a,b)=>sequence.indexOf(a.dataset.id)>sequence.indexOf(b.dataset.id)?1:-1)).forEach((node=>colcontainer.appendChild(node)))}this.toggleClass(element.locked,"mod_kanban_board_locked_columns"),this.toggleClass(element.hastemplate,"mod_kanban_hastemplate")}async _columnCreated(_ref3){let{element:element}=_ref3,data=Object.assign({id:element.id,title:element.title,options:element.options,sequence:element.sequence},_exporter.default.exportCapabilities(this.reactive.state)),placeholder=document.createElement("li");placeholder.setAttribute("data-id",data.id),this.getElement(_selectors.default.COLUMNCONTAINER).appendChild(placeholder);const newelement=(await this.renderComponent(placeholder,"mod_kanban/column",data)).getElement();this.getElement(_selectors.default.COLUMNCONTAINER).replaceChild(newelement,placeholder)}_addColumn(){document.activeElement.blur(),this.reactive.dispatch("addColumn",0)}_lockColumns(){this.reactive.dispatch("lockColumns")}_unlockColumns(){this.reactive.dispatch("unlockColumns")}validateDropData(dropdata){return"column"==(null==dropdata?void 0:dropdata.type)}drop(dropdata){this.reactive.dispatch("moveColumn",dropdata.id,0)}showDropZone(){this.getElement(_selectors.default.ADDCOLUMNCONTAINER).classList.add("mod_kanban_insert")}hideDropZone(){this.getElement(_selectors.default.ADDCOLUMNCONTAINER).classList.remove("mod_kanban_insert")}}return _exports.default=_default,_exports.default})); +define("mod_kanban/board",["exports","core/reactive","mod_kanban/selectors","mod_kanban/capabilities","mod_kanban/exporter","mod_kanban/kanbancomponent","core/log","core/notification","core/str"],(function(_exports,_reactive,_selectors,_capabilities,_exporter,_kanbancomponent,_log,_notification,Str){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 _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,_selectors=_interopRequireDefault(_selectors),_capabilities=_interopRequireDefault(_capabilities),_exporter=_interopRequireDefault(_exporter),_kanbancomponent=_interopRequireDefault(_kanbancomponent),_log=_interopRequireDefault(_log),Str=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Str);class _default extends _kanbancomponent.default{constructor(){super(...arguments),_defineProperty(this,"LOCKED_COLUMNS",1),_defineProperty(this,"LOCKED_COMPLETE",2)}static init(target){return new this({element:document.getElementById(target)})}create(){this.cmid=this.element.dataset.cmid,this.id=this.element.dataset.id}getWatchers(){return[{watch:"board:updated",handler:this._boardUpdated},{watch:"columns:created",handler:this._columnCreated},{watch:"board:deleted",handler:this._reload},{watch:"common:updated",handler:this._commonUpdated},{watch:"columns:deleted",handler:this._checkDeletedColumnPosition}]}async stateReady(state){this.addEventListener(this.getElement(_selectors.default.ADDCOLUMNFIRST),"click",this._addColumn),1==state.capabilities.get(_capabilities.default.MANAGEBOARD).value&&(this.addEventListener(this.getElement(_selectors.default.LOCKBOARDCOLUMNS),"click",this._lockColumns),this.addEventListener(this.getElement(_selectors.default.UNLOCKBOARDCOLUMNS),"click",this._unlockColumns),this.addEventListener(this.getElement(_selectors.default.SAVEASTEMPLATE),"click",this._templateConfirm),this.addEventListener(this.getElement(_selectors.default.SHOWTEMPLATE),"click",this._showTemplate),this.addEventListener(this.getElement(_selectors.default.DELETETEMPLATE),"click",this._deleteTemplateConfirm)),this.addEventListener(this.getElement(_selectors.default.DELETEBOARD),"click",this._deleteConfirm),this.addEventListener(this.getElement(_selectors.default.SCROLLLEFT),"click",this._scrollLeft),this.addEventListener(this.getElement(_selectors.default.SCROLLRIGHT),"click",this._scrollRight),this.addEventListener(this.getElement(_selectors.default.MAIN),"scroll",this._updateScrollButtons),this.dragdrop=new _reactive.DragDrop(this),state.common.liveupdate>0&&this._continuousUpdate(state.common.liveupdate),this.toggleClass("ontouchstart"in document.documentElement,"mod_kanban_touch"),this._updateScrollButtons()}_showTemplate(){window.location.href=M.cfg.wwwroot+"/mod/kanban/view.php?id="+this.reactive.state.common.id+"&boardid="+this.reactive.state.common.template}_reload(){window.location.replace(M.cfg.wwwroot+"/mod/kanban/view.php?id="+this.reactive.state.common.id+"&userid="+this.reactive.state.common.userid)}_continuousUpdate(){setInterval((()=>{this.reactive.dispatch("getUpdates")}),1e3*(arguments.length>0&&void 0!==arguments[0]?arguments[0]:10))}_commonUpdated(_ref){let{element:element}=_ref;this.toggleClass(0!=element.template,"mod_kanban_hastemplate")}destroy(){void 0!==this.dragdrop&&this.dragdrop.unregister(),this._reload()}_templateConfirm(){Str.get_strings([{key:"saveastemplate",component:"mod_kanban"},{key:"saveastemplateconfirm",component:"mod_kanban"},{key:"save",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._saveAsTemplate()})))).catch((error=>_log.default.debug(error)))}_saveAsTemplate(){this.reactive.dispatch("saveAsTemplate")}_deleteConfirm(){Str.get_strings([{key:"deleteboard",component:"mod_kanban"},{key:"deleteboardconfirm",component:"mod_kanban"},{key:"delete",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._deleteBoard()})))).catch((error=>_log.default.debug(error)))}_deleteTemplateConfirm(){Str.get_strings([{key:"deletetemplate",component:"mod_kanban"},{key:"deletetemplateconfirm",component:"mod_kanban"},{key:"delete",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._deleteBoard()})))).catch((error=>_log.default.debug(error)))}_deleteBoard(){this.reactive.dispatch("deleteBoard")}_boardUpdated(_ref2){let{element:element}=_ref2;const colcontainer=this.getElement(_selectors.default.COLUMNCONTAINER);if(void 0!==element.sequence){let sequence=element.sequence.split(",");[...colcontainer.children].forEach((node=>{node.classList.contains("mod_kanban_column")&&!sequence.includes(node.dataset.id)&&colcontainer.removeChild(node)})),[...colcontainer.children].sort(((a,b)=>sequence.indexOf(a.dataset.id)>sequence.indexOf(b.dataset.id)?1:-1)).forEach((node=>colcontainer.appendChild(node)))}this.toggleClass(element.locked,"mod_kanban_board_locked_columns"),this.toggleClass(element.hastemplate,"mod_kanban_hastemplate"),this._updateScrollButtons()}async _columnCreated(_ref3){let{element:element}=_ref3,data=Object.assign({id:element.id,title:element.title,options:element.options,sequence:element.sequence},_exporter.default.exportCapabilities(this.reactive.state)),placeholder=document.createElement("li");placeholder.setAttribute("data-id",data.id),this.getElement(_selectors.default.COLUMNCONTAINER).appendChild(placeholder);const newelement=(await this.renderComponent(placeholder,"mod_kanban/column",data)).getElement();this.getElement(_selectors.default.COLUMNCONTAINER).replaceChild(newelement,placeholder),this._updateScrollButtons()}_addColumn(){document.activeElement.blur(),this.reactive.dispatch("addColumn",0)}_lockColumns(){this.reactive.dispatch("lockColumns")}_unlockColumns(){this.reactive.dispatch("unlockColumns")}validateDropData(dropdata){return"column"==(null==dropdata?void 0:dropdata.type)}drop(dropdata){this.reactive.dispatch("moveColumn",dropdata.id,0)}showDropZone(){this.getElement(_selectors.default.ADDCOLUMNCONTAINER).classList.add("mod_kanban_insert")}hideDropZone(){this.getElement(_selectors.default.ADDCOLUMNCONTAINER).classList.remove("mod_kanban_insert")}_scrollLeft(){this.getElement(_selectors.default.MAIN).scrollLeft-=.75*document.querySelector(".mod_kanban_column").clientWidth}_scrollRight(){this.getElement(_selectors.default.MAIN).scrollLeft+=.75*document.querySelector(".mod_kanban_column").clientWidth}_updateScrollButtons(){let main=this.getElement(_selectors.default.MAIN);main.scrollLeft<=1?this.getElement(_selectors.default.SCROLLLEFT).style.setProperty("visibility","hidden"):this.getElement(_selectors.default.SCROLLLEFT).style.setProperty("visibility","visible"),main.clientWidth+main.scrollLeft 0) {\n this._continuousUpdate(state.common.liveupdate);\n }\n this.toggleClass('ontouchstart' in document.documentElement, 'mod_kanban_touch');\n }\n\n /**\n * Called to show template.\n */\n _showTemplate() {\n window.location.href =\n M.cfg.wwwroot +\n '/mod/kanban/view.php?id=' +\n this.reactive.state.common.id +\n '&boardid=' +\n this.reactive.state.common.template;\n }\n\n /**\n * Reload current page.\n */\n _reload() {\n window.location.replace(\n M.cfg.wwwroot + '/mod/kanban/view.php?id=' + this.reactive.state.common.id +\n '&userid=' + this.reactive.state.common.userid);\n }\n\n /**\n * Start continuous update.\n * @param {number} seconds Seconds between two refresh calls, defaults to 10\n */\n _continuousUpdate(seconds = 10) {\n setInterval(() => {\n this.reactive.dispatch('getUpdates');\n }, seconds * 1000);\n }\n\n /**\n * Called when common data was updated\n * @param {*} param0\n */\n _commonUpdated({element}) {\n this.toggleClass(element.template != 0, 'mod_kanban_hastemplate');\n }\n\n /**\n * Remove all subcomponents dependencies.\n */\n destroy() {\n if (this.dragdrop !== undefined) {\n this.dragdrop.unregister();\n }\n this._reload();\n }\n\n /**\n * Display confirmation modal for saving a board as template.\n */\n _templateConfirm() {\n Str.get_strings([\n {key: 'saveastemplate', component: 'mod_kanban'},\n {key: 'saveastemplateconfirm', component: 'mod_kanban'},\n {key: 'save', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n strings[1],\n strings[2],\n () => {\n this._saveAsTemplate();\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Called when current board should be saved as template.\n */\n _saveAsTemplate() {\n this.reactive.dispatch('saveAsTemplate');\n }\n\n /**\n * Display confirmation modal for deleting a board.\n */\n _deleteConfirm() {\n Str.get_strings([\n {key: 'deleteboard', component: 'mod_kanban'},\n {key: 'deleteboardconfirm', component: 'mod_kanban'},\n {key: 'delete', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n strings[1],\n strings[2],\n () => {\n this._deleteBoard();\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Display confirmation modal for deleting a template.\n */\n _deleteTemplateConfirm() {\n Str.get_strings([\n {key: 'deletetemplate', component: 'mod_kanban'},\n {key: 'deletetemplateconfirm', component: 'mod_kanban'},\n {key: 'delete', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n strings[1],\n strings[2],\n () => {\n this._deleteBoard();\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Called to delete current board.\n */\n _deleteBoard() {\n this.reactive.dispatch('deleteBoard');\n }\n\n /**\n * Called when board was updated.\n * @param {*} param0\n */\n _boardUpdated({element}) {\n const colcontainer = this.getElement(selectors.COLUMNCONTAINER);\n if (element.sequence !== undefined) {\n let sequence = element.sequence.split(',');\n // Remove all columns from frontend that are no longer present in the database.\n [...colcontainer.children]\n .forEach((node) => {\n if (node.classList.contains('mod_kanban_column') && !sequence.includes(node.dataset.id)) {\n colcontainer.removeChild(node);\n }\n });\n // Reorder columns according to sequence from the database.\n [...colcontainer.children]\n .sort((a, b) => sequence.indexOf(a.dataset.id) > sequence.indexOf(b.dataset.id) ? 1 : -1)\n .forEach(node => colcontainer.appendChild(node));\n }\n // Set CSS classes to show/hide action menu items.\n this.toggleClass(element.locked, 'mod_kanban_board_locked_columns');\n this.toggleClass(element.hastemplate, 'mod_kanban_hastemplate');\n }\n\n /**\n * Called when a new column was added. Creates a new subcomponent.\n * @param {*} param0\n */\n async _columnCreated({element}) {\n let data = Object.assign({\n id: element.id,\n title: element.title,\n options: element.options,\n sequence: element.sequence,\n }, exporter.exportCapabilities(this.reactive.state));\n let placeholder = document.createElement('li');\n placeholder.setAttribute('data-id', data.id);\n this.getElement(selectors.COLUMNCONTAINER).appendChild(placeholder);\n const newcomponent = await this.renderComponent(placeholder, 'mod_kanban/column', data);\n const newelement = newcomponent.getElement();\n this.getElement(selectors.COLUMNCONTAINER).replaceChild(newelement, placeholder);\n }\n\n /**\n * Called to add a column.\n */\n _addColumn() {\n document.activeElement.blur();\n // Board component only handles adding a column at the leftmost position, hence second parameter is always 0.\n this.reactive.dispatch('addColumn', 0);\n }\n\n /**\n * Called to lock all columns.\n */\n _lockColumns() {\n this.reactive.dispatch('lockColumns');\n }\n\n /**\n * Called to unlock all columns.\n */\n _unlockColumns() {\n this.reactive.dispatch('unlockColumns');\n }\n\n /**\n * Validate draggable data. This component only accepts columns.\n * @param {object} dropdata\n * @returns {boolean} if the data is valid for this drop-zone.\n */\n validateDropData(dropdata) {\n let type = dropdata?.type;\n return type == 'column';\n }\n\n /**\n * Executed when a valid dropdata is dropped over the drop-zone.\n * Moves the dropped column to the leftmost position (other positions are handled by column component).\n * @param {object} dropdata\n */\n drop(dropdata) {\n this.reactive.dispatch('moveColumn', dropdata.id, 0);\n }\n\n /**\n * Show some visual hints to the user.\n */\n showDropZone() {\n this.getElement(selectors.ADDCOLUMNCONTAINER).classList.add('mod_kanban_insert');\n }\n\n /**\n * Remove visual hints to the user.\n */\n hideDropZone() {\n this.getElement(selectors.ADDCOLUMNCONTAINER).classList.remove('mod_kanban_insert');\n }\n}\n"],"names":["KanbanComponent","target","this","element","document","getElementById","create","cmid","dataset","id","getWatchers","watch","handler","_boardUpdated","_columnCreated","_reload","_commonUpdated","state","addEventListener","getElement","selectors","ADDCOLUMNFIRST","_addColumn","capabilities","get","MANAGEBOARD","value","LOCKBOARDCOLUMNS","_lockColumns","UNLOCKBOARDCOLUMNS","_unlockColumns","SAVEASTEMPLATE","_templateConfirm","SHOWTEMPLATE","_showTemplate","DELETETEMPLATE","_deleteTemplateConfirm","DELETEBOARD","_deleteConfirm","dragdrop","DragDrop","common","liveupdate","_continuousUpdate","toggleClass","documentElement","window","location","href","M","cfg","wwwroot","reactive","template","replace","userid","setInterval","dispatch","destroy","undefined","unregister","Str","get_strings","key","component","then","strings","_saveAsTemplate","catch","error","Log","debug","_deleteBoard","colcontainer","COLUMNCONTAINER","sequence","split","children","forEach","node","classList","contains","includes","removeChild","sort","a","b","indexOf","appendChild","locked","hastemplate","data","Object","assign","title","options","exporter","exportCapabilities","placeholder","createElement","setAttribute","newelement","renderComponent","replaceChild","activeElement","blur","validateDropData","dropdata","type","drop","showDropZone","ADDCOLUMNCONTAINER","add","hideDropZone","remove"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"board.min.js","sources":["../src/board.js"],"sourcesContent":["import {DragDrop} from 'core/reactive';\nimport selectors from 'mod_kanban/selectors';\nimport capabilities from 'mod_kanban/capabilities';\nimport exporter from 'mod_kanban/exporter';\nimport KanbanComponent from 'mod_kanban/kanbancomponent';\nimport Log from 'core/log';\nimport {saveCancel} from 'core/notification';\nimport * as Str from 'core/str';\n\n/**\n * Component representing a kanban board.\n */\nexport default class extends KanbanComponent {\n LOCKED_COLUMNS = 1;\n LOCKED_COMPLETE = 2;\n\n /**\n * Init component\n * @param {HTMLElement} target Element to attach the component to\n * @returns {KanbanComponent}\n */\n static init(target) {\n let element = document.getElementById(target);\n return new this({\n element: element,\n });\n }\n\n /**\n * Called before registering to reactive instance.\n */\n create() {\n this.cmid = this.element.dataset.cmid;\n this.id = this.element.dataset.id;\n }\n\n /**\n * Watchers defined by this component.\n * @returns {array}\n */\n getWatchers() {\n return [\n {watch: `board:updated`, handler: this._boardUpdated},\n {watch: `columns:created`, handler: this._columnCreated},\n {watch: `board:deleted`, handler: this._reload},\n {watch: `common:updated`, handler: this._commonUpdated},\n {watch: `columns:deleted`, handler: this._checkDeletedColumnPosition},\n ];\n }\n\n /**\n * Called once when state is ready (also if component is registered after initial state was set), attaching event\n * isteners and initializing drag and drop.\n * @param {*} state The initial state\n */\n async stateReady(state) {\n this.addEventListener(\n this.getElement(selectors.ADDCOLUMNFIRST),\n 'click',\n this._addColumn\n );\n if (state.capabilities.get(capabilities.MANAGEBOARD).value == true) {\n this.addEventListener(\n this.getElement(selectors.LOCKBOARDCOLUMNS),\n 'click',\n this._lockColumns\n );\n this.addEventListener(\n this.getElement(selectors.UNLOCKBOARDCOLUMNS),\n 'click',\n this._unlockColumns\n );\n this.addEventListener(\n this.getElement(selectors.SAVEASTEMPLATE),\n 'click',\n this._templateConfirm\n );\n this.addEventListener(\n this.getElement(selectors.SHOWTEMPLATE),\n 'click',\n this._showTemplate\n );\n this.addEventListener(\n this.getElement(selectors.DELETETEMPLATE),\n 'click',\n this._deleteTemplateConfirm\n );\n }\n this.addEventListener(\n this.getElement(selectors.DELETEBOARD),\n 'click',\n this._deleteConfirm\n );\n this.addEventListener(\n this.getElement(selectors.SCROLLLEFT),\n 'click',\n this._scrollLeft\n );\n this.addEventListener(\n this.getElement(selectors.SCROLLRIGHT),\n 'click',\n this._scrollRight\n );\n this.addEventListener(\n this.getElement(selectors.MAIN),\n 'scroll',\n this._updateScrollButtons\n );\n this.dragdrop = new DragDrop(this);\n if (state.common.liveupdate > 0) {\n this._continuousUpdate(state.common.liveupdate);\n }\n this.toggleClass('ontouchstart' in document.documentElement, 'mod_kanban_touch');\n this._updateScrollButtons();\n }\n\n /**\n * Called to show template.\n */\n _showTemplate() {\n window.location.href =\n M.cfg.wwwroot +\n '/mod/kanban/view.php?id=' +\n this.reactive.state.common.id +\n '&boardid=' +\n this.reactive.state.common.template;\n }\n\n /**\n * Reload current page.\n */\n _reload() {\n window.location.replace(\n M.cfg.wwwroot + '/mod/kanban/view.php?id=' + this.reactive.state.common.id +\n '&userid=' + this.reactive.state.common.userid);\n }\n\n /**\n * Start continuous update.\n * @param {number} seconds Seconds between two refresh calls, defaults to 10\n */\n _continuousUpdate(seconds = 10) {\n setInterval(() => {\n this.reactive.dispatch('getUpdates');\n }, seconds * 1000);\n }\n\n /**\n * Called when common data was updated\n * @param {*} param0\n */\n _commonUpdated({element}) {\n this.toggleClass(element.template != 0, 'mod_kanban_hastemplate');\n }\n\n /**\n * Remove all subcomponents dependencies.\n */\n destroy() {\n if (this.dragdrop !== undefined) {\n this.dragdrop.unregister();\n }\n this._reload();\n }\n\n /**\n * Display confirmation modal for saving a board as template.\n */\n _templateConfirm() {\n Str.get_strings([\n {key: 'saveastemplate', component: 'mod_kanban'},\n {key: 'saveastemplateconfirm', component: 'mod_kanban'},\n {key: 'save', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n strings[1],\n strings[2],\n () => {\n this._saveAsTemplate();\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Called when current board should be saved as template.\n */\n _saveAsTemplate() {\n this.reactive.dispatch('saveAsTemplate');\n }\n\n /**\n * Display confirmation modal for deleting a board.\n */\n _deleteConfirm() {\n Str.get_strings([\n {key: 'deleteboard', component: 'mod_kanban'},\n {key: 'deleteboardconfirm', component: 'mod_kanban'},\n {key: 'delete', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n strings[1],\n strings[2],\n () => {\n this._deleteBoard();\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Display confirmation modal for deleting a template.\n */\n _deleteTemplateConfirm() {\n Str.get_strings([\n {key: 'deletetemplate', component: 'mod_kanban'},\n {key: 'deletetemplateconfirm', component: 'mod_kanban'},\n {key: 'delete', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n strings[1],\n strings[2],\n () => {\n this._deleteBoard();\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Called to delete current board.\n */\n _deleteBoard() {\n this.reactive.dispatch('deleteBoard');\n }\n\n /**\n * Called when board was updated.\n * @param {*} param0\n */\n _boardUpdated({element}) {\n const colcontainer = this.getElement(selectors.COLUMNCONTAINER);\n if (element.sequence !== undefined) {\n let sequence = element.sequence.split(',');\n // Remove all columns from frontend that are no longer present in the database.\n [...colcontainer.children]\n .forEach((node) => {\n if (node.classList.contains('mod_kanban_column') && !sequence.includes(node.dataset.id)) {\n colcontainer.removeChild(node);\n }\n });\n // Reorder columns according to sequence from the database.\n [...colcontainer.children]\n .sort((a, b) => sequence.indexOf(a.dataset.id) > sequence.indexOf(b.dataset.id) ? 1 : -1)\n .forEach(node => colcontainer.appendChild(node));\n }\n // Set CSS classes to show/hide action menu items.\n this.toggleClass(element.locked, 'mod_kanban_board_locked_columns');\n this.toggleClass(element.hastemplate, 'mod_kanban_hastemplate');\n this._updateScrollButtons();\n }\n\n /**\n * Called when a new column was added. Creates a new subcomponent.\n * @param {*} param0\n */\n async _columnCreated({element}) {\n let data = Object.assign({\n id: element.id,\n title: element.title,\n options: element.options,\n sequence: element.sequence,\n }, exporter.exportCapabilities(this.reactive.state));\n let placeholder = document.createElement('li');\n placeholder.setAttribute('data-id', data.id);\n this.getElement(selectors.COLUMNCONTAINER).appendChild(placeholder);\n const newcomponent = await this.renderComponent(placeholder, 'mod_kanban/column', data);\n const newelement = newcomponent.getElement();\n this.getElement(selectors.COLUMNCONTAINER).replaceChild(newelement, placeholder);\n this._updateScrollButtons();\n }\n\n /**\n * Called to add a column.\n */\n _addColumn() {\n document.activeElement.blur();\n // Board component only handles adding a column at the leftmost position, hence second parameter is always 0.\n this.reactive.dispatch('addColumn', 0);\n }\n\n /**\n * Called to lock all columns.\n */\n _lockColumns() {\n this.reactive.dispatch('lockColumns');\n }\n\n /**\n * Called to unlock all columns.\n */\n _unlockColumns() {\n this.reactive.dispatch('unlockColumns');\n }\n\n /**\n * Validate draggable data. This component only accepts columns.\n * @param {object} dropdata\n * @returns {boolean} if the data is valid for this drop-zone.\n */\n validateDropData(dropdata) {\n let type = dropdata?.type;\n return type == 'column';\n }\n\n /**\n * Executed when a valid dropdata is dropped over the drop-zone.\n * Moves the dropped column to the leftmost position (other positions are handled by column component).\n * @param {object} dropdata\n */\n drop(dropdata) {\n this.reactive.dispatch('moveColumn', dropdata.id, 0);\n }\n\n /**\n * Show some visual hints to the user.\n */\n showDropZone() {\n this.getElement(selectors.ADDCOLUMNCONTAINER).classList.add('mod_kanban_insert');\n }\n\n /**\n * Remove visual hints to the user.\n */\n hideDropZone() {\n this.getElement(selectors.ADDCOLUMNCONTAINER).classList.remove('mod_kanban_insert');\n }\n\n /**\n * Scroll to the left.\n */\n _scrollLeft() {\n this.getElement(selectors.MAIN).scrollLeft -= document.querySelector('.mod_kanban_column').clientWidth * 0.75;\n }\n\n /**\n * Scroll to the right.\n */\n _scrollRight() {\n this.getElement(selectors.MAIN).scrollLeft += document.querySelector('.mod_kanban_column').clientWidth * 0.75;\n }\n\n /**\n * Only show scroll buttons if it's possible to scroll in this direction.\n */\n _updateScrollButtons() {\n let main = this.getElement(selectors.MAIN);\n if (main.scrollLeft <= 1) {\n this.getElement(selectors.SCROLLLEFT).style.setProperty('visibility', 'hidden');\n } else {\n this.getElement(selectors.SCROLLLEFT).style.setProperty('visibility', 'visible');\n }\n if (main.clientWidth + main.scrollLeft < main.scrollWidth) {\n this.getElement(selectors.SCROLLRIGHT).style.setProperty('visibility', 'visible');\n } else {\n this.getElement(selectors.SCROLLRIGHT).style.setProperty('visibility', 'hidden');\n }\n }\n\n /**\n * If first column was deleted, reset scroll position.\n */\n _checkDeletedColumnPosition({element}) {\n if (this.reactive.state.board.sequence.split(',')[0] == element.id) {\n this.getElement(selectors.MAIN).scrollLeft = 0;\n }\n }\n}\n"],"names":["KanbanComponent","target","this","element","document","getElementById","create","cmid","dataset","id","getWatchers","watch","handler","_boardUpdated","_columnCreated","_reload","_commonUpdated","_checkDeletedColumnPosition","state","addEventListener","getElement","selectors","ADDCOLUMNFIRST","_addColumn","capabilities","get","MANAGEBOARD","value","LOCKBOARDCOLUMNS","_lockColumns","UNLOCKBOARDCOLUMNS","_unlockColumns","SAVEASTEMPLATE","_templateConfirm","SHOWTEMPLATE","_showTemplate","DELETETEMPLATE","_deleteTemplateConfirm","DELETEBOARD","_deleteConfirm","SCROLLLEFT","_scrollLeft","SCROLLRIGHT","_scrollRight","MAIN","_updateScrollButtons","dragdrop","DragDrop","common","liveupdate","_continuousUpdate","toggleClass","documentElement","window","location","href","M","cfg","wwwroot","reactive","template","replace","userid","setInterval","dispatch","destroy","undefined","unregister","Str","get_strings","key","component","then","strings","_saveAsTemplate","catch","error","Log","debug","_deleteBoard","colcontainer","COLUMNCONTAINER","sequence","split","children","forEach","node","classList","contains","includes","removeChild","sort","a","b","indexOf","appendChild","locked","hastemplate","data","Object","assign","title","options","exporter","exportCapabilities","placeholder","createElement","setAttribute","newelement","renderComponent","replaceChild","activeElement","blur","validateDropData","dropdata","type","drop","showDropZone","ADDCOLUMNCONTAINER","add","hideDropZone","remove","scrollLeft","querySelector","clientWidth","main","style","setProperty","scrollWidth","board"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/column.min.js.map b/amd/build/column.min.js.map index 9954ce14..24bc2037 100644 --- a/amd/build/column.min.js.map +++ b/amd/build/column.min.js.map @@ -1 +1 @@ -{"version":3,"file":"column.min.js","sources":["../src/column.js"],"sourcesContent":["import {DragDrop} from 'core/reactive';\nimport selectors from 'mod_kanban/selectors';\nimport capabilities from 'mod_kanban/capabilities';\nimport exporter from 'mod_kanban/exporter';\nimport {saveCancel} from 'core/notification';\nimport * as Str from 'core/str';\nimport {get_string as getString} from 'core/str';\nimport ModalForm from 'core_form/modalform';\nimport KanbanComponent from 'mod_kanban/kanbancomponent';\nimport Log from \"core/log\";\n\n/**\n * Component representing a column in a kanban board.\n */\nexport default class extends KanbanComponent {\n /**\n * Function to initialize component, called by mustache template.\n * @param {*} target The id of the HTMLElement to attach to\n * @returns {BaseComponent} New component attached to the HTMLElement represented by target\n */\n static init(target) {\n let element = document.getElementById(target);\n return new this({\n element: element,\n });\n }\n\n /**\n * Called after the component was created.\n */\n create() {\n this.id = this.element.dataset.id;\n }\n\n /**\n * Watchers for this component.\n * @returns {array}\n */\n getWatchers() {\n return [\n {watch: `columns[${this.id}]:updated`, handler: this._columnUpdated},\n {watch: `columns[${this.id}]:deleted`, handler: this._columnDeleted},\n {watch: `cards:created`, handler: this._cardCreated}\n ];\n }\n\n /**\n * Called once when state is ready, attaching event listeners and initializing drag and drop.\n * @param {object} state\n */\n stateReady(state) {\n this.addEventListener(\n this.getElement(selectors.DELETECOLUMN, this.id),\n 'click',\n this._removeConfirm\n );\n this.addEventListener(\n this.getElement(selectors.ADDCARDFIRST),\n 'click',\n this._addCard\n );\n this.addEventListener(\n this.getElement(selectors.ADDCOLUMN, this.id),\n 'click',\n this._addColumn\n );\n this.addEventListener(\n this.getElement(selectors.LOCKCOLUMN, this.id),\n 'click',\n this._lockColumn\n );\n this.addEventListener(\n this.getElement(selectors.UNLOCKCOLUMN, this.id),\n 'click',\n this._unlockColumn\n );\n this.addEventListener(\n this.getElement(selectors.EDITDETAILS, this.id),\n 'click',\n this._editDetails\n );\n this.addEventListener(\n this.getElement(selectors.SHOWHIDDEN),\n 'click',\n this._showHidden\n );\n this.addEventListener(\n this.getElement(selectors.HIDEHIDDEN),\n 'click',\n this._hideHidden\n );\n this.draggable = false;\n this.dragdrop = new DragDrop(this);\n this.checkDragging(state);\n this.boardid = state.board.id;\n this.cmid = state.common.id;\n }\n\n /**\n * Display confirmation modal for deleting a card.\n * @param {*} event\n */\n _removeConfirm(event) {\n Str.get_strings([\n {key: 'deletecolumn', component: 'mod_kanban'},\n {key: 'deletecolumnconfirm', component: 'mod_kanban'},\n {key: 'delete', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n strings[1],\n strings[2],\n () => {\n this._removeColumn(event);\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Remove all subcomponents dependencies.\n */\n destroy() {\n if (this.dragdrop !== undefined) {\n this.dragdrop.unregister();\n }\n }\n\n /**\n * Get the draggable data of this component.\n *\n * @returns {Object} the draggable data.\n */\n getDraggableData() {\n return {id: this.id, type: 'column'};\n }\n\n /**\n * Conditionally enable / disable dragging.\n * @param {*} state\n */\n checkDragging(state) {\n if (state === undefined) {\n state = this.reactive.stateManager.state;\n }\n\n if (state.capabilities.get(capabilities.MANAGECOLUMNS).value && state.columns.get(this.id).locked == 0) {\n this.dragdrop.setDraggable(true);\n } else {\n this.dragdrop.setDraggable(false);\n }\n }\n\n /**\n * Validate draggable data. This component accepts cards and columns.\n * @param {object} dropdata\n * @returns {boolean} if the data is valid for this drop-zone.\n */\n validateDropData(dropdata) {\n let type = dropdata?.type;\n return type == 'card' || type == 'column';\n }\n\n /**\n * Executed when a valid dropdata is dropped over the drop-zone.\n * @param {object} dropdata\n * @param {object} event\n */\n drop(dropdata, event) {\n if (dropdata.type == 'card') {\n let cards = this.getElements(selectors.CARD);\n let aftercard = 0;\n for (let i = 0; i < cards.length; i++) {\n if (cards[i].offsetTop + cards[i].clientHeight / 2 <= event.layerY) {\n aftercard = cards[i].dataset.id;\n }\n }\n this.reactive.dispatch('moveCard', dropdata.id, this.id, aftercard);\n }\n if (dropdata.type == 'column') {\n if (dropdata.id != this.id) {\n this.reactive.dispatch('moveColumn', dropdata.id, this.id);\n }\n }\n }\n\n /**\n * Show some visual hints to the user.\n * @param {object} dropdata\n * @param {object} event\n */\n showDropZone(dropdata, event) {\n if (dropdata.type == 'card') {\n let cards = this.getElements(selectors.CARD);\n let aftercard = 0;\n for (let i = 0; i < cards.length; i++) {\n if (cards[i].offsetTop + cards[i].clientHeight / 2 <= event.layerY) {\n aftercard = cards[i].dataset.id;\n }\n }\n if (aftercard == 0) {\n this.getElement(selectors.ADDCARDCONTAINER).classList.add('mod_kanban_insert');\n } else {\n this.getElement(selectors.ADDCARDCONTAINER, aftercard).classList.add('mod_kanban_insert');\n }\n }\n if (dropdata.type == 'column') {\n this.getElement(selectors.ADDCOLUMNCONTAINER).classList.add('mod_kanban_insert');\n }\n }\n\n /**\n * Remove visual hints to the user.\n */\n hideDropZone() {\n this.getElement(selectors.ADDCOLUMNCONTAINER).classList.remove('mod_kanban_insert');\n this.getElements(selectors.ADDCARDCONTAINER).forEach((e) => {\n e.classList.remove('mod_kanban_insert');\n });\n }\n\n /**\n * Dispatch event to add a column after this column.\n * @param {*} event\n */\n _addColumn(event) {\n document.activeElement.blur();\n let target = event.target.closest(selectors.ADDCOLUMN);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('addColumn', data.id);\n }\n\n /**\n * Called when a card was created in this column.\n * @param {*} param0\n */\n async _cardCreated({element}) {\n if (element.kanban_column == this.id) {\n let data = JSON.parse(JSON.stringify(element));\n Object.assign(data, exporter.exportCapabilities(this.reactive.state));\n let placeholder = document.createElement('li');\n placeholder.setAttribute('data-id', data.id);\n let node = this.getElement(selectors.COLUMNINNER, this.id);\n node.appendChild(placeholder);\n const newcomponent = await this.renderComponent(placeholder, 'mod_kanban/card', data);\n const newelement = newcomponent.getElement();\n node.replaceChild(newelement, placeholder);\n }\n }\n\n /**\n * Dispatch event to add a card in this column.\n * @param {*} event\n */\n _addCard(event) {\n document.activeElement.blur();\n let target = event.target.closest(selectors.ADDCARD);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('addCard', data.columnid, 0);\n }\n\n /**\n * Called when column is updated.\n * @param {*} param0\n */\n _columnUpdated({element}) {\n const el = this.getElement(selectors.COLUMNINNER, this.id);\n if (element.sequence !== undefined) {\n let sequence = element.sequence.split(',');\n // Remove all cards from frontend that are no longer present in the database.\n [...el.children]\n .forEach((node) => {\n if (node.classList.contains('mod_kanban_card') && !sequence.includes(node.dataset.id)) {\n el.removeChild(node);\n }\n });\n // Reorder cards according to sequence from the database.\n [...el.children]\n .sort((a, b) => sequence.indexOf(a.dataset.id) > sequence.indexOf(b.dataset.id) ? 1 : -1)\n .forEach(node => el.appendChild(node));\n }\n if (element.locked !== undefined) {\n this.toggleClass(element.locked != 0, 'mod_kanban_locked_column');\n // Inplace editing of the column title is disabled if the column is locked.\n if (element.locked != 0) {\n this.getElement(selectors.INPLACEEDITABLE).removeAttribute('data-inplaceeditable');\n } else {\n this.getElement(selectors.INPLACEEDITABLE).setAttribute('data-inplaceeditable', '1');\n }\n }\n // Update data for inplace editing if title was updated (this is important if title was modified by another user).\n if (element.title !== undefined) {\n this.getElement(selectors.INPLACEEDITABLE).setAttribute('data-value', element.title);\n this.getElement(selectors.INPLACEEDITABLE).querySelector('a').innerHTML = element.title;\n }\n // Only autohide option is relevant for the frontend for now. autoclose option is handled by the backend.\n if (element.options !== undefined) {\n let options = JSON.parse(element.options);\n this.toggleClass(options.autohide, 'mod_kanban_autohide');\n }\n // Enable/disable dragging (e.g. if column is locked).\n this.checkDragging();\n }\n\n /**\n * Called when this column is deleted.\n */\n _columnDeleted() {\n this.destroy();\n }\n\n /**\n * Dispatch event to remove this column.\n * @param {*} event\n */\n _removeColumn(event) {\n let target = event.target.closest(selectors.DELETECOLUMN);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('deleteColumn', data.id);\n }\n\n /**\n * Dispatch event to lock this column.\n * @param {*} event\n */\n _lockColumn(event) {\n let target = event.target.closest(selectors.LOCKCOLUMN);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('lockColumn', data.id);\n }\n\n /**\n * Dispatch event to unlock this column.\n * @param {*} event\n */\n _unlockColumn(event) {\n let target = event.target.closest(selectors.UNLOCKCOLUMN);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('unlockColumn', data.id);\n }\n\n /**\n * Show modal form to edit column details.\n * @param {*} event\n */\n _editDetails(event) {\n event.preventDefault();\n\n const modalForm = new ModalForm({\n formClass: \"mod_kanban\\\\form\\\\edit_column_form\",\n args: {\n id: this.id,\n boardid: this.boardid,\n cmid: this.cmid\n },\n modalConfig: {title: getString('editcolumn', 'mod_kanban')},\n returnFocus: this.getElement(),\n });\n this.addEventListener(modalForm, modalForm.events.FORM_SUBMITTED, this._updateColumn);\n modalForm.show();\n }\n\n /**\n * Dispatch an event to update column data from the detail modal.\n * @param {*} event\n */\n _updateColumn(event) {\n this.reactive.dispatch('processUpdates', event.detail);\n }\n\n /**\n * Show hidden cards.\n */\n _showHidden() {\n this.getElement().classList.add('mod_kanban_show_hidden');\n }\n\n /**\n * Hide hidden cards.\n */\n _hideHidden() {\n this.getElement().classList.remove('mod_kanban_show_hidden');\n }\n}\n"],"names":["KanbanComponent","target","this","element","document","getElementById","create","id","dataset","getWatchers","watch","handler","_columnUpdated","_columnDeleted","_cardCreated","stateReady","state","addEventListener","getElement","selectors","DELETECOLUMN","_removeConfirm","ADDCARDFIRST","_addCard","ADDCOLUMN","_addColumn","LOCKCOLUMN","_lockColumn","UNLOCKCOLUMN","_unlockColumn","EDITDETAILS","_editDetails","SHOWHIDDEN","_showHidden","HIDEHIDDEN","_hideHidden","draggable","dragdrop","DragDrop","checkDragging","boardid","board","cmid","common","event","Str","get_strings","key","component","then","strings","_removeColumn","catch","error","Log","debug","destroy","undefined","unregister","getDraggableData","type","reactive","stateManager","capabilities","get","MANAGECOLUMNS","value","columns","locked","setDraggable","validateDropData","dropdata","drop","cards","getElements","CARD","aftercard","i","length","offsetTop","clientHeight","layerY","dispatch","showDropZone","ADDCARDCONTAINER","classList","add","ADDCOLUMNCONTAINER","hideDropZone","remove","forEach","e","activeElement","blur","closest","data","Object","assign","kanban_column","JSON","parse","stringify","exporter","exportCapabilities","placeholder","createElement","setAttribute","node","COLUMNINNER","appendChild","newelement","renderComponent","replaceChild","ADDCARD","columnid","el","sequence","split","children","contains","includes","removeChild","sort","a","b","indexOf","toggleClass","INPLACEEDITABLE","removeAttribute","title","querySelector","innerHTML","options","autohide","preventDefault","modalForm","ModalForm","formClass","args","modalConfig","returnFocus","events","FORM_SUBMITTED","_updateColumn","show","detail"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"column.min.js","sources":["../src/column.js"],"sourcesContent":["import {DragDrop} from 'core/reactive';\nimport selectors from 'mod_kanban/selectors';\nimport capabilities from 'mod_kanban/capabilities';\nimport exporter from 'mod_kanban/exporter';\nimport {saveCancel} from 'core/notification';\nimport * as Str from 'core/str';\nimport {get_string as getString} from 'core/str';\nimport ModalForm from 'core_form/modalform';\nimport KanbanComponent from 'mod_kanban/kanbancomponent';\nimport Log from \"core/log\";\n\n/**\n * Component representing a column in a kanban board.\n */\nexport default class extends KanbanComponent {\n /**\n * Function to initialize component, called by mustache template.\n * @param {*} target The id of the HTMLElement to attach to\n * @returns {BaseComponent} New component attached to the HTMLElement represented by target\n */\n static init(target) {\n let element = document.getElementById(target);\n return new this({\n element: element,\n });\n }\n\n /**\n * Called after the component was created.\n */\n create() {\n this.id = this.element.dataset.id;\n }\n\n /**\n * Watchers for this component.\n * @returns {array}\n */\n getWatchers() {\n return [\n {watch: `columns[${this.id}]:updated`, handler: this._columnUpdated},\n {watch: `columns[${this.id}]:deleted`, handler: this._columnDeleted},\n {watch: `cards:created`, handler: this._cardCreated}\n ];\n }\n\n /**\n * Called once when state is ready, attaching event listeners and initializing drag and drop.\n * @param {object} state\n */\n stateReady(state) {\n this.addEventListener(\n this.getElement(selectors.DELETECOLUMN, this.id),\n 'click',\n this._removeConfirm\n );\n this.addEventListener(\n this.getElement(selectors.ADDCARDFIRST),\n 'click',\n this._addCard\n );\n this.addEventListener(\n this.getElement(selectors.ADDCOLUMN, this.id),\n 'click',\n this._addColumn\n );\n this.addEventListener(\n this.getElement(selectors.LOCKCOLUMN, this.id),\n 'click',\n this._lockColumn\n );\n this.addEventListener(\n this.getElement(selectors.UNLOCKCOLUMN, this.id),\n 'click',\n this._unlockColumn\n );\n this.addEventListener(\n this.getElement(selectors.EDITDETAILS, this.id),\n 'click',\n this._editDetails\n );\n this.addEventListener(\n this.getElement(selectors.SHOWHIDDEN),\n 'click',\n this._showHidden\n );\n this.addEventListener(\n this.getElement(selectors.HIDEHIDDEN),\n 'click',\n this._hideHidden\n );\n this.draggable = false;\n this.dragdrop = new DragDrop(this);\n this.checkDragging(state);\n this.boardid = state.board.id;\n this.cmid = state.common.id;\n }\n\n /**\n * Display confirmation modal for deleting a card.\n * @param {*} event\n */\n _removeConfirm(event) {\n Str.get_strings([\n {key: 'deletecolumn', component: 'mod_kanban'},\n {key: 'deletecolumnconfirm', component: 'mod_kanban'},\n {key: 'delete', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n strings[1],\n strings[2],\n () => {\n this._removeColumn(event);\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Remove all subcomponents dependencies.\n */\n destroy() {\n if (this.dragdrop !== undefined) {\n this.dragdrop.unregister();\n }\n }\n\n /**\n * Get the draggable data of this component.\n *\n * @returns {Object} the draggable data.\n */\n getDraggableData() {\n return {id: this.id, type: 'column'};\n }\n\n /**\n * Conditionally enable / disable dragging.\n * @param {*} state\n */\n checkDragging(state) {\n if (state === undefined) {\n state = this.reactive.stateManager.state;\n }\n\n if (state.capabilities.get(capabilities.MANAGECOLUMNS).value && state.columns.get(this.id).locked == 0) {\n this.dragdrop.setDraggable(true);\n } else {\n this.dragdrop.setDraggable(false);\n }\n }\n\n /**\n * Validate draggable data. This component accepts cards and columns.\n * @param {object} dropdata\n * @returns {boolean} if the data is valid for this drop-zone.\n */\n validateDropData(dropdata) {\n let type = dropdata?.type;\n return type == 'card' || type == 'column';\n }\n\n /**\n * Executed when a valid dropdata is dropped over the drop-zone.\n * @param {object} dropdata\n * @param {object} event\n */\n drop(dropdata, event) {\n if (dropdata.type == 'card') {\n let cards = this.getElements(selectors.CARD);\n let aftercard = 0;\n for (let i = 0; i < cards.length; i++) {\n if (cards[i].offsetTop + cards[i].clientHeight / 2 <= event.layerY) {\n aftercard = cards[i].dataset.id;\n }\n }\n this.reactive.dispatch('moveCard', dropdata.id, this.id, aftercard);\n }\n if (dropdata.type == 'column') {\n if (dropdata.id != this.id) {\n this.reactive.dispatch('moveColumn', dropdata.id, this.id);\n }\n }\n }\n\n /**\n * Show some visual hints to the user.\n * @param {object} dropdata\n * @param {object} event\n */\n showDropZone(dropdata, event) {\n if (dropdata.type == 'card') {\n let cards = this.getElements(selectors.CARD);\n let aftercard = 0;\n for (let i = 0; i < cards.length; i++) {\n if (cards[i].offsetTop + cards[i].clientHeight / 2 <= event.layerY) {\n aftercard = cards[i].dataset.id;\n }\n }\n if (aftercard == 0) {\n this.getElement(selectors.ADDCARDCONTAINER).classList.add('mod_kanban_insert');\n } else {\n this.getElement(selectors.ADDCARDCONTAINER, aftercard).classList.add('mod_kanban_insert');\n }\n }\n if (dropdata.type == 'column') {\n this.getElement(selectors.ADDCOLUMNCONTAINER).classList.add('mod_kanban_insert');\n }\n }\n\n /**\n * Remove visual hints to the user.\n */\n hideDropZone() {\n this.getElement(selectors.ADDCOLUMNCONTAINER).classList.remove('mod_kanban_insert');\n this.getElements(selectors.ADDCARDCONTAINER).forEach((e) => {\n e.classList.remove('mod_kanban_insert');\n });\n }\n\n /**\n * Dispatch event to add a column after this column.\n * @param {*} event\n */\n _addColumn(event) {\n document.activeElement.blur();\n let target = event.target.closest(selectors.ADDCOLUMN);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('addColumn', data.id);\n }\n\n /**\n * Called when a card was created in this column.\n * @param {*} param0\n */\n async _cardCreated({element}) {\n if (element.kanban_column == this.id) {\n let data = JSON.parse(JSON.stringify(element));\n Object.assign(data, exporter.exportCapabilities(this.reactive.state));\n let placeholder = document.createElement('li');\n placeholder.setAttribute('data-id', data.id);\n let node = this.getElement(selectors.COLUMNINNER, this.id);\n node.appendChild(placeholder);\n const newcomponent = await this.renderComponent(placeholder, 'mod_kanban/card', data);\n const newelement = newcomponent.getElement();\n node.replaceChild(newelement, placeholder);\n }\n }\n\n /**\n * Dispatch event to add a card in this column.\n * @param {*} event\n */\n _addCard(event) {\n document.activeElement.blur();\n let target = event.target.closest(selectors.ADDCARD);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('addCard', data.columnid, 0);\n }\n\n /**\n * Called when column is updated.\n * @param {*} param0\n */\n _columnUpdated({element}) {\n const el = this.getElement(selectors.COLUMNINNER, this.id);\n if (element.sequence !== undefined) {\n let sequence = element.sequence.split(',');\n // Remove all cards from frontend that are no longer present in the database.\n [...el.children]\n .forEach((node) => {\n if (node.classList.contains('mod_kanban_card') && !sequence.includes(node.dataset.id)) {\n el.removeChild(node);\n }\n });\n // Reorder cards according to sequence from the database.\n [...el.children]\n .sort((a, b) => sequence.indexOf(a.dataset.id) > sequence.indexOf(b.dataset.id) ? 1 : -1)\n .forEach(node => el.appendChild(node));\n }\n if (element.locked !== undefined) {\n this.toggleClass(element.locked != 0, 'mod_kanban_locked_column');\n // Inplace editing of the column title is disabled if the column is locked.\n if (element.locked != 0) {\n this.getElement(selectors.INPLACEEDITABLE).removeAttribute('data-inplaceeditable');\n } else {\n this.getElement(selectors.INPLACEEDITABLE).setAttribute('data-inplaceeditable', '1');\n }\n }\n // Update data for inplace editing if title was updated (this is important if title was modified by another user).\n if (element.title !== undefined) {\n this.getElement(selectors.INPLACEEDITABLE).setAttribute('data-value', element.title);\n this.getElement(selectors.INPLACEEDITABLE).querySelector('a').innerHTML = element.title;\n }\n // Only autohide option is relevant for the frontend for now. autoclose option is handled by the backend.\n if (element.options !== undefined) {\n let options = JSON.parse(element.options);\n this.toggleClass(options.autohide, 'mod_kanban_autohide');\n }\n // Enable/disable dragging (e.g. if column is locked).\n this.checkDragging();\n }\n\n /**\n * Called when this column is deleted.\n */\n _columnDeleted() {\n \n this.destroy();\n }\n\n /**\n * Dispatch event to remove this column.\n * @param {*} event\n */\n _removeColumn(event) {\n let target = event.target.closest(selectors.DELETECOLUMN);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('deleteColumn', data.id);\n }\n\n /**\n * Dispatch event to lock this column.\n * @param {*} event\n */\n _lockColumn(event) {\n let target = event.target.closest(selectors.LOCKCOLUMN);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('lockColumn', data.id);\n }\n\n /**\n * Dispatch event to unlock this column.\n * @param {*} event\n */\n _unlockColumn(event) {\n let target = event.target.closest(selectors.UNLOCKCOLUMN);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('unlockColumn', data.id);\n }\n\n /**\n * Show modal form to edit column details.\n * @param {*} event\n */\n _editDetails(event) {\n event.preventDefault();\n\n const modalForm = new ModalForm({\n formClass: \"mod_kanban\\\\form\\\\edit_column_form\",\n args: {\n id: this.id,\n boardid: this.boardid,\n cmid: this.cmid\n },\n modalConfig: {title: getString('editcolumn', 'mod_kanban')},\n returnFocus: this.getElement(),\n });\n this.addEventListener(modalForm, modalForm.events.FORM_SUBMITTED, this._updateColumn);\n modalForm.show();\n }\n\n /**\n * Dispatch an event to update column data from the detail modal.\n * @param {*} event\n */\n _updateColumn(event) {\n this.reactive.dispatch('processUpdates', event.detail);\n }\n\n /**\n * Show hidden cards.\n */\n _showHidden() {\n this.getElement().classList.add('mod_kanban_show_hidden');\n }\n\n /**\n * Hide hidden cards.\n */\n _hideHidden() {\n this.getElement().classList.remove('mod_kanban_show_hidden');\n }\n}\n"],"names":["KanbanComponent","target","this","element","document","getElementById","create","id","dataset","getWatchers","watch","handler","_columnUpdated","_columnDeleted","_cardCreated","stateReady","state","addEventListener","getElement","selectors","DELETECOLUMN","_removeConfirm","ADDCARDFIRST","_addCard","ADDCOLUMN","_addColumn","LOCKCOLUMN","_lockColumn","UNLOCKCOLUMN","_unlockColumn","EDITDETAILS","_editDetails","SHOWHIDDEN","_showHidden","HIDEHIDDEN","_hideHidden","draggable","dragdrop","DragDrop","checkDragging","boardid","board","cmid","common","event","Str","get_strings","key","component","then","strings","_removeColumn","catch","error","Log","debug","destroy","undefined","unregister","getDraggableData","type","reactive","stateManager","capabilities","get","MANAGECOLUMNS","value","columns","locked","setDraggable","validateDropData","dropdata","drop","cards","getElements","CARD","aftercard","i","length","offsetTop","clientHeight","layerY","dispatch","showDropZone","ADDCARDCONTAINER","classList","add","ADDCOLUMNCONTAINER","hideDropZone","remove","forEach","e","activeElement","blur","closest","data","Object","assign","kanban_column","JSON","parse","stringify","exporter","exportCapabilities","placeholder","createElement","setAttribute","node","COLUMNINNER","appendChild","newelement","renderComponent","replaceChild","ADDCARD","columnid","el","sequence","split","children","contains","includes","removeChild","sort","a","b","indexOf","toggleClass","INPLACEEDITABLE","removeAttribute","title","querySelector","innerHTML","options","autohide","preventDefault","modalForm","ModalForm","formClass","args","modalConfig","returnFocus","events","FORM_SUBMITTED","_updateColumn","show","detail"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/selectors.min.js b/amd/build/selectors.min.js index c8270934..4f8b2233 100644 --- a/amd/build/selectors.min.js +++ b/amd/build/selectors.min.js @@ -1,3 +1,3 @@ -define("mod_kanban/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={ADDCARD:'[data-action="add_card"]',ADDCARDCONTAINER:".mod_kanban_addcard_container",ADDCARDFIRST:".mod_kanban_addcard_first",ADDCOLUMN:'[data-action="add_column"]',ADDCOLUMNCONTAINER:".mod_kanban_addcolumn_container",ADDCOLUMNFIRST:".mod_kanban_addcolumn_first",ASSIGNEES:".mod_kanban_assignees",ASSIGNSELF:'[data-action="assign_self"]',ASSIGNUSER:'[data-action="assign_user"]',ASSIGNEDUSER:".mod_kanban_assigned_user",BOARD:".mod_kanban_board",CARD:".mod_kanban_card",COLUMN:".mod_kanban_column",COLUMNCONTAINER:".mod_kanban_column_container",COLUMNINNER:".mod_kanban_column_inner",COMPLETE:'[data-action="complete_card"]',COMPLETIONSTATE:".mod_kanban_card_completion",CONTAINER:".mod_kanban_render_container",DELETEBOARD:'[data-action="delete_board"]',DELETECARD:'[data-action="delete_card"]',DELETECOLUMN:'[data-action="delete_column"]',DELETEMESSAGE:'[data-action="delete_message"]',DELETETEMPLATE:'[data-action="delete_template"]',DESCRIPTIONMODAL:".mod_kanban_description",DESCRIPTIONMODALBODY:".mod_kanban_description_modal .modal-body",DESCRIPTIONMODALFOOTER:".mod_kanban_description_modal .modal-footer",DESCRIPTIONMODALTITLE:".mod_kanban_description_modal .modal-title",DESCRIPTIONTOGGLE:".mod_kanban_description",DISCUSSION:".mod_kanban_discussion",DISCUSSIONINPUT:".mod_kanban_discussion_input",DISCUSSIONMESSAGES:".mod_kanban_discussion_messages",DISCUSSIONMODAL:".mod_kanban_discussion_modal",DISCUSSIONMODALTITLE:".mod_kanban_discussion_modal .modal-title",DISCUSSIONMODALTRIGGER:".mod_kanban_discussion_trigger",DISCUSSIONSEND:'[data-action="send_discussion_message"]',DISCUSSIONSHOW:'[data-action="show_discussion"]',DUEDATE:".mod_kanban_duedate",EDITDETAILS:'[data-action="edit_details"]',HIDEHIDDEN:'[data-action="hide_hidden"]',HISTORY:".mod_kanban_history",HISTORYITEMS:".mod_kanban_history_items",HISTORYMODAL:".mod_kanban_history_modal",HISTORYMODALTRIGGER:'[data-action="show_history"]',INPLACEEDITABLE:".inplaceeditable",LOCKCOLUMN:'[data-action="lock_column"]',LOCKBOARDCOLUMNS:'[data-action="lock_board_columns"]',MOVECARDAFTERCARD:".mod_kanban_move_card_aftercard",MOVECARDCOLUMN:".mod_kanban_move_card_column",MOVEMODALTRIGGER:'[data-action="move_card"]',PUSHCARD:'[data-action="push_card"]',SAVEASTEMPLATE:'[data-action="create_template"]',SHOWBOARD:'[data-action="show_board"]',SHOWHIDDEN:'[data-action="show_hidden"]',SHOWTEMPLATE:'[data-action="show_template"]',UNASSIGNSELF:'[data-action="unassign_self"]',UNASSIGNUSER:'[data-action="unassign_user"]',UNCOMPLETE:'[data-action="uncomplete_card"]',UNLOCKCOLUMN:'[data-action="unlock_column"]',UNLOCKBOARDCOLUMNS:'[data-action="unlock_board_columns"]'},_exports.default})); +define("mod_kanban/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={ADDCARD:'[data-action="add_card"]',ADDCARDCONTAINER:".mod_kanban_addcard_container",ADDCARDFIRST:".mod_kanban_addcard_first",ADDCOLUMN:'[data-action="add_column"]',ADDCOLUMNCONTAINER:".mod_kanban_addcolumn_container",ADDCOLUMNFIRST:".mod_kanban_addcolumn_first",ASSIGNEES:".mod_kanban_assignees",ASSIGNSELF:'[data-action="assign_self"]',ASSIGNUSER:'[data-action="assign_user"]',ASSIGNEDUSER:".mod_kanban_assigned_user",BOARD:".mod_kanban_board",CARD:".mod_kanban_card",COLUMN:".mod_kanban_column",COLUMNCONTAINER:".mod_kanban_column_container",COLUMNINNER:".mod_kanban_column_inner",COMPLETE:'[data-action="complete_card"]',COMPLETIONSTATE:".mod_kanban_card_completion",CONTAINER:".mod_kanban_render_container",DELETEBOARD:'[data-action="delete_board"]',DELETECARD:'[data-action="delete_card"]',DELETECOLUMN:'[data-action="delete_column"]',DELETEMESSAGE:'[data-action="delete_message"]',DELETETEMPLATE:'[data-action="delete_template"]',DESCRIPTIONMODAL:".mod_kanban_description",DESCRIPTIONMODALBODY:".mod_kanban_description_modal .modal-body",DESCRIPTIONMODALFOOTER:".mod_kanban_description_modal .modal-footer",DESCRIPTIONMODALTITLE:".mod_kanban_description_modal .modal-title",DESCRIPTIONTOGGLE:".mod_kanban_description",DISCUSSION:".mod_kanban_discussion",DISCUSSIONINPUT:".mod_kanban_discussion_input",DISCUSSIONMESSAGES:".mod_kanban_discussion_messages",DISCUSSIONMODAL:".mod_kanban_discussion_modal",DISCUSSIONMODALTITLE:".mod_kanban_discussion_modal .modal-title",DISCUSSIONMODALTRIGGER:".mod_kanban_discussion_trigger",DISCUSSIONSEND:'[data-action="send_discussion_message"]',DISCUSSIONSHOW:'[data-action="show_discussion"]',DUEDATE:".mod_kanban_duedate",EDITDETAILS:'[data-action="edit_details"]',HIDEHIDDEN:'[data-action="hide_hidden"]',HISTORY:".mod_kanban_history",HISTORYITEMS:".mod_kanban_history_items",HISTORYMODAL:".mod_kanban_history_modal",HISTORYMODALTRIGGER:'[data-action="show_history"]',INPLACEEDITABLE:".inplaceeditable",LOCKCOLUMN:'[data-action="lock_column"]',LOCKBOARDCOLUMNS:'[data-action="lock_board_columns"]',MAIN:".mod_kanban_main",MOVECARDAFTERCARD:".mod_kanban_move_card_aftercard",MOVECARDCOLUMN:".mod_kanban_move_card_column",MOVEMODALTRIGGER:'[data-action="move_card"]',PUSHCARD:'[data-action="push_card"]',SAVEASTEMPLATE:'[data-action="create_template"]',SCROLLLEFT:".mod_kanban_scroll_left button",SCROLLRIGHT:".mod_kanban_scroll_right button",SHOWBOARD:'[data-action="show_board"]',SHOWHIDDEN:'[data-action="show_hidden"]',SHOWTEMPLATE:'[data-action="show_template"]',UNASSIGNSELF:'[data-action="unassign_self"]',UNASSIGNUSER:'[data-action="unassign_user"]',UNCOMPLETE:'[data-action="uncomplete_card"]',UNLOCKCOLUMN:'[data-action="unlock_column"]',UNLOCKBOARDCOLUMNS:'[data-action="unlock_board_columns"]'},_exports.default})); //# sourceMappingURL=selectors.min.js.map \ No newline at end of file diff --git a/amd/build/selectors.min.js.map b/amd/build/selectors.min.js.map index c9aa4f95..155b5350 100644 --- a/amd/build/selectors.min.js.map +++ b/amd/build/selectors.min.js.map @@ -1 +1 @@ -{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["/**\n * Selectors for mod_kanban.\n */\nexport default {\n ADDCARD: `[data-action=\"add_card\"]`,\n ADDCARDCONTAINER: `.mod_kanban_addcard_container`,\n ADDCARDFIRST: `.mod_kanban_addcard_first`,\n ADDCOLUMN: `[data-action=\"add_column\"]`,\n ADDCOLUMNCONTAINER: `.mod_kanban_addcolumn_container`,\n ADDCOLUMNFIRST: `.mod_kanban_addcolumn_first`,\n ASSIGNEES: `.mod_kanban_assignees`,\n ASSIGNSELF: `[data-action=\"assign_self\"]`,\n ASSIGNUSER: `[data-action=\"assign_user\"]`,\n ASSIGNEDUSER: `.mod_kanban_assigned_user`,\n BOARD: `.mod_kanban_board`,\n CARD: `.mod_kanban_card`,\n COLUMN: `.mod_kanban_column`,\n COLUMNCONTAINER: `.mod_kanban_column_container`,\n COLUMNINNER: `.mod_kanban_column_inner`,\n COMPLETE: `[data-action=\"complete_card\"]`,\n COMPLETIONSTATE: `.mod_kanban_card_completion`,\n CONTAINER: `.mod_kanban_render_container`,\n DELETEBOARD: `[data-action=\"delete_board\"]`,\n DELETECARD: `[data-action=\"delete_card\"]`,\n DELETECOLUMN: `[data-action=\"delete_column\"]`,\n DELETEMESSAGE: `[data-action=\"delete_message\"]`,\n DELETETEMPLATE: `[data-action=\"delete_template\"]`,\n DESCRIPTIONMODAL: `.mod_kanban_description`,\n DESCRIPTIONMODALBODY: `.mod_kanban_description_modal .modal-body`,\n DESCRIPTIONMODALFOOTER: `.mod_kanban_description_modal .modal-footer`,\n DESCRIPTIONMODALTITLE: `.mod_kanban_description_modal .modal-title`,\n DESCRIPTIONTOGGLE: `.mod_kanban_description`,\n DISCUSSION: `.mod_kanban_discussion`,\n DISCUSSIONINPUT: `.mod_kanban_discussion_input`,\n DISCUSSIONMESSAGES: `.mod_kanban_discussion_messages`,\n DISCUSSIONMODAL: `.mod_kanban_discussion_modal`,\n DISCUSSIONMODALTITLE: `.mod_kanban_discussion_modal .modal-title`,\n DISCUSSIONMODALTRIGGER: `.mod_kanban_discussion_trigger`,\n DISCUSSIONSEND: `[data-action=\"send_discussion_message\"]`,\n DISCUSSIONSHOW: `[data-action=\"show_discussion\"]`,\n DUEDATE: `.mod_kanban_duedate`,\n EDITDETAILS: `[data-action=\"edit_details\"]`,\n HIDEHIDDEN: `[data-action=\"hide_hidden\"]`,\n HISTORY: `.mod_kanban_history`,\n HISTORYITEMS: `.mod_kanban_history_items`,\n HISTORYMODAL: `.mod_kanban_history_modal`,\n HISTORYMODALTRIGGER: `[data-action=\"show_history\"]`,\n INPLACEEDITABLE: `.inplaceeditable`,\n LOCKCOLUMN: `[data-action=\"lock_column\"]`,\n LOCKBOARDCOLUMNS: `[data-action=\"lock_board_columns\"]`,\n MOVECARDAFTERCARD: `.mod_kanban_move_card_aftercard`,\n MOVECARDCOLUMN: `.mod_kanban_move_card_column`,\n MOVEMODALTRIGGER: `[data-action=\"move_card\"]`,\n PUSHCARD: `[data-action=\"push_card\"]`,\n SAVEASTEMPLATE: `[data-action=\"create_template\"]`,\n SHOWBOARD: `[data-action=\"show_board\"]`,\n SHOWHIDDEN: `[data-action=\"show_hidden\"]`,\n SHOWTEMPLATE: `[data-action=\"show_template\"]`,\n UNASSIGNSELF: `[data-action=\"unassign_self\"]`,\n UNASSIGNUSER: `[data-action=\"unassign_user\"]`,\n UNCOMPLETE: `[data-action=\"uncomplete_card\"]`,\n UNLOCKCOLUMN: `[data-action=\"unlock_column\"]`,\n UNLOCKBOARDCOLUMNS: `[data-action=\"unlock_board_columns\"]`,\n};"],"names":["ADDCARD","ADDCARDCONTAINER","ADDCARDFIRST","ADDCOLUMN","ADDCOLUMNCONTAINER","ADDCOLUMNFIRST","ASSIGNEES","ASSIGNSELF","ASSIGNUSER","ASSIGNEDUSER","BOARD","CARD","COLUMN","COLUMNCONTAINER","COLUMNINNER","COMPLETE","COMPLETIONSTATE","CONTAINER","DELETEBOARD","DELETECARD","DELETECOLUMN","DELETEMESSAGE","DELETETEMPLATE","DESCRIPTIONMODAL","DESCRIPTIONMODALBODY","DESCRIPTIONMODALFOOTER","DESCRIPTIONMODALTITLE","DESCRIPTIONTOGGLE","DISCUSSION","DISCUSSIONINPUT","DISCUSSIONMESSAGES","DISCUSSIONMODAL","DISCUSSIONMODALTITLE","DISCUSSIONMODALTRIGGER","DISCUSSIONSEND","DISCUSSIONSHOW","DUEDATE","EDITDETAILS","HIDEHIDDEN","HISTORY","HISTORYITEMS","HISTORYMODAL","HISTORYMODALTRIGGER","INPLACEEDITABLE","LOCKCOLUMN","LOCKBOARDCOLUMNS","MOVECARDAFTERCARD","MOVECARDCOLUMN","MOVEMODALTRIGGER","PUSHCARD","SAVEASTEMPLATE","SHOWBOARD","SHOWHIDDEN","SHOWTEMPLATE","UNASSIGNSELF","UNASSIGNUSER","UNCOMPLETE","UNLOCKCOLUMN","UNLOCKBOARDCOLUMNS"],"mappings":"sKAGe,CACXA,mCACAC,iDACAC,yCACAC,uCACAC,qDACAC,6CACAC,kCACAC,yCACAC,yCACAC,yCACAC,0BACAC,wBACAC,4BACAC,+CACAC,uCACAC,yCACAC,8CACAC,yCACAC,2CACAC,yCACAC,6CACAC,+CACAC,iDACAC,2CACAC,iEACAC,qEACAC,mEACAC,4CACAC,oCACAC,+CACAC,qDACAC,+CACAC,iEACAC,wDACAC,yDACAC,iDACAC,8BACAC,2CACAC,yCACAC,8BACAC,yCACAC,yCACAC,mDACAC,mCACAC,yCACAC,sDACAC,oDACAC,8CACAC,6CACAC,qCACAC,iDACAC,uCACAC,yCACAC,6CACAC,6CACAC,6CACAC,6CACAC,6CACAC"} \ No newline at end of file +{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["/**\n * Selectors for mod_kanban.\n */\nexport default {\n ADDCARD: `[data-action=\"add_card\"]`,\n ADDCARDCONTAINER: `.mod_kanban_addcard_container`,\n ADDCARDFIRST: `.mod_kanban_addcard_first`,\n ADDCOLUMN: `[data-action=\"add_column\"]`,\n ADDCOLUMNCONTAINER: `.mod_kanban_addcolumn_container`,\n ADDCOLUMNFIRST: `.mod_kanban_addcolumn_first`,\n ASSIGNEES: `.mod_kanban_assignees`,\n ASSIGNSELF: `[data-action=\"assign_self\"]`,\n ASSIGNUSER: `[data-action=\"assign_user\"]`,\n ASSIGNEDUSER: `.mod_kanban_assigned_user`,\n BOARD: `.mod_kanban_board`,\n CARD: `.mod_kanban_card`,\n COLUMN: `.mod_kanban_column`,\n COLUMNCONTAINER: `.mod_kanban_column_container`,\n COLUMNINNER: `.mod_kanban_column_inner`,\n COMPLETE: `[data-action=\"complete_card\"]`,\n COMPLETIONSTATE: `.mod_kanban_card_completion`,\n CONTAINER: `.mod_kanban_render_container`,\n DELETEBOARD: `[data-action=\"delete_board\"]`,\n DELETECARD: `[data-action=\"delete_card\"]`,\n DELETECOLUMN: `[data-action=\"delete_column\"]`,\n DELETEMESSAGE: `[data-action=\"delete_message\"]`,\n DELETETEMPLATE: `[data-action=\"delete_template\"]`,\n DESCRIPTIONMODAL: `.mod_kanban_description`,\n DESCRIPTIONMODALBODY: `.mod_kanban_description_modal .modal-body`,\n DESCRIPTIONMODALFOOTER: `.mod_kanban_description_modal .modal-footer`,\n DESCRIPTIONMODALTITLE: `.mod_kanban_description_modal .modal-title`,\n DESCRIPTIONTOGGLE: `.mod_kanban_description`,\n DISCUSSION: `.mod_kanban_discussion`,\n DISCUSSIONINPUT: `.mod_kanban_discussion_input`,\n DISCUSSIONMESSAGES: `.mod_kanban_discussion_messages`,\n DISCUSSIONMODAL: `.mod_kanban_discussion_modal`,\n DISCUSSIONMODALTITLE: `.mod_kanban_discussion_modal .modal-title`,\n DISCUSSIONMODALTRIGGER: `.mod_kanban_discussion_trigger`,\n DISCUSSIONSEND: `[data-action=\"send_discussion_message\"]`,\n DISCUSSIONSHOW: `[data-action=\"show_discussion\"]`,\n DUEDATE: `.mod_kanban_duedate`,\n EDITDETAILS: `[data-action=\"edit_details\"]`,\n HIDEHIDDEN: `[data-action=\"hide_hidden\"]`,\n HISTORY: `.mod_kanban_history`,\n HISTORYITEMS: `.mod_kanban_history_items`,\n HISTORYMODAL: `.mod_kanban_history_modal`,\n HISTORYMODALTRIGGER: `[data-action=\"show_history\"]`,\n INPLACEEDITABLE: `.inplaceeditable`,\n LOCKCOLUMN: `[data-action=\"lock_column\"]`,\n LOCKBOARDCOLUMNS: `[data-action=\"lock_board_columns\"]`,\n MAIN: `.mod_kanban_main`,\n MOVECARDAFTERCARD: `.mod_kanban_move_card_aftercard`,\n MOVECARDCOLUMN: `.mod_kanban_move_card_column`,\n MOVEMODALTRIGGER: `[data-action=\"move_card\"]`,\n PUSHCARD: `[data-action=\"push_card\"]`,\n SAVEASTEMPLATE: `[data-action=\"create_template\"]`,\n SCROLLLEFT: `.mod_kanban_scroll_left button`,\n SCROLLRIGHT: `.mod_kanban_scroll_right button`,\n SHOWBOARD: `[data-action=\"show_board\"]`,\n SHOWHIDDEN: `[data-action=\"show_hidden\"]`,\n SHOWTEMPLATE: `[data-action=\"show_template\"]`,\n UNASSIGNSELF: `[data-action=\"unassign_self\"]`,\n UNASSIGNUSER: `[data-action=\"unassign_user\"]`,\n UNCOMPLETE: `[data-action=\"uncomplete_card\"]`,\n UNLOCKCOLUMN: `[data-action=\"unlock_column\"]`,\n UNLOCKBOARDCOLUMNS: `[data-action=\"unlock_board_columns\"]`,\n};"],"names":["ADDCARD","ADDCARDCONTAINER","ADDCARDFIRST","ADDCOLUMN","ADDCOLUMNCONTAINER","ADDCOLUMNFIRST","ASSIGNEES","ASSIGNSELF","ASSIGNUSER","ASSIGNEDUSER","BOARD","CARD","COLUMN","COLUMNCONTAINER","COLUMNINNER","COMPLETE","COMPLETIONSTATE","CONTAINER","DELETEBOARD","DELETECARD","DELETECOLUMN","DELETEMESSAGE","DELETETEMPLATE","DESCRIPTIONMODAL","DESCRIPTIONMODALBODY","DESCRIPTIONMODALFOOTER","DESCRIPTIONMODALTITLE","DESCRIPTIONTOGGLE","DISCUSSION","DISCUSSIONINPUT","DISCUSSIONMESSAGES","DISCUSSIONMODAL","DISCUSSIONMODALTITLE","DISCUSSIONMODALTRIGGER","DISCUSSIONSEND","DISCUSSIONSHOW","DUEDATE","EDITDETAILS","HIDEHIDDEN","HISTORY","HISTORYITEMS","HISTORYMODAL","HISTORYMODALTRIGGER","INPLACEEDITABLE","LOCKCOLUMN","LOCKBOARDCOLUMNS","MAIN","MOVECARDAFTERCARD","MOVECARDCOLUMN","MOVEMODALTRIGGER","PUSHCARD","SAVEASTEMPLATE","SCROLLLEFT","SCROLLRIGHT","SHOWBOARD","SHOWHIDDEN","SHOWTEMPLATE","UNASSIGNSELF","UNASSIGNUSER","UNCOMPLETE","UNLOCKCOLUMN","UNLOCKBOARDCOLUMNS"],"mappings":"sKAGe,CACXA,mCACAC,iDACAC,yCACAC,uCACAC,qDACAC,6CACAC,kCACAC,yCACAC,yCACAC,yCACAC,0BACAC,wBACAC,4BACAC,+CACAC,uCACAC,yCACAC,8CACAC,yCACAC,2CACAC,yCACAC,6CACAC,+CACAC,iDACAC,2CACAC,iEACAC,qEACAC,mEACAC,4CACAC,oCACAC,+CACAC,qDACAC,+CACAC,iEACAC,wDACAC,yDACAC,iDACAC,8BACAC,2CACAC,yCACAC,8BACAC,yCACAC,yCACAC,mDACAC,mCACAC,yCACAC,sDACAC,wBACAC,oDACAC,8CACAC,6CACAC,qCACAC,iDACAC,4CACAC,8CACAC,uCACAC,yCACAC,6CACAC,6CACAC,6CACAC,6CACAC,6CACAC"} \ No newline at end of file diff --git a/amd/src/board.js b/amd/src/board.js index 767ef577..cdd6cec5 100644 --- a/amd/src/board.js +++ b/amd/src/board.js @@ -44,6 +44,7 @@ export default class extends KanbanComponent { {watch: `columns:created`, handler: this._columnCreated}, {watch: `board:deleted`, handler: this._reload}, {watch: `common:updated`, handler: this._commonUpdated}, + {watch: `columns:deleted`, handler: this._checkDeletedColumnPosition}, ]; } @@ -90,11 +91,27 @@ export default class extends KanbanComponent { 'click', this._deleteConfirm ); + this.addEventListener( + this.getElement(selectors.SCROLLLEFT), + 'click', + this._scrollLeft + ); + this.addEventListener( + this.getElement(selectors.SCROLLRIGHT), + 'click', + this._scrollRight + ); + this.addEventListener( + this.getElement(selectors.MAIN), + 'scroll', + this._updateScrollButtons + ); this.dragdrop = new DragDrop(this); if (state.common.liveupdate > 0) { this._continuousUpdate(state.common.liveupdate); } this.toggleClass('ontouchstart' in document.documentElement, 'mod_kanban_touch'); + this._updateScrollButtons(); } /** @@ -243,6 +260,7 @@ export default class extends KanbanComponent { // Set CSS classes to show/hide action menu items. this.toggleClass(element.locked, 'mod_kanban_board_locked_columns'); this.toggleClass(element.hastemplate, 'mod_kanban_hastemplate'); + this._updateScrollButtons(); } /** @@ -262,6 +280,7 @@ export default class extends KanbanComponent { const newcomponent = await this.renderComponent(placeholder, 'mod_kanban/column', data); const newelement = newcomponent.getElement(); this.getElement(selectors.COLUMNCONTAINER).replaceChild(newelement, placeholder); + this._updateScrollButtons(); } /** @@ -319,4 +338,44 @@ export default class extends KanbanComponent { hideDropZone() { this.getElement(selectors.ADDCOLUMNCONTAINER).classList.remove('mod_kanban_insert'); } + + /** + * Scroll to the left. + */ + _scrollLeft() { + this.getElement(selectors.MAIN).scrollLeft -= document.querySelector('.mod_kanban_column').clientWidth * 0.75; + } + + /** + * Scroll to the right. + */ + _scrollRight() { + this.getElement(selectors.MAIN).scrollLeft += document.querySelector('.mod_kanban_column').clientWidth * 0.75; + } + + /** + * Only show scroll buttons if it's possible to scroll in this direction. + */ + _updateScrollButtons() { + let main = this.getElement(selectors.MAIN); + if (main.scrollLeft <= 1) { + this.getElement(selectors.SCROLLLEFT).style.setProperty('visibility', 'hidden'); + } else { + this.getElement(selectors.SCROLLLEFT).style.setProperty('visibility', 'visible'); + } + if (main.clientWidth + main.scrollLeft < main.scrollWidth) { + this.getElement(selectors.SCROLLRIGHT).style.setProperty('visibility', 'visible'); + } else { + this.getElement(selectors.SCROLLRIGHT).style.setProperty('visibility', 'hidden'); + } + } + + /** + * If first column was deleted, reset scroll position. + */ + _checkDeletedColumnPosition({element}) { + if (this.reactive.state.board.sequence.split(',')[0] == element.id) { + this.getElement(selectors.MAIN).scrollLeft = 0; + } + } } diff --git a/amd/src/column.js b/amd/src/column.js index 6ff84c58..c67875c0 100644 --- a/amd/src/column.js +++ b/amd/src/column.js @@ -306,6 +306,7 @@ export default class extends KanbanComponent { * Called when this column is deleted. */ _columnDeleted() { + this.destroy(); } diff --git a/amd/src/selectors.js b/amd/src/selectors.js index 4172e4ba..04000b37 100644 --- a/amd/src/selectors.js +++ b/amd/src/selectors.js @@ -48,11 +48,14 @@ export default { INPLACEEDITABLE: `.inplaceeditable`, LOCKCOLUMN: `[data-action="lock_column"]`, LOCKBOARDCOLUMNS: `[data-action="lock_board_columns"]`, + MAIN: `.mod_kanban_main`, MOVECARDAFTERCARD: `.mod_kanban_move_card_aftercard`, MOVECARDCOLUMN: `.mod_kanban_move_card_column`, MOVEMODALTRIGGER: `[data-action="move_card"]`, PUSHCARD: `[data-action="push_card"]`, SAVEASTEMPLATE: `[data-action="create_template"]`, + SCROLLLEFT: `.mod_kanban_scroll_left button`, + SCROLLRIGHT: `.mod_kanban_scroll_right button`, SHOWBOARD: `[data-action="show_board"]`, SHOWHIDDEN: `[data-action="show_hidden"]`, SHOWTEMPLATE: `[data-action="show_template"]`, diff --git a/styles.css b/styles.css index c98716d6..feece6dc 100644 --- a/styles.css +++ b/styles.css @@ -391,3 +391,41 @@ a.mod_kanban_attachment_item { .mod_kanban_board .btn { background-color: white; } + +.mod_kanban_column_container.row { + margin-left: -30px; +} + +.mod_kanban_scroll.row { + display: block; + position: sticky; + top: 50%; + z-index: 3; + width: 30px; + float: left; +} + +.mod_kanban_scroll_button { + height: 50px; + width: 30px; + border: none; + font-weight: 900; +} + +.mod_kanban_scroll_left { + left: 0; +} + +.mod_kanban_scroll_right { + left: calc(100vw - 30px); +} + +.mod_kanban_scroll_right .mod_kanban_scroll_button { + border-top-left-radius: 10px; + border-bottom-left-radius: 10px; +} + +.mod_kanban_scroll_left .mod_kanban_scroll_button { + border-top-right-radius: 10px; + border-bottom-right-radius: 10px; +} diff --git a/templates/board.mustache b/templates/board.mustache index 3175e8bd..4d8f88f5 100644 --- a/templates/board.mustache +++ b/templates/board.mustache @@ -44,6 +44,12 @@ {{>mod_kanban/actionmenuboard}} +
+ +
+
+ +