From 5e4b40665fa11ce0fd0fe957a19e2b7e63f47446 Mon Sep 17 00:00:00 2001 From: Frédéric Guillot Date: Sat, 17 May 2014 17:35:39 -0400 Subject: Rewrite board drag and drop with jquery (touch devices, IE, auto-update) --- assets/js/board.js | 301 +++++++++++++---------------------------------------- 1 file changed, 73 insertions(+), 228 deletions(-) (limited to 'assets/js/board.js') diff --git a/assets/js/board.js b/assets/js/board.js index 948ebf01..eab3916b 100644 --- a/assets/js/board.js +++ b/assets/js/board.js @@ -1,259 +1,102 @@ (function () { - function handleItemDragStart(e) - { - this.style.opacity = '0.4'; - - dragSrcItem = this; - dragSrcColumn = this.parentNode; - - e.dataTransfer.effectAllowed = 'copy'; - e.dataTransfer.setData('text/plain', this.innerHTML); - } - - function handleItemDragEnd(e) - { - // Restore styles - removeOver(); - this.style.opacity = '1.0'; - - dragSrcColumn = null; - dragSrcItem = null; - } - - function handleItemDragOver(e) - { - if (e.preventDefault) e.preventDefault(); - - e.dataTransfer.dropEffect = 'copy'; - - return false; - } - - function handleItemDragEnter(e) - { - if (dragSrcItem != this) { - removeOver(); - this.classList.add('over'); - } - } + var checkInterval = null; - function handleItemDrop(e) + // Setup the board + function board_load_events() { - if (e.preventDefault) e.preventDefault(); - if (e.stopPropagation) e.stopPropagation(); - - // Drop the element if the item is not the same - if (dragSrcItem != this) { - - var position = getItemPosition(this); - var item = createItem(e.dataTransfer.getData('text/plain')); - - if (countColumnItems(this.parentNode) == position) { - this.parentNode.appendChild(item); - } - else { - this.parentNode.insertBefore(item, this); + $(".column").sortable({ + connectWith: ".column", + placeholder: "draggable-placeholder", + stop: function(event, ui) { + board_save(); } + }); - dragSrcItem.parentNode.removeChild(dragSrcItem); - - saveBoard(); - } - - dragSrcColumn = null; - dragSrcItem = null; - - return false; - } - - - function handleColumnDragOver(e) - { - if (e.preventDefault) e.preventDefault(); - - e.dataTransfer.dropEffect = 'copy'; - - return false; - } + var interval = parseInt($("#board").attr("data-check-interval")); - function handleColumnDragEnter(e) - { - if (dragSrcColumn != this) { - removeOver(); - this.classList.add('over'); + if (interval > 0) { + checkInterval = window.setInterval(board_check, interval * 1000); } } - function handleColumnDrop(e) + // Stop events + function board_unload_events() { - if (e.preventDefault) e.preventDefault(); - if (e.stopPropagation) e.stopPropagation(); - - // Drop the element if the column is not the same - if (dragSrcColumn != this) { - - var item = createItem(e.dataTransfer.getData('text/plain')); - this.appendChild(item); - dragSrcColumn.removeChild(dragSrcItem); - - saveBoard(); - } - - return false; + clearInterval(checkInterval); } - function saveBoard() + // Save and refresh the board + function board_save() { var data = []; - var projectId = document.getElementById("board").getAttribute("data-project-id"); - var cols = document.querySelectorAll('.column'); - - [].forEach.call(cols, function(col) { - - var task_limit = col.getAttribute("data-task-limit"); + var projectId = $("#board").attr("data-project-id"); - if (task_limit != "" && task_limit != "0") { - - task_limit = parseInt(task_limit); - - if (col.children.length > task_limit) { - col.classList.add("task-limit-warning"); - } - else { - col.classList.remove("task-limit-warning"); - } - - var counter = document.getElementById("task-number-column-" + col.getAttribute("data-column-id")); - if (counter) counter.innerHTML = col.children.length; - } + board_unload_events(); - [].forEach.call(col.children, function(item) { + $(".column").each(function() { + var columnId = $(this).attr("data-column-id"); + $("#column-" + columnId + " .task").each(function(index) { data.push({ - "task_id": item.firstElementChild.getAttribute("data-task-id"), - "position": getItemPosition(item), - "column_id": col.getAttribute("data-column-id") - }) + "task_id": parseInt($(this).attr("data-task-id")), + "position": index + 1, + "column_id": parseInt(columnId) + }); }); }); - var xhr = new XMLHttpRequest(); - xhr.open("POST", "?controller=board&action=save&project_id=" + projectId, true); - - xhr.onreadystatechange = function(response) { - - if (this.readyState == this.DONE) { - try { - var response = JSON.parse(this.responseText); - - if (response.result == false) { - window.alert('Unable to update the board'); - } - else if (response.refresh == true) { - window.location = "?controller=board&action=show&project_id=" + projectId; - } - } - catch (e) {} + $.ajax({ + url: "?controller=board&action=save&project_id=" + projectId, + data: {positions: data}, + type: "POST", + success: function(data) { + $("#board").remove(); + $("#main").append(data); + board_load_events(); + applyFilter(getSelectedUserFilter(), hasDueDateFilter()); } - }; - - xhr.send(JSON.stringify(data)); + }); } - function getItemPosition(element) + // Check if a board have been changed by someone else + function board_check() { - var i = 0; - - while ((element = element.previousSibling) != null) { + var projectId = $("#board").attr("data-project-id"); + var timestamp = $("#board").attr("data-time"); - if (element.nodeName == "DIV" && element.className == "draggable-item") { - i++; - } + if (projectId != undefined && timestamp != undefined) { + $.ajax({ + url: "?controller=board&action=check&project_id=" + projectId + "×tamp=" + timestamp, + statusCode: { + 200: function(data) { + $("#board").remove(); + $("#main").append(data); + board_unload_events(); + board_load_events(); + applyFilter(getSelectedUserFilter(), hasDueDateFilter()); + } + } + }); } - - return i + 1; - } - - function countColumnItems(element) - { - return element.children.length; - } - - function createItem(html) - { - var item = document.createElement("div"); - item.className = "draggable-item"; - item.draggable = true; - item.innerHTML = html; - item.ondragstart = handleItemDragStart; - item.ondragend = handleItemDragEnd; - item.ondragenter = handleItemDragEnter; - item.ondragover = handleItemDragOver; - item.ondrop = handleItemDrop; - - return item; } - function removeOver() - { - // Remove column over - [].forEach.call(document.querySelectorAll('.column'), function (col) { - col.classList.remove('over'); - }); - - // Remove item over - [].forEach.call(document.querySelectorAll('.draggable-item'), function (item) { - item.classList.remove('over'); - }); - } - - // Drag and drop events - - var dragSrcItem = null; - var dragSrcColumn = null; - - var items = document.querySelectorAll('.draggable-item'); - - [].forEach.call(items, function(item) { - item.addEventListener('dragstart', handleItemDragStart, false); - item.addEventListener('dragend', handleItemDragEnd, false); - item.addEventListener('dragenter', handleItemDragEnter, false); - item.addEventListener('dragover', handleItemDragOver, false); - item.addEventListener('drop', handleItemDrop, false); - }); - - var cols = document.querySelectorAll('.column'); - - [].forEach.call(cols, function(col) { - col.addEventListener('dragenter', handleColumnDragEnter, false); - col.addEventListener('dragover', handleColumnDragOver, false); - col.addEventListener('drop', handleColumnDrop, false); - }); - - [].forEach.call(document.querySelectorAll('[data-task-id]'), function (item) { - item.addEventListener('click', function() { - window.location.href = '?controller=task&action=show&task_id=' + item.getAttribute('data-task-id'); - }); - }); - - // Filtering - + // Get the selected user id function getSelectedUserFilter() { - var select = document.getElementById("form-user_id"); - return select.options[select.selectedIndex].value; + return $("#form-user_id").val(); } + // Return true if the filter is activated function hasDueDateFilter() { - var dateFilter = document.getElementById("filter-due-date"); - return dateFilter.classList.contains("filter-on"); + return $("#filter-due-date").hasClass("filter-on"); } + // Apply user or date filter (change tasks opacity) function applyFilter(selectedUserId, filterDueDate) { - [].forEach.call(document.querySelectorAll('[data-task-id]'), function (item) { + $("[data-task-id]").each(function(index, item) { var ownerId = item.getAttribute("data-owner-id"); var dueDate = item.getAttribute("data-due-date"); @@ -271,22 +114,24 @@ }); } - var userFilter = document.getElementById("form-user_id"); - var dateFilter = document.getElementById("filter-due-date"); - - if (userFilter) { - userFilter.onchange = function() { + // Load filter events + function filter_load_events() + { + $("#form-user_id").change(function() { applyFilter(getSelectedUserFilter(), hasDueDateFilter()); - }; - } - - if (dateFilter) { + }); - dateFilter.onclick = function(e) { - dateFilter.classList.toggle("filter-on"); + $("#filter-due-date").click(function(e) { + $(this).toggleClass("filter-on"); applyFilter(getSelectedUserFilter(), hasDueDateFilter()); e.preventDefault(); - }; + }); } + // Initialization + $(function() { + board_load_events(); + filter_load_events(); + }); + }()); -- cgit v1.2.3