From 5f356a081bfa7c0e4c8361dd1d69e2a47fc6948b Mon Sep 17 00:00:00 2001 From: Stefan Hanauska Date: Wed, 27 Mar 2024 21:49:15 +0100 Subject: [PATCH] MBS-8982: Add card numbers --- amd/build/card.min.js | 2 +- amd/build/card.min.js.map | 2 +- amd/build/cardnumber.min.js | 3 ++ amd/build/cardnumber.min.js.map | 1 + amd/build/exporter.min.js | 2 +- amd/build/exporter.min.js.map | 2 +- amd/build/selectors.min.js | 2 +- amd/build/selectors.min.js.map | 2 +- amd/src/card.js | 58 +++++++++++++++++----- amd/src/cardnumber.js | 33 ++++++++++++ amd/src/exporter.js | 6 ++- amd/src/selectors.js | 2 + backup/moodle2/restore_kanban_stepslib.php | 4 ++ classes/boardmanager.php | 17 +++++++ classes/external/get_kanban_content.php | 14 +++++- classes/numberfilter.php | 46 +++++++++++++++++ db/install.xml | 2 + db/upgrade.php | 42 +++++++++++++++- lang/en/kanban.php | 2 + mod_form.php | 3 ++ styles.css | 21 +++++++- templates/board.mustache | 5 +- templates/card.mustache | 10 ++-- templates/descriptionmodal.mustache | 55 +++++++++++--------- version.php | 2 +- 25 files changed, 280 insertions(+), 58 deletions(-) create mode 100644 amd/build/cardnumber.min.js create mode 100644 amd/build/cardnumber.min.js.map create mode 100644 amd/src/cardnumber.js create mode 100644 classes/numberfilter.php diff --git a/amd/build/card.min.js b/amd/build/card.min.js index ccf53fa9..e7105741 100644 --- a/amd/build/card.min.js +++ b/amd/build/card.min.js @@ -1,3 +1,3 @@ -define("mod_kanban/card",["exports","core/reactive","mod_kanban/selectors","mod_kanban/exporter","core/notification","core_form/modalform","core/str","core/templates","mod_kanban/kanbancomponent","core/log"],(function(_exports,_reactive,_selectors,_exporter,_notification,_modalform,Str,_templates,_kanbancomponent,_log){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}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_selectors=_interopRequireDefault(_selectors),_exporter=_interopRequireDefault(_exporter),_modalform=_interopRequireDefault(_modalform),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),_templates=_interopRequireDefault(_templates),_kanbancomponent=_interopRequireDefault(_kanbancomponent),_log=_interopRequireDefault(_log);class _default extends _kanbancomponent.default{constructor(){var obj,key,value;super(...arguments),value={year:31536e6,month:2628e6,day:864e5,hour:36e5,minute:6e4,second:1e3},(key="_units")in(obj=this)?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}static init(target){return new this({element:document.getElementById(target)})}create(){this.id=this.element.dataset.id}getWatchers(){return[{watch:"cards[".concat(this.id,"]:updated"),handler:this._cardUpdated},{watch:"cards[".concat(this.id,"]:deleted"),handler:this._cardDeleted},{watch:"discussions:created",handler:this._discussionUpdated},{watch:"discussions:updated",handler:this._discussionUpdated},{watch:"discussions:deleted",handler:this._discussionUpdated},{watch:"history:created",handler:this._historyUpdated},{watch:"history:updated",handler:this._historyUpdated},{watch:"history:deleted",handler:this._historyUpdated}]}stateReady(state){let lang="en";void 0!==state.common.lang&&(lang=state.common.lang);try{this.rtf=new Intl.RelativeTimeFormat(lang,{numeric:"auto"})}catch(e){this.rtf=new Intl.RelativeTimeFormat("en",{numeric:"auto"})}this.addEventListener(this.getElement(_selectors.default.DELETECARD,this.id),"click",this._removeConfirm),this.addEventListener(this.getElement(_selectors.default.ADDCARD,this.id),"click",this._addCard),this.addEventListener(this.getElement(_selectors.default.COMPLETE,this.id),"click",this._completeCard),this.addEventListener(this.getElement(_selectors.default.UNCOMPLETE,this.id),"click",this._uncompleteCard),this.addEventListener(this.getElement(_selectors.default.ASSIGNSELF,this.id),"click",this._assignSelf),this.addEventListener(this.getElement(_selectors.default.UNASSIGNSELF,this.id),"click",this._unassignSelf),this.addEventListener(this.getElement(_selectors.default.EDITDETAILS,this.id),"click",this._editDetails),this.addEventListener(this.getElement(_selectors.default.DISCUSSIONMODALTRIGGER),"click",this._updateDiscussion),this.addEventListener(this.getElement(_selectors.default.DISCUSSIONSHOW,this.id),"click",this._updateDiscussion),this.addEventListener(this.getElement(_selectors.default.DISCUSSIONSEND),"click",this._sendMessage),this.addEventListener(this.getElement(_selectors.default.HISTORYMODALTRIGGER),"click",this._updateHistory),this.addEventListener(this.getElement(_selectors.default.MOVEMODALTRIGGER),"click",this._showMoveModal),this.addEventListener(this.getElement(_selectors.default.PUSHCARD),"click",this._pushCardConfirm),this.draggable=!1,this.dragdrop=new _reactive.DragDrop(this),this.checkEditing(state),this.boardid=state.board.id,this.cmid=state.common.id,this.userid=state.board.userid,this.groupid=state.board.groupid,this._dueDateFormat()}_showMoveModal(){let data=_exporter.default.exportStateForTemplate(this.reactive.state);data.cardid=this.id,data.kanbancolumn=this.reactive.state.cards.get(this.id).kanban_column,Str.get_strings([{key:"movecard",component:"mod_kanban"},{key:"move",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],_templates.default.render("mod_kanban/movemodal",data),strings[1],(()=>{let column=document.querySelector(_selectors.default.MOVECARDCOLUMN+'[data-id="'.concat(this.id,'"]')).value,aftercard=document.querySelector(_selectors.default.MOVECARDAFTERCARD+'[data-id="'.concat(this.id,'"]')).value;this.reactive.dispatch("moveCard",this.id,column,aftercard)})))).catch((error=>_log.default.debug(error)))}_pushCardConfirm(event){Str.get_strings([{key:"pushcard",component:"mod_kanban"},{key:"pushcardconfirm",component:"mod_kanban"},{key:"copy",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._pushCard(event)})))).catch((error=>_log.default.debug(error)))}_removeConfirm(event){Str.get_strings([{key:"deletecard",component:"mod_kanban"},{key:"deletecardconfirm",component:"mod_kanban"},{key:"delete",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._removeCard(event)})))).catch((error=>_log.default.debug(error)))}_removeMessageConfirm(event){Str.get_strings([{key:"deletemessage",component:"mod_kanban"},{key:"deletemessageconfirm",component:"mod_kanban"},{key:"delete",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._removeMessage(event)})))).catch((error=>_log.default.debug(error)))}_sendMessage(){let el=this.getElement(_selectors.default.DISCUSSIONINPUT),message=el.value.trim();""!=message&&(this.reactive.dispatch("sendDiscussionMessage",this.id,message),el.value="")}_updateDiscussion(){this.getElement(_selectors.default.DISCUSSIONMODAL).classList.add("mod_kanban_loading"),this.reactive.dispatch("getDiscussionUpdates",this.id)}async _discussionUpdated(){let data={discussions:_exporter.default.exportDiscussion(this.reactive.state,this.id)};_templates.default.renderForPromise("mod_kanban/discussionmessages",data).then((_ref=>{let{html:html}=_ref;this.getElement(_selectors.default.DISCUSSION,this.id).innerHTML=html,this.getElement(_selectors.default.DISCUSSIONMODAL,this.id).classList.remove("mod_kanban_loading");let el=this.getElement(_selectors.default.DISCUSSIONMESSAGES);return el.scrollTop=el.scrollHeight,data.discussions.forEach((d=>{d.candelete&&this.addEventListener(this.getElement(_selectors.default.DELETEMESSAGE,d.id),"click",this._removeMessageConfirm)})),!0})).catch((error=>(0,_notification.exception)(error)))}_updateHistory(){this.getElement(_selectors.default.HISTORYMODAL).classList.add("mod_kanban_loading"),this.reactive.dispatch("getHistoryUpdates",this.id)}async _historyUpdated(){let data={historyitems:_exporter.default.exportHistory(this.reactive.state,this.id)};_templates.default.renderForPromise("mod_kanban/historyitems",data).then((_ref2=>{let{html:html}=_ref2;this.getElement(_selectors.default.HISTORY,this.id).innerHTML=html,this.getElement(_selectors.default.HISTORYMODAL).classList.remove("mod_kanban_loading");let el=this.getElement(_selectors.default.HISTORYITEMS);return el.scrollTop=el.scrollHeight,!0})).catch((error=>(0,_notification.exception)(error)))}_assignSelf(event){let target=event.target.closest(_selectors.default.ASSIGNSELF),data=Object.assign({},target.dataset);this.reactive.dispatch("assignUser",data.id)}_addCard(event){document.activeElement.blur();let target=event.target.closest(_selectors.default.ADDCARD),data=Object.assign({},target.dataset);this.reactive.dispatch("addCard",data.columnid,data.id)}async _cardUpdated(_ref3){let{element:element}=_ref3;const card=this.getElement();if(card.dataset.columnid!=element.kanban_column){document.querySelector(_selectors.default.COLUMNINNER+'[data-id="'+element.kanban_column+'"]').appendChild(card),this.getElement(_selectors.default.ADDCARD,this.id).setAttribute("data-columnid",element.kanban_column),card.setAttribute("data-columnid",element.kanban_column)}const assignees=this.getElement(_selectors.default.ASSIGNEES,this.id),assignedUsers=this.getElements(_selectors.default.ASSIGNEDUSER,this.id),userids=[...assignedUsers].map((v=>v.dataset.userid));if(void 0!==element.assignees){const additional=element.assignees.filter((x=>!userids.includes(x)));null!==assignedUsers&&assignedUsers.forEach((assignedUser=>{element.assignees.includes(assignedUser.dataset.userid)||assignedUser.parentNode.removeChild(assignedUser)})),this.toggleClass(0==element.assignees.length,"mod_kanban_unassigned"),element.assignees.length>0&&additional.forEach((async user=>{let userdata=this.reactive.state.users.get(user),data=Object.assign({cardid:element.id},userdata);data=Object.assign(data,_exporter.default.exportCapabilities(this.reactive.state)),_templates.default.renderForPromise("mod_kanban/user",data).then((_ref4=>{let{html:html,js:js}=_ref4;return _templates.default.appendNodeContents(assignees,html,js),!0})).catch((error=>(0,_notification.exception)(error)))}))}if(this.toggleClass(element.selfassigned,"mod_kanban_selfassigned"),this.toggleClass(1==element.completed,"mod_kanban_closed"),void 0!==element.title){let doc=(new DOMParser).parseFromString(element.title,"text/html");this.getElement(_selectors.default.INPLACEEDITABLE).setAttribute("data-value",doc.documentElement.textContent),this.getElement(_selectors.default.INPLACEEDITABLE).querySelector("a").innerHTML=element.title,this.getElement(_selectors.default.DESCRIPTIONMODALTITLE).innerHTML=element.title,this.getElement(_selectors.default.DISCUSSIONMODALTITLE).innerHTML=element.title}if(void 0!==element.description&&(this.getElement(_selectors.default.DESCRIPTIONMODALBODY).innerHTML=element.description),void 0!==element.attachments&&_templates.default.renderForPromise("mod_kanban/attachmentitems",{attachments:element.attachments}).then((_ref5=>{let{html:html}=_ref5;return this.getElement(_selectors.default.DESCRIPTIONMODALFOOTER).innerHTML=html,!0})).catch((error=>(0,_notification.exception)(error))),this.toggleClass(element.hasdescription,"mod_kanban_hasdescription"),this.toggleClass(element.hasattachment,"mod_kanban_hasattachment"),void 0!==element.duedate&&(this.getElement(_selectors.default.DUEDATE).setAttribute("data-date",element.duedate),this._dueDateFormat()),this.toggleClass(element.discussion,"mod_kanban_hasdiscussion"),void 0!==element.options){let options=JSON.parse(element.options);void 0===options.background?this.getElement().removeAttribute("style"):this.getElement().setAttribute("style","background-color: "+options.background)}this.checkEditing()}_cardDeleted(){this.destroy()}_removeCard(event){let target=event.target.closest(_selectors.default.DELETECARD),data=Object.assign({},target.dataset);this.reactive.dispatch("deleteCard",data.id)}_pushCard(event){let target=event.target.closest(_selectors.default.PUSHCARD),data=Object.assign({},target.dataset);this.reactive.dispatch("pushCard",data.id)}_removeMessage(event){let target=event.target.closest(_selectors.default.DELETEMESSAGE),data=Object.assign({},target.dataset);this.reactive.dispatch("deleteMessage",data.id)}_completeCard(event){let target=event.target.closest(_selectors.default.COMPLETE),data=Object.assign({},target.dataset);this.reactive.dispatch("completeCard",data.id)}_uncompleteCard(event){let target=event.target.closest(_selectors.default.UNCOMPLETE),data=Object.assign({},target.dataset);this.reactive.dispatch("uncompleteCard",data.id)}destroy(){void 0!==this.dragdrop&&this.dragdrop.unregister()}getDraggableData(){return{id:this.id,type:"card"}}checkEditing(state){void 0===state&&(state=this.reactive.stateManager.state),state.cards.get(this.id).canedit?(this.draggable=!0,this.dragdrop.setDraggable(!0)):(this.draggable=!1,this.dragdrop.setDraggable(!1)),1!=state.cards.get(this.id).completed&&state.cards.get(this.id).canedit?this.getElement(_selectors.default.INPLACEEDITABLE).setAttribute("data-inplaceeditable","1"):this.getElement(_selectors.default.INPLACEEDITABLE).removeAttribute("data-inplaceeditable"),this.toggleClass(state.cards.get(this.id).canedit,"mod_kanban_canedit")}validateDropData(dropdata){return"card"==(null==dropdata?void 0:dropdata.type)}drop(dropdata){if(dropdata.id!=this.id){let newcolumn=this.getElement(_selectors.default.ADDCARD,this.id).dataset.columnid,aftercard=this.id;this.reactive.dispatch("moveCard",dropdata.id,newcolumn,aftercard)}}_unassignSelf(event){let target=event.target.closest(_selectors.default.UNASSIGNSELF),data=Object.assign({},target.dataset);this.reactive.dispatch("unassignUser",data.id)}_editDetails(event){event.preventDefault();const modalForm=new _modalform.default({formClass:"mod_kanban\\form\\edit_card_form",args:{id:this.id,boardid:this.boardid,cmid:this.cmid,groupid:this.groupid,userid:this.userid},modalConfig:{title:(0,Str.get_string)("editcard","mod_kanban")},returnFocus:this.getElement()});this.addEventListener(modalForm,modalForm.events.FORM_SUBMITTED,this._updateCard),modalForm.show()}_updateCard(event){this.reactive.dispatch("processUpdates",event.detail)}updateRelativeTime(timestamp){let elapsed=new Date(timestamp)-new Date;for(var u in this._units)if(Math.abs(elapsed)>this._units[u]||"second"==u)return this.rtf.format(Math.round(elapsed/this._units[u]),u);return""}_dueDateFormat(){let duedate=1e3*this.getElement(_selectors.default.DUEDATE).dataset.date;if(duedate>0){let element=this.getElement(_selectors.default.DUEDATE);element.innerHTML=this.updateRelativeTime(duedate),duedate<(new Date).getTime()?element.classList.add("mod_kanban_overdue"):element.classList.remove("mod_kanban_overdue")}else this.getElement(_selectors.default.DUEDATE).innerHTML=""}}return _exports.default=_default,_exports.default})); +define("mod_kanban/card",["exports","core/reactive","mod_kanban/selectors","mod_kanban/exporter","core/notification","core_form/modalform","core/modal_events","core/str","core/templates","mod_kanban/kanbancomponent","core/log"],(function(_exports,_reactive,_selectors,_exporter,_notification,_modalform,_modal_events,Str,_templates,_kanbancomponent,_log){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}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_selectors=_interopRequireDefault(_selectors),_exporter=_interopRequireDefault(_exporter),_modalform=_interopRequireDefault(_modalform),_modal_events=_interopRequireDefault(_modal_events),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),_templates=_interopRequireDefault(_templates),_kanbancomponent=_interopRequireDefault(_kanbancomponent),_log=_interopRequireDefault(_log);class _default extends _kanbancomponent.default{constructor(){var obj,key,value;super(...arguments),value={year:31536e6,month:2628e6,day:864e5,hour:36e5,minute:6e4,second:1e3},(key="_units")in(obj=this)?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}static init(target){return new this({element:document.getElementById(target)})}create(){this.id=this.element.dataset.id}getWatchers(){return[{watch:"cards[".concat(this.id,"]:updated"),handler:this._cardUpdated},{watch:"cards[".concat(this.id,"]:deleted"),handler:this._cardDeleted},{watch:"discussions:created",handler:this._discussionUpdated},{watch:"discussions:updated",handler:this._discussionUpdated},{watch:"discussions:deleted",handler:this._discussionUpdated},{watch:"history:created",handler:this._historyUpdated},{watch:"history:updated",handler:this._historyUpdated},{watch:"history:deleted",handler:this._historyUpdated}]}stateReady(state){let lang="en";void 0!==state.common.lang&&(lang=state.common.lang);try{this.rtf=new Intl.RelativeTimeFormat(lang,{numeric:"auto"})}catch(e){this.rtf=new Intl.RelativeTimeFormat("en",{numeric:"auto"})}this.addEventListener(this.getElement(_selectors.default.DELETECARD,this.id),"click",this._removeConfirm),this.addEventListener(this.getElement(_selectors.default.ADDCARD,this.id),"click",this._addCard),this.addEventListener(this.getElement(_selectors.default.COMPLETE,this.id),"click",this._completeCard),this.addEventListener(this.getElement(_selectors.default.UNCOMPLETE,this.id),"click",this._uncompleteCard),this.addEventListener(this.getElement(_selectors.default.ASSIGNSELF,this.id),"click",this._assignSelf),this.addEventListener(this.getElement(_selectors.default.UNASSIGNSELF,this.id),"click",this._unassignSelf),this.addEventListener(this.getElement(_selectors.default.EDITDETAILS,this.id),"click",this._editDetails),this.addEventListener(this.getElement(_selectors.default.DISCUSSIONMODALTRIGGER),"click",this._updateDiscussion),this.addEventListener(this.getElement(_selectors.default.DISCUSSIONSHOW,this.id),"click",this._updateDiscussion),this.addEventListener(this.getElement(_selectors.default.DISCUSSIONSEND),"click",this._sendMessage),this.addEventListener(this.getElement(_selectors.default.HISTORYMODALTRIGGER),"click",this._updateHistory),this.addEventListener(this.getElement(_selectors.default.MOVEMODALTRIGGER),"click",this._showMoveModal),this.addEventListener(this.getElement(_selectors.default.PUSHCARD),"click",this._pushCardConfirm),this.addEventListener(this.getElement(_selectors.default.DETAILBUTTON),"click",this._showDetailsModal),this.draggable=!1,this.dragdrop=new _reactive.DragDrop(this),this.checkEditing(state),this.boardid=state.board.id,this.cmid=state.common.id,this.userid=state.board.userid,this.groupid=state.board.groupid,this._dueDateFormat()}_showMoveModal(){let data=_exporter.default.exportStateForTemplate(this.reactive.state);data.cardid=this.id,data.kanbancolumn=this.reactive.state.cards.get(this.id).kanban_column,Str.get_strings([{key:"movecard",component:"mod_kanban"},{key:"move",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],_templates.default.render("mod_kanban/movemodal",data),strings[1],(()=>{let column=document.querySelector(_selectors.default.MOVECARDCOLUMN+'[data-id="'.concat(this.id,'"]')).value,aftercard=document.querySelector(_selectors.default.MOVECARDAFTERCARD+'[data-id="'.concat(this.id,'"]')).value;this.reactive.dispatch("moveCard",this.id,column,aftercard)})))).catch((error=>_log.default.debug(error)))}_showDetailsModal(event){let id=this.id;void 0!==event.target.dataset.id&&(id=event.target.dataset.id);let data=_exporter.default.exportCard(this.reactive.state,id),title=this.reactive.state.common.usenumbers?"#"+data.number+" "+data.title:data.title;(0,_notification.alert)(title,_templates.default.render("mod_kanban/descriptionmodal",data),(0,Str.get_string)("close","form")).then((modal=>(modal.modal[0].addEventListener(_modal_events.default.bodyRendered,(()=>{document.querySelectorAll(_selectors.default.CARDNUMBER).forEach((el=>{this.removeEventListener(el,"click",this._clickDetailsButton),this.addEventListener(el,"click",this._clickDetailsButton)}))})),!0))).catch((error=>_log.default.debug(error)))}_clickDetailsButton(event){document.querySelector(_selectors.default.CARD+'[data-number="'.concat(event.target.dataset.id,'"]')+" "+_selectors.default.DETAILBUTTON).click()}_pushCardConfirm(event){Str.get_strings([{key:"pushcard",component:"mod_kanban"},{key:"pushcardconfirm",component:"mod_kanban"},{key:"copy",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._pushCard(event)})))).catch((error=>_log.default.debug(error)))}_removeConfirm(event){Str.get_strings([{key:"deletecard",component:"mod_kanban"},{key:"deletecardconfirm",component:"mod_kanban"},{key:"delete",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._removeCard(event)})))).catch((error=>_log.default.debug(error)))}_removeMessageConfirm(event){Str.get_strings([{key:"deletemessage",component:"mod_kanban"},{key:"deletemessageconfirm",component:"mod_kanban"},{key:"delete",component:"core"}]).then((strings=>(0,_notification.saveCancel)(strings[0],strings[1],strings[2],(()=>{this._removeMessage(event)})))).catch((error=>_log.default.debug(error)))}_sendMessage(){let el=this.getElement(_selectors.default.DISCUSSIONINPUT),message=el.value.trim();""!=message&&(this.reactive.dispatch("sendDiscussionMessage",this.id,message),el.value="")}_updateDiscussion(){this.getElement(_selectors.default.DISCUSSIONMODAL).classList.add("mod_kanban_loading"),this.reactive.dispatch("getDiscussionUpdates",this.id)}async _discussionUpdated(){let data={discussions:_exporter.default.exportDiscussion(this.reactive.state,this.id)};_templates.default.renderForPromise("mod_kanban/discussionmessages",data).then((_ref=>{let{html:html}=_ref;this.getElement(_selectors.default.DISCUSSION,this.id).innerHTML=html,this.getElement(_selectors.default.DISCUSSIONMODAL,this.id).classList.remove("mod_kanban_loading");let el=this.getElement(_selectors.default.DISCUSSIONMESSAGES);return el.scrollTop=el.scrollHeight,data.discussions.forEach((d=>{d.candelete&&this.addEventListener(this.getElement(_selectors.default.DELETEMESSAGE,d.id),"click",this._removeMessageConfirm)})),!0})).catch((error=>(0,_notification.exception)(error)))}_updateHistory(){this.getElement(_selectors.default.HISTORYMODAL).classList.add("mod_kanban_loading"),this.reactive.dispatch("getHistoryUpdates",this.id)}async _historyUpdated(){let data={historyitems:_exporter.default.exportHistory(this.reactive.state,this.id)};_templates.default.renderForPromise("mod_kanban/historyitems",data).then((_ref2=>{let{html:html}=_ref2;this.getElement(_selectors.default.HISTORY,this.id).innerHTML=html,this.getElement(_selectors.default.HISTORYMODAL).classList.remove("mod_kanban_loading");let el=this.getElement(_selectors.default.HISTORYITEMS);return el.scrollTop=el.scrollHeight,!0})).catch((error=>(0,_notification.exception)(error)))}_assignSelf(event){let target=event.target.closest(_selectors.default.ASSIGNSELF),data=Object.assign({},target.dataset);this.reactive.dispatch("assignUser",data.id)}_addCard(event){document.activeElement.blur();let target=event.target.closest(_selectors.default.ADDCARD),data=Object.assign({},target.dataset);this.reactive.dispatch("addCard",data.columnid,data.id)}async _cardUpdated(_ref3){let{element:element}=_ref3;const card=this.getElement();if(card.dataset.columnid!=element.kanban_column){document.querySelector(_selectors.default.COLUMNINNER+'[data-id="'+element.kanban_column+'"]').appendChild(card),this.getElement(_selectors.default.ADDCARD,this.id).setAttribute("data-columnid",element.kanban_column),card.setAttribute("data-columnid",element.kanban_column)}const assignees=this.getElement(_selectors.default.ASSIGNEES,this.id),assignedUsers=this.getElements(_selectors.default.ASSIGNEDUSER,this.id),userids=[...assignedUsers].map((v=>v.dataset.userid));if(void 0!==element.assignees){const additional=element.assignees.filter((x=>!userids.includes(x)));null!==assignedUsers&&assignedUsers.forEach((assignedUser=>{element.assignees.includes(assignedUser.dataset.userid)||assignedUser.parentNode.removeChild(assignedUser)})),this.toggleClass(0==element.assignees.length,"mod_kanban_unassigned"),element.assignees.length>0&&additional.forEach((async user=>{let userdata=this.reactive.state.users.get(user),data=Object.assign({cardid:element.id},userdata);data=Object.assign(data,_exporter.default.exportCapabilities(this.reactive.state)),_templates.default.renderForPromise("mod_kanban/user",data).then((_ref4=>{let{html:html,js:js}=_ref4;return _templates.default.appendNodeContents(assignees,html,js),!0})).catch((error=>(0,_notification.exception)(error)))}))}if(this.toggleClass(element.selfassigned,"mod_kanban_selfassigned"),this.toggleClass(1==element.completed,"mod_kanban_closed"),void 0!==element.title){let doc=(new DOMParser).parseFromString(element.title,"text/html");this.getElement(_selectors.default.INPLACEEDITABLE).setAttribute("data-value",doc.documentElement.textContent),this.getElement(_selectors.default.INPLACEEDITABLE).querySelector("a").innerHTML=element.title,this.getElement(_selectors.default.DISCUSSIONMODALTITLE).innerHTML=element.title}if(this.toggleClass(element.hasdescription,"mod_kanban_hasdescription"),this.toggleClass(element.hasattachment,"mod_kanban_hasattachment"),void 0!==element.duedate&&(this.getElement(_selectors.default.DUEDATE).setAttribute("data-date",element.duedate),this._dueDateFormat()),this.toggleClass(element.discussion,"mod_kanban_hasdiscussion"),void 0!==element.options){let options=JSON.parse(element.options);void 0===options.background?this.getElement().removeAttribute("style"):this.getElement().setAttribute("style","background-color: "+options.background)}this.checkEditing()}_cardDeleted(){this.destroy()}_removeCard(event){let target=event.target.closest(_selectors.default.DELETECARD),data=Object.assign({},target.dataset);this.reactive.dispatch("deleteCard",data.id)}_pushCard(event){let target=event.target.closest(_selectors.default.PUSHCARD),data=Object.assign({},target.dataset);this.reactive.dispatch("pushCard",data.id)}_removeMessage(event){let target=event.target.closest(_selectors.default.DELETEMESSAGE),data=Object.assign({},target.dataset);this.reactive.dispatch("deleteMessage",data.id)}_completeCard(event){let target=event.target.closest(_selectors.default.COMPLETE),data=Object.assign({},target.dataset);this.reactive.dispatch("completeCard",data.id)}_uncompleteCard(event){let target=event.target.closest(_selectors.default.UNCOMPLETE),data=Object.assign({},target.dataset);this.reactive.dispatch("uncompleteCard",data.id)}destroy(){void 0!==this.dragdrop&&this.dragdrop.unregister()}getDraggableData(){return{id:this.id,type:"card"}}checkEditing(state){void 0===state&&(state=this.reactive.stateManager.state),state.cards.get(this.id).canedit?(this.draggable=!0,this.dragdrop.setDraggable(!0)):(this.draggable=!1,this.dragdrop.setDraggable(!1)),1!=state.cards.get(this.id).completed&&state.cards.get(this.id).canedit?this.getElement(_selectors.default.INPLACEEDITABLE).setAttribute("data-inplaceeditable","1"):this.getElement(_selectors.default.INPLACEEDITABLE).removeAttribute("data-inplaceeditable"),this.toggleClass(state.cards.get(this.id).canedit,"mod_kanban_canedit")}validateDropData(dropdata){return"card"==(null==dropdata?void 0:dropdata.type)}drop(dropdata){if(dropdata.id!=this.id){let newcolumn=this.getElement(_selectors.default.ADDCARD,this.id).dataset.columnid,aftercard=this.id;this.reactive.dispatch("moveCard",dropdata.id,newcolumn,aftercard)}}_unassignSelf(event){let target=event.target.closest(_selectors.default.UNASSIGNSELF),data=Object.assign({},target.dataset);this.reactive.dispatch("unassignUser",data.id)}_editDetails(event){event.preventDefault();const modalForm=new _modalform.default({formClass:"mod_kanban\\form\\edit_card_form",args:{id:this.id,boardid:this.boardid,cmid:this.cmid,groupid:this.groupid,userid:this.userid},modalConfig:{title:(0,Str.get_string)("editcard","mod_kanban")},returnFocus:this.getElement()});this.addEventListener(modalForm,modalForm.events.FORM_SUBMITTED,this._updateCard),modalForm.show()}_updateCard(event){this.reactive.dispatch("processUpdates",event.detail)}updateRelativeTime(timestamp){let elapsed=new Date(timestamp)-new Date;for(var u in this._units)if(Math.abs(elapsed)>this._units[u]||"second"==u)return this.rtf.format(Math.round(elapsed/this._units[u]),u);return""}_dueDateFormat(){let duedate=1e3*this.getElement(_selectors.default.DUEDATE).dataset.date;if(duedate>0){let element=this.getElement(_selectors.default.DUEDATE);element.innerHTML=this.updateRelativeTime(duedate),duedate<(new Date).getTime()?element.classList.add("mod_kanban_overdue"):element.classList.remove("mod_kanban_overdue")}else this.getElement(_selectors.default.DUEDATE).innerHTML=""}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=card.min.js.map \ No newline at end of file diff --git a/amd/build/card.min.js.map b/amd/build/card.min.js.map index 9d3f0b19..25e936b6 100644 --- a/amd/build/card.min.js.map +++ b/amd/build/card.min.js.map @@ -1 +1 @@ -{"version":3,"file":"card.min.js","sources":["../src/card.js"],"sourcesContent":["import {DragDrop} from 'core/reactive';\nimport selectors from 'mod_kanban/selectors';\nimport exporter from 'mod_kanban/exporter';\nimport {exception as displayException, saveCancel} from 'core/notification';\nimport ModalForm from 'core_form/modalform';\nimport * as Str from 'core/str';\nimport {get_string as getString} from 'core/str';\nimport Templates from 'core/templates';\nimport KanbanComponent from 'mod_kanban/kanbancomponent';\nimport Log from 'core/log';\n\n/**\n * Component representing a card in a kanban board.\n */\nexport default class extends KanbanComponent {\n /**\n * For relative time helper.\n */\n _units = {\n year: 24 * 60 * 60 * 1000 * 365,\n month: 24 * 60 * 60 * 1000 * 365 / 12,\n day: 24 * 60 * 60 * 1000,\n hour: 60 * 60 * 1000,\n minute: 60 * 1000,\n second: 1000\n };\n\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} All watchers for this component\n */\n getWatchers() {\n return [\n {watch: `cards[${this.id}]:updated`, handler: this._cardUpdated},\n {watch: `cards[${this.id}]:deleted`, handler: this._cardDeleted},\n {watch: `discussions:created`, handler: this._discussionUpdated},\n {watch: `discussions:updated`, handler: this._discussionUpdated},\n {watch: `discussions:deleted`, handler: this._discussionUpdated},\n {watch: `history:created`, handler: this._historyUpdated},\n {watch: `history:updated`, handler: this._historyUpdated},\n {watch: `history:deleted`, handler: this._historyUpdated},\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 stateReady(state) {\n // Get language for relative time formatting.\n let lang = 'en';\n if (state.common.lang !== undefined) {\n lang = state.common.lang;\n }\n // The property state.common.lang contains the locale extracted from the currently used moodle language pack.\n // This should be a real locale and thus suitable for RelativeTimeFormat, for edge cases however we are\n // using a fallback locale here.\n try {\n this.rtf = new Intl.RelativeTimeFormat(lang, {numeric: 'auto'});\n } catch (e) {\n // Fallback if there is no valid lang found.\n this.rtf = new Intl.RelativeTimeFormat('en', {numeric: 'auto'});\n }\n\n this.addEventListener(\n this.getElement(selectors.DELETECARD, this.id),\n 'click',\n this._removeConfirm\n );\n this.addEventListener(\n this.getElement(selectors.ADDCARD, this.id),\n 'click',\n this._addCard\n );\n this.addEventListener(\n this.getElement(selectors.COMPLETE, this.id),\n 'click',\n this._completeCard\n );\n this.addEventListener(\n this.getElement(selectors.UNCOMPLETE, this.id),\n 'click',\n this._uncompleteCard\n );\n this.addEventListener(\n this.getElement(selectors.ASSIGNSELF, this.id),\n 'click',\n this._assignSelf\n );\n this.addEventListener(\n this.getElement(selectors.UNASSIGNSELF, this.id),\n 'click',\n this._unassignSelf\n );\n this.addEventListener(\n this.getElement(selectors.EDITDETAILS, this.id),\n 'click',\n this._editDetails\n );\n this.addEventListener(\n this.getElement(selectors.DISCUSSIONMODALTRIGGER),\n 'click',\n this._updateDiscussion\n );\n this.addEventListener(\n this.getElement(selectors.DISCUSSIONSHOW, this.id),\n 'click',\n this._updateDiscussion\n );\n this.addEventListener(\n this.getElement(selectors.DISCUSSIONSEND),\n 'click',\n this._sendMessage\n );\n this.addEventListener(\n this.getElement(selectors.HISTORYMODALTRIGGER),\n 'click',\n this._updateHistory\n );\n this.addEventListener(\n this.getElement(selectors.MOVEMODALTRIGGER),\n 'click',\n this._showMoveModal\n );\n this.addEventListener(\n this.getElement(selectors.PUSHCARD),\n 'click',\n this._pushCardConfirm\n );\n\n this.draggable = false;\n this.dragdrop = new DragDrop(this);\n this.checkEditing(state);\n this.boardid = state.board.id;\n this.cmid = state.common.id;\n this.userid = state.board.userid;\n this.groupid = state.board.groupid;\n this._dueDateFormat();\n }\n\n /**\n * Show modal to move a column.\n */\n _showMoveModal() {\n let data = exporter.exportStateForTemplate(this.reactive.state);\n data.cardid = this.id;\n data.kanbancolumn = this.reactive.state.cards.get(this.id).kanban_column;\n Str.get_strings([\n {key: 'movecard', component: 'mod_kanban'},\n {key: 'move', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n Templates.render('mod_kanban/movemodal', data),\n strings[1],\n () => {\n let column = document.querySelector(selectors.MOVECARDCOLUMN + `[data-id=\"${this.id}\"]`).value;\n let aftercard = document.querySelector(selectors.MOVECARDAFTERCARD + `[data-id=\"${this.id}\"]`).value;\n this.reactive.dispatch('moveCard', this.id, column, aftercard);\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Display confirmation modal for pushing a card.\n * @param {*} event\n */\n _pushCardConfirm(event) {\n Str.get_strings([\n {key: 'pushcard', component: 'mod_kanban'},\n {key: 'pushcardconfirm', component: 'mod_kanban'},\n {key: 'copy', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n strings[1],\n strings[2],\n () => {\n this._pushCard(event);\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Display confirmation modal for deleting a card.\n * @param {*} event\n */\n _removeConfirm(event) {\n Str.get_strings([\n {key: 'deletecard', component: 'mod_kanban'},\n {key: 'deletecardconfirm', 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._removeCard(event);\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Display confirmation modal for deleting a discussion message.\n * @param {*} event\n */\n _removeMessageConfirm(event) {\n Str.get_strings([\n {key: 'deletemessage', component: 'mod_kanban'},\n {key: 'deletemessageconfirm', 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._removeMessage(event);\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Dispatch event to add a message to discussion.\n */\n _sendMessage() {\n let el = this.getElement(selectors.DISCUSSIONINPUT);\n let message = el.value.trim();\n if (message != '') {\n this.reactive.dispatch('sendDiscussionMessage', this.id, message);\n el.value = '';\n }\n }\n\n /**\n * Dispatch event to update the discussion data.\n */\n _updateDiscussion() {\n this.getElement(selectors.DISCUSSIONMODAL).classList.add('mod_kanban_loading');\n this.reactive.dispatch('getDiscussionUpdates', this.id);\n }\n\n /**\n * Called when discussion was updated.\n */\n async _discussionUpdated() {\n let data = {\n discussions: exporter.exportDiscussion(this.reactive.state, this.id)\n };\n Templates.renderForPromise('mod_kanban/discussionmessages', data).then(({html}) => {\n this.getElement(selectors.DISCUSSION, this.id).innerHTML = html;\n this.getElement(selectors.DISCUSSIONMODAL, this.id).classList.remove('mod_kanban_loading');\n let el = this.getElement(selectors.DISCUSSIONMESSAGES);\n // Scroll down to latest message.\n el.scrollTop = el.scrollHeight;\n data.discussions.forEach((d) => {\n if (d.candelete) {\n this.addEventListener(this.getElement(selectors.DELETEMESSAGE, d.id), 'click', this._removeMessageConfirm);\n }\n });\n return true;\n }).catch((error) => displayException(error));\n }\n\n /**\n * Dispatch event to update the history data.\n */\n _updateHistory() {\n this.getElement(selectors.HISTORYMODAL).classList.add('mod_kanban_loading');\n this.reactive.dispatch('getHistoryUpdates', this.id);\n }\n\n /**\n * Called when history was updated.\n */\n async _historyUpdated() {\n let data = {\n historyitems: exporter.exportHistory(this.reactive.state, this.id)\n };\n Templates.renderForPromise('mod_kanban/historyitems', data).then(({html}) => {\n this.getElement(selectors.HISTORY, this.id).innerHTML = html;\n this.getElement(selectors.HISTORYMODAL).classList.remove('mod_kanban_loading');\n // Scroll down to latest history item.\n let el = this.getElement(selectors.HISTORYITEMS);\n el.scrollTop = el.scrollHeight;\n return true;\n }).catch((error) => displayException(error));\n }\n\n /**\n * Dispatch event to assign the current user to the card.\n * @param {*} event\n */\n _assignSelf(event) {\n let target = event.target.closest(selectors.ASSIGNSELF);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('assignUser', data.id);\n }\n\n /**\n * Dispatch event to add a card after this card.\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, data.id);\n }\n\n /**\n * Called when card is updated.\n * @param {*} param0\n */\n async _cardUpdated({element}) {\n const card = this.getElement();\n // Card was moved to another column. Move the element to new card (right position is handled by column component).\n if (card.dataset.columnid != element.kanban_column) {\n const col = document.querySelector(selectors.COLUMNINNER + '[data-id=\"' + element.kanban_column + '\"]');\n col.appendChild(card);\n this.getElement(selectors.ADDCARD, this.id).setAttribute('data-columnid', element.kanban_column);\n card.setAttribute('data-columnid', element.kanban_column);\n }\n const assignees = this.getElement(selectors.ASSIGNEES, this.id);\n const assignedUsers = this.getElements(selectors.ASSIGNEDUSER, this.id);\n const userids = [...assignedUsers].map(v => {\n return v.dataset.userid;\n });\n // Update assignees.\n if (element.assignees !== undefined) {\n const additional = element.assignees.filter(x => !userids.includes(x));\n // Remove all elements that represent users that are no longer assigned to this card.\n if (assignedUsers !== null) {\n assignedUsers.forEach(assignedUser => {\n if (!element.assignees.includes(assignedUser.dataset.userid)) {\n assignedUser.parentNode.removeChild(assignedUser);\n }\n });\n }\n this.toggleClass(element.assignees.length == 0, 'mod_kanban_unassigned');\n // Add new assignees.\n if (element.assignees.length > 0) {\n additional.forEach(async user => {\n let userdata = this.reactive.state.users.get(user);\n let data = Object.assign({cardid: element.id}, userdata);\n data = Object.assign(data, exporter.exportCapabilities(this.reactive.state));\n Templates.renderForPromise('mod_kanban/user', data).then(({html, js}) => {\n Templates.appendNodeContents(assignees, html, js);\n return true;\n }).catch((error) => displayException(error));\n });\n }\n }\n this.toggleClass(element.selfassigned, 'mod_kanban_selfassigned');\n // Set card completion state.\n this.toggleClass(element.completed == 1, 'mod_kanban_closed');\n // Update title (also in modals).\n if (element.title !== undefined) {\n // For Moodle inplace editing title is once needed plain and once with html entities encoded.\n // This avoids double encoding of html entities as the value of \"data-value\" is exactly what is shown\n // in the input field when clicking on the inplace editable.\n let doc = new DOMParser().parseFromString(element.title, 'text/html');\n this.getElement(selectors.INPLACEEDITABLE).setAttribute('data-value', doc.documentElement.textContent);\n this.getElement(selectors.INPLACEEDITABLE).querySelector('a').innerHTML = element.title;\n this.getElement(selectors.DESCRIPTIONMODALTITLE).innerHTML = element.title;\n this.getElement(selectors.DISCUSSIONMODALTITLE).innerHTML = element.title;\n }\n // Update description.\n if (element.description !== undefined) {\n this.getElement(selectors.DESCRIPTIONMODALBODY).innerHTML = element.description;\n }\n // Render attachments in description modal.\n if (element.attachments !== undefined) {\n Templates.renderForPromise('mod_kanban/attachmentitems', {attachments: element.attachments}).then(({html}) => {\n this.getElement(selectors.DESCRIPTIONMODALFOOTER).innerHTML = html;\n return true;\n }).catch((error) => displayException(error));\n }\n this.toggleClass(element.hasdescription, 'mod_kanban_hasdescription');\n this.toggleClass(element.hasattachment, 'mod_kanban_hasattachment');\n // Update due date.\n if (element.duedate !== undefined) {\n this.getElement(selectors.DUEDATE).setAttribute('data-date', element.duedate);\n this._dueDateFormat();\n }\n this.toggleClass(element.discussion, 'mod_kanban_hasdiscussion');\n // Only option for now is background color.\n if (element.options !== undefined) {\n let options = JSON.parse(element.options);\n if (options.background === undefined) {\n this.getElement().removeAttribute('style');\n } else {\n this.getElement().setAttribute('style', 'background-color: ' + options.background);\n }\n }\n // Enable/disable dragging and inplace editing (e.g. if user is not assigned to the card anymore).\n this.checkEditing();\n }\n\n /**\n * Delete this card.\n */\n _cardDeleted() {\n this.destroy();\n }\n\n /**\n * Dispatch event to remove this card.\n * @param {*} event\n */\n _removeCard(event) {\n let target = event.target.closest(selectors.DELETECARD);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('deleteCard', data.id);\n }\n\n /**\n * Dispatch event to push this card.\n * @param {*} event\n */\n _pushCard(event) {\n let target = event.target.closest(selectors.PUSHCARD);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('pushCard', data.id);\n }\n\n /**\n * Dispatch event to remove this card.\n * @param {*} event\n */\n _removeMessage(event) {\n let target = event.target.closest(selectors.DELETEMESSAGE);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('deleteMessage', data.id);\n }\n\n /**\n * Dispatch event to complete this card.\n * @param {*} event\n */\n _completeCard(event) {\n let target = event.target.closest(selectors.COMPLETE);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('completeCard', data.id);\n }\n\n /**\n * Dispatch event to complete this card.\n * @param {*} event\n */\n _uncompleteCard(event) {\n let target = event.target.closest(selectors.UNCOMPLETE);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('uncompleteCard', data.id);\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 * @returns {object}\n */\n getDraggableData() {\n return {\n id: this.id,\n type: 'card',\n };\n }\n\n /**\n * Conditionally enable / disable dragging and inplace editing.\n * @param {*} state\n */\n checkEditing(state) {\n if (state === undefined) {\n state = this.reactive.stateManager.state;\n }\n if (state.cards.get(this.id).canedit) {\n this.draggable = true;\n this.dragdrop.setDraggable(true);\n } else {\n this.draggable = false;\n this.dragdrop.setDraggable(false);\n }\n if (state.cards.get(this.id).completed != 1 && state.cards.get(this.id).canedit) {\n this.getElement(selectors.INPLACEEDITABLE).setAttribute('data-inplaceeditable', '1');\n } else {\n this.getElement(selectors.INPLACEEDITABLE).removeAttribute('data-inplaceeditable');\n }\n\n this.toggleClass(state.cards.get(this.id).canedit, 'mod_kanban_canedit');\n }\n\n /**\n * Validate draggable data.\n * @param {object} dropdata\n * @returns {boolean} if the data is valid for this drop-zone.\n */\n validateDropData(dropdata) {\n return dropdata?.type == 'card';\n }\n\n /**\n * Executed when a valid dropdata is dropped over the drop-zone.\n * @param {object} dropdata\n */\n drop(dropdata) {\n if (dropdata.id != this.id) {\n let newcolumn = this.getElement(selectors.ADDCARD, this.id).dataset.columnid;\n let aftercard = this.id;\n this.reactive.dispatch('moveCard', dropdata.id, newcolumn, aftercard);\n }\n }\n\n /**\n * Dispatch event to unassign the current user.\n * @param {*} event\n */\n _unassignSelf(event) {\n let target = event.target.closest(selectors.UNASSIGNSELF);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('unassignUser', data.id);\n }\n\n /**\n * Show modal form to edit card details.\n * @param {*} event\n */\n _editDetails(event) {\n event.preventDefault();\n\n const modalForm = new ModalForm({\n formClass: \"mod_kanban\\\\form\\\\edit_card_form\",\n args: {\n id: this.id,\n boardid: this.boardid,\n cmid: this.cmid,\n groupid: this.groupid,\n userid: this.userid\n },\n modalConfig: {title: getString('editcard', 'mod_kanban')},\n returnFocus: this.getElement(),\n });\n this.addEventListener(modalForm, modalForm.events.FORM_SUBMITTED, this._updateCard);\n modalForm.show();\n }\n\n /**\n * Dispatch an event to update card data from the detail modal.\n * @param {*} event\n */\n _updateCard(event) {\n this.reactive.dispatch('processUpdates', event.detail);\n }\n\n /**\n * Update relative time.\n * @param {int} timestamp\n * @returns {string}\n */\n updateRelativeTime(timestamp) {\n let elapsed = new Date(timestamp) - new Date();\n for (var u in this._units) {\n if (Math.abs(elapsed) > this._units[u] || u == 'second') {\n return this.rtf.format(Math.round(elapsed / this._units[u]), u);\n }\n }\n return '';\n }\n\n /**\n * Format due date using relative time.\n */\n _dueDateFormat() {\n // Convert timestamp to ms.\n let duedate = this.getElement(selectors.DUEDATE).dataset.date * 1000;\n if (duedate > 0) {\n let element = this.getElement(selectors.DUEDATE);\n element.innerHTML = this.updateRelativeTime(duedate);\n if (duedate < new Date().getTime()) {\n element.classList.add('mod_kanban_overdue');\n } else {\n element.classList.remove('mod_kanban_overdue');\n }\n } else {\n this.getElement(selectors.DUEDATE).innerHTML = '';\n }\n }\n}\n"],"names":["KanbanComponent","year","month","day","hour","minute","second","target","this","element","document","getElementById","create","id","dataset","getWatchers","watch","handler","_cardUpdated","_cardDeleted","_discussionUpdated","_historyUpdated","stateReady","state","lang","undefined","common","rtf","Intl","RelativeTimeFormat","numeric","e","addEventListener","getElement","selectors","DELETECARD","_removeConfirm","ADDCARD","_addCard","COMPLETE","_completeCard","UNCOMPLETE","_uncompleteCard","ASSIGNSELF","_assignSelf","UNASSIGNSELF","_unassignSelf","EDITDETAILS","_editDetails","DISCUSSIONMODALTRIGGER","_updateDiscussion","DISCUSSIONSHOW","DISCUSSIONSEND","_sendMessage","HISTORYMODALTRIGGER","_updateHistory","MOVEMODALTRIGGER","_showMoveModal","PUSHCARD","_pushCardConfirm","draggable","dragdrop","DragDrop","checkEditing","boardid","board","cmid","userid","groupid","_dueDateFormat","data","exporter","exportStateForTemplate","reactive","cardid","kanbancolumn","cards","get","kanban_column","Str","get_strings","key","component","then","strings","Templates","render","column","querySelector","MOVECARDCOLUMN","value","aftercard","MOVECARDAFTERCARD","dispatch","catch","error","Log","debug","event","_pushCard","_removeCard","_removeMessageConfirm","_removeMessage","el","DISCUSSIONINPUT","message","trim","DISCUSSIONMODAL","classList","add","discussions","exportDiscussion","renderForPromise","_ref","html","DISCUSSION","innerHTML","remove","DISCUSSIONMESSAGES","scrollTop","scrollHeight","forEach","d","candelete","DELETEMESSAGE","HISTORYMODAL","historyitems","exportHistory","_ref2","HISTORY","HISTORYITEMS","closest","Object","assign","activeElement","blur","columnid","card","COLUMNINNER","appendChild","setAttribute","assignees","ASSIGNEES","assignedUsers","getElements","ASSIGNEDUSER","userids","map","v","additional","filter","x","includes","assignedUser","parentNode","removeChild","toggleClass","length","async","userdata","users","user","exportCapabilities","_ref4","js","appendNodeContents","selfassigned","completed","title","doc","DOMParser","parseFromString","INPLACEEDITABLE","documentElement","textContent","DESCRIPTIONMODALTITLE","DISCUSSIONMODALTITLE","description","DESCRIPTIONMODALBODY","attachments","_ref5","DESCRIPTIONMODALFOOTER","hasdescription","hasattachment","duedate","DUEDATE","discussion","options","JSON","parse","background","removeAttribute","destroy","unregister","getDraggableData","type","stateManager","canedit","setDraggable","validateDropData","dropdata","drop","newcolumn","preventDefault","modalForm","ModalForm","formClass","args","modalConfig","returnFocus","events","FORM_SUBMITTED","_updateCard","show","detail","updateRelativeTime","timestamp","elapsed","Date","u","_units","Math","abs","format","round","date","getTime"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"card.min.js","sources":["../src/card.js"],"sourcesContent":["import {DragDrop} from 'core/reactive';\nimport selectors from 'mod_kanban/selectors';\nimport exporter from 'mod_kanban/exporter';\nimport {alert, exception as displayException, saveCancel} from 'core/notification';\nimport ModalForm from 'core_form/modalform';\nimport ModalEvents from 'core/modal_events';\nimport * as Str from 'core/str';\nimport {get_string as getString} from 'core/str';\nimport Templates from 'core/templates';\nimport KanbanComponent from 'mod_kanban/kanbancomponent';\nimport Log from 'core/log';\n\n/**\n * Component representing a card in a kanban board.\n */\nexport default class extends KanbanComponent {\n /**\n * For relative time helper.\n */\n _units = {\n year: 24 * 60 * 60 * 1000 * 365,\n month: 24 * 60 * 60 * 1000 * 365 / 12,\n day: 24 * 60 * 60 * 1000,\n hour: 60 * 60 * 1000,\n minute: 60 * 1000,\n second: 1000\n };\n\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} All watchers for this component\n */\n getWatchers() {\n return [\n {watch: `cards[${this.id}]:updated`, handler: this._cardUpdated},\n {watch: `cards[${this.id}]:deleted`, handler: this._cardDeleted},\n {watch: `discussions:created`, handler: this._discussionUpdated},\n {watch: `discussions:updated`, handler: this._discussionUpdated},\n {watch: `discussions:deleted`, handler: this._discussionUpdated},\n {watch: `history:created`, handler: this._historyUpdated},\n {watch: `history:updated`, handler: this._historyUpdated},\n {watch: `history:deleted`, handler: this._historyUpdated},\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 stateReady(state) {\n // Get language for relative time formatting.\n let lang = 'en';\n if (state.common.lang !== undefined) {\n lang = state.common.lang;\n }\n // The property state.common.lang contains the locale extracted from the currently used moodle language pack.\n // This should be a real locale and thus suitable for RelativeTimeFormat, for edge cases however we are\n // using a fallback locale here.\n try {\n this.rtf = new Intl.RelativeTimeFormat(lang, {numeric: 'auto'});\n } catch (e) {\n // Fallback if there is no valid lang found.\n this.rtf = new Intl.RelativeTimeFormat('en', {numeric: 'auto'});\n }\n\n this.addEventListener(\n this.getElement(selectors.DELETECARD, this.id),\n 'click',\n this._removeConfirm\n );\n this.addEventListener(\n this.getElement(selectors.ADDCARD, this.id),\n 'click',\n this._addCard\n );\n this.addEventListener(\n this.getElement(selectors.COMPLETE, this.id),\n 'click',\n this._completeCard\n );\n this.addEventListener(\n this.getElement(selectors.UNCOMPLETE, this.id),\n 'click',\n this._uncompleteCard\n );\n this.addEventListener(\n this.getElement(selectors.ASSIGNSELF, this.id),\n 'click',\n this._assignSelf\n );\n this.addEventListener(\n this.getElement(selectors.UNASSIGNSELF, this.id),\n 'click',\n this._unassignSelf\n );\n this.addEventListener(\n this.getElement(selectors.EDITDETAILS, this.id),\n 'click',\n this._editDetails\n );\n this.addEventListener(\n this.getElement(selectors.DISCUSSIONMODALTRIGGER),\n 'click',\n this._updateDiscussion\n );\n this.addEventListener(\n this.getElement(selectors.DISCUSSIONSHOW, this.id),\n 'click',\n this._updateDiscussion\n );\n this.addEventListener(\n this.getElement(selectors.DISCUSSIONSEND),\n 'click',\n this._sendMessage\n );\n this.addEventListener(\n this.getElement(selectors.HISTORYMODALTRIGGER),\n 'click',\n this._updateHistory\n );\n this.addEventListener(\n this.getElement(selectors.MOVEMODALTRIGGER),\n 'click',\n this._showMoveModal\n );\n this.addEventListener(\n this.getElement(selectors.PUSHCARD),\n 'click',\n this._pushCardConfirm\n );\n this.addEventListener(\n this.getElement(selectors.DETAILBUTTON),\n 'click',\n this._showDetailsModal\n );\n\n this.draggable = false;\n this.dragdrop = new DragDrop(this);\n this.checkEditing(state);\n this.boardid = state.board.id;\n this.cmid = state.common.id;\n this.userid = state.board.userid;\n this.groupid = state.board.groupid;\n this._dueDateFormat();\n }\n\n /**\n * Show modal to move a column.\n */\n _showMoveModal() {\n let data = exporter.exportStateForTemplate(this.reactive.state);\n data.cardid = this.id;\n data.kanbancolumn = this.reactive.state.cards.get(this.id).kanban_column;\n Str.get_strings([\n {key: 'movecard', component: 'mod_kanban'},\n {key: 'move', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n Templates.render('mod_kanban/movemodal', data),\n strings[1],\n () => {\n let column = document.querySelector(selectors.MOVECARDCOLUMN + `[data-id=\"${this.id}\"]`).value;\n let aftercard = document.querySelector(selectors.MOVECARDAFTERCARD + `[data-id=\"${this.id}\"]`).value;\n this.reactive.dispatch('moveCard', this.id, column, aftercard);\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Show modal with card details.\n * @param {*} event\n */\n _showDetailsModal(event) {\n let id = this.id;\n if (event.target.dataset.id !== undefined) {\n id = event.target.dataset.id;\n }\n\n let data = exporter.exportCard(this.reactive.state, id);\n let title = this.reactive.state.common.usenumbers ? '#' + data.number + ' ' + data.title : data.title;\n\n alert(\n title,\n Templates.render('mod_kanban/descriptionmodal', data),\n getString('close', 'form')\n ).then((modal) => {\n modal.modal[0].addEventListener(ModalEvents.bodyRendered, () => {\n document.querySelectorAll(selectors.CARDNUMBER).forEach((el) => {\n this.removeEventListener(el, 'click', this._clickDetailsButton);\n this.addEventListener(el, 'click', this._clickDetailsButton);\n });\n });\n return true;\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Simulate click on details button.\n * @param {*} event\n */\n _clickDetailsButton(event) {\n document.querySelector(\n selectors.CARD + `[data-number=\"${event.target.dataset.id}\"]` + ' ' + selectors.DETAILBUTTON\n ).click();\n }\n\n /**\n * Display confirmation modal for pushing a card.\n * @param {*} event\n */\n _pushCardConfirm(event) {\n Str.get_strings([\n {key: 'pushcard', component: 'mod_kanban'},\n {key: 'pushcardconfirm', component: 'mod_kanban'},\n {key: 'copy', component: 'core'},\n ]).then((strings) => {\n return saveCancel(\n strings[0],\n strings[1],\n strings[2],\n () => {\n this._pushCard(event);\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Display confirmation modal for deleting a card.\n * @param {*} event\n */\n _removeConfirm(event) {\n Str.get_strings([\n {key: 'deletecard', component: 'mod_kanban'},\n {key: 'deletecardconfirm', 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._removeCard(event);\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Display confirmation modal for deleting a discussion message.\n * @param {*} event\n */\n _removeMessageConfirm(event) {\n Str.get_strings([\n {key: 'deletemessage', component: 'mod_kanban'},\n {key: 'deletemessageconfirm', 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._removeMessage(event);\n }\n );\n }).catch((error) => Log.debug(error));\n }\n\n /**\n * Dispatch event to add a message to discussion.\n */\n _sendMessage() {\n let el = this.getElement(selectors.DISCUSSIONINPUT);\n let message = el.value.trim();\n if (message != '') {\n this.reactive.dispatch('sendDiscussionMessage', this.id, message);\n el.value = '';\n }\n }\n\n /**\n * Dispatch event to update the discussion data.\n */\n _updateDiscussion() {\n this.getElement(selectors.DISCUSSIONMODAL).classList.add('mod_kanban_loading');\n this.reactive.dispatch('getDiscussionUpdates', this.id);\n }\n\n /**\n * Called when discussion was updated.\n */\n async _discussionUpdated() {\n let data = {\n discussions: exporter.exportDiscussion(this.reactive.state, this.id)\n };\n Templates.renderForPromise('mod_kanban/discussionmessages', data).then(({html}) => {\n this.getElement(selectors.DISCUSSION, this.id).innerHTML = html;\n this.getElement(selectors.DISCUSSIONMODAL, this.id).classList.remove('mod_kanban_loading');\n let el = this.getElement(selectors.DISCUSSIONMESSAGES);\n // Scroll down to latest message.\n el.scrollTop = el.scrollHeight;\n data.discussions.forEach((d) => {\n if (d.candelete) {\n this.addEventListener(this.getElement(selectors.DELETEMESSAGE, d.id), 'click', this._removeMessageConfirm);\n }\n });\n return true;\n }).catch((error) => displayException(error));\n }\n\n /**\n * Dispatch event to update the history data.\n */\n _updateHistory() {\n this.getElement(selectors.HISTORYMODAL).classList.add('mod_kanban_loading');\n this.reactive.dispatch('getHistoryUpdates', this.id);\n }\n\n /**\n * Called when history was updated.\n */\n async _historyUpdated() {\n let data = {\n historyitems: exporter.exportHistory(this.reactive.state, this.id)\n };\n Templates.renderForPromise('mod_kanban/historyitems', data).then(({html}) => {\n this.getElement(selectors.HISTORY, this.id).innerHTML = html;\n this.getElement(selectors.HISTORYMODAL).classList.remove('mod_kanban_loading');\n // Scroll down to latest history item.\n let el = this.getElement(selectors.HISTORYITEMS);\n el.scrollTop = el.scrollHeight;\n return true;\n }).catch((error) => displayException(error));\n }\n\n /**\n * Dispatch event to assign the current user to the card.\n * @param {*} event\n */\n _assignSelf(event) {\n let target = event.target.closest(selectors.ASSIGNSELF);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('assignUser', data.id);\n }\n\n /**\n * Dispatch event to add a card after this card.\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, data.id);\n }\n\n /**\n * Called when card is updated.\n * @param {*} param0\n */\n async _cardUpdated({element}) {\n const card = this.getElement();\n // Card was moved to another column. Move the element to new card (right position is handled by column component).\n if (card.dataset.columnid != element.kanban_column) {\n const col = document.querySelector(selectors.COLUMNINNER + '[data-id=\"' + element.kanban_column + '\"]');\n col.appendChild(card);\n this.getElement(selectors.ADDCARD, this.id).setAttribute('data-columnid', element.kanban_column);\n card.setAttribute('data-columnid', element.kanban_column);\n }\n const assignees = this.getElement(selectors.ASSIGNEES, this.id);\n const assignedUsers = this.getElements(selectors.ASSIGNEDUSER, this.id);\n const userids = [...assignedUsers].map(v => {\n return v.dataset.userid;\n });\n // Update assignees.\n if (element.assignees !== undefined) {\n const additional = element.assignees.filter(x => !userids.includes(x));\n // Remove all elements that represent users that are no longer assigned to this card.\n if (assignedUsers !== null) {\n assignedUsers.forEach(assignedUser => {\n if (!element.assignees.includes(assignedUser.dataset.userid)) {\n assignedUser.parentNode.removeChild(assignedUser);\n }\n });\n }\n this.toggleClass(element.assignees.length == 0, 'mod_kanban_unassigned');\n // Add new assignees.\n if (element.assignees.length > 0) {\n additional.forEach(async user => {\n let userdata = this.reactive.state.users.get(user);\n let data = Object.assign({cardid: element.id}, userdata);\n data = Object.assign(data, exporter.exportCapabilities(this.reactive.state));\n Templates.renderForPromise('mod_kanban/user', data).then(({html, js}) => {\n Templates.appendNodeContents(assignees, html, js);\n return true;\n }).catch((error) => displayException(error));\n });\n }\n }\n this.toggleClass(element.selfassigned, 'mod_kanban_selfassigned');\n // Set card completion state.\n this.toggleClass(element.completed == 1, 'mod_kanban_closed');\n // Update title (also in modals).\n if (element.title !== undefined) {\n // For Moodle inplace editing title is once needed plain and once with html entities encoded.\n // This avoids double encoding of html entities as the value of \"data-value\" is exactly what is shown\n // in the input field when clicking on the inplace editable.\n let doc = new DOMParser().parseFromString(element.title, 'text/html');\n this.getElement(selectors.INPLACEEDITABLE).setAttribute('data-value', doc.documentElement.textContent);\n this.getElement(selectors.INPLACEEDITABLE).querySelector('a').innerHTML = element.title;\n this.getElement(selectors.DISCUSSIONMODALTITLE).innerHTML = element.title;\n }\n this.toggleClass(element.hasdescription, 'mod_kanban_hasdescription');\n this.toggleClass(element.hasattachment, 'mod_kanban_hasattachment');\n // Update due date.\n if (element.duedate !== undefined) {\n this.getElement(selectors.DUEDATE).setAttribute('data-date', element.duedate);\n this._dueDateFormat();\n }\n this.toggleClass(element.discussion, 'mod_kanban_hasdiscussion');\n // Only option for now is background color.\n if (element.options !== undefined) {\n let options = JSON.parse(element.options);\n if (options.background === undefined) {\n this.getElement().removeAttribute('style');\n } else {\n this.getElement().setAttribute('style', 'background-color: ' + options.background);\n }\n }\n // Enable/disable dragging and inplace editing (e.g. if user is not assigned to the card anymore).\n this.checkEditing();\n }\n\n /**\n * Delete this card.\n */\n _cardDeleted() {\n this.destroy();\n }\n\n /**\n * Dispatch event to remove this card.\n * @param {*} event\n */\n _removeCard(event) {\n let target = event.target.closest(selectors.DELETECARD);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('deleteCard', data.id);\n }\n\n /**\n * Dispatch event to push this card.\n * @param {*} event\n */\n _pushCard(event) {\n let target = event.target.closest(selectors.PUSHCARD);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('pushCard', data.id);\n }\n\n /**\n * Dispatch event to remove this card.\n * @param {*} event\n */\n _removeMessage(event) {\n let target = event.target.closest(selectors.DELETEMESSAGE);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('deleteMessage', data.id);\n }\n\n /**\n * Dispatch event to complete this card.\n * @param {*} event\n */\n _completeCard(event) {\n let target = event.target.closest(selectors.COMPLETE);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('completeCard', data.id);\n }\n\n /**\n * Dispatch event to complete this card.\n * @param {*} event\n */\n _uncompleteCard(event) {\n let target = event.target.closest(selectors.UNCOMPLETE);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('uncompleteCard', data.id);\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 * @returns {object}\n */\n getDraggableData() {\n return {\n id: this.id,\n type: 'card',\n };\n }\n\n /**\n * Conditionally enable / disable dragging and inplace editing.\n * @param {*} state\n */\n checkEditing(state) {\n if (state === undefined) {\n state = this.reactive.stateManager.state;\n }\n if (state.cards.get(this.id).canedit) {\n this.draggable = true;\n this.dragdrop.setDraggable(true);\n } else {\n this.draggable = false;\n this.dragdrop.setDraggable(false);\n }\n if (state.cards.get(this.id).completed != 1 && state.cards.get(this.id).canedit) {\n this.getElement(selectors.INPLACEEDITABLE).setAttribute('data-inplaceeditable', '1');\n } else {\n this.getElement(selectors.INPLACEEDITABLE).removeAttribute('data-inplaceeditable');\n }\n\n this.toggleClass(state.cards.get(this.id).canedit, 'mod_kanban_canedit');\n }\n\n /**\n * Validate draggable data.\n * @param {object} dropdata\n * @returns {boolean} if the data is valid for this drop-zone.\n */\n validateDropData(dropdata) {\n return dropdata?.type == 'card';\n }\n\n /**\n * Executed when a valid dropdata is dropped over the drop-zone.\n * @param {object} dropdata\n */\n drop(dropdata) {\n if (dropdata.id != this.id) {\n let newcolumn = this.getElement(selectors.ADDCARD, this.id).dataset.columnid;\n let aftercard = this.id;\n this.reactive.dispatch('moveCard', dropdata.id, newcolumn, aftercard);\n }\n }\n\n /**\n * Dispatch event to unassign the current user.\n * @param {*} event\n */\n _unassignSelf(event) {\n let target = event.target.closest(selectors.UNASSIGNSELF);\n let data = Object.assign({}, target.dataset);\n this.reactive.dispatch('unassignUser', data.id);\n }\n\n /**\n * Show modal form to edit card details.\n * @param {*} event\n */\n _editDetails(event) {\n event.preventDefault();\n\n const modalForm = new ModalForm({\n formClass: \"mod_kanban\\\\form\\\\edit_card_form\",\n args: {\n id: this.id,\n boardid: this.boardid,\n cmid: this.cmid,\n groupid: this.groupid,\n userid: this.userid\n },\n modalConfig: {title: getString('editcard', 'mod_kanban')},\n returnFocus: this.getElement(),\n });\n this.addEventListener(modalForm, modalForm.events.FORM_SUBMITTED, this._updateCard);\n modalForm.show();\n }\n\n /**\n * Dispatch an event to update card data from the detail modal.\n * @param {*} event\n */\n _updateCard(event) {\n this.reactive.dispatch('processUpdates', event.detail);\n }\n\n /**\n * Update relative time.\n * @param {int} timestamp\n * @returns {string}\n */\n updateRelativeTime(timestamp) {\n let elapsed = new Date(timestamp) - new Date();\n for (var u in this._units) {\n if (Math.abs(elapsed) > this._units[u] || u == 'second') {\n return this.rtf.format(Math.round(elapsed / this._units[u]), u);\n }\n }\n return '';\n }\n\n /**\n * Format due date using relative time.\n */\n _dueDateFormat() {\n // Convert timestamp to ms.\n let duedate = this.getElement(selectors.DUEDATE).dataset.date * 1000;\n if (duedate > 0) {\n let element = this.getElement(selectors.DUEDATE);\n element.innerHTML = this.updateRelativeTime(duedate);\n if (duedate < new Date().getTime()) {\n element.classList.add('mod_kanban_overdue');\n } else {\n element.classList.remove('mod_kanban_overdue');\n }\n } else {\n this.getElement(selectors.DUEDATE).innerHTML = '';\n }\n }\n}\n"],"names":["KanbanComponent","year","month","day","hour","minute","second","target","this","element","document","getElementById","create","id","dataset","getWatchers","watch","handler","_cardUpdated","_cardDeleted","_discussionUpdated","_historyUpdated","stateReady","state","lang","undefined","common","rtf","Intl","RelativeTimeFormat","numeric","e","addEventListener","getElement","selectors","DELETECARD","_removeConfirm","ADDCARD","_addCard","COMPLETE","_completeCard","UNCOMPLETE","_uncompleteCard","ASSIGNSELF","_assignSelf","UNASSIGNSELF","_unassignSelf","EDITDETAILS","_editDetails","DISCUSSIONMODALTRIGGER","_updateDiscussion","DISCUSSIONSHOW","DISCUSSIONSEND","_sendMessage","HISTORYMODALTRIGGER","_updateHistory","MOVEMODALTRIGGER","_showMoveModal","PUSHCARD","_pushCardConfirm","DETAILBUTTON","_showDetailsModal","draggable","dragdrop","DragDrop","checkEditing","boardid","board","cmid","userid","groupid","_dueDateFormat","data","exporter","exportStateForTemplate","reactive","cardid","kanbancolumn","cards","get","kanban_column","Str","get_strings","key","component","then","strings","Templates","render","column","querySelector","MOVECARDCOLUMN","value","aftercard","MOVECARDAFTERCARD","dispatch","catch","error","Log","debug","event","exportCard","title","usenumbers","number","modal","ModalEvents","bodyRendered","querySelectorAll","CARDNUMBER","forEach","el","removeEventListener","_clickDetailsButton","CARD","click","_pushCard","_removeCard","_removeMessageConfirm","_removeMessage","DISCUSSIONINPUT","message","trim","DISCUSSIONMODAL","classList","add","discussions","exportDiscussion","renderForPromise","_ref","html","DISCUSSION","innerHTML","remove","DISCUSSIONMESSAGES","scrollTop","scrollHeight","d","candelete","DELETEMESSAGE","HISTORYMODAL","historyitems","exportHistory","_ref2","HISTORY","HISTORYITEMS","closest","Object","assign","activeElement","blur","columnid","card","COLUMNINNER","appendChild","setAttribute","assignees","ASSIGNEES","assignedUsers","getElements","ASSIGNEDUSER","userids","map","v","additional","filter","x","includes","assignedUser","parentNode","removeChild","toggleClass","length","async","userdata","users","user","exportCapabilities","_ref4","js","appendNodeContents","selfassigned","completed","doc","DOMParser","parseFromString","INPLACEEDITABLE","documentElement","textContent","DISCUSSIONMODALTITLE","hasdescription","hasattachment","duedate","DUEDATE","discussion","options","JSON","parse","background","removeAttribute","destroy","unregister","getDraggableData","type","stateManager","canedit","setDraggable","validateDropData","dropdata","drop","newcolumn","preventDefault","modalForm","ModalForm","formClass","args","modalConfig","returnFocus","events","FORM_SUBMITTED","_updateCard","show","detail","updateRelativeTime","timestamp","elapsed","Date","u","_units","Math","abs","format","round","date","getTime"],"mappings":"2wDAe6BA,mFAIhB,CACLC,KAAM,QACNC,MAAO,OACPC,IAAK,MACLC,KAAM,KACNC,OAAQ,IACRC,OAAQ,kJAQAC,eAED,IAAIC,KAAK,CACZC,QAFUC,SAASC,eAAeJ,UAS1CK,cACSC,GAAKL,KAAKC,QAAQK,QAAQD,GAOnCE,oBACW,CACH,CAACC,sBAAgBR,KAAKK,gBAAeI,QAAST,KAAKU,cACnD,CAACF,sBAAgBR,KAAKK,gBAAeI,QAAST,KAAKW,cACnD,CAACH,4BAA8BC,QAAST,KAAKY,oBAC7C,CAACJ,4BAA8BC,QAAST,KAAKY,oBAC7C,CAACJ,4BAA8BC,QAAST,KAAKY,oBAC7C,CAACJ,wBAA0BC,QAAST,KAAKa,iBACzC,CAACL,wBAA0BC,QAAST,KAAKa,iBACzC,CAACL,wBAA0BC,QAAST,KAAKa,kBASjDC,WAAWC,WAEHC,KAAO,UACeC,IAAtBF,MAAMG,OAAOF,OACbA,KAAOD,MAAMG,OAAOF,eAMfG,IAAM,IAAIC,KAAKC,mBAAmBL,KAAM,CAACM,QAAS,SACzD,MAAOC,QAEAJ,IAAM,IAAIC,KAAKC,mBAAmB,KAAM,CAACC,QAAS,cAGtDE,iBACDxB,KAAKyB,WAAWC,mBAAUC,WAAY3B,KAAKK,IAC3C,QACAL,KAAK4B,qBAEJJ,iBACDxB,KAAKyB,WAAWC,mBAAUG,QAAS7B,KAAKK,IACxC,QACAL,KAAK8B,eAEJN,iBACDxB,KAAKyB,WAAWC,mBAAUK,SAAU/B,KAAKK,IACzC,QACAL,KAAKgC,oBAEJR,iBACDxB,KAAKyB,WAAWC,mBAAUO,WAAYjC,KAAKK,IAC3C,QACAL,KAAKkC,sBAEJV,iBACDxB,KAAKyB,WAAWC,mBAAUS,WAAYnC,KAAKK,IAC3C,QACAL,KAAKoC,kBAEJZ,iBACDxB,KAAKyB,WAAWC,mBAAUW,aAAcrC,KAAKK,IAC7C,QACAL,KAAKsC,oBAEJd,iBACDxB,KAAKyB,WAAWC,mBAAUa,YAAavC,KAAKK,IAC5C,QACAL,KAAKwC,mBAEJhB,iBACDxB,KAAKyB,WAAWC,mBAAUe,wBAC1B,QACAzC,KAAK0C,wBAEJlB,iBACDxB,KAAKyB,WAAWC,mBAAUiB,eAAgB3C,KAAKK,IAC/C,QACAL,KAAK0C,wBAEJlB,iBACDxB,KAAKyB,WAAWC,mBAAUkB,gBAC1B,QACA5C,KAAK6C,mBAEJrB,iBACDxB,KAAKyB,WAAWC,mBAAUoB,qBAC1B,QACA9C,KAAK+C,qBAEJvB,iBACDxB,KAAKyB,WAAWC,mBAAUsB,kBAC1B,QACAhD,KAAKiD,qBAEJzB,iBACDxB,KAAKyB,WAAWC,mBAAUwB,UAC1B,QACAlD,KAAKmD,uBAEJ3B,iBACDxB,KAAKyB,WAAWC,mBAAU0B,cAC1B,QACApD,KAAKqD,wBAGJC,WAAY,OACZC,SAAW,IAAIC,mBAASxD,WACxByD,aAAa1C,YACb2C,QAAU3C,MAAM4C,MAAMtD,QACtBuD,KAAO7C,MAAMG,OAAOb,QACpBwD,OAAS9C,MAAM4C,MAAME,YACrBC,QAAU/C,MAAM4C,MAAMG,aACtBC,iBAMTd,qBACQe,KAAOC,kBAASC,uBAAuBlE,KAAKmE,SAASpD,OACzDiD,KAAKI,OAASpE,KAAKK,GACnB2D,KAAKK,aAAerE,KAAKmE,SAASpD,MAAMuD,MAAMC,IAAIvE,KAAKK,IAAImE,cAC3DC,IAAIC,YAAY,CACZ,CAACC,IAAK,WAAYC,UAAW,cAC7B,CAACD,IAAK,OAAQC,UAAW,UAC1BC,MAAMC,UACE,4BACHA,QAAQ,GACRC,mBAAUC,OAAO,uBAAwBhB,MACzCc,QAAQ,IACR,SACQG,OAAS/E,SAASgF,cAAcxD,mBAAUyD,mCAA8BnF,KAAKK,UAAQ+E,MACrFC,UAAYnF,SAASgF,cAAcxD,mBAAU4D,sCAAiCtF,KAAKK,UAAQ+E,WAC1FjB,SAASoB,SAAS,WAAYvF,KAAKK,GAAI4E,OAAQI,gBAG7DG,OAAOC,OAAUC,aAAIC,MAAMF,SAOlCpC,kBAAkBuC,WACVvF,GAAKL,KAAKK,QACkBY,IAA5B2E,MAAM7F,OAAOO,QAAQD,KACrBA,GAAKuF,MAAM7F,OAAOO,QAAQD,QAG1B2D,KAAOC,kBAAS4B,WAAW7F,KAAKmE,SAASpD,MAAOV,IAChDyF,MAAQ9F,KAAKmE,SAASpD,MAAMG,OAAO6E,WAAa,IAAM/B,KAAKgC,OAAS,IAAMhC,KAAK8B,MAAQ9B,KAAK8B,8BAG5FA,MACAf,mBAAUC,OAAO,8BAA+BhB,OAChD,kBAAU,QAAS,SACrBa,MAAMoB,QACJA,MAAMA,MAAM,GAAGzE,iBAAiB0E,sBAAYC,cAAc,KACtDjG,SAASkG,iBAAiB1E,mBAAU2E,YAAYC,SAASC,UAChDC,oBAAoBD,GAAI,QAASvG,KAAKyG,0BACtCjF,iBAAiB+E,GAAI,QAASvG,KAAKyG,4BAGzC,KACRjB,OAAOC,OAAUC,aAAIC,MAAMF,SAOlCgB,oBAAoBb,OAChB1F,SAASgF,cACLxD,mBAAUgF,6BAAwBd,MAAM7F,OAAOO,QAAQD,SAAS,IAAMqB,mBAAU0B,cAClFuD,QAONxD,iBAAiByC,OACbnB,IAAIC,YAAY,CACZ,CAACC,IAAK,WAAYC,UAAW,cAC7B,CAACD,IAAK,kBAAmBC,UAAW,cACpC,CAACD,IAAK,OAAQC,UAAW,UAC1BC,MAAMC,UACE,4BACHA,QAAQ,GACRA,QAAQ,GACRA,QAAQ,IACR,UACS8B,UAAUhB,YAGxBJ,OAAOC,OAAUC,aAAIC,MAAMF,SAOlC7D,eAAegE,OACXnB,IAAIC,YAAY,CACZ,CAACC,IAAK,aAAcC,UAAW,cAC/B,CAACD,IAAK,oBAAqBC,UAAW,cACtC,CAACD,IAAK,SAAUC,UAAW,UAC5BC,MAAMC,UACE,4BACHA,QAAQ,GACRA,QAAQ,GACRA,QAAQ,IACR,UACS+B,YAAYjB,YAG1BJ,OAAOC,OAAUC,aAAIC,MAAMF,SAOlCqB,sBAAsBlB,OAClBnB,IAAIC,YAAY,CACZ,CAACC,IAAK,gBAAiBC,UAAW,cAClC,CAACD,IAAK,uBAAwBC,UAAW,cACzC,CAACD,IAAK,SAAUC,UAAW,UAC5BC,MAAMC,UACE,4BACHA,QAAQ,GACRA,QAAQ,GACRA,QAAQ,IACR,UACSiC,eAAenB,YAG7BJ,OAAOC,OAAUC,aAAIC,MAAMF,SAMlC5C,mBACQ0D,GAAKvG,KAAKyB,WAAWC,mBAAUsF,iBAC/BC,QAAUV,GAAGnB,MAAM8B,OACR,IAAXD,eACK9C,SAASoB,SAAS,wBAAyBvF,KAAKK,GAAI4G,SACzDV,GAAGnB,MAAQ,IAOnB1C,yBACSjB,WAAWC,mBAAUyF,iBAAiBC,UAAUC,IAAI,2BACpDlD,SAASoB,SAAS,uBAAwBvF,KAAKK,mCAOhD2D,KAAO,CACPsD,YAAarD,kBAASsD,iBAAiBvH,KAAKmE,SAASpD,MAAOf,KAAKK,wBAE3DmH,iBAAiB,gCAAiCxD,MAAMa,MAAK4C,WAACC,KAACA,gBAChEjG,WAAWC,mBAAUiG,WAAY3H,KAAKK,IAAIuH,UAAYF,UACtDjG,WAAWC,mBAAUyF,gBAAiBnH,KAAKK,IAAI+G,UAAUS,OAAO,0BACjEtB,GAAKvG,KAAKyB,WAAWC,mBAAUoG,2BAEnCvB,GAAGwB,UAAYxB,GAAGyB,aAClBhE,KAAKsD,YAAYhB,SAAS2B,IAClBA,EAAEC,gBACG1G,iBAAiBxB,KAAKyB,WAAWC,mBAAUyG,cAAeF,EAAE5H,IAAK,QAASL,KAAK8G,2BAGrF,KACRtB,OAAOC,QAAU,2BAAiBA,SAMzC1C,sBACStB,WAAWC,mBAAU0G,cAAchB,UAAUC,IAAI,2BACjDlD,SAASoB,SAAS,oBAAqBvF,KAAKK,gCAO7C2D,KAAO,CACPqE,aAAcpE,kBAASqE,cAActI,KAAKmE,SAASpD,MAAOf,KAAKK,wBAEzDmH,iBAAiB,0BAA2BxD,MAAMa,MAAK0D,YAACb,KAACA,iBAC1DjG,WAAWC,mBAAU8G,QAASxI,KAAKK,IAAIuH,UAAYF,UACnDjG,WAAWC,mBAAU0G,cAAchB,UAAUS,OAAO,0BAErDtB,GAAKvG,KAAKyB,WAAWC,mBAAU+G,qBACnClC,GAAGwB,UAAYxB,GAAGyB,cACX,KACRxC,OAAOC,QAAU,2BAAiBA,SAOzCrD,YAAYwD,WACJ7F,OAAS6F,MAAM7F,OAAO2I,QAAQhH,mBAAUS,YACxC6B,KAAO2E,OAAOC,OAAO,GAAI7I,OAAOO,cAC/B6D,SAASoB,SAAS,aAAcvB,KAAK3D,IAO9CyB,SAAS8D,OACL1F,SAAS2I,cAAcC,WACnB/I,OAAS6F,MAAM7F,OAAO2I,QAAQhH,mBAAUG,SACxCmC,KAAO2E,OAAOC,OAAO,GAAI7I,OAAOO,cAC/B6D,SAASoB,SAAS,UAAWvB,KAAK+E,SAAU/E,KAAK3D,kCAOvCJ,QAACA,qBACV+I,KAAOhJ,KAAKyB,gBAEduH,KAAK1I,QAAQyI,UAAY9I,QAAQuE,cAAe,CACpCtE,SAASgF,cAAcxD,mBAAUuH,YAAc,aAAehJ,QAAQuE,cAAgB,MAC9F0E,YAAYF,WACXvH,WAAWC,mBAAUG,QAAS7B,KAAKK,IAAI8I,aAAa,gBAAiBlJ,QAAQuE,eAClFwE,KAAKG,aAAa,gBAAiBlJ,QAAQuE,qBAEzC4E,UAAYpJ,KAAKyB,WAAWC,mBAAU2H,UAAWrJ,KAAKK,IACtDiJ,cAAgBtJ,KAAKuJ,YAAY7H,mBAAU8H,aAAcxJ,KAAKK,IAC9DoJ,QAAU,IAAIH,eAAeI,KAAIC,GAC5BA,EAAErJ,QAAQuD,iBAGK5C,IAAtBhB,QAAQmJ,UAAyB,OAC3BQ,WAAa3J,QAAQmJ,UAAUS,QAAOC,IAAML,QAAQM,SAASD,KAE7C,OAAlBR,eACAA,cAAchD,SAAQ0D,eACb/J,QAAQmJ,UAAUW,SAASC,aAAa1J,QAAQuD,SACjDmG,aAAaC,WAAWC,YAAYF,sBAI3CG,YAAwC,GAA5BlK,QAAQmJ,UAAUgB,OAAa,yBAE5CnK,QAAQmJ,UAAUgB,OAAS,GAC3BR,WAAWtD,SAAQ+D,MAAAA,WACXC,SAAWtK,KAAKmE,SAASpD,MAAMwJ,MAAMhG,IAAIiG,MACzCxG,KAAO2E,OAAOC,OAAO,CAACxE,OAAQnE,QAAQI,IAAKiK,UAC/CtG,KAAO2E,OAAOC,OAAO5E,KAAMC,kBAASwG,mBAAmBzK,KAAKmE,SAASpD,2BAC3DyG,iBAAiB,kBAAmBxD,MAAMa,MAAK6F,YAAChD,KAACA,KAADiD,GAAOA,oCACnDC,mBAAmBxB,UAAW1B,KAAMiD,KACvC,KACRnF,OAAOC,QAAU,2BAAiBA,oBAI5C0E,YAAYlK,QAAQ4K,aAAc,gCAElCV,YAAiC,GAArBlK,QAAQ6K,UAAgB,0BAEnB7J,IAAlBhB,QAAQ6F,MAAqB,KAIzBiF,KAAM,IAAIC,WAAYC,gBAAgBhL,QAAQ6F,MAAO,kBACpDrE,WAAWC,mBAAUwJ,iBAAiB/B,aAAa,aAAc4B,IAAII,gBAAgBC,kBACrF3J,WAAWC,mBAAUwJ,iBAAiBhG,cAAc,KAAK0C,UAAY3H,QAAQ6F,WAC7ErE,WAAWC,mBAAU2J,sBAAsBzD,UAAY3H,QAAQ6F,cAEnEqE,YAAYlK,QAAQqL,eAAgB,kCACpCnB,YAAYlK,QAAQsL,cAAe,iCAEhBtK,IAApBhB,QAAQuL,eACH/J,WAAWC,mBAAU+J,SAAStC,aAAa,YAAalJ,QAAQuL,cAChEzH,uBAEJoG,YAAYlK,QAAQyL,WAAY,iCAEbzK,IAApBhB,QAAQ0L,QAAuB,KAC3BA,QAAUC,KAAKC,MAAM5L,QAAQ0L,cACN1K,IAAvB0K,QAAQG,gBACHrK,aAAasK,gBAAgB,cAE7BtK,aAAa0H,aAAa,QAAS,qBAAuBwC,QAAQG,iBAI1ErI,eAMT9C,oBACSqL,UAOTnF,YAAYjB,WACJ7F,OAAS6F,MAAM7F,OAAO2I,QAAQhH,mBAAUC,YACxCqC,KAAO2E,OAAOC,OAAO,GAAI7I,OAAOO,cAC/B6D,SAASoB,SAAS,aAAcvB,KAAK3D,IAO9CuG,UAAUhB,WACF7F,OAAS6F,MAAM7F,OAAO2I,QAAQhH,mBAAUwB,UACxCc,KAAO2E,OAAOC,OAAO,GAAI7I,OAAOO,cAC/B6D,SAASoB,SAAS,WAAYvB,KAAK3D,IAO5C0G,eAAenB,WACP7F,OAAS6F,MAAM7F,OAAO2I,QAAQhH,mBAAUyG,eACxCnE,KAAO2E,OAAOC,OAAO,GAAI7I,OAAOO,cAC/B6D,SAASoB,SAAS,gBAAiBvB,KAAK3D,IAOjD2B,cAAc4D,WACN7F,OAAS6F,MAAM7F,OAAO2I,QAAQhH,mBAAUK,UACxCiC,KAAO2E,OAAOC,OAAO,GAAI7I,OAAOO,cAC/B6D,SAASoB,SAAS,eAAgBvB,KAAK3D,IAOhD6B,gBAAgB0D,WACR7F,OAAS6F,MAAM7F,OAAO2I,QAAQhH,mBAAUO,YACxC+B,KAAO2E,OAAOC,OAAO,GAAI7I,OAAOO,cAC/B6D,SAASoB,SAAS,iBAAkBvB,KAAK3D,IAMlD2L,eAC0B/K,IAAlBjB,KAAKuD,eACAA,SAAS0I,aAQtBC,yBACW,CACH7L,GAAIL,KAAKK,GACT8L,KAAM,QAQd1I,aAAa1C,YACKE,IAAVF,QACAA,MAAQf,KAAKmE,SAASiI,aAAarL,OAEnCA,MAAMuD,MAAMC,IAAIvE,KAAKK,IAAIgM,cACpB/I,WAAY,OACZC,SAAS+I,cAAa,UAEtBhJ,WAAY,OACZC,SAAS+I,cAAa,IAEW,GAAtCvL,MAAMuD,MAAMC,IAAIvE,KAAKK,IAAIyK,WAAkB/J,MAAMuD,MAAMC,IAAIvE,KAAKK,IAAIgM,aAC/D5K,WAAWC,mBAAUwJ,iBAAiB/B,aAAa,uBAAwB,UAE3E1H,WAAWC,mBAAUwJ,iBAAiBa,gBAAgB,6BAG1D5B,YAAYpJ,MAAMuD,MAAMC,IAAIvE,KAAKK,IAAIgM,QAAS,sBAQvDE,iBAAiBC,gBACY,SAAlBA,MAAAA,gBAAAA,SAAUL,MAOrBM,KAAKD,aACGA,SAASnM,IAAML,KAAKK,GAAI,KACpBqM,UAAY1M,KAAKyB,WAAWC,mBAAUG,QAAS7B,KAAKK,IAAIC,QAAQyI,SAChE1D,UAAYrF,KAAKK,QAChB8D,SAASoB,SAAS,WAAYiH,SAASnM,GAAIqM,UAAWrH,YAQnE/C,cAAcsD,WACN7F,OAAS6F,MAAM7F,OAAO2I,QAAQhH,mBAAUW,cACxC2B,KAAO2E,OAAOC,OAAO,GAAI7I,OAAOO,cAC/B6D,SAASoB,SAAS,eAAgBvB,KAAK3D,IAOhDmC,aAAaoD,OACTA,MAAM+G,uBAEAC,UAAY,IAAIC,mBAAU,CAC5BC,UAAW,mCACXC,KAAM,CACF1M,GAAIL,KAAKK,GACTqD,QAAS1D,KAAK0D,QACdE,KAAM5D,KAAK4D,KACXE,QAAS9D,KAAK8D,QACdD,OAAQ7D,KAAK6D,QAEjBmJ,YAAa,CAAClH,OAAO,kBAAU,WAAY,eAC3CmH,YAAajN,KAAKyB,oBAEjBD,iBAAiBoL,UAAWA,UAAUM,OAAOC,eAAgBnN,KAAKoN,aACvER,UAAUS,OAOdD,YAAYxH,YACHzB,SAASoB,SAAS,iBAAkBK,MAAM0H,QAQnDC,mBAAmBC,eACXC,QAAU,IAAIC,KAAKF,WAAa,IAAIE,SACnC,IAAIC,KAAK3N,KAAK4N,UACXC,KAAKC,IAAIL,SAAWzN,KAAK4N,OAAOD,IAAW,UAALA,SAC/B3N,KAAKmB,IAAI4M,OAAOF,KAAKG,MAAMP,QAAUzN,KAAK4N,OAAOD,IAAKA,SAG9D,GAMX5J,qBAEQyH,QAA4D,IAAlDxL,KAAKyB,WAAWC,mBAAU+J,SAASnL,QAAQ2N,QACrDzC,QAAU,EAAG,KACTvL,QAAUD,KAAKyB,WAAWC,mBAAU+J,SACxCxL,QAAQ2H,UAAY5H,KAAKuN,mBAAmB/B,SACxCA,SAAU,IAAIkC,MAAOQ,UACrBjO,QAAQmH,UAAUC,IAAI,sBAEtBpH,QAAQmH,UAAUS,OAAO,gCAGxBpG,WAAWC,mBAAU+J,SAAS7D,UAAY"} \ No newline at end of file diff --git a/amd/build/cardnumber.min.js b/amd/build/cardnumber.min.js new file mode 100644 index 00000000..9ae2a17a --- /dev/null +++ b/amd/build/cardnumber.min.js @@ -0,0 +1,3 @@ +define("mod_kanban/cardnumber",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0;_exports.init=element=>{document.querySelectorAll("#"+element+" .mod_kanban_card_number").forEach((el=>{el.addEventListener("click",(event=>{document.querySelector('.mod_kanban_card[data-number="'.concat(event.target.dataset.id,'"] .mod_kanban_description_trigger')).click()}))}))}})); + +//# sourceMappingURL=cardnumber.min.js.map \ No newline at end of file diff --git a/amd/build/cardnumber.min.js.map b/amd/build/cardnumber.min.js.map new file mode 100644 index 00000000..60cde107 --- /dev/null +++ b/amd/build/cardnumber.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"cardnumber.min.js","sources":["../src/cardnumber.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 * Helper for card number filter\n *\n * @module mod_kanban/cardnumber\n * @copyright 2024 ISB Bayern\n * @author Stefan Hanauska \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport const init = (element) => {\n document.querySelectorAll('#' + element + ' .mod_kanban_card_number').forEach((el) => {\n el.addEventListener('click', (event) => {\n document.querySelector(\n `.mod_kanban_card[data-number=\"${event.target.dataset.id}\"] .mod_kanban_description_trigger`\n ).click();\n });\n });\n};\n"],"names":["element","document","querySelectorAll","forEach","el","addEventListener","event","querySelector","target","dataset","id","click"],"mappings":"0JAwBqBA,UACjBC,SAASC,iBAAiB,IAAMF,QAAU,4BAA4BG,SAASC,KAC3EA,GAAGC,iBAAiB,SAAUC,QAC1BL,SAASM,sDAC4BD,MAAME,OAAOC,QAAQC,0CACxDC"} \ No newline at end of file diff --git a/amd/build/exporter.min.js b/amd/build/exporter.min.js index adb89760..8daa8c06 100644 --- a/amd/build/exporter.min.js +++ b/amd/build/exporter.min.js @@ -1,3 +1,3 @@ -define("mod_kanban/exporter",["exports","mod_kanban/capabilities"],(function(_exports,_capabilities){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_capabilities=(obj=_capabilities)&&obj.__esModule?obj:{default:obj};return _exports.default=class{static exportStateForTemplate(state){let columnOrder=state.board.sequence.split(","),columns=[],hascolumns=""!=state.board.sequence;hascolumns&&(columns=columnOrder.map((value=>this.exportCardsForColumn(state,value))));let showactionmenu=1==state.common.userboards||""!=state.common.groupselector||state.capabilities.get(_capabilities.default.MANAGEBOARD).value||2==state.common.userboards&&state.capabilities.get(_capabilities.default.VIEWALLBOARDS).value;return Object.assign({cmid:state.common.id,id:state.board.id,sequence:state.board.sequence,hascolumns:hascolumns,columns:columns,locked:state.board.locked,hastemplate:0!=state.common.template,istemplate:0!=state.board.template,heading:state.board.heading,groupselector:state.common.groupselector,userboards:state.common.userboards,history:state.common.history&&state.capabilities.get(_capabilities.default.VIEWHISTORY).value,groupmode:state.common.groupmode,ismyuserboard:state.common.userid==state.board.userid,myuserid:state.common.userid,showactionmenu:showactionmenu,userboardsonly:2==state.common.userboards,iscourseboard:0==state.board.userid&&0==state.board.groupid&&0==state.board.template,users:JSON.parse(JSON.stringify(state.users))},this.exportCapabilities(state))}static exportCardsForColumn(state,columnid){let col=JSON.parse(JSON.stringify(state.columns.get(columnid))),options=JSON.parse(col.options);if(col.hascards=""!=col.sequence,col.autoclose=options.autoclose,col.autohide=options.autohide,col.hascards){let cardOrder=col.sequence.split(",");col.cards=cardOrder.map((value=>this.exportCard(state,value)))}return col}static exportCard(state,cardid){let card={id:cardid,title:"-",assignees:[],options:"{}",canedit:!1};void 0!==state.cards.get(cardid)&&(card=JSON.parse(JSON.stringify(state.cards.get(cardid)))),card.cardid=card.id,card.hasassignees=card.assignees.length>0;let options=JSON.parse(card.options);return card.hasassignees&&"number"==typeof card.assignees[0]&&(card.assignees=card.assignees.map((userid=>state.users.get(userid))),card.assignees=[...new Set(card.assignees)]),Object.assign(card,options)}static exportCapabilities(state){let capabilities=[];return state.capabilities.forEach((c=>{capabilities[c.id]=c.value})),Object.assign({},capabilities)}static exportDiscussion(state,cardId){let d=[];return state.discussions.forEach((c=>{c.kanban_card==cardId&&d.push(c)})),d=d.sort(((a,b)=>parseInt(a.timecreated)>parseInt(b.timecreated))),d}static exportHistory(state,cardId){let d=[];return state.history.forEach((c=>{c.kanban_card==cardId&&d.push(c)})),d=d.sort(((a,b)=>parseInt(a.timestamp)>parseInt(b.timestamp))),d}},_exports.default})); +define("mod_kanban/exporter",["exports","mod_kanban/capabilities"],(function(_exports,_capabilities){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_capabilities=(obj=_capabilities)&&obj.__esModule?obj:{default:obj};return _exports.default=class{static exportStateForTemplate(state){let columnOrder=state.board.sequence.split(","),columns=[],hascolumns=""!=state.board.sequence;hascolumns&&(columns=columnOrder.map((value=>this.exportCardsForColumn(state,value))));let showactionmenu=1==state.common.userboards||""!=state.common.groupselector||state.capabilities.get(_capabilities.default.MANAGEBOARD).value||2==state.common.userboards&&state.capabilities.get(_capabilities.default.VIEWALLBOARDS).value;return Object.assign({cmid:state.common.id,id:state.board.id,sequence:state.board.sequence,hascolumns:hascolumns,columns:columns,locked:state.board.locked,hastemplate:0!=state.common.template,istemplate:0!=state.board.template,heading:state.board.heading,groupselector:state.common.groupselector,userboards:state.common.userboards,history:state.common.history&&state.capabilities.get(_capabilities.default.VIEWHISTORY).value,groupmode:state.common.groupmode,ismyuserboard:state.common.userid==state.board.userid,myuserid:state.common.userid,showactionmenu:showactionmenu,userboardsonly:2==state.common.userboards,iscourseboard:0==state.board.userid&&0==state.board.groupid&&0==state.board.template,users:JSON.parse(JSON.stringify(state.users)),usenumbers:state.common.usenumbers},this.exportCapabilities(state))}static exportCardsForColumn(state,columnid){let col=JSON.parse(JSON.stringify(state.columns.get(columnid))),options=JSON.parse(col.options);if(col.hascards=""!=col.sequence,col.autoclose=options.autoclose,col.autohide=options.autohide,col.hascards){let cardOrder=col.sequence.split(",");col.cards=cardOrder.map((value=>this.exportCard(state,value)))}return col}static exportCard(state,cardid){let card={id:cardid,title:"-",assignees:[],options:"{}",canedit:!1,number:0};void 0!==state.cards.get(cardid)&&(card=JSON.parse(JSON.stringify(state.cards.get(cardid)))),card.cardid=card.id,card.hasassignees=card.assignees.length>0;let options=JSON.parse(card.options);return card.hasassignees&&"number"==typeof card.assignees[0]&&(card.assignees=card.assignees.map((userid=>state.users.get(userid))),card.assignees=[...new Set(card.assignees)]),Object.assign(card,options)}static exportCapabilities(state){let capabilities=[];return state.capabilities.forEach((c=>{capabilities[c.id]=c.value})),Object.assign({},capabilities)}static exportDiscussion(state,cardId){let d=[];return state.discussions.forEach((c=>{c.kanban_card==cardId&&d.push(c)})),d=d.sort(((a,b)=>parseInt(a.timecreated)>parseInt(b.timecreated))),d}static exportHistory(state,cardId){let d=[];return state.history.forEach((c=>{c.kanban_card==cardId&&d.push(c)})),d=d.sort(((a,b)=>parseInt(a.timestamp)>parseInt(b.timestamp))),d}},_exports.default})); //# sourceMappingURL=exporter.min.js.map \ No newline at end of file diff --git a/amd/build/exporter.min.js.map b/amd/build/exporter.min.js.map index 9db53237..600e29b0 100644 --- a/amd/build/exporter.min.js.map +++ b/amd/build/exporter.min.js.map @@ -1 +1 @@ -{"version":3,"file":"exporter.min.js","sources":["../src/exporter.js"],"sourcesContent":["import capabilities from 'mod_kanban/capabilities';\n\n/**\n * Exporter for use in mustache template.\n */\nexport default class {\n /**\n * Exports the complete state (for initial rendering).\n * @param {*} state\n * @returns {object}\n */\n static exportStateForTemplate(state) {\n let columnOrder = state.board.sequence.split(',');\n let columns = [];\n let hascolumns = state.board.sequence != '';\n if (hascolumns) {\n columns = columnOrder.map((value) => {\n return this.exportCardsForColumn(state, value);\n });\n }\n\n let showactionmenu = state.common.userboards == 1 || state.common.groupselector != '' ||\n state.capabilities.get(capabilities.MANAGEBOARD).value ||\n (state.common.userboards == 2 && state.capabilities.get(capabilities.VIEWALLBOARDS).value);\n\n return Object.assign({\n cmid: state.common.id,\n id: state.board.id,\n sequence: state.board.sequence,\n hascolumns: hascolumns,\n columns: columns,\n locked: state.board.locked,\n hastemplate: state.common.template != 0,\n istemplate: state.board.template != 0,\n heading: state.board.heading,\n groupselector: state.common.groupselector,\n userboards: state.common.userboards,\n history: state.common.history && state.capabilities.get(capabilities.VIEWHISTORY).value,\n groupmode: state.common.groupmode,\n ismyuserboard: state.common.userid == state.board.userid,\n myuserid: state.common.userid,\n showactionmenu: showactionmenu,\n userboardsonly: state.common.userboards == 2,\n iscourseboard: state.board.userid == 0 && state.board.groupid == 0 && state.board.template == 0,\n users: JSON.parse(JSON.stringify(state.users)),\n }, this.exportCapabilities(state));\n }\n\n /**\n * Exports the card for one column.\n * @param {*} state\n * @param {*} columnid\n * @returns {object}\n */\n static exportCardsForColumn(state, columnid) {\n let col = JSON.parse(JSON.stringify(state.columns.get(columnid)));\n let options = JSON.parse(col.options);\n col.hascards = col.sequence != '';\n col.autoclose = options.autoclose;\n col.autohide = options.autohide;\n if (col.hascards) {\n let cardOrder = col.sequence.split(',');\n col.cards = cardOrder.map((value) => {\n return this.exportCard(state, value);\n });\n }\n return col;\n }\n\n /**\n * Exports a card.\n * @param {*} state\n * @param {*} cardid\n * @returns {object}\n */\n static exportCard(state, cardid) {\n let card = {\n id: cardid,\n title: '-',\n assignees: [],\n options: '{}',\n canedit: false\n };\n if (state.cards.get(cardid) !== undefined) {\n card = JSON.parse(JSON.stringify(state.cards.get(cardid)));\n }\n card.cardid = card.id;\n card.hasassignees = card.assignees.length > 0;\n let options = JSON.parse(card.options);\n if (card.hasassignees && typeof card.assignees[0] == 'number') {\n card.assignees = card.assignees.map((userid) => {\n return state.users.get(userid);\n });\n card.assignees = [...new Set(card.assignees)];\n }\n return Object.assign(card, options);\n }\n\n /**\n * Exports the capabilities.\n * @param {*} state\n * @returns {object}\n */\n static exportCapabilities(state) {\n let capabilities = [];\n state.capabilities.forEach((c) => {\n capabilities[c.id] = c.value;\n });\n return Object.assign({}, capabilities);\n }\n\n /**\n * Exports the discussion for a card.\n * @param {*} state\n * @param {number} cardId\n * @returns {array}\n */\n static exportDiscussion(state, cardId) {\n let d = [];\n state.discussions.forEach((c) => {\n if (c.kanban_card == cardId) {\n d.push(c);\n }\n });\n d = d.sort((a, b) => parseInt(a.timecreated) > parseInt(b.timecreated));\n return d;\n }\n\n /**\n * Exports history for a card.\n * @param {*} state\n * @param {number} cardId\n * @returns {array}\n */\n static exportHistory(state, cardId) {\n let d = [];\n // Only get history of this card.\n state.history.forEach((c) => {\n if (c.kanban_card == cardId) {\n d.push(c);\n }\n });\n // Sort by timestamp.\n d = d.sort((a, b) => parseInt(a.timestamp) > parseInt(b.timestamp));\n return d;\n }\n}"],"names":["state","columnOrder","board","sequence","split","columns","hascolumns","map","value","this","exportCardsForColumn","showactionmenu","common","userboards","groupselector","capabilities","get","MANAGEBOARD","VIEWALLBOARDS","Object","assign","cmid","id","locked","hastemplate","template","istemplate","heading","history","VIEWHISTORY","groupmode","ismyuserboard","userid","myuserid","userboardsonly","iscourseboard","groupid","users","JSON","parse","stringify","exportCapabilities","columnid","col","options","hascards","autoclose","autohide","cardOrder","cards","exportCard","cardid","card","title","assignees","canedit","undefined","hasassignees","length","Set","forEach","c","cardId","d","discussions","kanban_card","push","sort","a","b","parseInt","timecreated","timestamp"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"exporter.min.js","sources":["../src/exporter.js"],"sourcesContent":["import capabilities from 'mod_kanban/capabilities';\n\n/**\n * Exporter for use in mustache template.\n */\nexport default class {\n /**\n * Exports the complete state (for initial rendering).\n * @param {*} state\n * @returns {object}\n */\n static exportStateForTemplate(state) {\n let columnOrder = state.board.sequence.split(',');\n let columns = [];\n let hascolumns = state.board.sequence != '';\n if (hascolumns) {\n columns = columnOrder.map((value) => {\n return this.exportCardsForColumn(state, value);\n });\n }\n\n let showactionmenu = state.common.userboards == 1 || state.common.groupselector != '' ||\n state.capabilities.get(capabilities.MANAGEBOARD).value ||\n (state.common.userboards == 2 && state.capabilities.get(capabilities.VIEWALLBOARDS).value);\n\n return Object.assign({\n cmid: state.common.id,\n id: state.board.id,\n sequence: state.board.sequence,\n hascolumns: hascolumns,\n columns: columns,\n locked: state.board.locked,\n hastemplate: state.common.template != 0,\n istemplate: state.board.template != 0,\n heading: state.board.heading,\n groupselector: state.common.groupselector,\n userboards: state.common.userboards,\n history: state.common.history && state.capabilities.get(capabilities.VIEWHISTORY).value,\n groupmode: state.common.groupmode,\n ismyuserboard: state.common.userid == state.board.userid,\n myuserid: state.common.userid,\n showactionmenu: showactionmenu,\n userboardsonly: state.common.userboards == 2,\n iscourseboard: state.board.userid == 0 && state.board.groupid == 0 && state.board.template == 0,\n users: JSON.parse(JSON.stringify(state.users)),\n usenumbers: state.common.usenumbers,\n }, this.exportCapabilities(state));\n }\n\n /**\n * Exports the card for one column.\n * @param {*} state\n * @param {*} columnid\n * @returns {object}\n */\n static exportCardsForColumn(state, columnid) {\n let col = JSON.parse(JSON.stringify(state.columns.get(columnid)));\n let options = JSON.parse(col.options);\n col.hascards = col.sequence != '';\n col.autoclose = options.autoclose;\n col.autohide = options.autohide;\n if (col.hascards) {\n let cardOrder = col.sequence.split(',');\n col.cards = cardOrder.map((value) => {\n return this.exportCard(state, value);\n });\n }\n return col;\n }\n\n /**\n * Exports a card.\n * @param {*} state\n * @param {*} cardid\n * @returns {object}\n */\n static exportCard(state, cardid) {\n let card = {\n id: cardid,\n title: '-',\n assignees: [],\n options: '{}',\n canedit: false,\n number: 0,\n };\n if (state.cards.get(cardid) !== undefined) {\n card = JSON.parse(JSON.stringify(state.cards.get(cardid)));\n }\n card.cardid = card.id;\n card.hasassignees = card.assignees.length > 0;\n let options = JSON.parse(card.options);\n if (card.hasassignees && typeof card.assignees[0] == 'number') {\n card.assignees = card.assignees.map((userid) => {\n return state.users.get(userid);\n });\n card.assignees = [...new Set(card.assignees)];\n }\n return Object.assign(card, options);\n }\n\n /**\n * Exports the capabilities.\n * @param {*} state\n * @returns {object}\n */\n static exportCapabilities(state) {\n let capabilities = [];\n state.capabilities.forEach((c) => {\n capabilities[c.id] = c.value;\n });\n return Object.assign({}, capabilities);\n }\n\n /**\n * Exports the discussion for a card.\n * @param {*} state\n * @param {number} cardId\n * @returns {array}\n */\n static exportDiscussion(state, cardId) {\n let d = [];\n state.discussions.forEach((c) => {\n if (c.kanban_card == cardId) {\n d.push(c);\n }\n });\n d = d.sort((a, b) => parseInt(a.timecreated) > parseInt(b.timecreated));\n return d;\n }\n\n /**\n * Exports history for a card.\n * @param {*} state\n * @param {number} cardId\n * @returns {array}\n */\n static exportHistory(state, cardId) {\n let d = [];\n // Only get history of this card.\n state.history.forEach((c) => {\n if (c.kanban_card == cardId) {\n d.push(c);\n }\n });\n // Sort by timestamp.\n d = d.sort((a, b) => parseInt(a.timestamp) > parseInt(b.timestamp));\n return d;\n }\n}\n"],"names":["state","columnOrder","board","sequence","split","columns","hascolumns","map","value","this","exportCardsForColumn","showactionmenu","common","userboards","groupselector","capabilities","get","MANAGEBOARD","VIEWALLBOARDS","Object","assign","cmid","id","locked","hastemplate","template","istemplate","heading","history","VIEWHISTORY","groupmode","ismyuserboard","userid","myuserid","userboardsonly","iscourseboard","groupid","users","JSON","parse","stringify","usenumbers","exportCapabilities","columnid","col","options","hascards","autoclose","autohide","cardOrder","cards","exportCard","cardid","card","title","assignees","canedit","number","undefined","hasassignees","length","Set","forEach","c","cardId","d","discussions","kanban_card","push","sort","a","b","parseInt","timecreated","timestamp"],"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 4f8b2233..7874f356 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"]',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})); +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",CARDNUMBER:".mod_kanban_card_number",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",DETAILBUTTON:".mod_kanban_description_trigger",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 155b5350..3f7001da 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 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 +{"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 CARDNUMBER: `.mod_kanban_card_number`,\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 DETAILBUTTON: `.mod_kanban_description_trigger`,\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","CARDNUMBER","COLUMN","COLUMNCONTAINER","COLUMNINNER","COMPLETE","COMPLETIONSTATE","CONTAINER","DELETEBOARD","DELETECARD","DELETECOLUMN","DELETEMESSAGE","DELETETEMPLATE","DESCRIPTIONMODAL","DESCRIPTIONMODALBODY","DESCRIPTIONMODALFOOTER","DESCRIPTIONMODALTITLE","DESCRIPTIONTOGGLE","DETAILBUTTON","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,qCACAC,4BACAC,+CACAC,uCACAC,yCACAC,8CACAC,yCACAC,2CACAC,yCACAC,6CACAC,+CACAC,iDACAC,2CACAC,iEACAC,qEACAC,mEACAC,4CACAC,+CACAC,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/card.js b/amd/src/card.js index eba0e145..36f208ea 100644 --- a/amd/src/card.js +++ b/amd/src/card.js @@ -1,8 +1,9 @@ import {DragDrop} from 'core/reactive'; import selectors from 'mod_kanban/selectors'; import exporter from 'mod_kanban/exporter'; -import {exception as displayException, saveCancel} from 'core/notification'; +import {alert, exception as displayException, saveCancel} from 'core/notification'; import ModalForm from 'core_form/modalform'; +import ModalEvents from 'core/modal_events'; import * as Str from 'core/str'; import {get_string as getString} from 'core/str'; import Templates from 'core/templates'; @@ -147,6 +148,11 @@ export default class extends KanbanComponent { 'click', this._pushCardConfirm ); + this.addEventListener( + this.getElement(selectors.DETAILBUTTON), + 'click', + this._showDetailsModal + ); this.draggable = false; this.dragdrop = new DragDrop(this); @@ -182,6 +188,44 @@ export default class extends KanbanComponent { }).catch((error) => Log.debug(error)); } + /** + * Show modal with card details. + * @param {*} event + */ + _showDetailsModal(event) { + let id = this.id; + if (event.target.dataset.id !== undefined) { + id = event.target.dataset.id; + } + + let data = exporter.exportCard(this.reactive.state, id); + let title = this.reactive.state.common.usenumbers ? '#' + data.number + ' ' + data.title : data.title; + + alert( + title, + Templates.render('mod_kanban/descriptionmodal', data), + getString('close', 'form') + ).then((modal) => { + modal.modal[0].addEventListener(ModalEvents.bodyRendered, () => { + document.querySelectorAll(selectors.CARDNUMBER).forEach((el) => { + this.removeEventListener(el, 'click', this._clickDetailsButton); + this.addEventListener(el, 'click', this._clickDetailsButton); + }); + }); + return true; + }).catch((error) => Log.debug(error)); + } + + /** + * Simulate click on details button. + * @param {*} event + */ + _clickDetailsButton(event) { + document.querySelector( + selectors.CARD + `[data-number="${event.target.dataset.id}"]` + ' ' + selectors.DETAILBUTTON + ).click(); + } + /** * Display confirmation modal for pushing a card. * @param {*} event @@ -387,20 +431,8 @@ export default class extends KanbanComponent { let doc = new DOMParser().parseFromString(element.title, 'text/html'); this.getElement(selectors.INPLACEEDITABLE).setAttribute('data-value', doc.documentElement.textContent); this.getElement(selectors.INPLACEEDITABLE).querySelector('a').innerHTML = element.title; - this.getElement(selectors.DESCRIPTIONMODALTITLE).innerHTML = element.title; this.getElement(selectors.DISCUSSIONMODALTITLE).innerHTML = element.title; } - // Update description. - if (element.description !== undefined) { - this.getElement(selectors.DESCRIPTIONMODALBODY).innerHTML = element.description; - } - // Render attachments in description modal. - if (element.attachments !== undefined) { - Templates.renderForPromise('mod_kanban/attachmentitems', {attachments: element.attachments}).then(({html}) => { - this.getElement(selectors.DESCRIPTIONMODALFOOTER).innerHTML = html; - return true; - }).catch((error) => displayException(error)); - } this.toggleClass(element.hasdescription, 'mod_kanban_hasdescription'); this.toggleClass(element.hasattachment, 'mod_kanban_hasattachment'); // Update due date. diff --git a/amd/src/cardnumber.js b/amd/src/cardnumber.js new file mode 100644 index 00000000..e5e3b5e8 --- /dev/null +++ b/amd/src/cardnumber.js @@ -0,0 +1,33 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Helper for card number filter + * + * @module mod_kanban/cardnumber + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +export const init = (element) => { + document.querySelectorAll('#' + element + ' .mod_kanban_card_number').forEach((el) => { + el.addEventListener('click', (event) => { + document.querySelector( + `.mod_kanban_card[data-number="${event.target.dataset.id}"] .mod_kanban_description_trigger` + ).click(); + }); + }); +}; diff --git a/amd/src/exporter.js b/amd/src/exporter.js index 4f0f7c19..31b74734 100644 --- a/amd/src/exporter.js +++ b/amd/src/exporter.js @@ -43,6 +43,7 @@ export default class { userboardsonly: state.common.userboards == 2, iscourseboard: state.board.userid == 0 && state.board.groupid == 0 && state.board.template == 0, users: JSON.parse(JSON.stringify(state.users)), + usenumbers: state.common.usenumbers, }, this.exportCapabilities(state)); } @@ -79,7 +80,8 @@ export default class { title: '-', assignees: [], options: '{}', - canedit: false + canedit: false, + number: 0, }; if (state.cards.get(cardid) !== undefined) { card = JSON.parse(JSON.stringify(state.cards.get(cardid))); @@ -144,4 +146,4 @@ export default class { d = d.sort((a, b) => parseInt(a.timestamp) > parseInt(b.timestamp)); return d; } -} \ No newline at end of file +} diff --git a/amd/src/selectors.js b/amd/src/selectors.js index 04000b37..221d6a31 100644 --- a/amd/src/selectors.js +++ b/amd/src/selectors.js @@ -14,6 +14,7 @@ export default { ASSIGNEDUSER: `.mod_kanban_assigned_user`, BOARD: `.mod_kanban_board`, CARD: `.mod_kanban_card`, + CARDNUMBER: `.mod_kanban_card_number`, COLUMN: `.mod_kanban_column`, COLUMNCONTAINER: `.mod_kanban_column_container`, COLUMNINNER: `.mod_kanban_column_inner`, @@ -30,6 +31,7 @@ export default { DESCRIPTIONMODALFOOTER: `.mod_kanban_description_modal .modal-footer`, DESCRIPTIONMODALTITLE: `.mod_kanban_description_modal .modal-title`, DESCRIPTIONTOGGLE: `.mod_kanban_description`, + DETAILBUTTON: `.mod_kanban_description_trigger`, DISCUSSION: `.mod_kanban_discussion`, DISCUSSIONINPUT: `.mod_kanban_discussion_input`, DISCUSSIONMESSAGES: `.mod_kanban_discussion_messages`, diff --git a/backup/moodle2/restore_kanban_stepslib.php b/backup/moodle2/restore_kanban_stepslib.php index a20f223a..05274944 100644 --- a/backup/moodle2/restore_kanban_stepslib.php +++ b/backup/moodle2/restore_kanban_stepslib.php @@ -139,6 +139,10 @@ protected function process_card($data): void { $data->originalid = $this->get_mappingid('kanban_card_id', $data->originalid); $data->createdby = $this->get_mappingid('user', $data->createdby); + if (empty($data->number)) { + $data->number = $DB->get_field('kanban_card', 'MAX(number)', ['kanban_board' => $data->kanban_board]) + 1; + } + $newid = $DB->insert_record('kanban_card', $data); $this->set_mapping('kanban_card_id', $oldid, $newid, true); $this->add_related_files('mod_kanban', 'attachments', 'kanban_card_id', null, $oldid); diff --git a/classes/boardmanager.php b/classes/boardmanager.php index 20635f51..c9ca25c3 100644 --- a/classes/boardmanager.php +++ b/classes/boardmanager.php @@ -461,6 +461,8 @@ public function add_card(int $columnid, int $aftercard = 0, array $data = []): i ]; $data = array_merge($defaults, $data, $defaultsfixed); + $data['number'] = self::get_next_card_number(); + $data['id'] = $DB->insert_record('kanban_card', $data); $data['assignees'] = []; // Sanitize title to be extra safe. @@ -1230,4 +1232,19 @@ public function can_user_manage_specific_card(int $cardid, int $userid = 0): boo return false; } + + /** + * Returns the next card number for a board. + * + * @param int $boardid Id of the board + * @return int Next card number + */ + public function get_next_card_number(int $boardid = 0): int { + global $DB; + if (empty($boardid)) { + $boardid = $this->board->id; + } + $nextnumber = $DB->get_field('kanban_card', 'MAX(number)+1', ['kanban_board' => $boardid]); + return empty($nextnumber) ? 1 : $nextnumber; + } } diff --git a/classes/external/get_kanban_content.php b/classes/external/get_kanban_content.php index 3e23b3e3..78318953 100644 --- a/classes/external/get_kanban_content.php +++ b/classes/external/get_kanban_content.php @@ -18,7 +18,7 @@ * Class for delivering kanban content * * @package mod_kanban - * @copyright 2023-2024 ISB Bayern + * @copyright 2023-2024 ISB Bayern * @author Stefan Hanauska * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ @@ -42,6 +42,7 @@ use mod_kanban\boardmanager; use mod_kanban\constants; use mod_kanban\helper; +use mod_kanban\numberfilter; use mod_kanban\updateformatter; use moodle_exception; use required_capability_exception; @@ -51,7 +52,7 @@ /** * Class for delivering kanban content * - * @copyright 2023-2024 ISB Bayern + * @copyright 2023-2024 ISB Bayern * @author Stefan Hanauska * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ @@ -115,6 +116,7 @@ public static function get_kanban_content_init_returns(): external_single_struct 'groupselector' => new external_value(PARAM_RAW, 'group selector'), 'userboards' => new external_value(PARAM_INT, 'userboards'), 'history' => new external_value(PARAM_INT, 'history'), + 'usenumbers' => new external_value(PARAM_INT, 'use numbers for the cards'), ]), 'board' => new external_single_structure([ 'id' => new external_value(PARAM_INT, 'board id'), @@ -208,6 +210,10 @@ public static function get_kanban_content_init_returns(): external_single_struct VALUE_OPTIONAL, false ), + 'number' => new external_value( + PARAM_INT, + 'number of the card', + ), ], '', VALUE_OPTIONAL @@ -460,6 +466,7 @@ public static function execute(int $cmid, int $boardid, int $timestamp = 0, bool $common->groupmode = $cminfo->groupmode; $common->groupselector = $groupselector; $common->history = $kanban->history; + $common->usenumbers = $kanban->usenumbers; if (!$asupdate) { $common->template = $DB->get_field_sql( @@ -539,6 +546,9 @@ public static function execute(int $cmid, int $boardid, int $timestamp = 0, bool 'attachments', $card->id ); + if ($common->usenumbers) { + $card->description = numberfilter::filter($card->description); + } $card->attachments = helper::get_attachments($context->id, $card->id); $card->hasattachment = count($card->attachments) > 0; } diff --git a/classes/numberfilter.php b/classes/numberfilter.php new file mode 100644 index 00000000..b32e0e75 --- /dev/null +++ b/classes/numberfilter.php @@ -0,0 +1,46 @@ +. + +namespace mod_kanban; + +/** + * Class numberfilter + * + * @package mod_kanban + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class numberfilter { + /** + * Adds custom tags to card numbers in the text. + * + * @param string $text + * @return string + */ + public static function filter(string $text): string { + if (stripos($text, '#') === false) { + return $text; + } + + $pattern = '/#(\d+)/'; + $text = preg_replace_callback($pattern, function ($matches) { + $number = (int)$matches[1]; + return '#' . $number . ''; + }, $text); + return $text; + } +} diff --git a/db/install.xml b/db/install.xml index 6227c5a1..ee1d6ca4 100755 --- a/db/install.xml +++ b/db/install.xml @@ -13,6 +13,7 @@ + @@ -78,6 +79,7 @@ + diff --git a/db/upgrade.php b/db/upgrade.php index 5a15e923..255c487d 100755 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -18,7 +18,7 @@ * mod_kanban db upgrades. * * @package mod_kanban - * @copyright 2023-2024 ISB Bayern + * @copyright 2023-2024 ISB Bayern * @author Stefan Hanauska * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ @@ -29,6 +29,44 @@ * @param int $oldversion Version number the plugin is being upgraded from. */ function xmldb_kanban_upgrade($oldversion) { - // No upgrade steps until now. + global $DB; + $dbman = $DB->get_manager(); + + if ($oldversion < 2024032701) { + // Define field usenumbers to be added to kanban. + $table = new xmldb_table('kanban'); + $field = new xmldb_field('usenumbers', XMLDB_TYPE_INTEGER, '2', null, null, null, '0', 'history'); + + // Conditionally launch add field id. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Define field number to be added to kanban_card. + $table = new xmldb_table('kanban_card'); + $field = new xmldb_field('number', XMLDB_TYPE_INTEGER, '10', null, null, null, '0', 'timemodified'); + + // Conditionally launch add field id. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Set numbers for all cards. + $board = 0; + $nextnumber = 0; + $cards = $DB->get_recordset('kanban_card', ['number' => 0], 'kanban_board ASC, timecreated ASC'); + foreach ($cards as $card) { + if ($card->kanban_board != $board) { + $board = $card->kanban_board; + $nextnumber = $DB->get_field('kanban_card', 'MAX(number)', ['kanban_board' => $board]) + 1; + } else { + $nextnumber++; + } + $DB->set_field('kanban_card', 'number', $nextnumber, ['id' => $card->id]); + } + + // Kanban savepoint reached. + upgrade_mod_savepoint(true, 2024032701, 'kanban'); + } return true; } diff --git a/lang/en/kanban.php b/lang/en/kanban.php index 24662a89..31d147c2 100644 --- a/lang/en/kanban.php +++ b/lang/en/kanban.php @@ -179,6 +179,8 @@ $string['uncomplete'] = 'Reopen'; $string['unlock'] = 'Unlock'; $string['unlockboardcolumns'] = 'Unlock board columns'; +$string['usenumbers'] = 'Use card numbers'; +$string['usenumbers_help'] = 'This enables card numbers for this kanban activity. Numbers are unique per board (i.e. cards in user / group boards and the shared board can have the same number).'; $string['userboard'] = 'Personal board for {$a}'; $string['userboards'] = 'Personal boards'; $string['userboards_help'] = 'Enables personal boards for the participants (only visible to them and to the trainers)'; diff --git a/mod_form.php b/mod_form.php index 43113179..a53dd3e5 100644 --- a/mod_form.php +++ b/mod_form.php @@ -59,6 +59,9 @@ public function definition(): void { $mform->addHelpButton('history', 'enablehistory', 'mod_kanban'); } + $mform->addElement('advcheckbox', 'usenumbers', get_string('usenumbers', 'kanban')); + $mform->addHelpButton('usenumbers', 'usenumbers', 'kanban'); + $this->standard_coursemodule_elements(); $this->add_action_buttons(true, null, null); diff --git a/styles.css b/styles.css index feece6dc..63b85d3b 100644 --- a/styles.css +++ b/styles.css @@ -187,11 +187,14 @@ max-width: 80%; } -.mod_kanban_assignees { +:not(.mod_kanban_description_modal) > .mod_kanban_assignees { position: absolute; bottom: 10px; left: 12px; max-width: 14rem; +} + +.mod_kanban_assignees { overflow: hidden; max-height: 2.5rem; } @@ -305,6 +308,7 @@ a.mod_kanban_attachment_item { .mod_kanban_board:not(.mod_kanban_manageallcards):not(.mod_kanban_manageassignedcards) .mod_kanban_card:not(.mod_kanban_canedit) .mod_kanban_uncomplete_card, .mod_kanban_board:not(.mod_kanban_manageallcards):not(.mod_kanban_manageassignedcards) .mod_kanban_card:not(.mod_kanban_canedit) .mod_kanban_move_card, .mod_kanban_board:not(.mod_kanban_history) .mod_kanban_card_view_history, +.mod_kanban_board:not(.mod_kanban_usenumbers) .mod_kanban_number, .mod_kanban_board.mod_kanban_manageassignedcards:not(.mod_kanban_manageallcards) .mod_kanban_card:not(.mod_kanban_selfassigned) .mod_kanban_complete_card, .mod_kanban_board.mod_kanban_manageassignedcards:not(.mod_kanban_manageallcards) .mod_kanban_card:not(.mod_kanban_selfassigned) @@ -381,7 +385,7 @@ a.mod_kanban_attachment_item { .mod_kanban_history_modal, .mod_kanban_discussion_modal, .mod_kanban_description_modal { - cursor: pointer; + cursor: default; } .mod_kanban_addcard { @@ -429,3 +433,16 @@ a.mod_kanban_attachment_item { border-top-right-radius: 10px; border-bottom-right-radius: 10px; } + +.mod_kanban_number { + font-weight: bold; +} + +.mod_kanban_card_number { + cursor: pointer; + font-weight: bold; +} + +.mod_kanban_card_number::before { + background-image: url([[pix:i/show]]); +} diff --git a/templates/board.mustache b/templates/board.mustache index 4d8f88f5..5bae0003 100644 --- a/templates/board.mustache +++ b/templates/board.mustache @@ -34,10 +34,11 @@ "istemplate": true, "history": true, "heading": "Course board", - "ismyuserboard": true + "ismyuserboard": true, + "usenumbers": true, } }} -
+

{{heading}}

diff --git a/templates/card.mustache b/templates/card.mustache index fd46bc30..03147fdf 100644 --- a/templates/card.mustache +++ b/templates/card.mustache @@ -27,12 +27,13 @@ "hasassignees": false, "completed": true, "canedit": true, - "duedate": 123456778 + "duedate": 123456778, + "number": 12 } }} -
  • +
  • - diff --git a/templates/descriptionmodal.mustache b/templates/descriptionmodal.mustache index d4206be6..7eac0cfc 100644 --- a/templates/descriptionmodal.mustache +++ b/templates/descriptionmodal.mustache @@ -26,27 +26,36 @@ "duedate": 123456789 } }} -