/** * App Kanban */ 'use strict'; (async function () { let boards; const kanbanSidebar = document.querySelector('.kanban-update-item-sidebar'), kanbanWrapper = document.querySelector('.kanban-wrapper'), commentEditor = document.querySelector('.comment-editor'), kanbanAddNewBoard = document.querySelector('.kanban-add-new-board'), kanbanAddNewInput = [].slice.call(document.querySelectorAll('.kanban-add-board-input')), kanbanAddBoardBtn = document.querySelector('.kanban-add-board-btn'), datePicker = document.querySelector('#due-date'), select2 = $('.select2'), // ! Using jquery vars due to select2 jQuery dependency assetsPath = document.querySelector('html').getAttribute('data-assets-path'); // Init kanban Offcanvas const kanbanOffcanvas = new bootstrap.Offcanvas(kanbanSidebar); // Get kanban data const kanbanResponse = await fetch(assetsPath + 'json/kanban.json'); if (!kanbanResponse.ok) { console.error('error', kanbanResponse); } boards = await kanbanResponse.json(); // datepicker init if (datePicker) { datePicker.flatpickr({ monthSelectorType: 'static', altInput: true, altFormat: 'j F, Y', dateFormat: 'Y-m-d' }); } //! TODO: Update Event label and guest code to JS once select removes jQuery dependency // select2 if (select2.length) { function renderLabels(option) { if (!option.id) { return option.text; } var $badge = "
" + option.text + '
'; return $badge; } select2.each(function () { var $this = $(this); $this.wrap("
").select2({ placeholder: 'Select Label', dropdownParent: $this.parent(), templateResult: renderLabels, templateSelection: renderLabels, escapeMarkup: function (es) { return es; } }); }); } // Comment editor if (commentEditor) { new Quill(commentEditor, { modules: { toolbar: '.comment-toolbar' }, placeholder: 'Write a Comment... ', theme: 'snow' }); } // Render board dropdown function renderBoardDropdown() { return ( "' ); } // Render item dropdown function renderDropdown() { return ( "' ); } // Render header function renderHeader(color, text) { return ( "
" + "
" + "
" + text + '
' + '
' + renderDropdown() + '
' ); } // Render avatar function renderAvatar(images, pullUp, size, margin, members) { var $transition = pullUp ? ' pull-up' : '', $size = size ? 'avatar-' + size + '' : '', member = members == undefined ? ' ' : members.split(','); return images == undefined ? ' ' : images .split(',') .map(function (img, index, arr) { var $margin = margin && index !== arr.length - 1 ? ' me-' + margin + '' : ''; return ( "
' + "Avatar" + '
' ); }) .join(' '); } // Render footer function renderFooter(attachments, comments, assigned, members) { return ( "
" + "
" + "" + attachments + '' + " " + ' ' + comments + ' ' + '
' + "
" + renderAvatar(assigned, true, 'xs', null, members) + '
' + '
' ); } // Init kanban const kanban = new jKanban({ element: '.kanban-wrapper', gutter: '15px', widthBoard: '250px', dragItems: true, boards: boards, dragBoards: true, addItemButton: true, buttonContent: '+ Add Item', itemAddOptions: { enabled: true, // add a button to board for easy item creation content: '+ Add New Item', // text or html content of the board button class: 'kanban-title-button btn', // default class of the button footer: false // position the button on footer }, click: function (el) { let element = el; let title = element.getAttribute('data-eid') ? element.querySelector('.kanban-text').textContent : element.textContent, date = element.getAttribute('data-due-date'), dateObj = new Date(), year = dateObj.getFullYear(), dateToUse = date ? date + ', ' + year : dateObj.getDate() + ' ' + dateObj.toLocaleString('en', { month: 'long' }) + ', ' + year, label = element.getAttribute('data-badge-text'), avatars = element.getAttribute('data-assigned'); // Show kanban offcanvas kanbanOffcanvas.show(); // To get data on sidebar kanbanSidebar.querySelector('#title').value = title; kanbanSidebar.querySelector('#due-date').nextSibling.value = dateToUse; // ! Using jQuery method to get sidebar due to select2 dependency $('.kanban-update-item-sidebar').find(select2).val(label).trigger('change'); // Remove & Update assigned kanbanSidebar.querySelector('.assigned').innerHTML = ''; kanbanSidebar .querySelector('.assigned') .insertAdjacentHTML( 'afterbegin', renderAvatar(avatars, false, 'xs', '1', el.getAttribute('data-members')) + "
" + "" + '
' ); }, buttonClick: function (el, boardId) { const addNew = document.createElement('form'); addNew.setAttribute('class', 'new-item-form'); addNew.innerHTML = '
' + '' + '
' + '
' + '' + '' + '
'; kanban.addForm(boardId, addNew); addNew.addEventListener('submit', function (e) { e.preventDefault(); const currentBoard = [].slice.call( document.querySelectorAll('.kanban-board[data-id=' + boardId + '] .kanban-item') ); kanban.addElement(boardId, { title: "" + e.target[0].value + '', id: boardId + '-' + currentBoard.length + 1 }); // add dropdown in new boards const kanbanText = [].slice.call( document.querySelectorAll('.kanban-board[data-id=' + boardId + '] .kanban-text') ); kanbanText.forEach(function (e) { e.insertAdjacentHTML('beforebegin', renderDropdown()); }); // prevent sidebar to open onclick dropdown buttons of new tasks const newTaskDropdown = [].slice.call(document.querySelectorAll('.kanban-item .kanban-tasks-item-dropdown')); if (newTaskDropdown) { newTaskDropdown.forEach(function (e) { e.addEventListener('click', function (el) { el.stopPropagation(); }); }); } // delete tasks for new boards const deleteTask = [].slice.call( document.querySelectorAll('.kanban-board[data-id=' + boardId + '] .delete-task') ); deleteTask.forEach(function (e) { e.addEventListener('click', function () { const id = this.closest('.kanban-item').getAttribute('data-eid'); kanban.removeElement(id); }); }); addNew.remove(); }); // Remove form on clicking cancel button addNew.querySelector('.cancel-add-item').addEventListener('click', function (e) { addNew.remove(); }); } }); // Kanban Wrapper scrollbar if (kanbanWrapper) { new PerfectScrollbar(kanbanWrapper); } const kanbanContainer = document.querySelector('.kanban-container'), kanbanTitleBoard = [].slice.call(document.querySelectorAll('.kanban-title-board')), kanbanItem = [].slice.call(document.querySelectorAll('.kanban-item')); // Render custom items if (kanbanItem) { kanbanItem.forEach(function (el) { const element = "" + el.textContent + ''; let img = ''; if (el.getAttribute('data-image') !== null) { img = ""; } el.textContent = ''; if (el.getAttribute('data-badge') !== undefined && el.getAttribute('data-badge-text') !== undefined) { el.insertAdjacentHTML( 'afterbegin', renderHeader(el.getAttribute('data-badge'), el.getAttribute('data-badge-text')) + img + element ); } if ( el.getAttribute('data-comments') !== undefined || el.getAttribute('data-due-date') !== undefined || el.getAttribute('data-assigned') !== undefined ) { el.insertAdjacentHTML( 'beforeend', renderFooter( el.getAttribute('data-attachments'), el.getAttribute('data-comments'), el.getAttribute('data-assigned'), el.getAttribute('data-members') ) ); } }); } // To initialize tooltips for rendered items const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl); }); // prevent sidebar to open onclick dropdown buttons of tasks const tasksItemDropdown = [].slice.call(document.querySelectorAll('.kanban-tasks-item-dropdown')); if (tasksItemDropdown) { tasksItemDropdown.forEach(function (e) { e.addEventListener('click', function (el) { el.stopPropagation(); }); }); } // Toggle add new input and actions add-new-btn if (kanbanAddBoardBtn) { kanbanAddBoardBtn.addEventListener('click', () => { kanbanAddNewInput.forEach(el => { el.value = ''; el.classList.toggle('d-none'); }); }); } // Render add new inline with boards if (kanbanContainer) { kanbanContainer.appendChild(kanbanAddNewBoard); } // Makes kanban title editable for rendered boards if (kanbanTitleBoard) { kanbanTitleBoard.forEach(function (elem) { elem.addEventListener('mouseenter', function () { this.contentEditable = 'true'; }); // Appends delete icon with title elem.insertAdjacentHTML('afterend', renderBoardDropdown()); }); } // To delete Board for rendered boards const deleteBoards = [].slice.call(document.querySelectorAll('.delete-board')); if (deleteBoards) { deleteBoards.forEach(function (elem) { elem.addEventListener('click', function () { const id = this.closest('.kanban-board').getAttribute('data-id'); kanban.removeBoard(id); }); }); } // Delete task for rendered boards const deleteTask = [].slice.call(document.querySelectorAll('.delete-task')); if (deleteTask) { deleteTask.forEach(function (e) { e.addEventListener('click', function () { const id = this.closest('.kanban-item').getAttribute('data-eid'); kanban.removeElement(id); }); }); } // Cancel btn add new input const cancelAddNew = document.querySelector('.kanban-add-board-cancel-btn'); if (cancelAddNew) { cancelAddNew.addEventListener('click', function () { kanbanAddNewInput.forEach(el => { el.classList.toggle('d-none'); }); }); } // Add new board if (kanbanAddNewBoard) { kanbanAddNewBoard.addEventListener('submit', function (e) { e.preventDefault(); const thisEle = this, value = thisEle.querySelector('.form-control').value, id = value.replace(/\s+/g, '-').toLowerCase(); kanban.addBoards([ { id: id, title: value } ]); // Adds delete board option to new board, delete new boards & updates data-order const kanbanBoardLastChild = document.querySelectorAll('.kanban-board:last-child')[0]; if (kanbanBoardLastChild) { const header = kanbanBoardLastChild.querySelector('.kanban-title-board'); header.insertAdjacentHTML('afterend', renderBoardDropdown()); // To make newly added boards title editable kanbanBoardLastChild.querySelector('.kanban-title-board').addEventListener('mouseenter', function () { this.contentEditable = 'true'; }); } // Add delete event to delete newly added boards const deleteNewBoards = kanbanBoardLastChild.querySelector('.delete-board'); if (deleteNewBoards) { deleteNewBoards.addEventListener('click', function () { const id = this.closest('.kanban-board').getAttribute('data-id'); kanban.removeBoard(id); }); } // Remove current append new add new form if (kanbanAddNewInput) { kanbanAddNewInput.forEach(el => { el.classList.add('d-none'); }); } // To place inline add new btn after clicking add btn if (kanbanContainer) { kanbanContainer.appendChild(kanbanAddNewBoard); } }); } // Clear comment editor on close kanbanSidebar.addEventListener('hidden.bs.offcanvas', function () { kanbanSidebar.querySelector('.ql-editor').firstElementChild.innerHTML = ''; }); // Re-init tooltip when offcanvas opens(Bootstrap bug) if (kanbanSidebar) { kanbanSidebar.addEventListener('shown.bs.offcanvas', function () { const tooltipTriggerList = [].slice.call(kanbanSidebar.querySelectorAll('[data-bs-toggle="tooltip"]')); tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl); }); }); } })();