From 92dfffdaf0d104bb078c41d5bcd5a8e80325ff25 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 10 Jul 2014 15:52:50 +0200 Subject: [PATCH] Implemented drag and drop on taskboard. --- app/coffee/modules/taskboard/main.coffee | 34 ++++++- app/coffee/modules/taskboard/sortable.coffee | 94 +++++++++++++++++++ .../views/modules/taskboard-table.jade | 18 ++-- app/styles/modules/taskboard-table.scss | 4 +- 4 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 app/coffee/modules/taskboard/sortable.coffee diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee index 7a94b695..fcb3f0b6 100644 --- a/app/coffee/modules/taskboard/main.coffee +++ b/app/coffee/modules/taskboard/main.coffee @@ -45,6 +45,8 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q) -> + _.bindAll(@) + @scope.sprintId = @params.id @scope.sectionName = "Taskboard" @@ -58,7 +60,8 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.$on("taskform:new:success", => @.loadTaskboard()) @scope.$on("taskform:edit:success", => @.loadTaskboard()) - @scope.$on("assigned-to:added", (task) => @scope.$apply(=> @repo.save(task))) + @scope.$on("assigned-to:added", (ctx, task) => @scope.$apply(=> @repo.save(task))) + @scope.$on("taskboard:task:move", @.taskMove) loadSprintStats: -> return @rs.sprints.stats(@scope.projectId, @scope.sprintId).then (stats) => @@ -124,6 +127,24 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) .then(=> @.loadUsersAndRoles()) .then(=> @.loadTaskboard()) + taskMove: (ctx, task, usId, statusId, order) -> + # Remove task from old position + r = @scope.usTasks[task.user_story][task.status].indexOf(task) + @scope.usTasks[task.user_story][task.status].splice(r, 1) + + # Add task to new position + @scope.usTasks[usId][statusId].splice(order, 0, task) + + task.user_story = usId + task.status = statusId + task.order = order + + promise = @repo.save(task) + promise.then -> + console.log "SUCCESS TASK SAVE" + promise.then null, -> + console.log "FAIL TASK SAVE" + ## Template actions addNewTask: (type, us) -> switch type @@ -165,6 +186,17 @@ TaskboardDirective = ($rootscope) -> return {link: link} +TaskboardTaskDirective = -> + link = ($scope, $el, $attrs) -> + console.log "taskboard task" + $el.disableSelection() + + return {link:link} + + +module.directive("tgTaskboardTask", TaskboardTaskDirective) + + ############################################################################# ## Task Row Size Fixer Directive ############################################################################# diff --git a/app/coffee/modules/taskboard/sortable.coffee b/app/coffee/modules/taskboard/sortable.coffee new file mode 100644 index 00000000..753ec80c --- /dev/null +++ b/app/coffee/modules/taskboard/sortable.coffee @@ -0,0 +1,94 @@ +### +# Copyright (C) 2014 Andrey Antukh +# Copyright (C) 2014 Jesús Espino Garcia +# Copyright (C) 2014 David Barragán Merino +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/taskboard/sortable.coffee +### + +taiga = @.taiga + +mixOf = @.taiga.mixOf +toggleText = @.taiga.toggleText +scopeDefer = @.taiga.scopeDefer +bindOnce = @.taiga.bindOnce +groupBy = @.taiga.groupBy + +module = angular.module("taigaBacklog") + + +############################################################################# +## Sortable Directive +############################################################################# + +TaskboardSortableDirective = ($repo, $rs, $rootscope) -> + + ######################### + ## Drag & Drop Link + ######################### + + link = ($scope, $el, $attrs) -> + oldParentScope = null + newParentScope = null + itemEl = null + tdom = $el + + deleteElement = (itemEl) -> + # Completelly remove item and its scope from dom + itemEl.scope().$destroy() + itemEl.off() + itemEl.remove() + + tdom.sortable({ + handle: ".icon-drag-h", + dropOnEmpty: true + connectWith: ".taskboard-tasks-box" + revert: 400 + }) + + tdom.on "sortstop", (event, ui) -> + parentEl = ui.item.parent() + itemEl = ui.item + itemTask = itemEl.scope().task + itemIndex = itemEl.index() + newParentScope = parentEl.scope() + + oldUsId = if oldParentScope.us then oldParentScope.us.id else null + oldStatusId = oldParentScope.st.id + newUsId = if newParentScope.us then newParentScope.us.id else null + newStatusId = newParentScope.st.id + + if newStatusId != oldStatusId or newUsId != oldUsId + deleteElement(itemEl) + + $scope.$apply -> + $rootscope.$broadcast("taskboard:task:move", itemTask, newUsId, newStatusId, itemIndex) + + tdom.on "sortstart", (event, ui) -> + oldParentScope = ui.item.parent().scope() + + $scope.$on "$destroy", -> + $el.off() + + return {link: link} + + +module.directive("tgTaskboardSortable", [ + "$tgRepo", + "$tgResources", + "$rootScope", + TaskboardSortableDirective +]) diff --git a/app/partials/views/modules/taskboard-table.jade b/app/partials/views/modules/taskboard-table.jade index 9719929f..b504bfa9 100644 --- a/app/partials/views/modules/taskboard-table.jade +++ b/app/partials/views/modules/taskboard-table.jade @@ -5,8 +5,8 @@ div.taskboard-table h2.task-colum_name(ng-repeat="s in taskStatusList track by s.id", tg-bo-html="s.name") div.taskboard-table-body div.taskboard-table-inner(tg-taskboard-row-size-fixer) - div.task-row(ng-repeat="us in userstories track by us.id", tg-taskboard-taskrow) - div.taskboard_us-list.task-column + div.task-row(ng-repeat="us in userstories track by us.id") + div.taskboard-userstory-box.task-column div.tag-list span.tag(ng-repeat="tag in us.tags") {{ tag }} h3.us-title @@ -19,16 +19,18 @@ div.taskboard-table ul.points-list(tg-taskboard-us-points="us") include ../components/addnewtask - div.taskboard_task-playground.task-column(ng-repeat="st in taskStatusList track by st.id") - div.taskboard-task(ng-repeat="task in usTasks[us.id][st.id] track by task.id") + div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", tg-taskboard-sortable) + div.taskboard-task(ng-repeat="task in usTasks[us.id][st.id] track by task.id", + tg-taskboard-task) include ../components/taskboard-task - div.task-row(ng-init="us = null", tg-taskboard-taskrow) - div.taskboard_us-list.task-column + div.task-row(ng-init="us = null") + div.taskboard-userstory-box.task-column h3.us-title span Unassigned tasks include ../components/addnewtask - div.taskboard_task-playground.task-column(ng-repeat="st in taskStatusList track by st.id") - div.taskboard-task(ng-repeat="task in usTasks[null][st.id] track by task.id") + div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", tg-taskboard-sortable) + div.taskboard-task(ng-repeat="task in usTasks[null][st.id] track by task.id", + tg-taskboard-task) include ../components/taskboard-task diff --git a/app/styles/modules/taskboard-table.scss b/app/styles/modules/taskboard-table.scss index bb6d6454..077bc2b5 100644 --- a/app/styles/modules/taskboard-table.scss +++ b/app/styles/modules/taskboard-table.scss @@ -53,12 +53,12 @@ $column-margin: 0 10px 0 0; min-height: 30rem; width: 100%; } - .taskboard_task-playground { + .taskboard-tasks-box { background: $whitish; } } -.taskboard_us-list { +.taskboard-userstory-box { position: relative; .tag-list { display: none;