diff --git a/appinfo/routes.php b/appinfo/routes.php index ac84404e8..b18313cba 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -17,42 +17,40 @@ return [ ['name' => 'share#searchUser', 'url' => '/share/search/{search}', 'verb' => 'GET'], // boards - ['name' => 'board#index', 'url' => '/boards/', 'verb' => 'GET'], - ['name' => 'board#create', 'url' => '/boards/', 'verb' => 'POST'], - ['name' => 'board#read', 'url' => '/boards/{boardId}/', 'verb' => 'GET'], - ['name' => 'board#update', 'url' => '/boards/', 'verb' => 'PUT'], - ['name' => 'board#delete', 'url' => '/boards/{boardId}/', 'verb' => 'DELETE'], - // boards - acl - ['name' => 'board#addAcl', 'url' => '/boards/acl', 'verb' => 'POST'], - ['name' => 'board#updateAcl', 'url' => '/boards/acl', 'verb' => 'PUT'], - ['name' => 'board#deleteAcl', 'url' => '/boards/acl/{id}', 'verb' => 'DELETE'], + ['name' => 'board#index', 'url' => '/boards', 'verb' => 'GET'], + ['name' => 'board#create', 'url' => '/boards', 'verb' => 'POST'], + ['name' => 'board#read', 'url' => '/boards/{boardId}', 'verb' => 'GET'], + ['name' => 'board#update', 'url' => '/boards/{boardId}', 'verb' => 'PUT'], + ['name' => 'board#delete', 'url' => '/boards/{boardId}', 'verb' => 'DELETE'], + ['name' => 'board#addAcl', 'url' => '/boards/{boardId}/acl', 'verb' => 'POST'], + ['name' => 'board#updateAcl', 'url' => '/boards/{boardId}/acl', 'verb' => 'PUT'], + ['name' => 'board#deleteAcl', 'url' => '/boards/{boardId}/acl/{aclId}', 'verb' => 'DELETE'], // stacks - ['name' => 'stack#index', 'url' => '/stacks/{boardId}/', 'verb' => 'GET'], - ['name' => 'stack#create', 'url' => '/stacks/', 'verb' => 'POST'], - ['name' => 'stack#update', 'url' => '/stacks/', 'verb' => 'PUT'], - ['name' => 'stack#delete', 'url' => '/stacks/{stackId}/', 'verb' => 'DELETE'], + ['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#delete', 'url' => '/stacks/{stackId}', 'verb' => 'DELETE'], + ['name' => 'stack#archived', 'url' => '/stacks/{boardId}/archived', 'verb' => 'GET'], // cards - ['name' => 'card#read', 'url' => '/cards/{cardId}/', 'verb' => 'GET'], - ['name' => 'card#create', 'url' => '/cards/', 'verb' => 'POST'], - ['name' => 'card#update', 'url' => '/cards/', 'verb' => 'PUT'], - ['name' => 'card#rename', 'url' => '/cards/rename/', 'verb' => 'PUT'], - ['name' => 'card#reorder', 'url' => '/cards/reorder/', 'verb' => 'PUT'], - ['name' => 'card#delete', 'url' => '/cards/{cardId}/', 'verb' => 'DELETE'], - - // card - assign labels + ['name' => 'card#read', 'url' => '/cards/{cardId}', 'verb' => 'GET'], + ['name' => 'card#create', 'url' => '/cards', 'verb' => 'POST'], + ['name' => 'card#update', 'url' => '/cards/{cardId}', 'verb' => 'PUT'], + ['name' => 'card#delete', 'url' => '/cards/{cardId}', 'verb' => 'DELETE'], + ['name' => 'card#rename', 'url' => '/cards/{cardId}/rename', 'verb' => 'PUT'], + ['name' => 'card#reorder', 'url' => '/cards/{cardId}/reorder', 'verb' => 'PUT'], + ['name' => 'card#archive', 'url' => '/cards/{cardId}/archive', 'verb' => 'PUT'], ['name' => 'card#assignLabel', 'url' => '/cards/{cardId}/label/{labelId}', 'verb' => 'POST'], ['name' => 'card#removeLabel', 'url' => '/cards/{cardId}/label/{labelId}', 'verb' => 'DELETE'], - // TODO: card - assign user ['name' => 'card#assignUser', 'url' => '/cards/{cardId}/user/{labelId}', 'verb' => 'POST'], ['name' => 'card#removeUser', 'url' => '/cards/{cardId}/user/{labelId}', 'verb' => 'DELETE'], // labels - ['name' => 'label#create', 'url' => '/labels/', 'verb' => 'POST'], - ['name' => 'label#update', 'url' => '/labels/', 'verb' => 'PUT'], - ['name' => 'label#delete', 'url' => '/labels/{labelId}/', 'verb' => 'DELETE'], + ['name' => 'label#create', 'url' => '/labels', 'verb' => 'POST'], + ['name' => 'label#update', 'url' => '/labels({labelId}', 'verb' => 'PUT'], + ['name' => 'label#delete', 'url' => '/labels/{labelId}', 'verb' => 'DELETE'], // TODO: Implement public board sharing ['name' => 'public#index', 'url' => '/public/board/:hash', 'verb' => 'GET'], diff --git a/controller/boardcontroller.php b/controller/boardcontroller.php index 708a0f2f9..5fd122b7f 100644 --- a/controller/boardcontroller.php +++ b/controller/boardcontroller.php @@ -35,7 +35,7 @@ class BoardController extends Controller { */ public function read($boardId) { // FIXME: Remove as this is just for testing if loading animation works out nicely - usleep(200000); + //usleep(2000); return $this->boardService->find($this->userId, $boardId); } diff --git a/controller/cardcontroller.php b/controller/cardcontroller.php index 9135dbaea..ccc4c36d2 100644 --- a/controller/cardcontroller.php +++ b/controller/cardcontroller.php @@ -60,6 +60,19 @@ class CardController extends Controller { public function delete($cardId) { return $this->cardService->delete($this->userId, $cardId); } + + /** + * @NoAdminRequired + */ + public function archive($id) { + return $this->cardService->archive($id); + } + /** + * @NoAdminRequired + */ + public function unarchive($id) { + return $this->cardService->unarchive($id); + } /** * @NoAdminRequired */ diff --git a/controller/stackcontroller.php b/controller/stackcontroller.php index f1ecbcc23..2152819fc 100644 --- a/controller/stackcontroller.php +++ b/controller/stackcontroller.php @@ -26,6 +26,12 @@ class StackController extends Controller { public function index($boardId) { return $this->stackService->findAll($boardId); } + /** + * @NoAdminRequired + */ + public function archived($boardId) { + return $this->stackService->findAllArchived($boardId); + } /** * @NoAdminRequired */ diff --git a/css/style.css b/css/style.css index c61b8ab9a..7f12a8db3 100644 --- a/css/style.css +++ b/css/style.css @@ -1,3 +1,8 @@ +#searchbox { + display:block !important; +} + + .app-navigation-entry-utils-menu-button { display: block !important; } @@ -154,12 +159,16 @@ float:right; } .card { - background-color:#f6f6f6; + background-color:#f0f0f0; margin:5px; white-space: normal; padding-bottom:4px; position: relative; opacity: 1.0; + border:1px solid #aaaaaa; +} +.card.archived { + opacity:0.5; } .card-upper { overflow: hidden; diff --git a/db/board.php b/db/board.php index 033b092f4..abf2e7ccc 100644 --- a/db/board.php +++ b/db/board.php @@ -33,7 +33,7 @@ class Board extends \OCA\Deck\Db\Entity implements JsonSerializable { public function setLabels($labels) { foreach ($labels as $l) { - $this->labels[$l->id] = $l; + $this->labels[] = $l; } } diff --git a/db/card.php b/db/card.php index b43744a7d..45775fa44 100644 --- a/db/card.php +++ b/db/card.php @@ -22,6 +22,9 @@ class Card extends Entity implements JsonSerializable { $this->addType('id','integer'); $this->addType('stackId','integer'); $this->addType('order','integer'); + $this->addType('lastModified', 'integer'); + $this->addType('createdAt', 'integer'); + $this->addType('archived','boolean'); $this->addRelation('labels'); } diff --git a/db/cardmapper.php b/db/cardmapper.php index d1a92d2cc..38b5828cd 100644 --- a/db/cardmapper.php +++ b/db/cardmapper.php @@ -51,6 +51,7 @@ class CardMapper extends Mapper { } public function findAll($stackId, $limit=null, $offset=null) { + // TODO: Exclude fields like text $sql = 'SELECT * FROM `*PREFIX*deck_cards` WHERE `stack_id` = ? AND NOT archived ORDER BY `order`'; $entities = $this->findEntities($sql, [$stackId], $limit, $offset); @@ -58,9 +59,8 @@ class CardMapper extends Mapper { } // TODO: test - public function findAllArchived($boardId, $limit=null, $offset=null) { - $sql = 'SELECT * FROM `*PREFIX*deck_cards` as c, `*PREFIX*deck_stacks` as s - WHERE `s.board_id` = ? AND c.stack_id = s.id AND archived ORDER BY `last_modified`'; + public function findAllArchived($stackId, $limit=null, $offset=null) { + $sql = 'SELECT * FROM `*PREFIX*deck_cards` WHERE `stack_id`=? AND archived ORDER BY `last_modified`'; $entities = $this->findEntities($sql, [$stackId], $limit, $offset); return $entities; } diff --git a/db/stackmapper.php b/db/stackmapper.php index 802fd2b4d..52f052b59 100644 --- a/db/stackmapper.php +++ b/db/stackmapper.php @@ -32,6 +32,7 @@ class StackMapper extends Mapper { $sql = 'SELECT * FROM `*PREFIX*deck_stacks` WHERE `board_id` = ? ORDER BY `order`'; return $this->findEntities($sql, [$boardId], $limit, $offset); } + public function delete(Entity $entity) { // FIXME: delete linked elements, because owncloud doesn't support foreign keys for apps diff --git a/js/Gruntfile.js b/js/Gruntfile.js index 822242591..1869cce83 100644 --- a/js/Gruntfile.js +++ b/js/Gruntfile.js @@ -40,6 +40,7 @@ module.exports = function(grunt) { buildJS: [ 'app/**/*.js', 'controller/**/*.js', + 'filters/**/*.js', 'directive/**/*.js', 'service/**/*.js' ], diff --git a/js/app/Config.js b/js/app/Config.js index 687cb83b1..f407f6d33 100644 --- a/js/app/Config.js +++ b/js/app/Config.js @@ -24,7 +24,7 @@ app.config(function ($provide, $routeProvider, $interpolateProvider, $httpProvid .state('board', { url: "/board/:boardId", templateUrl: "/board.html", - controller: 'BoardController' + controller: 'BoardController', }) .state('board.detail', { url: "/detail/", @@ -32,7 +32,12 @@ app.config(function ($provide, $routeProvider, $interpolateProvider, $httpProvid "sidebarView": { templateUrl: "/board.sidebarView.html", } - } + }, + }) + .state('board.archive', { + url: "/archive/", + templateUrl: "/board.html", + controller: 'BoardController', }) .state('board.card', { url: "/card/:cardId", diff --git a/js/app/Run.js b/js/app/Run.js index 547244dcb..179242b7e 100644 --- a/js/app/Run.js +++ b/js/app/Run.js @@ -18,6 +18,10 @@ app.run(function ($document, $rootScope, $transitions) { $transitions.onExit({from: 'board.detail'}, function ($state) { $rootScope.sidebar.show = false; }); + $transitions.onEnter({to: 'board.archive'}, function ($state) { + //BoardController.update(); + console.log($state.$current.parent) + }); $('link[rel="shortcut icon"]').attr( 'href', diff --git a/js/controller/AppController.js b/js/controller/AppController.js index e29db012c..f0fbde9a6 100644 --- a/js/controller/AppController.js +++ b/js/controller/AppController.js @@ -4,4 +4,16 @@ app.controller('AppController', function ($scope, $location, $http, $route, $log show: false }; $scope.sidebar = $rootScope.sidebar; + + $scope.search = function (value) { + if (value === '') { + $location.search('search', null); + } else { + $location.search('search', value); + } + $scope.searchText = value; + }; + + $scope.searchText = $location.search().search; + }); \ No newline at end of file diff --git a/js/controller/ArchiveController.js b/js/controller/ArchiveController.js new file mode 100644 index 000000000..196e381a3 --- /dev/null +++ b/js/controller/ArchiveController.js @@ -0,0 +1,165 @@ + +app.controller('ArchiveController', function ($rootScope, $scope, $stateParams, StatusService, BoardService, StackService, CardService, LabelService, $state, $transitions) { + + $scope.sidebar = $rootScope.sidebar; + + $scope.id = $stateParams.boardId; + $scope.status={}, + $scope.newLabel={}; + $scope.status.boardtab = $stateParams.detailTab; + $scope.state = $state.current; + + console.log($scope.state); + $scope.stackservice = StackService; + $scope.boardservice = BoardService; + $scope.cardservice = CardService; + $scope.statusservice = StatusService.getInstance(); + $scope.labelservice = LabelService; + + $scope.foo = function(state) { + console.log(state); + } + + + // fetch data + StackService.clear(); + $scope.statusservice.retainWaiting(); + $scope.statusservice.retainWaiting(); + + BoardService.fetchOne($scope.id).then(function(data) { + $scope.statusservice.releaseWaiting(); + }, function(error) { + $scope.statusservice.setError('Error occured', error); + }); + + console.log($scope); + StackService.fetchArchived($scope.id).then(function(data) { + console.log(data); + $scope.statusservice.releaseWaiting(); + }, function(error) { + $scope.statusservice.setError('Error occured', error); + }); + + + + + + BoardService.searchUsers(); + + + + + $scope.cardDelete = function(card) { + CardService.delete(card.id); + StackService.deleteCard(card); + + } + + + // TODO: move to filter? + // Lighten Color of the board for background usage + $scope.rgblight = function (hex) { + var result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex); + var color = result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; + if(result !== null) { + var rgba = "rgba(" + color.r + "," + color.g + "," + color.b + ",0.7)"; + return rgba; + } else { + return "#"+hex; + } + }; + + // TODO: move to filter? + // RGB2HLS by Garry Tan + // http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c + $scope.textColor = function (hex) { + var result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex); + var color = result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; + if(result !== null) { + r = color.r/255; + g = color.g/255; + b = color.b/255; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min){ + h = s = 0; // achromatic + }else{ + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max){ + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + // TODO: Maybe just darken/lighten the color + if(l<0.5) { + return "#ffffff"; + } else { + return "#000000"; + } + //var rgba = "rgba(" + color.r + "," + color.g + "," + color.b + ",0.7)"; + //return rgba; + } else { + return "#aa0000"; + } + }; + + + + // settings for card sorting + $scope.sortOptions = { + itemMoved: function (event) { + // TODO: Implement reodering here + event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column; + var order = event.dest.index; + var card = event.source.itemScope.c; + var newStack = event.dest.sortableScope.$parent.s.id; + card.stackId = newStack; + CardService.update(card); + + CardService.reorder(card, order).then(function(data) { + StackService.data[newStack].addCard(card); + }); + }, + orderChanged: function (event) { + // TODO: Implement ordering here + var order = event.dest.index; + var card = event.source.itemScope.c; + CardService.reorder(card, order); + }, + scrollableContainer: '#board', + containerPositioning: 'relative', + containment: '#board', + // auto scroll on drag + dragMove: function (itemPosition, containment, eventObj) { + if (eventObj) { + var container = $("#board"); + var offset = container.offset(); + targetX = eventObj.pageX - (offset.left || container.scrollLeft()); + 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); + } + } + } + }; + +}); diff --git a/js/controller/BoardController.js b/js/controller/BoardController.js index bd3877d4c..b96612755 100644 --- a/js/controller/BoardController.js +++ b/js/controller/BoardController.js @@ -1,47 +1,51 @@ - -app.controller('BoardController', function ($rootScope, $scope, $stateParams, StatusService, BoardService, StackService, CardService, LabelService) { +app.controller('BoardController', function ($rootScope, $scope, $stateParams, StatusService, BoardService, StackService, CardService, LabelService, $state, $transitions) { $scope.sidebar = $rootScope.sidebar; $scope.id = $stateParams.boardId; $scope.status={}, - $scope.newLabel={}; + $scope.newLabel={}; $scope.status.boardtab = $stateParams.detailTab; + $scope.state = $state.current; + + + $scope.stackservice = StackService; $scope.boardservice = BoardService; + $scope.cardservice = CardService; $scope.statusservice = StatusService.getInstance(); $scope.labelservice = LabelService; $scope.defaultColors = ['31CC7C', '317CCC', 'FF7A66', 'F1DB50', '7C31CC', 'CC317C', '3A3B3D', 'CACBCD']; - // fetch data StackService.clear(); $scope.statusservice.retainWaiting(); $scope.statusservice.retainWaiting(); - StackService.fetchAll($scope.id).then(function(data) { - console.log(data); - + BoardService.fetchOne($scope.id).then(function(data) { $scope.statusservice.releaseWaiting(); }, function(error) { $scope.statusservice.setError('Error occured', error); }); + console.log($scope.state); + + StackService.fetchAll($scope.id).then(function(data) { + $scope.statusservice.releaseWaiting(); + }, function(error) { + $scope.statusservice.setError('Error occured', error); + }); + + + + + BoardService.searchUsers(); - BoardService.fetchOne($scope.id).then(function(data) { - console.log(BoardService.getCurrent()); - $scope.statusservice.releaseWaiting(); - }, function(error) { - $scope.statusservice.setError('Error occured', error); - }); - $scope.newStack = { 'boardId': $scope.id}; $scope.newCard = {}; - - // Create a new Stack $scope.createStack = function () { StackService.create($scope.newStack).then(function (data) { @@ -97,64 +101,6 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St $scope.updateAcl = function(acl) { BoardService.updateAcl(acl); } - // TODO: move to filter? - // Lighten Color of the board for background usage - $scope.rgblight = function (hex) { - var result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex); - var color = result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; - if(result !== null) { - var rgba = "rgba(" + color.r + "," + color.g + "," + color.b + ",0.7)"; - return rgba; - } else { - return "#"+hex; - } - }; - - // TODO: move to filter? - // RGB2HLS by Garry Tan - // http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c - $scope.textColor = function (hex) { - var result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex); - var color = result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; - if(result !== null) { - r = color.r/255; - g = color.g/255; - b = color.b/255; - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h, s, l = (max + min) / 2; - - if(max == min){ - h = s = 0; // achromatic - }else{ - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max){ - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - // TODO: Maybe just darken/lighten the color - if(l<0.5) { - return "#ffffff"; - } else { - return "#000000"; - } - //var rgba = "rgba(" + color.r + "," + color.g + "," + color.b + ",0.7)"; - //return rgba; - } else { - return "#aa0000"; - } - }; diff --git a/js/directive/search.js b/js/directive/search.js new file mode 100644 index 000000000..e01efe609 --- /dev/null +++ b/js/directive/search.js @@ -0,0 +1,28 @@ +app.directive('search', function ($document, $location) { + 'use strict'; + + return { + restrict: 'E', + scope: { + 'onSearch': '=' + }, + link: function (scope) { + var box = $('#searchbox'); + box.val($location.search().search); + + var doSearch = function() { + var value = box.val(); + scope.$apply(function () { + scope.onSearch(value); + }); + } + + box.on('search keyup', function (event) { + if (event.type === 'search' || event.keyCode === 13 ) { + doSearch(); + } + }); + + } + }; +}); diff --git a/js/filters/cardFilter.js b/js/filters/cardFilter.js new file mode 100644 index 000000000..4189ba37a --- /dev/null +++ b/js/filters/cardFilter.js @@ -0,0 +1,16 @@ +// usage | cardFilter({ member: 'admin'}) + +app.filter('cardFilter', function() { + return function(cards, rules) { + var _result = {}; + angular.forEach(cards, function(card){ + var _card = card; + angular.some(rules, function(rule, condition) { + if(_card[rule]===condition) { + _result.push(_card); + } + }); + }); + return result; + }; +}); \ No newline at end of file diff --git a/js/filters/cardSearchFilter.js b/js/filters/cardSearchFilter.js new file mode 100644 index 000000000..9cf754b1b --- /dev/null +++ b/js/filters/cardSearchFilter.js @@ -0,0 +1,20 @@ +// usage | cardFilter({ member: 'admin'}) + +app.filter('cardSearchFilter', function() { + return function(cards, searchString) { + var _result = {}; + var rules = { + title: searchString, + owner: searchString, + }; + angular.forEach(cards, function(card){ + var _card = card; + Object.keys(rules).some(function(rule) { + if(_card[rule].search(rules[rule])>=0) { + _result[_card.id] = _card; + } + }); + }); + return _result; + }; +}); \ No newline at end of file diff --git a/js/filters/lightenColorFilter.js b/js/filters/lightenColorFilter.js new file mode 100644 index 000000000..b3a434cb0 --- /dev/null +++ b/js/filters/lightenColorFilter.js @@ -0,0 +1,16 @@ +app.filter('lightenColorFilter', function() { + return function (hex) { + var result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex); + var color = result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; + if (result !== null) { + var rgba = "rgba(" + color.r + "," + color.g + "," + color.b + ",0.7)"; + return rgba; + } else { + return "#" + hex; + } + } +}); \ No newline at end of file diff --git a/js/filters/orderObjectBy.js b/js/filters/orderObjectBy.js new file mode 100644 index 000000000..4e55e46d5 --- /dev/null +++ b/js/filters/orderObjectBy.js @@ -0,0 +1,16 @@ +app.filter('orderObjectBy', function(){ + return function(input, attribute) { + if (!angular.isObject(input)) return input; + var array = []; + for(var objectKey in input) { + array.push(input[objectKey]); + } + + array.sort(function(a, b){ + a = parseInt(a[attribute]); + b = parseInt(b[attribute]); + return a - b; + }); + return array; + } +}); \ No newline at end of file diff --git a/js/filters/textColorFilter.js b/js/filters/textColorFilter.js new file mode 100644 index 000000000..12bccd1ce --- /dev/null +++ b/js/filters/textColorFilter.js @@ -0,0 +1,43 @@ +app.filter('lightenColorFilter', function() { + return function (hex) { + // RGB2HLS by Garry Tan + // http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c + var result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex); + var color = result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; + if(result !== null) { + r = color.r/255; + g = color.g/255; + b = color.b/255; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min){ + h = s = 0; // achromatic + }else{ + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max){ + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + // TODO: Maybe just darken/lighten the color + if(l<0.5) { + return "#ffffff"; + } else { + return "#000000"; + } + //var rgba = "rgba(" + color.r + "," + color.g + "," + color.b + ",0.7)"; + //return rgba; + } else { + return "#aa0000"; + } + + } +}); \ No newline at end of file diff --git a/js/public/app.js b/js/public/app.js index 017fe6248..00c8dfcb1 100644 --- a/js/public/app.js +++ b/js/public/app.js @@ -54,7 +54,7 @@ app.config(["$provide", "$routeProvider", "$interpolateProvider", "$httpProvider .state('board', { url: "/board/:boardId", templateUrl: "/board.html", - controller: 'BoardController' + controller: 'BoardController', }) .state('board.detail', { url: "/detail/", @@ -62,7 +62,12 @@ app.config(["$provide", "$routeProvider", "$interpolateProvider", "$httpProvider "sidebarView": { templateUrl: "/board.sidebarView.html", } - } + }, + }) + .state('board.archive', { + url: "/archive/", + templateUrl: "/board.html", + controller: 'BoardController', }) .state('board.card', { url: "/card/:cardId", @@ -102,6 +107,10 @@ app.run(["$document", "$rootScope", "$transitions", function ($document, $rootSc $transitions.onExit({from: 'board.detail'}, function ($state) { $rootScope.sidebar.show = false; }); + $transitions.onEnter({to: 'board.archive'}, function ($state) { + //BoardController.update(); + console.log($state.$current.parent) + }); $('link[rel="shortcut icon"]').attr( 'href', @@ -116,22 +125,40 @@ app.controller('AppController', ["$scope", "$location", "$http", "$route", "$log show: false }; $scope.sidebar = $rootScope.sidebar; + + $scope.search = function (value) { + if (value === '') { + $location.search('search', null); + } else { + $location.search('search', value); + } + $scope.searchText = value; + }; + + $scope.searchText = $location.search().search; + }]); -app.controller('BoardController', ["$rootScope", "$scope", "$stateParams", "StatusService", "BoardService", "StackService", "CardService", "LabelService", function ($rootScope, $scope, $stateParams, StatusService, BoardService, StackService, CardService, LabelService) { +app.controller('ArchiveController', ["$rootScope", "$scope", "$stateParams", "StatusService", "BoardService", "StackService", "CardService", "LabelService", "$state", "$transitions", function ($rootScope, $scope, $stateParams, StatusService, BoardService, StackService, CardService, LabelService, $state, $transitions) { $scope.sidebar = $rootScope.sidebar; $scope.id = $stateParams.boardId; $scope.status={}, - $scope.newLabel={}; + $scope.newLabel={}; $scope.status.boardtab = $stateParams.detailTab; + $scope.state = $state.current; + console.log($scope.state); $scope.stackservice = StackService; $scope.boardservice = BoardService; + $scope.cardservice = CardService; $scope.statusservice = StatusService.getInstance(); $scope.labelservice = LabelService; - $scope.defaultColors = ['31CC7C', '317CCC', 'FF7A66', 'F1DB50', '7C31CC', 'CC317C', '3A3B3D', 'CACBCD']; + + $scope.foo = function(state) { + console.log(state); + } // fetch data @@ -139,83 +166,36 @@ app.controller('BoardController', ["$rootScope", "$scope", "$stateParams", "Stat $scope.statusservice.retainWaiting(); $scope.statusservice.retainWaiting(); - StackService.fetchAll($scope.id).then(function(data) { - console.log(data); - + BoardService.fetchOne($scope.id).then(function(data) { $scope.statusservice.releaseWaiting(); }, function(error) { $scope.statusservice.setError('Error occured', error); }); + console.log($scope); + StackService.fetchArchived($scope.id).then(function(data) { + console.log(data); + $scope.statusservice.releaseWaiting(); + }, function(error) { + $scope.statusservice.setError('Error occured', error); + }); + + + + + BoardService.searchUsers(); - BoardService.fetchOne($scope.id).then(function(data) { - console.log(BoardService.getCurrent()); - $scope.statusservice.releaseWaiting(); - }, function(error) { - $scope.statusservice.setError('Error occured', error); - }); - - $scope.newStack = { 'boardId': $scope.id}; - $scope.newCard = {}; - // Create a new Stack - $scope.createStack = function () { - StackService.create($scope.newStack).then(function (data) { - $scope.newStack.title=""; - }); - }; - - $scope.createCard = function(stack, title) { - var newCard = { - 'title': title, - 'stackId': stack, - 'type': 'plain', - }; - CardService.create(newCard).then(function (data) { - $scope.stackservice.addCard(data); - $scope.newCard.title = ""; - }); - } - $scope.cardDelete = function(card) { CardService.delete(card.id); StackService.deleteCard(card); } - $scope.labelDelete = function(label) { - LabelService.delete(label.id); - // remove from board data - var i = BoardService.getCurrent().labels.indexOf(label); - BoardService.getCurrent().labels.splice(i, 1); - // TODO: remove from cards - } - $scope.labelCreate = function(label) { - label.boardId = $scope.id; - LabelService.create(label); - BoardService.getCurrent().labels.push(label); - $scope.status.createLabel = false; - $scope.newLabel = {}; - } - $scope.labelUpdate = function(label) { - label.edit = false; - LabelService.update(label); - } - $scope.addAcl = function(sharee) { - sharee.boardId = $scope.id; - BoardService.addAcl(sharee); - $scope.status.addSharee = null; - } - $scope.deleteAcl = function(acl) { - BoardService.deleteAcl(acl.id); - } - $scope.updateAcl = function(acl) { - BoardService.updateAcl(acl); - } // TODO: move to filter? // Lighten Color of the board for background usage $scope.rgblight = function (hex) { @@ -277,6 +257,159 @@ app.controller('BoardController', ["$rootScope", "$scope", "$stateParams", "Stat + // settings for card sorting + $scope.sortOptions = { + itemMoved: function (event) { + // TODO: Implement reodering here + event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column; + var order = event.dest.index; + var card = event.source.itemScope.c; + var newStack = event.dest.sortableScope.$parent.s.id; + card.stackId = newStack; + CardService.update(card); + + CardService.reorder(card, order).then(function(data) { + StackService.data[newStack].addCard(card); + }); + }, + orderChanged: function (event) { + // TODO: Implement ordering here + var order = event.dest.index; + var card = event.source.itemScope.c; + CardService.reorder(card, order); + }, + scrollableContainer: '#board', + containerPositioning: 'relative', + containment: '#board', + // auto scroll on drag + dragMove: function (itemPosition, containment, eventObj) { + if (eventObj) { + var container = $("#board"); + var offset = container.offset(); + targetX = eventObj.pageX - (offset.left || container.scrollLeft()); + 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); + } + } + } + }; + +}]); + +app.controller('BoardController', ["$rootScope", "$scope", "$stateParams", "StatusService", "BoardService", "StackService", "CardService", "LabelService", "$state", "$transitions", function ($rootScope, $scope, $stateParams, StatusService, BoardService, StackService, CardService, LabelService, $state, $transitions) { + + $scope.sidebar = $rootScope.sidebar; + + $scope.id = $stateParams.boardId; + $scope.status={}, + $scope.newLabel={}; + $scope.status.boardtab = $stateParams.detailTab; + $scope.state = $state.current; + + + + + $scope.stackservice = StackService; + $scope.boardservice = BoardService; + $scope.cardservice = CardService; + $scope.statusservice = StatusService.getInstance(); + $scope.labelservice = LabelService; + $scope.defaultColors = ['31CC7C', '317CCC', 'FF7A66', 'F1DB50', '7C31CC', 'CC317C', '3A3B3D', 'CACBCD']; + + // fetch data + StackService.clear(); + $scope.statusservice.retainWaiting(); + $scope.statusservice.retainWaiting(); + + BoardService.fetchOne($scope.id).then(function(data) { + $scope.statusservice.releaseWaiting(); + }, function(error) { + $scope.statusservice.setError('Error occured', error); + }); + + console.log($scope.state); + + StackService.fetchAll($scope.id).then(function(data) { + $scope.statusservice.releaseWaiting(); + }, function(error) { + $scope.statusservice.setError('Error occured', error); + }); + + + + + + BoardService.searchUsers(); + + $scope.newStack = { 'boardId': $scope.id}; + $scope.newCard = {}; + + // Create a new Stack + $scope.createStack = function () { + StackService.create($scope.newStack).then(function (data) { + $scope.newStack.title=""; + }); + }; + + $scope.createCard = function(stack, title) { + var newCard = { + 'title': title, + 'stackId': stack, + 'type': 'plain', + }; + CardService.create(newCard).then(function (data) { + $scope.stackservice.addCard(data); + $scope.newCard.title = ""; + }); + } + + $scope.cardDelete = function(card) { + CardService.delete(card.id); + StackService.deleteCard(card); + + } + + $scope.labelDelete = function(label) { + LabelService.delete(label.id); + // remove from board data + var i = BoardService.getCurrent().labels.indexOf(label); + BoardService.getCurrent().labels.splice(i, 1); + // TODO: remove from cards + } + $scope.labelCreate = function(label) { + label.boardId = $scope.id; + LabelService.create(label); + BoardService.getCurrent().labels.push(label); + $scope.status.createLabel = false; + $scope.newLabel = {}; + } + $scope.labelUpdate = function(label) { + label.edit = false; + LabelService.update(label); + } + + $scope.addAcl = function(sharee) { + sharee.boardId = $scope.id; + BoardService.addAcl(sharee); + $scope.status.addSharee = null; + } + $scope.deleteAcl = function(acl) { + BoardService.deleteAcl(acl.id); + } + $scope.updateAcl = function(acl) { + BoardService.updateAcl(acl); + } + + + // settings for card sorting $scope.sortOptions = { itemMoved: function (event) { @@ -421,6 +554,117 @@ app.controller('ListController', ["$scope", "$location", "BoardService", functio }]); +// usage | cardFilter({ member: 'admin'}) + +app.filter('cardFilter', function() { + return function(cards, rules) { + var _result = {}; + angular.forEach(cards, function(card){ + var _card = card; + angular.some(rules, function(rule, condition) { + if(_card[rule]===condition) { + _result.push(_card); + } + }); + }); + return result; + }; +}); +// usage | cardFilter({ member: 'admin'}) + +app.filter('cardSearchFilter', function() { + return function(cards, searchString) { + var _result = {}; + var rules = { + title: searchString, + owner: searchString, + }; + angular.forEach(cards, function(card){ + var _card = card; + Object.keys(rules).some(function(rule) { + if(_card[rule].search(rules[rule])>=0) { + _result[_card.id] = _card; + } + }); + }); + return _result; + }; +}); +app.filter('lightenColorFilter', function() { + return function (hex) { + var result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex); + var color = result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; + if (result !== null) { + var rgba = "rgba(" + color.r + "," + color.g + "," + color.b + ",0.7)"; + return rgba; + } else { + return "#" + hex; + } + } +}); +app.filter('orderObjectBy', function(){ + return function(input, attribute) { + if (!angular.isObject(input)) return input; + var array = []; + for(var objectKey in input) { + array.push(input[objectKey]); + } + + array.sort(function(a, b){ + a = parseInt(a[attribute]); + b = parseInt(b[attribute]); + return a - b; + }); + return array; + } +}); +app.filter('lightenColorFilter', function() { + return function (hex) { + // RGB2HLS by Garry Tan + // http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c + var result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex); + var color = result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; + if(result !== null) { + r = color.r/255; + g = color.g/255; + b = color.b/255; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min){ + h = s = 0; // achromatic + }else{ + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max){ + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + // TODO: Maybe just darken/lighten the color + if(l<0.5) { + return "#ffffff"; + } else { + return "#000000"; + } + //var rgba = "rgba(" + color.r + "," + color.g + "," + color.b + ",0.7)"; + //return rgba; + } else { + return "#aa0000"; + } + + } +}); // OwnCloud Click Handling // https://doc.owncloud.org/server/8.0/developer_manual/app/css.html app.directive('appNavigationEntryUtils', function () { @@ -531,6 +775,35 @@ app.directive('markdownChecklist', function () { }); +app.directive('search', ["$document", "$location", function ($document, $location) { + 'use strict'; + + return { + restrict: 'E', + scope: { + 'onSearch': '=' + }, + link: function (scope) { + var box = $('#searchbox'); + box.val($location.search().search); + + var doSearch = function() { + var value = box.val(); + scope.$apply(function () { + scope.onSearch(value); + }); + } + + box.on('search keyup', function (event) { + if (event.type === 'search' || event.keyCode === 13 ) { + doSearch(); + } + }); + + } + }; +}]); + app.factory('ApiService', ["$http", "$q", function($http, $q){ var ApiService = function(http, endpoint) { this.endpoint = endpoint; @@ -594,7 +867,7 @@ app.factory('ApiService', ["$http", "$q", function($http, $q){ ApiService.prototype.update = function (entity) { var deferred = $q.defer(); var self = this; - $http.put(this.baseUrl, entity).then(function (response) { + $http.put(this.baseUrl + '/' + entity.id, entity).then(function (response) { self.add(response.data); deferred.resolve(response.data); }, function (error) { @@ -691,7 +964,7 @@ app.factory('BoardService', ["ApiService", "$http", "$q", function(ApiService, $ var deferred = $q.defer(); var self = this; var _acl = acl; - $http.post(this.baseUrl + '/acl', _acl).then(function (response) { + $http.post(this.baseUrl + '/' + acl.boardId + '/acl', _acl).then(function (response) { if(!board.acl) { board.acl = {}; } @@ -704,11 +977,11 @@ app.factory('BoardService', ["ApiService", "$http", "$q", function(ApiService, $ return deferred.promise; }; - BoardService.prototype.deleteAcl = function(id) { + BoardService.prototype.deleteAcl = function(acl) { var board = this.getCurrent(); var deferred = $q.defer(); var self = this; - $http.delete(this.baseUrl + '/acl/' + id).then(function (response) { + $http.delete(this.baseUrl + '/' + acl.boardId + '/acl/' + acl.id).then(function (response) { delete board.acl[response.data.id]; deferred.resolve(response.data); }, function (error) { @@ -723,7 +996,7 @@ app.factory('BoardService', ["ApiService", "$http", "$q", function(ApiService, $ var deferred = $q.defer(); var self = this; var _acl = acl; - $http.put(this.baseUrl + '/acl', _acl).then(function (response) { + $http.put(this.baseUrl + '/' + acl.boardId + '/acl', _acl).then(function (response) { board.acl[_acl.id] = response.data; deferred.resolve(response.data); }, function (error) { @@ -746,7 +1019,7 @@ app.factory('CardService', ["ApiService", "$http", "$q", function(ApiService, $h CardService.prototype.reorder = function(card, order) { var deferred = $q.defer(); var self = this; - $http.put(this.baseUrl + '/reorder', {cardId: card.id, order: order, stackId: card.stackId}).then(function (response) { + $http.put(this.baseUrl + '/' + card.id + '/reorder', {cardId: card.id, order: order, stackId: card.stackId}).then(function (response) { card.order = order; deferred.resolve(response.data); }, function (error) { @@ -758,7 +1031,7 @@ app.factory('CardService', ["ApiService", "$http", "$q", function(ApiService, $h CardService.prototype.rename = function(card) { var deferred = $q.defer(); var self = this; - $http.put(this.baseUrl + '/rename', {cardId: card.id, title: card.title}).then(function (response) { + $http.put(this.baseUrl + '/' + card.id + '/rename', {cardId: card.id, title: card.title}).then(function (response) { self.data[card.id].title = card.title; deferred.resolve(response.data); }, function (error) { @@ -768,7 +1041,6 @@ app.factory('CardService', ["ApiService", "$http", "$q", function(ApiService, $h } CardService.prototype.assignLabel = function(card, label) { - //['name' => 'card#assignLabel', 'url' => '/cards/{cardId}/label/{labelId}', 'verb' => 'POST'], var url = this.baseUrl + '/' + card + '/label/' + label; var deferred = $q.defer(); var self = this; @@ -780,7 +1052,6 @@ app.factory('CardService', ["ApiService", "$http", "$q", function(ApiService, $h return deferred.promise; } CardService.prototype.removeLabel = function(card, label) { - // ['name' => 'card#removeLabel', 'url' => '/cards/{cardId}/label/{labelId}', 'verb' => 'DELETE'], var url = this.baseUrl + '/' + card + '/label/' + label; var deferred = $q.defer(); var self = this; @@ -792,6 +1063,18 @@ app.factory('CardService', ["ApiService", "$http", "$q", function(ApiService, $h return deferred.promise; } + CardService.prototype.archive = function (card) { + var deferred = $q.defer(); + var self = this; + $http.put(this.baseUrl + '/' + card.id + '/archive').then(function (response) { + deferred.resolve(response.data); + }, function (error) { + deferred.reject('Error while update ' + self.endpoint); + }); + return deferred.promise; + + }; + service = new CardService($http, 'cards', $q) return service; }]); @@ -812,18 +1095,31 @@ app.factory('StackService', ["ApiService", "$http", "$q", function(ApiService, $ var deferred = $q.defer(); var self=this; $http.get(this.baseUrl +'/'+boardId).then(function (response) { + self.clear(); self.addAll(response.data); deferred.resolve(self.data); }, function (error) { deferred.reject('Error while loading stacks'); }); return deferred.promise; + }; - } + StackService.prototype.fetchArchived = function(boardId) { + var deferred = $q.defer(); + var self=this; + $http.get(this.baseUrl +'/'+boardId+'/archived').then(function (response) { + self.clear(); + self.addAll(response.data); + deferred.resolve(self.data); + }, function (error) { + deferred.reject('Error while loading stacks'); + }); + return deferred.promise; + }; StackService.prototype.addCard = function(entity) { this.data[entity.stackId].cards.push(entity); - } + }; StackService.prototype.updateCard = function(entity) { var self = this; var cards = this.data[entity.stackId].cards; @@ -832,7 +1128,7 @@ app.factory('StackService', ["ApiService", "$http", "$q", function(ApiService, $ cards[i] = entity; } } - } + }; StackService.prototype.deleteCard = function(entity) { var self = this; var cards = this.data[entity.stackId].cards; @@ -841,7 +1137,7 @@ app.factory('StackService', ["ApiService", "$http", "$q", function(ApiService, $ cards.splice(i, 1); } } - } + }; service = new StackService($http, 'stacks', $q); return service; }]); diff --git a/js/service/ApiService.js b/js/service/ApiService.js index c1b758088..07ed52799 100644 --- a/js/service/ApiService.js +++ b/js/service/ApiService.js @@ -61,7 +61,7 @@ app.factory('ApiService', function($http, $q){ ApiService.prototype.update = function (entity) { var deferred = $q.defer(); var self = this; - $http.put(this.baseUrl, entity).then(function (response) { + $http.put(this.baseUrl + '/' + entity.id, entity).then(function (response) { self.add(response.data); deferred.resolve(response.data); }, function (error) { diff --git a/js/service/BoardService.js b/js/service/BoardService.js index 5d436f3e5..41b3470a4 100644 --- a/js/service/BoardService.js +++ b/js/service/BoardService.js @@ -23,7 +23,7 @@ app.factory('BoardService', function(ApiService, $http, $q){ var deferred = $q.defer(); var self = this; var _acl = acl; - $http.post(this.baseUrl + '/acl', _acl).then(function (response) { + $http.post(this.baseUrl + '/' + acl.boardId + '/acl', _acl).then(function (response) { if(!board.acl) { board.acl = {}; } @@ -36,11 +36,11 @@ app.factory('BoardService', function(ApiService, $http, $q){ return deferred.promise; }; - BoardService.prototype.deleteAcl = function(id) { + BoardService.prototype.deleteAcl = function(acl) { var board = this.getCurrent(); var deferred = $q.defer(); var self = this; - $http.delete(this.baseUrl + '/acl/' + id).then(function (response) { + $http.delete(this.baseUrl + '/' + acl.boardId + '/acl/' + acl.id).then(function (response) { delete board.acl[response.data.id]; deferred.resolve(response.data); }, function (error) { @@ -55,7 +55,7 @@ app.factory('BoardService', function(ApiService, $http, $q){ var deferred = $q.defer(); var self = this; var _acl = acl; - $http.put(this.baseUrl + '/acl', _acl).then(function (response) { + $http.put(this.baseUrl + '/' + acl.boardId + '/acl', _acl).then(function (response) { board.acl[_acl.id] = response.data; deferred.resolve(response.data); }, function (error) { diff --git a/js/service/CardService.js b/js/service/CardService.js index 16ec396ad..ea210874f 100644 --- a/js/service/CardService.js +++ b/js/service/CardService.js @@ -7,7 +7,7 @@ app.factory('CardService', function(ApiService, $http, $q){ CardService.prototype.reorder = function(card, order) { var deferred = $q.defer(); var self = this; - $http.put(this.baseUrl + '/reorder', {cardId: card.id, order: order, stackId: card.stackId}).then(function (response) { + $http.put(this.baseUrl + '/' + card.id + '/reorder', {cardId: card.id, order: order, stackId: card.stackId}).then(function (response) { card.order = order; deferred.resolve(response.data); }, function (error) { @@ -19,7 +19,7 @@ app.factory('CardService', function(ApiService, $http, $q){ CardService.prototype.rename = function(card) { var deferred = $q.defer(); var self = this; - $http.put(this.baseUrl + '/rename', {cardId: card.id, title: card.title}).then(function (response) { + $http.put(this.baseUrl + '/' + card.id + '/rename', {cardId: card.id, title: card.title}).then(function (response) { self.data[card.id].title = card.title; deferred.resolve(response.data); }, function (error) { @@ -29,7 +29,6 @@ app.factory('CardService', function(ApiService, $http, $q){ } CardService.prototype.assignLabel = function(card, label) { - //['name' => 'card#assignLabel', 'url' => '/cards/{cardId}/label/{labelId}', 'verb' => 'POST'], var url = this.baseUrl + '/' + card + '/label/' + label; var deferred = $q.defer(); var self = this; @@ -41,7 +40,6 @@ app.factory('CardService', function(ApiService, $http, $q){ return deferred.promise; } CardService.prototype.removeLabel = function(card, label) { - // ['name' => 'card#removeLabel', 'url' => '/cards/{cardId}/label/{labelId}', 'verb' => 'DELETE'], var url = this.baseUrl + '/' + card + '/label/' + label; var deferred = $q.defer(); var self = this; @@ -53,6 +51,18 @@ app.factory('CardService', function(ApiService, $http, $q){ return deferred.promise; } + CardService.prototype.archive = function (card) { + var deferred = $q.defer(); + var self = this; + $http.put(this.baseUrl + '/' + card.id + '/archive').then(function (response) { + deferred.resolve(response.data); + }, function (error) { + deferred.reject('Error while update ' + self.endpoint); + }); + return deferred.promise; + + }; + service = new CardService($http, 'cards', $q) return service; }); \ No newline at end of file diff --git a/js/service/StackService.js b/js/service/StackService.js index b60d3cac3..54f441636 100644 --- a/js/service/StackService.js +++ b/js/service/StackService.js @@ -7,18 +7,31 @@ app.factory('StackService', function(ApiService, $http, $q){ var deferred = $q.defer(); var self=this; $http.get(this.baseUrl +'/'+boardId).then(function (response) { + self.clear(); self.addAll(response.data); deferred.resolve(self.data); }, function (error) { deferred.reject('Error while loading stacks'); }); return deferred.promise; + }; - } + StackService.prototype.fetchArchived = function(boardId) { + var deferred = $q.defer(); + var self=this; + $http.get(this.baseUrl +'/'+boardId+'/archived').then(function (response) { + self.clear(); + self.addAll(response.data); + deferred.resolve(self.data); + }, function (error) { + deferred.reject('Error while loading stacks'); + }); + return deferred.promise; + }; StackService.prototype.addCard = function(entity) { this.data[entity.stackId].cards.push(entity); - } + }; StackService.prototype.updateCard = function(entity) { var self = this; var cards = this.data[entity.stackId].cards; @@ -27,7 +40,7 @@ app.factory('StackService', function(ApiService, $http, $q){ cards[i] = entity; } } - } + }; StackService.prototype.deleteCard = function(entity) { var self = this; var cards = this.data[entity.stackId].cards; @@ -36,7 +49,7 @@ app.factory('StackService', function(ApiService, $http, $q){ cards.splice(i, 1); } } - } + }; service = new StackService($http, 'stacks', $q); return service; }); diff --git a/service/cardservice.php b/service/cardservice.php index 23fab002a..c548a9702 100644 --- a/service/cardservice.php +++ b/service/cardservice.php @@ -69,7 +69,7 @@ class CardService { if($card->id !== $id) { $card->setOrder($i++); } - + $card->setLastModified(time()); $this->cardMapper->update($card); } // FIXME: return reordered cards without an additional db query @@ -77,6 +77,17 @@ class CardService { return $cards; } + public function archive($id) { + $card = $this->cardMapper->find($id); + $card->setArchived(true); + return $this->cardMapper->update($card); + } + + public function unarchive($id) { + $card = $this->cardMapper->find($id); + $card->setArchived(false); + return $this->cardMapper->update($card); + } public function assignLabel($userId, $cardId, $labelId) { $this->cardMapper->assignLabel($cardId, $labelId); diff --git a/service/stackservice.php b/service/stackservice.php index a55b63219..b65a40fa3 100644 --- a/service/stackservice.php +++ b/service/stackservice.php @@ -46,6 +46,19 @@ class StackService { return $stacks; } + public function findAllArchived($boardId) { + $stacks = $this->stackMapper->findAll($boardId); + $labels = $this->labelMapper->getAssignedLabelsForBoard($boardId); + foreach ($stacks as $idx => $s) { + $cards = $this->cardMapper->findAllArchived($s->id); + foreach ($cards as $idxc => $card) { + $cards[$idxc]->setLabels($labels[$card->id]); + } + $stacks[$idx]->setCards($cards); + } + return $stacks; + } + public function create($title, $boardId, $order) { $stack = new Stack(); $stack->setTitle($title); diff --git a/templates/part.board.mainView.php b/templates/part.board.mainView.php index 188ceda06..6836f58be 100644 --- a/templates/part.board.mainView.php +++ b/templates/part.board.mainView.php @@ -9,6 +9,7 @@ {{ boardservice.data[id].title }}
Filter
+
{{ searchText }}
by label
-
-
+
@@ -28,6 +28,8 @@
+ +
@@ -43,7 +45,7 @@
+