diff --git a/appinfo/routes.php b/appinfo/routes.php index 0e9a54899..52ddf0455 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -40,6 +40,7 @@ return [ ['name' => 'stack#index', 'url' => '/stacks/{boardId}', 'verb' => 'GET'], ['name' => 'stack#create', 'url' => '/stacks', 'verb' => 'POST'], ['name' => 'stack#update', 'url' => '/stacks/{stackId}', 'verb' => 'PUT'], + ['name' => 'stack#reorder', 'url' => '/stacks/{stackId}/reorder', 'verb' => 'PUT'], ['name' => 'stack#delete', 'url' => '/stacks/{stackId}', 'verb' => 'DELETE'], ['name' => 'stack#archived', 'url' => '/stacks/{boardId}/archived', 'verb' => 'GET'], diff --git a/css/style.css b/css/style.css index 0638d2dd3..33c7b769c 100644 --- a/css/style.css +++ b/css/style.css @@ -398,6 +398,11 @@ button:hover { margin: 10px; border: 1px dashed #aaa; } +#innerBoard > .as-sortable-placeholder { + display: inline-block !important; + margin-top: 0; + margin-left: 0; +} .info { padding-left: 5px; diff --git a/js/controller/BoardController.js b/js/controller/BoardController.js index 8931e2b97..cc06fd855 100644 --- a/js/controller/BoardController.js +++ b/js/controller/BoardController.js @@ -68,7 +68,7 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St $scope.stacksData = StackService; - $scope.stacks = {}; + $scope.stacks = []; $scope.$watch('stacksData', function (value) { $scope.refreshData(); }, true); @@ -87,7 +87,8 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St $scope.filterData = function (order, text) { if ($scope.stacks === undefined) return; - angular.copy(StackService.getAll(), $scope.stacks); + angular.copy(StackService.getData(), $scope.stacks); + $scope.stacks = $filter('orderBy')($scope.stacks, order); angular.forEach($scope.stacks, function (value, key) { var cards = $filter('cardSearchFilter')(value.cards, text); cards = $filter('orderBy')(cards, order); @@ -192,6 +193,7 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St // settings for card sorting $scope.sortOptions = { + id: 'card', itemMoved: function (event) { event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column; var order = event.dest.index; @@ -202,7 +204,7 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St CardService.update(card); CardService.reorder(card, order).then(function (data) { StackService.addCard(card); - StackService.reorder(card, order); + StackService.reorderCard(card, order); StackService.removeCard({ id: card.id, stackId: oldStack @@ -214,13 +216,14 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St var card = event.source.itemScope.c; var stack = event.dest.sortableScope.$parent.s.id; CardService.reorder(card, order).then(function (data) { - StackService.reorder(card, order); + StackService.reorderCard(card, order); $scope.refreshData(); }); }, scrollableContainer: '#board', containerPositioning: 'relative', containment: '#board', + longTouch: true, // auto scroll on drag dragMove: function (itemPosition, containment, eventObj) { if (eventObj) { @@ -239,6 +242,44 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St container.scrollTop(container.scrollTop() + 50); } } + }, + accept: function (sourceItemHandleScope, destSortableScope, destItemScope) { + return sourceItemHandleScope.sortableScope.options.id === 'card'; + } + }; + + $scope.sortOptionsStack = { + id: 'stack', + orderChanged: function (event) { + var order = event.dest.index; + var stack = event.source.itemScope.s; + StackService.reorder(stack, order).then(function (data) { + $scope.refreshData(); + }); + }, + scrollableContainer: '#board', + containerPositioning: 'relative', + containment: '#board', + dragMove: function (itemPosition, containment, eventObj) { + if (eventObj) { + var container = $("#board"); + var offset = container.offset(); + var targetX = eventObj.pageX - (offset.left || container.scrollLeft()); + var targetY = eventObj.pageY - (offset.top || container.scrollTop()); + if (targetX < offset.left) { + container.scrollLeft(container.scrollLeft() - 50); + } else if (targetX > container.width()) { + container.scrollLeft(container.scrollLeft() + 50); + } + if (targetY < offset.top) { + container.scrollTop(container.scrollTop() - 50); + } else if (targetY > container.height()) { + container.scrollTop(container.scrollTop() + 50); + } + } + }, + accept: function (sourceItemHandleScope, destSortableScope, destItemScope) { + return sourceItemHandleScope.sortableScope.options.id === 'stack'; } }; diff --git a/js/service/StackService.js b/js/service/StackService.js index 78460c1e7..8059f1163 100644 --- a/js/service/StackService.js +++ b/js/service/StackService.js @@ -58,7 +58,22 @@ app.factory('StackService', function(ApiService, $http, $q){ this.data[entity.stackId].cards.push(entity); }; - StackService.prototype.reorder = function(entity, order) { + StackService.prototype.reorder = function(stack, order) { + var deferred = $q.defer(); + var self = this; + $http.put(this.baseUrl + '/' + stack.id + '/reorder', {stackId: stack.id, order: order}).then(function (response) { + angular.forEach(response.data, function (value, key) { + var id = value.id; + self.data[id].order = value.order; + }); + deferred.resolve(response.data); + }, function (error) { + deferred.reject('Error while update ' + self.endpoint); + }); + return deferred.promise; + }; + + StackService.prototype.reorderCard = function(entity, order) { // assign new order for(var i=0, j=0;istackService->update($id, $title, $boardId, $order); } + /** + * @NoAdminRequired + * @param $stackId + * @param $order + * @return array + */ + public function reorder($stackId, $order) { + return $this->stackService->reorder($stackId, $order); + } + /** * @NoAdminRequired * @param $stackId diff --git a/lib/Service/StackService.php b/lib/Service/StackService.php index 84c293604..7c94ee3ce 100644 --- a/lib/Service/StackService.php +++ b/lib/Service/StackService.php @@ -102,4 +102,29 @@ class StackService { $stack->setOrder($order); return $this->stackMapper->update($stack); } + + public function reorder($id, $order) { + $this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_EDIT); + $stackToSort = $this->stackMapper->find($id); + $stacks = $this->stackMapper->findAll($stackToSort->getBoardId()); + $result = []; + $i = 0; + foreach ($stacks as $stack) { + if ($stack->id === $id) { + $stack->setOrder($order); + } + + if ($i === $order) { + $i++; + } + + if ($stack->id !== $id) { + $stack->setOrder($i++); + } + $this->stackMapper->update($stack); + $result[$stack->getOrder()] = $stack; + } + + return $result; + } } \ No newline at end of file diff --git a/templates/part.board.mainView.php b/templates/part.board.mainView.php index 0cbaeea19..a7c4c7f0c 100644 --- a/templates/part.board.mainView.php +++ b/templates/part.board.mainView.php @@ -42,11 +42,11 @@ -
-
+
-

{{ s.title }} +

{{ s.title }}
setOrder(1); $result = $this->stackService->update(123, 'Foo', 2, 1); $this->assertEquals($stack, $result); - } + public function testReorder() { + $this->permissionService->expects($this->once())->method('checkPermission'); + $a = $this->createStack(1, 0); + $b = $this->createStack(2, 1); + $c = $this->createStack(3, 2); + $stacks = [$a, $b, $c]; + $this->stackMapper->expects($this->once()) + ->method('find') + ->with(1) + ->willReturn($a); + $this->stackMapper->expects($this->once()) + ->method('findAll') + ->willReturn($stacks); + $actual = $this->stackService->reorder(1, 2); + $a = $this->createStack(1, 2); + $b = $this->createStack(2, 0); + $c = $this->createStack(3, 1); + $expected = [$b, $c, $a]; + $this->assertEquals($expected, $actual); + } + + private function createStack($id, $order) { + $stack = new Stack(); + $stack->setId($id); + $stack->setOrder($order); + return $stack; + } + } \ No newline at end of file diff --git a/tests/unit/controller/StackControllerTest.php b/tests/unit/controller/StackControllerTest.php index 6b287df33..e4e88eb66 100644 --- a/tests/unit/controller/StackControllerTest.php +++ b/tests/unit/controller/StackControllerTest.php @@ -84,6 +84,14 @@ class StackControllerTest extends \PHPUnit_Framework_TestCase { $this->assertEquals(1, $this->controller->update(1, 2, 3, 4)); } + public function testReorder() { + $this->stackService->expects($this->once()) + ->method('reorder') + ->with(1, 2) + ->willReturn(1); + $this->assertEquals(1, $this->controller->reorder(1, 2)); + } + public function testDelete() { $this->stackService->expects($this->once()) ->method('delete')