This commit is contained in:
Julius Haertl
2016-06-15 14:05:19 +02:00
parent ae9d5da329
commit cf3bbcb888
35 changed files with 686 additions and 465 deletions

View File

@@ -99,6 +99,7 @@
<type>text</type> <type>text</type>
<notnull>true</notnull> <notnull>true</notnull>
<length>64</length> <length>64</length>
<default>plain</default>
</field> </field>
<field> <field>
<name>last_modified</name> <name>last_modified</name>

View File

@@ -34,9 +34,10 @@ return [
['name' => 'stack#update', 'url' => '/stacks/', 'verb' => 'PUT'], ['name' => 'stack#update', 'url' => '/stacks/', 'verb' => 'PUT'],
['name' => 'stack#delete', 'url' => '/stacks/{stackId}/', 'verb' => 'DELETE'], ['name' => 'stack#delete', 'url' => '/stacks/{stackId}/', 'verb' => 'DELETE'],
// cards // cards
['name' => 'card#index', 'url' => '/cards/{stackId}/', 'verb' => 'GET'], ['name' => 'card#read', 'url' => '/cards/{cardId}/', 'verb' => 'GET'],
['name' => 'card#create', 'url' => '/cards/', 'verb' => 'POST'], ['name' => 'card#create', 'url' => '/cards/', 'verb' => 'POST'],
['name' => 'card#update', 'url' => '/cards/', 'verb' => 'PUT'], ['name' => 'card#update', 'url' => '/cards/', 'verb' => 'PUT'],
['name' => 'card#reorder', 'url' => '/cards/reorder/', 'verb' => 'PUT'],
['name' => 'card#delete', 'url' => '/cards/{cardId}/', 'verb' => 'DELETE'], ['name' => 'card#delete', 'url' => '/cards/{cardId}/', 'verb' => 'DELETE'],
// TODO: Implement public board sharing // TODO: Implement public board sharing

View File

@@ -1,5 +1,6 @@
<?php <?php
// TODO: Implement LATER
namespace OCA\Deck\Controller; namespace OCA\Deck\Controller;
use OCA\Deck\Service\BoardService; use OCA\Deck\Service\BoardService;
@@ -13,11 +14,11 @@ class BoardApiController extends BaseApiController {
private $userId; private $userId;
public function __construct($appName, public function __construct($appName,
IRequest $request, IRequest $request,
BoardService $stackService, BoardService $cardService,
$userId){ $userId){
parent::__construct($appName, $request); parent::__construct($appName, $request);
$this->userId = $userId; $this->userId = $userId;
$this->boardService = $stackService; $this->boardService = $cardService;
} }
/** /**
* @NoAdminRequired * @NoAdminRequired

View File

@@ -14,11 +14,11 @@ class BoardController extends Controller {
private $boardService; private $boardService;
public function __construct($appName, public function __construct($appName,
IRequest $request, IRequest $request,
BoardService $stackService, BoardService $cardService,
$userId){ $userId){
parent::__construct($appName, $request); parent::__construct($appName, $request);
$this->userId = $userId; $this->userId = $userId;
$this->boardService = $stackService; $this->boardService = $cardService;
} }
/** /**
* @NoAdminRequired * @NoAdminRequired
@@ -32,7 +32,7 @@ class BoardController extends Controller {
*/ */
public function read($boardId) { public function read($boardId) {
// FIXME: Remove as this is just for testing if loading animation works out nicely // FIXME: Remove as this is just for testing if loading animation works out nicely
usleep(500000); usleep(200000);
return $this->boardService->find($this->userId, $boardId); return $this->boardService->find($this->userId, $boardId);
} }
/** /**

View File

@@ -0,0 +1,57 @@
<?php
namespace OCA\Deck\Controller;
use OCA\Deck\Service\CardService;
use OCP\IRequest;
use OCP\AppFramework\Controller;
class CardController extends Controller {
private $userId;
private $cardService;
public function __construct($appName,
IRequest $request,
CardService $cardService,
$userId){
parent::__construct($appName, $request);
$this->userId = $userId;
$this->cardService = $cardService;
}
/**
* @NoAdminRequired
*/
public function index($cardId) {
return $this->cardService->findAll($boardId);
}
/**
* @NoAdminRequired
*/
public function read($cardId) {
return $this->cardService->find($this->userId, $cardId);
}
/**
* @NoAdminRequired
*/
public function reorder($cardId, $stackId, $order) {
return $this->cardService->reorder($cardId, $stackId, $order);
}
/**
* @NoAdminRequired
*/
public function create($title, $stackId, $type, $order=999) {
return $this->cardService->create($title, $stackId, $type, $order, $this->userId);
}
/**
* @NoAdminRequired
*/
public function update($id, $title, $stackId, $type, $order) {
return $this->cardService->update($id, $title, $stackId, $type, $order, $this->userId);
}
/**
* @NoAdminRequired
*/
public function delete($cardId) {
return $this->cardService->delete($this->userId, $cardId);
}
}

View File

@@ -27,27 +27,15 @@ class PageController extends Controller {
} }
/** /**
* CAUTION: the @Stuff turns off security checks; for this page no admin is * Handle main html view from templates/main.php
* required and no CSRF check. If you don't know what CSRF is, read * This will return the main angular application
* it up in the docs or you might create a security hole. This is
* basically the only required method to add this exemption, don't
* add it to any other method if you don't exactly know what it does
* *
* @NoAdminRequired * @NoAdminRequired
* @NoCSRFRequired * @NoCSRFRequired
*/ */
public function index() { public function index() {
$params = ['user' => $this->userId]; $params = ['user' => $this->userId];
return new TemplateResponse('deck', 'main', $params); // templates/main.php return new TemplateResponse('deck', 'main', $params);
} }
/**
* Simply method that posts back the payload of the request
* @NoAdminRequired
*/
public function doEcho($echo) {
return new DataResponse(['echo' => $echo]);
}
} }

View File

@@ -14,11 +14,11 @@ class StackController extends Controller {
private $stackService; private $stackService;
public function __construct($appName, public function __construct($appName,
IRequest $request, IRequest $request,
StackService $stackService, StackService $cardService,
$userId){ $userId){
parent::__construct($appName, $request); parent::__construct($appName, $request);
$this->userId = $userId; $this->userId = $userId;
$this->stackService = $stackService; $this->stackService = $cardService;
} }
/** /**
* @NoAdminRequired * @NoAdminRequired

View File

@@ -1,16 +1,3 @@
/*li:hover .app-navigation-entry-utils-buttom {
display: inline-block;
}
li .app-navigation-entry-utils-buttom,
li:hover .app-navigation-entry-utils-counter {
display: none;
}
.app-navigation-entry-utils button {
border:none;
color: #aaa !important;
background-color: #ffffff !important;
}
*/
.app-navigation-entry-utils-menu-button { .app-navigation-entry-utils-menu-button {
display: block !important; display: block !important;
} }
@@ -36,10 +23,12 @@ li:hover .app-navigation-entry-utils-counter {
background-color:#fff; background-color:#fff;
} }
#board { #board {
position-relative; position: relative;
height:100%; height:100%;
white-space: nowrap; /* important */ white-space: nowrap; /* important */
overflow: auto; overflow: auto;
background-color:#ffffff;
padding:0; padding:0;
} }
#board #innerBoard { #board #innerBoard {
@@ -53,10 +42,10 @@ li:hover .app-navigation-entry-utils-counter {
padding:10px; padding:10px;
position: fixed; position: fixed;
width:100%; width:100%;
color: #fff; color: #333333;
padding-right:250px; padding-right:250px;
z-index:100; z-index:100;
background-color:#aaa; background-color:#ffffff;
} }
#board .board-actions { #board .board-actions {
position:absolute; position:absolute;
@@ -71,12 +60,9 @@ li:hover .app-navigation-entry-utils-counter {
} }
.stack { .stack {
width:320px; width:320px;
background-color:#f1f1f1;
border-radius: 3px;
margin-right:10px; margin-right:10px;
-webkit-box-shadow: 0px 0px 3px 0px #aaa;
vertical-align: top; vertical-align: top;
display:inline-block !important; display:inline-block !important;
} }
.stack h2 { .stack h2 {
padding: 5px; padding: 5px;
@@ -113,7 +99,8 @@ li:hover .app-navigation-entry-utils-counter {
float:right; float:right;
} }
.card { .card {
background-color:#fff; background-color:#fafafa;
border: 1px solid #aaa;
margin:5px; margin:5px;
padding:5px; padding:5px;
padding-bottom:4px; padding-bottom:4px;
@@ -140,6 +127,12 @@ li:hover .app-navigation-entry-utils-counter {
vertical-align: middle; vertical-align: middle;
} }
.as-sortable-placeholder {
margin:5px;
margin-bottom:5px;
border: 1px dashed #aaa;
}
.labels { .labels {
position:absolute; position:absolute;
top:0px; top:0px;
@@ -172,12 +165,17 @@ li:hover .app-navigation-entry-utils-counter {
.card.create { .card.create {
text-align:center; text-align:center;
opacity: 0.6; margin:0;
border: none;
} }
.card.create:hover { .card.create:hover {
text-align:center; text-align:center;
opacity: 1; opacity: 1;
} }
.card.create h3 {
margin:0;
padding:0;
}
.card.create h3 input { .card.create h3 input {
width:100%; width:100%;
border:0px; border:0px;
@@ -187,9 +185,18 @@ li:hover .app-navigation-entry-utils-counter {
font-size:10pt; font-size:10pt;
margin:0; margin:0;
padding:0; padding:0;
border-bottom:1px solid #aaa; border-bottom:1px solid #ffffff;
border-radius: 0px; border-radius: 0px;
margin-bottom:20px; color: #ffffff;
background-color: transparent;
}
.card.create .fa {
color:#ffffff;
width:100%;
}
.card.create .fa:hover {
opacity: 0.5;
cursor: pointer;
} }
.due { .due {
background-color:#eee; background-color:#eee;

View File

@@ -2,6 +2,7 @@
namespace OCA\Deck\Db; namespace OCA\Deck\Db;
use OCP\AppFramework\Db\Entity;
use OCP\IDb; use OCP\IDb;
use OCP\AppFramework\Db\Mapper; use OCP\AppFramework\Db\Mapper;
@@ -29,5 +30,8 @@ class BoardMapper extends Mapper {
return $this->findEntities($sql, [$userId], $limit, $offset); return $this->findEntities($sql, [$userId], $limit, $offset);
} }
public function delete(Entity $entity) {
// FIXME: delete linked elements, because owncloud doesn't support foreign keys for apps
return parent::delete($entity);
}
} }

36
db/card.php Normal file
View File

@@ -0,0 +1,36 @@
<?php
// db/author.php
namespace OCA\Deck\Db;
use JsonSerializable;
use OCP\AppFramework\Db\Entity;
class Card extends Entity implements JsonSerializable {
public $id;
protected $title;
protected $stackId;
protected $type;
protected $lastModified;
protected $createdAt;
protected $owner;
protected $order;
public function __construct() {
$this->addType('id','integer');
$this->addType('stackId','integer');
$this->addType('order','integer');
}
public function jsonSerialize() {
return [
'id' => $this->id,
'title' => $this->title,
'type' => $this->type,
'lastModified' => $this->lastModified,
'createdAt' => $this->createdAt,
'owner' => $this->owner,
'order' => $this->order,
'stackId' => $this->stackId,
];
}
}

39
db/cardmapper.php Normal file
View File

@@ -0,0 +1,39 @@
<?php
namespace OCA\Deck\Db;
use OCP\AppFramework\Db\Entity;
use OCP\IDb;
use OCP\AppFramework\Db\Mapper;
class CardMapper extends Mapper {
public function __construct(IDb $db) {
parent::__construct($db, 'deck_cards', '\OCA\Deck\Db\Card');
}
/**
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result
*/
public function find($id) {
$sql = 'SELECT * FROM `*PREFIX*deck_cards` ' .
'WHERE `id` = ?';
return $this->findEntity($sql, [$id]);
}
public function findAll($stackId, $limit=null, $offset=null) {
$sql = 'SELECT * FROM `*PREFIX*deck_cards` WHERE `stack_id` = ? ORDER BY `order`';
return $this->findEntities($sql, [$stackId], $limit, $offset);
}
public function delete(Entity $entity) {
// FIXME: delete linked elements, because owncloud doesn't support foreign keys for apps
return parent::delete($entity);
}
}

View File

@@ -10,6 +10,7 @@ class Stack extends Entity implements JsonSerializable {
public $id; public $id;
protected $title; protected $title;
protected $boardId; protected $boardId;
protected $cards = array();
protected $order; protected $order;
public function __construct() { public function __construct() {
$this->addType('id','integer'); $this->addType('id','integer');
@@ -17,12 +18,16 @@ class Stack extends Entity implements JsonSerializable {
$this->addType('order','integer'); $this->addType('order','integer');
} }
public function setCards($cards) {
$this->cards = $cards;
}
public function jsonSerialize() { public function jsonSerialize() {
return [ return [
'id' => $this->id, 'id' => $this->id,
'title' => $this->title, 'title' => $this->title,
'order' => $this->order, 'order' => $this->order,
'boardId' => $this->boardId 'boardId' => $this->boardId,
'cards' => $this->cards,
]; ];
} }
} }

View File

@@ -2,14 +2,18 @@
namespace OCA\Deck\Db; namespace OCA\Deck\Db;
use OCP\AppFramework\Db\Entity;
use OCP\IDb; use OCP\IDb;
use OCP\AppFramework\Db\Mapper; use OCP\AppFramework\Db\Mapper;
class StackMapper extends Mapper { class StackMapper extends Mapper {
public function __construct(IDb $db) { private $cardMapper;
public function __construct(IDb $db, CardMapper $cardMapper) {
parent::__construct($db, 'deck_stacks', '\OCA\Deck\Db\Stack'); parent::__construct($db, 'deck_stacks', '\OCA\Deck\Db\Stack');
$this->cardMapper = $cardMapper;
} }
@@ -29,5 +33,8 @@ class StackMapper extends Mapper {
return $this->findEntities($sql, [$boardId], $limit, $offset); 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
return parent::delete($entity);
}
} }

View File

@@ -1,78 +1,2 @@
var app = angular.module('Deck', ['ngRoute', 'ngSanitize', 'ui.router', 'as.sortable']); var app = angular.module('Deck', ['ngRoute', 'ngSanitize', 'ui.router', 'as.sortable']);
app.config(function ($provide, $routeProvider, $interpolateProvider, $httpProvider, $urlRouterProvider, $stateProvider) {
'use strict';
$httpProvider.defaults.headers.common.requesttoken = oc_requesttoken;
$urlRouterProvider.otherwise("/");
$stateProvider
.state('list', {
url: "/",
templateUrl: "/boardlist.mainView.html",
controller: 'ListController',
})
.state('board', {
url: "/board/:boardId",
templateUrl: "/board.html",
controller: 'BoardController'
})
.state('board.card', {
url: "/card/:cardId",
views: {
"sidebarView": {
templateUrl: "/card.sidebarView.html",
controller: 'CardController'
}
}
})
.state('board.settings', {})
.state('board.sharing', {});
});
// OwnCloud Click Handling
// https://doc.owncloud.org/server/8.0/developer_manual/app/css.html
app.directive('appNavigationEntryUtils', function () {
'use strict';
return {
restrict: 'C',
link: function (scope, elm) {
var menu = elm.siblings('.app-navigation-entry-menu');
var button = $(elm)
.find('.app-navigation-entry-utils-menu-button button');
button.click(function () {
menu.toggleClass('open');
});
scope.$on('documentClicked', function (scope, event) {
if (event.target !== button[0]) {
menu.removeClass('open');
}
});
}
};
});
app.directive('autofocusOnInsert', function () {
'use strict';
return function (scope, elm) {
elm.focus();
};
});
app.run(function ($document, $rootScope, $transitions) {
'use strict';
$document.click(function (event) {
$rootScope.$broadcast('documentClicked', event);
});
$transitions.onEnter({to: 'board.card'}, function ($state, $transition$) {
$rootScope.sidebar.show = true;
});
$transitions.onEnter({to: 'board'}, function ($state) {
$rootScope.sidebar.show = false;
});
$transitions.onExit({from: 'board.card'}, function ($state) {
$rootScope.sidebar.show = false;
});
});

35
js/app/Config.js Normal file
View File

@@ -0,0 +1,35 @@
app.config(function ($provide, $routeProvider, $interpolateProvider, $httpProvider, $urlRouterProvider, $stateProvider, $compileProvider) {
'use strict';
$httpProvider.defaults.headers.common.requesttoken = oc_requesttoken;
$compileProvider.debugInfoEnabled(true);
$urlRouterProvider.otherwise("/");
$stateProvider
.state('list', {
url: "/",
templateUrl: "/boardlist.mainView.html",
controller: 'ListController',
})
.state('board', {
url: "/board/:boardId",
templateUrl: "/board.html",
controller: 'BoardController'
})
.state('board.card', {
url: "/card/:cardId",
views: {
"sidebarView": {
templateUrl: "/card.sidebarView.html",
controller: 'CardController'
}
}
})
.state('board.settings', {
})
.state('board.sharing', {
});
});

15
js/app/Run.js Normal file
View File

@@ -0,0 +1,15 @@
app.run(function ($document, $rootScope, $transitions) {
'use strict';
$document.click(function (event) {
$rootScope.$broadcast('documentClicked', event);
});
$transitions.onEnter({to: 'board.card'}, function ($state, $transition$) {
$rootScope.sidebar.show = true;
});
$transitions.onEnter({to: 'board'}, function ($state) {
$rootScope.sidebar.show = false;
});
$transitions.onExit({from: 'board.card'}, function ($state) {
$rootScope.sidebar.show = false;
});
});

View File

@@ -1,72 +1,33 @@
app.controller('BoardController', function ($rootScope, $scope, $location, $http, $route, $stateParams, BoardService, StackService) { app.controller('BoardController', function ($rootScope, $scope, $stateParams, StatusService, BoardService, StackService, CardService) {
$scope.sidebar = $rootScope.sidebar; $scope.sidebar = $rootScope.sidebar;
$scope.id = $stateParams.boardId; $scope.id = $stateParams.boardId;
$scope.stackservice = StackService; $scope.stackservice = StackService;
$scope.boardservice = BoardService; $scope.boardservice = BoardService;
$scope.statusservice = StatusService;
// fetch data // fetch data
StackService.clear(); StackService.clear();
console.log("foo");
StackService.fetchAll($scope.id).then(function(data) { StackService.fetchAll($scope.id).then(function(data) {
console.log($scope.stackservice.data) $scope.statusservice.releaseWaiting();
$scope.releaseWaiting();
}, function(error) { }, function(error) {
$scope.setError('Error occured', error); $scope.statusservice.setError('Error occured', error);
}); });
BoardService.fetchOne($scope.id).then(function(data) { BoardService.fetchOne($scope.id).then(function(data) {
$scope.releaseWaiting(); $scope.statusservice.releaseWaiting();
}, function(error) { }, function(error) {
$scope.setError('Error occured', error); $scope.statusservice.setError('Error occured', error);
}); });
$scope.newStack = { 'boardId': $scope.id}; $scope.newStack = { 'boardId': $scope.id};
$scope.newCard = {}; $scope.newCard = {};
// Status Helper
$scope.status = {
'active': true,
'icon': 'loading',
'title': 'Bitte warten',
'text': 'Es dauert noch einen kleinen Moment',
'counter': 2,
};
$scope.setStatus = function($icon, $title, $text='') {
$scope.status.active = true;
$scope.status.icon = $icon;
$scope.status.title = $title;
$scope.status.text = $text;
}
$scope.setError = function($title, $text) {
$scope.status.active = true;
$scope.status.icon = 'error';
$scope.status.title = $title;
$scope.status.text = $text;
$scope.status.counter = 0;
}
$scope.releaseWaiting = function() {
if($scope.status.counter>0)
$scope.status.counter--;
if($scope.status.counter==0) {
$scope.status = {
'active': false
}
}
}
$scope.unsetStatus = function() {
$scope.status = {
'active': false
}
}
// Create a new Stack // Create a new Stack
$scope.createStack = function () { $scope.createStack = function () {
@@ -75,6 +36,18 @@ app.controller('BoardController', function ($rootScope, $scope, $location, $http
}); });
}; };
$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 = "";
});
}
// Lighten Color of the board for background usage // Lighten Color of the board for background usage
$scope.rgblight = function (hex) { $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 result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex);
@@ -95,10 +68,23 @@ app.controller('BoardController', function ($rootScope, $scope, $location, $http
// settings for card sorting // settings for card sorting
$scope.sortOptions = { $scope.sortOptions = {
itemMoved: function (event) { itemMoved: function (event) {
// TODO: Implement reodering here
event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column; event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column;
console.log(event.dest.sortableScope.$parent); 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].cards = data;
});
}, },
orderChanged: function (event) { orderChanged: function (event) {
// TODO: Implement ordering here
var order = event.dest.index;
var card = event.source.itemScope.c;
CardService.reorder(card, order);
}, },
scrollableContainer: '#board', scrollableContainer: '#board',
containerPositioning: 'relative', containerPositioning: 'relative',

View File

@@ -1,16 +1,16 @@
app.controller('CardController', function ($scope, $rootScope, $routeParams, $location, $stateParams) { app.controller('CardController', function ($scope, $rootScope, $routeParams, $location, $stateParams, CardService) {
$scope.sidebar = $rootScope.sidebar; $scope.sidebar = $rootScope.sidebar;
$scope.location = $location; $scope.cardservice = CardService;
$scope.card = {'id': 1, 'title': 'We should implement all the useful things, that a kanban like project managemnt system needs for having success', 'description': 'Non et quibusdam officiis expedita excepturi. Tenetur ea et dignissimos qui. Rerum quis commodi aperiam amet dolorum suscipit asperiores. Enim dolorem ea nisi voluptate. \
Consequatur enim iste dolore autem est unde voluptatum. Aut sit et iure. Suscipit deserunt nisi repellat in officiis alias. Nihil beatae ea ut laudantium at.\
Doloribus nihil ipsa consequatur laudantium qui enim eveniet quo. Voluptatum tenetur sunt quis sint aliquam et molestias. Quae voluptatem tempora qui eaque qui esse possimus magni. Animi dolorem maiores iste.\
Totam ut tempora officiis ipsam dolorem modi. Dolores hic aut itaque. Earum in est voluptas voluptatum. Cumque pariatur qui omnis placeat. Eius sed sunt corrupti dolorem quo.'};
$scope.cardId = $stateParams.cardId; $scope.cardId = $stateParams.cardId;
console.log($stateParams); CardService.fetchOne($scope.cardId).then(function(data) {
console.log(data);
}, function(error) {
});

View File

@@ -1,70 +1,39 @@
app.controller('ListController', function ($scope, $location, boardFactory, BoardService) { app.controller('ListController', function ($scope, $location, BoardService) {
$scope.boards = null; $scope.boards = null;
$scope.newBoard = {}; $scope.newBoard = {};
$scope.status = {}; $scope.status = {};
$scope.colors = ['31CC7C', '317CCC', 'FF7A66', 'F1DB50', '7C31CC', 'CC317C', '3A3B3D', 'CACBCD']; $scope.colors = ['31CC7C', '317CCC', 'FF7A66', 'F1DB50', '7C31CC', 'CC317C', '3A3B3D', 'CACBCD'];
$scope.boardservice = BoardService; $scope.boardservice = BoardService;
BoardService.fetchAll().then(function(data) {
console.log($scope.boardservice);
console.log(data);
}, function(error) {
//$scope.setStatus('error','Error occured', error);
});
$scope.getBoards = function() { BoardService.fetchAll(); // TODO: show error when loading fails
boardFactory.getBoards()
.then(function (response) { $scope.selectColor = function(color) {
$scope.boards = response.data; $scope.newBoard.color = color;
for (var i = 0; i < $scope.boards.length; i++) { };
$scope.boards[i].status = {
'edit': false,
}
}
}, function (error) {
$scope.status.getBoards = 'Unable to load customer data: ' + error.message;
});
}
$scope.createBoard = function () { $scope.createBoard = function () {
boardFactory.createBoard($scope.newBoard) BoardService.create($scope.newBoard)
.then(function (response) { .then(function (response) {
$scope.boards.push(response.data);
$scope.newBoard = {}; $scope.newBoard = {};
$scope.status.addBoard=false; $scope.status.addBoard=false;
}, function(error) { }, function(error) {
$scope.status.createBoard = 'Unable to insert board: ' + error.message; $scope.status.createBoard = 'Unable to insert board: ' + error.message;
}); });
}; };
$scope.updateBoard = function(board) { $scope.updateBoard = function(board) {
boardFactory.updateBoard(board) BoardService.update(board);
.then(function (response) {
board = response.data;
}, function(error) {
$scope.status.createBoard = 'Unable to insert board: ' + error.message;
});
board.status.edit = false; board.status.edit = false;
$scope.$apply(); };
$scope.deleteBoard = function(board) {
// TODO: Ask for confirmation
//if (confirm('Are you sure you want to delete this?')) {
BoardService.delete(board.id);
//}
}; };
$scope.selectColor = function(color) {
$scope.newBoard.color = color;
};
$scope.deleteBoard = function (index) {
var board = $scope.boards[index];
boardFactory.deleteBoard(board.id)
.then(function (response) {
$scope.status.deleteBoard = 'Deleted Board';
$scope.boards.splice( index, 1 );
}, function(error) {
$scope.status.deleteBoard = 'Unable to insert board: ' + error.message;
});
};
$scope.getBoards();
}); });

View File

@@ -0,0 +1,24 @@
// OwnCloud Click Handling
// https://doc.owncloud.org/server/8.0/developer_manual/app/css.html
app.directive('appNavigationEntryUtils', function () {
'use strict';
return {
restrict: 'C',
link: function (scope, elm) {
var menu = elm.siblings('.app-navigation-entry-menu');
var button = $(elm)
.find('.app-navigation-entry-utils-menu-button button');
button.click(function () {
menu.toggleClass('open');
});
scope.$on('documentClicked', function (scope, event) {
if (event.target !== button[0]) {
menu.removeClass('open');
}
});
}
};
});

View File

@@ -0,0 +1,6 @@
app.directive('autofocusOnInsert', function () {
'use strict';
return function (scope, elm) {
elm.focus();
};
});

View File

@@ -1,10 +1,13 @@
var app = angular.module('Deck', ['ngRoute', 'ngSanitize', 'ui.router', 'as.sortable']); var app = angular.module('Deck', ['ngRoute', 'ngSanitize', 'ui.router', 'as.sortable']);
app.config(function ($provide, $routeProvider, $interpolateProvider, $httpProvider, $urlRouterProvider, $stateProvider) {
app.config(["$provide", "$routeProvider", "$interpolateProvider", "$httpProvider", "$urlRouterProvider", "$stateProvider", "$compileProvider", function ($provide, $routeProvider, $interpolateProvider, $httpProvider, $urlRouterProvider, $stateProvider, $compileProvider) {
'use strict'; 'use strict';
$httpProvider.defaults.headers.common.requesttoken = oc_requesttoken; $httpProvider.defaults.headers.common.requesttoken = oc_requesttoken;
$compileProvider.debugInfoEnabled(true);
$urlRouterProvider.otherwise("/"); $urlRouterProvider.otherwise("/");
$stateProvider $stateProvider
@@ -27,42 +30,14 @@ app.config(function ($provide, $routeProvider, $interpolateProvider, $httpProvid
} }
} }
}) })
.state('board.settings', {}) .state('board.settings', {
.state('board.sharing', {});
});
// OwnCloud Click Handling })
// https://doc.owncloud.org/server/8.0/developer_manual/app/css.html .state('board.sharing', {
app.directive('appNavigationEntryUtils', function () {
'use strict';
return {
restrict: 'C',
link: function (scope, elm) {
var menu = elm.siblings('.app-navigation-entry-menu'); });
var button = $(elm) }]);
.find('.app-navigation-entry-utils-menu-button button'); app.run(["$document", "$rootScope", "$transitions", function ($document, $rootScope, $transitions) {
button.click(function () {
menu.toggleClass('open');
});
scope.$on('documentClicked', function (scope, event) {
if (event.target !== button[0]) {
menu.removeClass('open');
}
});
}
};
});
app.directive('autofocusOnInsert', function () {
'use strict';
return function (scope, elm) {
elm.focus();
};
});
app.run(function ($document, $rootScope, $transitions) {
'use strict'; 'use strict';
$document.click(function (event) { $document.click(function (event) {
$rootScope.$broadcast('documentClicked', event); $rootScope.$broadcast('documentClicked', event);
@@ -76,83 +51,45 @@ app.run(function ($document, $rootScope, $transitions) {
$transitions.onExit({from: 'board.card'}, function ($state) { $transitions.onExit({from: 'board.card'}, function ($state) {
$rootScope.sidebar.show = false; $rootScope.sidebar.show = false;
}); });
}); }]);
app.controller('AppController', function ($scope, $location, $http, $route, $log, $rootScope, $stateParams) {
app.controller('AppController', ["$scope", "$location", "$http", "$route", "$log", "$rootScope", "$stateParams", function ($scope, $location, $http, $route, $log, $rootScope, $stateParams) {
$rootScope.sidebar = { $rootScope.sidebar = {
show: false show: false
}; };
$scope.sidebar = $rootScope.sidebar; $scope.sidebar = $rootScope.sidebar;
}); }]);
app.controller('BoardController', function ($rootScope, $scope, $location, $http, $route, $stateParams, BoardService, StackService) {
app.controller('BoardController', ["$rootScope", "$scope", "$stateParams", "StatusService", "BoardService", "StackService", "CardService", function ($rootScope, $scope, $stateParams, StatusService, BoardService, StackService, CardService) {
$scope.sidebar = $rootScope.sidebar; $scope.sidebar = $rootScope.sidebar;
$scope.id = $stateParams.boardId; $scope.id = $stateParams.boardId;
$scope.stackservice = StackService; $scope.stackservice = StackService;
$scope.boardservice = BoardService; $scope.boardservice = BoardService;
$scope.statusservice = StatusService;
// fetch data // fetch data
StackService.clear(); StackService.clear();
console.log("foo");
StackService.fetchAll($scope.id).then(function(data) { StackService.fetchAll($scope.id).then(function(data) {
console.log($scope.stackservice.data) $scope.statusservice.releaseWaiting();
$scope.releaseWaiting();
}, function(error) { }, function(error) {
$scope.setError('Error occured', error); $scope.statusservice.setError('Error occured', error);
}); });
BoardService.fetchOne($scope.id).then(function(data) { BoardService.fetchOne($scope.id).then(function(data) {
$scope.releaseWaiting(); $scope.statusservice.releaseWaiting();
}, function(error) { }, function(error) {
$scope.setError('Error occured', error); $scope.statusservice.setError('Error occured', error);
}); });
$scope.newStack = { 'boardId': $scope.id}; $scope.newStack = { 'boardId': $scope.id};
$scope.newCard = {}; $scope.newCard = {};
// Status Helper
$scope.status = {
'active': true,
'icon': 'loading',
'title': 'Bitte warten',
'text': 'Es dauert noch einen kleinen Moment',
'counter': 2,
};
$scope.setStatus = function($icon, $title, $text='') {
$scope.status.active = true;
$scope.status.icon = $icon;
$scope.status.title = $title;
$scope.status.text = $text;
}
$scope.setError = function($title, $text) {
$scope.status.active = true;
$scope.status.icon = 'error';
$scope.status.title = $title;
$scope.status.text = $text;
$scope.status.counter = 0;
}
$scope.releaseWaiting = function() {
if($scope.status.counter>0)
$scope.status.counter--;
if($scope.status.counter==0) {
$scope.status = {
'active': false
}
}
}
$scope.unsetStatus = function() {
$scope.status = {
'active': false
}
}
// Create a new Stack // Create a new Stack
$scope.createStack = function () { $scope.createStack = function () {
@@ -161,6 +98,18 @@ app.controller('BoardController', function ($rootScope, $scope, $location, $http
}); });
}; };
$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 = "";
});
}
// Lighten Color of the board for background usage // Lighten Color of the board for background usage
$scope.rgblight = function (hex) { $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 result = /^([A-Fa-f\d]{2})([A-Fa-f\d]{2})([A-Fa-f\d]{2})$/i.exec(hex);
@@ -181,10 +130,23 @@ app.controller('BoardController', function ($rootScope, $scope, $location, $http
// settings for card sorting // settings for card sorting
$scope.sortOptions = { $scope.sortOptions = {
itemMoved: function (event) { itemMoved: function (event) {
// TODO: Implement reodering here
event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column; event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column;
console.log(event.dest.sortableScope.$parent); 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].cards = data;
});
}, },
orderChanged: function (event) { orderChanged: function (event) {
// TODO: Implement ordering here
var order = event.dest.index;
var card = event.source.itemScope.c;
CardService.reorder(card, order);
}, },
scrollableContainer: '#board', scrollableContainer: '#board',
containerPositioning: 'relative', containerPositioning: 'relative',
@@ -210,21 +172,21 @@ app.controller('BoardController', function ($rootScope, $scope, $location, $http
} }
}; };
}); }]);
app.controller('CardController', function ($scope, $rootScope, $routeParams, $location, $stateParams) { app.controller('CardController', ["$scope", "$rootScope", "$routeParams", "$location", "$stateParams", "CardService", function ($scope, $rootScope, $routeParams, $location, $stateParams, CardService) {
$scope.sidebar = $rootScope.sidebar; $scope.sidebar = $rootScope.sidebar;
$scope.location = $location; $scope.cardservice = CardService;
$scope.card = {'id': 1, 'title': 'We should implement all the useful things, that a kanban like project managemnt system needs for having success', 'description': 'Non et quibusdam officiis expedita excepturi. Tenetur ea et dignissimos qui. Rerum quis commodi aperiam amet dolorum suscipit asperiores. Enim dolorem ea nisi voluptate. \
Consequatur enim iste dolore autem est unde voluptatum. Aut sit et iure. Suscipit deserunt nisi repellat in officiis alias. Nihil beatae ea ut laudantium at.\
Doloribus nihil ipsa consequatur laudantium qui enim eveniet quo. Voluptatum tenetur sunt quis sint aliquam et molestias. Quae voluptatem tempora qui eaque qui esse possimus magni. Animi dolorem maiores iste.\
Totam ut tempora officiis ipsam dolorem modi. Dolores hic aut itaque. Earum in est voluptas voluptatum. Cumque pariatur qui omnis placeat. Eius sed sunt corrupti dolorem quo.'};
$scope.cardId = $stateParams.cardId; $scope.cardId = $stateParams.cardId;
console.log($stateParams); CardService.fetchOne($scope.cardId).then(function(data) {
console.log(data);
}, function(error) {
});
@@ -234,81 +196,81 @@ app.controller('CardController', function ($scope, $rootScope, $routeParams, $lo
$scope.$apply(); $scope.$apply();
});*/ });*/
}); }]);
app.controller('ListController', function ($scope, $location, boardFactory, BoardService) { app.controller('ListController', ["$scope", "$location", "BoardService", function ($scope, $location, BoardService) {
$scope.boards = null; $scope.boards = null;
$scope.newBoard = {}; $scope.newBoard = {};
$scope.status = {}; $scope.status = {};
$scope.colors = ['31CC7C', '317CCC', 'FF7A66', 'F1DB50', '7C31CC', 'CC317C', '3A3B3D', 'CACBCD']; $scope.colors = ['31CC7C', '317CCC', 'FF7A66', 'F1DB50', '7C31CC', 'CC317C', '3A3B3D', 'CACBCD'];
$scope.boardservice = BoardService; $scope.boardservice = BoardService;
BoardService.fetchAll().then(function(data) {
console.log($scope.boardservice);
console.log(data);
}, function(error) {
//$scope.setStatus('error','Error occured', error);
});
$scope.getBoards = function() { BoardService.fetchAll(); // TODO: show error when loading fails
boardFactory.getBoards()
.then(function (response) { $scope.selectColor = function(color) {
$scope.boards = response.data; $scope.newBoard.color = color;
for (var i = 0; i < $scope.boards.length; i++) { };
$scope.boards[i].status = {
'edit': false,
}
}
}, function (error) {
$scope.status.getBoards = 'Unable to load customer data: ' + error.message;
});
}
$scope.createBoard = function () { $scope.createBoard = function () {
boardFactory.createBoard($scope.newBoard) BoardService.create($scope.newBoard)
.then(function (response) { .then(function (response) {
$scope.boards.push(response.data);
$scope.newBoard = {}; $scope.newBoard = {};
$scope.status.addBoard=false; $scope.status.addBoard=false;
}, function(error) { }, function(error) {
$scope.status.createBoard = 'Unable to insert board: ' + error.message; $scope.status.createBoard = 'Unable to insert board: ' + error.message;
}); });
}; };
$scope.updateBoard = function(board) { $scope.updateBoard = function(board) {
boardFactory.updateBoard(board) BoardService.update(board);
.then(function (response) {
board = response.data;
}, function(error) {
$scope.status.createBoard = 'Unable to insert board: ' + error.message;
});
board.status.edit = false; board.status.edit = false;
$scope.$apply(); };
$scope.deleteBoard = function(board) {
// TODO: Ask for confirmation
//if (confirm('Are you sure you want to delete this?')) {
BoardService.delete(board.id);
//}
}; };
$scope.selectColor = function(color) {
$scope.newBoard.color = color;
};
$scope.deleteBoard = function (index) {
var board = $scope.boards[index];
boardFactory.deleteBoard(board.id)
.then(function (response) {
$scope.status.deleteBoard = 'Deleted Board';
$scope.boards.splice( index, 1 );
}, function(error) {
$scope.status.deleteBoard = 'Unable to insert board: ' + error.message; }]);
// OwnCloud Click Handling
// https://doc.owncloud.org/server/8.0/developer_manual/app/css.html
app.directive('appNavigationEntryUtils', function () {
'use strict';
return {
restrict: 'C',
link: function (scope, elm) {
var menu = elm.siblings('.app-navigation-entry-menu');
var button = $(elm)
.find('.app-navigation-entry-utils-menu-button button');
button.click(function () {
menu.toggleClass('open');
}); });
scope.$on('documentClicked', function (scope, event) {
if (event.target !== button[0]) {
menu.removeClass('open');
}
});
}
}; };
$scope.getBoards();
}); });
app.factory('ApiService', function($http, $q){ app.directive('autofocusOnInsert', function () {
'use strict';
return function (scope, elm) {
elm.focus();
};
});
app.factory('ApiService', ["$http", "$q", function($http, $q){
var ApiService = function(http, endpoint) { var ApiService = function(http, endpoint) {
this.endpoint = endpoint; this.endpoint = endpoint;
this.baseUrl = OC.generateUrl('/apps/deck/' + endpoint); this.baseUrl = OC.generateUrl('/apps/deck/' + endpoint);
@@ -433,46 +395,37 @@ app.factory('ApiService', function($http, $q){
return ApiService; return ApiService;
}); }]);
app.factory('boardFactory', function($http){ app.factory('BoardService', ["ApiService", "$http", "$q", function(ApiService, $http, $q){
var service = {};
var baseUrl = OC.generateUrl('/apps/deck/boards');
service.getBoards = function(){
return $http.get(baseUrl);
}
service.getBoard = function (id) {
board = $http.get(baseUrl + '/' + id);
return board;
};
service.createBoard = function (board) {
return $http.post(baseUrl, board);
};
service.updateBoard = function (board) {
return $http.put(baseUrl, board)
};
service.deleteBoard = function (id) {
return $http.delete(baseUrl + '/' + id);
};
return service;
});
app.factory('BoardService', function(ApiService, $http, $q){
var BoardService = function($http, ep, $q) { var BoardService = function($http, ep, $q) {
ApiService.call(this, $http, ep, $q); ApiService.call(this, $http, ep, $q);
}; };
BoardService.prototype = angular.copy(ApiService.prototype); BoardService.prototype = angular.copy(ApiService.prototype);
service = new BoardService($http, 'boards', $q) service = new BoardService($http, 'boards', $q)
return service; return service;
}); }]);
app.factory('StackService', function(ApiService, $http, $q){ app.factory('CardService', ["ApiService", "$http", "$q", function(ApiService, $http, $q){
var CardService = function($http, ep, $q) {
ApiService.call(this, $http, ep, $q);
};
CardService.prototype = angular.copy(ApiService.prototype);
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) {
card.order = order;
deferred.resolve(response.data);
}, function (error) {
deferred.reject('Error while update ' + self.endpoint);
});
return deferred.promise;
}
service = new CardService($http, 'cards', $q)
return service;
}]);
app.factory('StackService', ["ApiService", "$http", "$q", function(ApiService, $http, $q){
var StackService = function($http, ep, $q) { var StackService = function($http, ep, $q) {
ApiService.call(this, $http, ep, $q); ApiService.call(this, $http, ep, $q);
}; };
@@ -489,8 +442,52 @@ app.factory('StackService', function(ApiService, $http, $q){
return deferred.promise; return deferred.promise;
} }
StackService.prototype.addCard = function(entity) {
console.log(this.data[entity.stackId]);
this.data[entity.stackId].cards.push(entity);
}
service = new StackService($http, 'stacks', $q) service = new StackService($http, 'stacks', $q)
return service; return service;
}]);
app.service('StatusService', function(){
// Status Helper
this.active = true;
this.icon = 'loading';
this.title = 'Please wait';
this.text = 'Es dauert noch einen kleinen Moment';
this.counter = 2;
this.setStatus = function($icon, $title, $text) {
this.active = true;
this.icon = $icon;
this.title = $title;
this.text = $text;
}
this.setError = function($title, $text) {
this.active = true;
this.icon = 'error';
this.title = $title;
this.text = $text;
this.counter = 0;
}
this.releaseWaiting = function() {
if(this.counter>0)
this.counter--;
if(this.counter<=0) {
this.active = false;
this.counter = 0;
}
}
this.unsetStatus = function() {
this.active = false;
}
}); });

View File

@@ -0,0 +1,8 @@
app.factory('BoardService', function(ApiService, $http, $q){
var BoardService = function($http, ep, $q) {
ApiService.call(this, $http, ep, $q);
};
BoardService.prototype = angular.copy(ApiService.prototype);
service = new BoardService($http, 'boards', $q)
return service;
});

20
js/service/CardService.js Normal file
View File

@@ -0,0 +1,20 @@
app.factory('CardService', function(ApiService, $http, $q){
var CardService = function($http, ep, $q) {
ApiService.call(this, $http, ep, $q);
};
CardService.prototype = angular.copy(ApiService.prototype);
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) {
card.order = order;
deferred.resolve(response.data);
}, function (error) {
deferred.reject('Error while update ' + self.endpoint);
});
return deferred.promise;
}
service = new CardService($http, 'cards', $q)
return service;
});

View File

@@ -15,6 +15,11 @@ app.factory('StackService', function(ApiService, $http, $q){
return deferred.promise; return deferred.promise;
} }
StackService.prototype.addCard = function(entity) {
console.log(this.data[entity.stackId]);
this.data[entity.stackId].cards.push(entity);
}
service = new StackService($http, 'stacks', $q) service = new StackService($http, 'stacks', $q)
return service; return service;
}); });

View File

@@ -0,0 +1,38 @@
app.service('StatusService', function(){
// Status Helper
this.active = true;
this.icon = 'loading';
this.title = 'Please wait';
this.text = 'Es dauert noch einen kleinen Moment';
this.counter = 2;
this.setStatus = function($icon, $title, $text) {
this.active = true;
this.icon = $icon;
this.title = $title;
this.text = $text;
}
this.setError = function($title, $text) {
this.active = true;
this.icon = 'error';
this.title = $title;
this.text = $text;
this.counter = 0;
}
this.releaseWaiting = function() {
if(this.counter>0)
this.counter--;
if(this.counter<=0) {
this.active = false;
this.counter = 0;
}
}
this.unsetStatus = function() {
this.active = false;
}
});

View File

@@ -1,37 +0,0 @@
app.factory('boardFactory', function($http){
var service = {};
var baseUrl = OC.generateUrl('/apps/deck/boards');
service.getBoards = function(){
return $http.get(baseUrl);
}
service.getBoard = function (id) {
board = $http.get(baseUrl + '/' + id);
return board;
};
service.createBoard = function (board) {
return $http.post(baseUrl, board);
};
service.updateBoard = function (board) {
return $http.put(baseUrl, board)
};
service.deleteBoard = function (id) {
return $http.delete(baseUrl + '/' + id);
};
return service;
});
app.factory('BoardService', function(ApiService, $http, $q){
var BoardService = function($http, ep, $q) {
ApiService.call(this, $http, ep, $q);
};
BoardService.prototype = angular.copy(ApiService.prototype);
service = new BoardService($http, 'boards', $q)
return service;
});

73
service/cardservice.php Normal file
View File

@@ -0,0 +1,73 @@
<?php
namespace OCA\Deck\Service;
use OCP\ILogger;
use OCP\IL10N;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Utility\ITimeFactory;
use \OCA\Deck\Db\Card;
use \OCA\Deck\Db\CardMapper;
class CardService {
private $cardMapper;
private $logger;
public function __construct(CardMapper $cardMapper) {
$this->cardMapper = $cardMapper;
}
public function find($userId, $cardId) {
return $this->cardMapper->find($cardId);
}
public function create($title, $stackId, $type, $order, $owner) {
$card = new Card();
$card->setTitle($title);
$card->setStackId($stackId);
$card->setType($type);
$card->setOrder($order);
$card->setOwner($owner);
return $this->cardMapper->insert($card);
}
public function delete($userId, $id) {
return $this->cardMapper->delete($this->cardMapper->find($id));
}
public function update($id, $title, $stackId, $type, $order, $owner) {
$card = $this->cardMapper->find($id);
$card->setTitle($title);
$card->setStackId($stackId);
$card->setType($type);
$card->setOrder($order);
$card->setOwner($owner);
return $this->cardMapper->update($card);
}
public function reorder($id, $stackId, $order) {
$cards = $this->cardMapper->findAll($stackId);
$i = 0;
foreach ($cards as $card) {
if($card->id == $id) {
$card->setOrder($order);
}
if($i == $order)
$i++;
if($card->id !== $id) {
$card->setOrder($i++);
}
$this->cardMapper->update($card);
}
// FIXME: return reordered cards without an additional db query
$cards = $this->cardMapper->findAll($stackId);
return $cards;
}
}

View File

@@ -2,6 +2,7 @@
namespace OCA\Deck\Service; namespace OCA\Deck\Service;
use OCA\Deck\Db\CardMapper;
use OCP\ILogger; use OCP\ILogger;
use OCP\IL10N; use OCP\IL10N;
use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\DoesNotExistException;
@@ -14,19 +15,25 @@ use \OCA\Deck\Db\StackMapper;
class StackService { class StackService {
private $stackMapper; private $stackMapper;
private $cardMapper;
private $logger; private $logger;
private $l10n; private $l10n;
private $timeFactory; private $timeFactory;
public function __construct(StackMapper $stackMapper, ILogger $logger, public function __construct(StackMapper $stackMapper, CardMapper $cardMapper,ILogger $logger,
IL10N $l10n, IL10N $l10n,
ITimeFactory $timeFactory) { ITimeFactory $timeFactory) {
$this->stackMapper = $stackMapper; $this->stackMapper = $stackMapper;
$this->cardMapper = $cardMapper;
$this->logger = $logger; $this->logger = $logger;
} }
public function findAll($boardId) { public function findAll($boardId) {
return $this->stackMapper->findAll($boardId); $stacks = $this->stackMapper->findAll($boardId);
foreach ($stacks as $idx => $s) {
$stacks[$idx]->setCards($this->cardMapper->findAll($s->id));
}
return $stacks;
} }
public function create($title, $boardId, $order) { public function create($title, $boardId, $order) {

View File

@@ -5,7 +5,7 @@ use OCP\Util;
Util::addStyle('deck', 'font-awesome'); Util::addStyle('deck', 'font-awesome');
Util::addStyle('deck', 'style'); Util::addStyle('deck', 'style');
Util::addStyle('deck', '../js/vendor/ng-sortable/dist/ng-sortable.min'); Util::addStyle('deck', '../js/vendor/ng-sortable/dist/ng-sortable.min');
Util::addStyle('deck', '../js/vendor/ng-sortable/dist/ng-sortable.style.min'); //Util::addStyle('deck', '../js/vendor/ng-sortable/dist/ng-sortable.style.min');
Util::addScript('deck', 'vendor/angular/angular.min'); Util::addScript('deck', 'vendor/angular/angular.min');
Util::addScript('deck', 'vendor/angular-route/angular-route.min'); Util::addScript('deck', 'vendor/angular-route/angular-route.min');
Util::addScript('deck', 'vendor/angular-sanitize/angular-sanitize.min'); Util::addScript('deck', 'vendor/angular-sanitize/angular-sanitize.min');

View File

@@ -1,11 +1,12 @@
<div id="board-status" ng-if="status.active"> <div id="board-status" ng-if="statusservice.active">
<div id="emptycontent"> <div id="emptycontent">
<div class="icon-{{ status.icon }}"></div> <div class="icon-{{ statusservice.icon }}"></div>
<h2>{{ status.title }}</h2> <h2>{{ statusservice.title }}</h2>
<p>{{ status.text }}</p></div> <p>{{ statusservice.text }}</p></div>
</div> </div>
<div id="board" class="scroll-container" style="background-color:{{rgblight(boardservice.getCurrent().color)}};"> <div id="board" class="scroll-container" >
<h1 style="background-color:#{{ boardservice.getCurrent().color }};">{{ boardservice.data[id].title }} <h1 style="border-bottom: 1px solid {{rgblight(boardservice.getCurrent().color)}};">
{{ boardservice.data[id].title }}
</h1> </h1>
<?php /* maybe later <?php /* maybe later
<div class="board-actions"> <div class="board-actions">
@@ -15,7 +16,7 @@
</div> */ ?> </div> */ ?>
<div id="innerBoard" data-ng-model="stacks"> <div id="innerBoard" data-ng-model="stacks">
<div class="stack" ng-repeat="s in stackservice.data" data-columnindex="{{$index}}" id="column{{$index}}" data-ng-model="stackservice.data"> <div class="stack" ng-repeat="s in stackservice.data" data-columnindex="{{$index}}" id="column{{$index}}" data-ng-model="stackservice.data" style="border: 3px solid #{{ boardservice.getCurrent().color }};">
<h2><span ng-show="!s.status.editStack">{{ s.title }}</span> <h2><span ng-show="!s.status.editStack">{{ s.title }}</span>
<form ng-submit="stackservice.update(s)"> <form ng-submit="stackservice.update(s)">
<input type="text" placeholder="Add a new stack" ng-blur="s.status.editStack=false" ng-model="s.title" ng-if="s.status.editStack" autofocus-on-insert/> <input type="text" placeholder="Add a new stack" ng-blur="s.status.editStack=false" ng-model="s.title" ng-if="s.status.editStack" autofocus-on-insert/>
@@ -29,25 +30,24 @@
<ul data-as-sortable="sortOptions" data-ng-model="s.cards" style="min-height: 40px;"> <ul data-as-sortable="sortOptions" data-ng-model="s.cards" style="min-height: 40px;">
<li class="card as-sortable-item" ng-repeat="c in s.cards" data-as-sortable-item> <li class="card as-sortable-item" ng-repeat="c in s.cards" data-as-sortable-item>
<a href="#/board/{{ id }}/card/{{ c.id }}" data-as-sortable-item-handle> <a href="#/board/{{ id }}/card/{{ c.id }}" data-as-sortable-item-handle>
<h3><i class="fa fa-github"></i> {{ c.title }}</h3> <h3><!--<i class="fa fa-github"></i>//--> {{ c.title }}</h3>
<!--
<span class="info due"><i class="fa fa-clock-o" aria-hidden="true"></i> <span>Today</span></span> <span class="info due"><i class="fa fa-clock-o" aria-hidden="true"></i> <span>Today</span></span>
<span class="info tasks"><i class="fa fa-list" aria-hidden="true"></i> <span>3/12</span></span> <span class="info tasks"><i class="fa fa-list" aria-hidden="true"></i> <span>3/12</span></span>
<span class="info members"><i class="fa fa-users" aria-hidden="true"></i> <span>4</span></span> <span class="info members"><i class="fa fa-users" aria-hidden="true"></i> <span>4</span></span>
//-->
<button class="icon-more"></button> <button class="icon-more"></button>
<ul class="labels">
<li style="color:#a00; border-color:#aa0000;">important</li>
<li style="color:#0a0; border-color:#00aa00;">action-needed</li>
<li style="color:#00a; border-color:#00a;">action-needed</li>
<li style="color:#ac8ac8; border-color:#ac8ac8;">action-needed</li>
</ul>
</a> </a>
</li> </li>
</ul> </ul>
<div class="card create" ng-click="s.status.addCard=!s.status.addCard"> <!-- CREATE CARD //-->
<h3 ng-if="s.status.addCard" ><input type="text" autofocus-on-insert/></h3> <div class="card create" style="background-color:#{{ boardservice.getCurrent().color }};">
<i class="fa fa-plus" ></i> <form ng-submit="createCard(s.id, newCard.title)">
<h3 ng-if="s.status.addCard" ><input type="text" autofocus-on-insert ng-model="newCard.title" ng-blur="s.status.addCard=false"/></h3>
</form>
<div class="fa fa-plus" ng-if="!s.status.addCard" ng-click="s.status.addCard=!s.status.addCard"></div>
</div> </div>
</div> </div>
<div class="stack" style="display: inline-block;"> <div class="stack" style="display: inline-block;">

View File

@@ -10,7 +10,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr data-ng-repeat="b in boards" ui-sref="board({boardId: b.id})"> <tr data-ng-repeat="b in boardservice.data" ui-sref="board({boardId: b.id})">
<td> <td>
<span class="board-bullet" style="background-color:#{{b.color}};"> </span> <span class="board-bullet" style="background-color:#{{b.color}};"> </span>
</td> </td>

View File

@@ -1,6 +1,8 @@
<div id="card-header"> <div id="card-header">
<h2>{{ cardId }} {{ card.title }}<a class="icon-close" ng-click="sidebar.show=!sidebar.show"> &nbsp;</a></h2> <h2>{{ cardservice.getCurrent().title }}<a class="icon-close" ng-click="sidebar.show=!sidebar.show"> &nbsp;</a></h2>
Modified: {{ cardservice.getCurrent().modifiedAt }}
Created: {{ cardservice.getCurrent().createdAt }}
<ul class="labels"> <ul class="labels">
<li style="color:#a00; border-color:#aa0000;">important</li> <li style="color:#a00; border-color:#aa0000;">important</li>
<li style="color:#0a0; border-color:#00aa00;">action-needed</li> <li style="color:#0a0; border-color:#00aa00;">action-needed</li>

View File

@@ -1,8 +1,12 @@
<ul class="with-icon"> <ul class="with-icon">
<li><a href="#" class="">All Boards</a></li> <li><a href="#" class="">All Boards</a></li>
<!--<li><a href="#" class="icon-starred">Starred Boards</a></li> <!--
<li><a href="#" class="icon-starred">Starred Boards</a></li>
<li><a href="#" class="icon-share">Shared Boards</a></li> <li><a href="#" class="icon-share">Shared Boards</a></li>
<li><a href="#" class="icon-public">Public Boards</a></li> //--> <li><a href="#" class="icon-public">Public Boards</a></li>
//-->
<li class="with-menu" data-ng-repeat="b in boardservice.data"> <li class="with-menu" data-ng-repeat="b in boardservice.data">
<span class="board-bullet" style="background-color:#{{b.color}};" ng-if="!b.status.edit"> </span> <span class="board-bullet" style="background-color:#{{b.color}};" ng-if="!b.status.edit"> </span>
<a href="#/board/{{b.id}}" ng-if="!b.status.edit">{{ b.title }}</a> <a href="#/board/{{b.id}}" ng-if="!b.status.edit">{{ b.title }}</a>
@@ -15,7 +19,7 @@
<ul> <ul>
<li><button class="icon-share svg" title="share"></button></li> <li><button class="icon-share svg" title="share"></button></li>
<li><button class="icon-rename svg" title="rename" ng-click="b.status.edit=true"></button></li> <li><button class="icon-rename svg" title="rename" ng-click="b.status.edit=true"></button></li>
<li><button class="icon-delete svg" title="delete" ng-click="deleteBoard($index)"></button></li> <li><button class="icon-delete svg" title="delete" ng-click="deleteBoard(b)"></button></li>
</ul> </ul>
</div> </div>
<div class="app-navigation-entry-deleted" ng-show="false"> <div class="app-navigation-entry-deleted" ng-show="false">
@@ -24,7 +28,7 @@
</div> </div>
<div class="app-navigation-entry-edit" ng-show="b.status.edit"> <div class="app-navigation-entry-edit" ng-show="b.status.edit">
<form ng-disabled="isAddingList" class="ng-pristine ng-valid" ng-submit="boardservice.update(b)"> <form ng-disabled="isAddingList" class="ng-pristine ng-valid" ng-submit="updateBoard(b)">
<input id="newTitle" class="edit ng-valid ng-empty" type="text" autofocus-on-insert ng-model="b.title"> <input id="newTitle" class="edit ng-valid ng-empty" type="text" autofocus-on-insert ng-model="b.title">
<input type="submit" value="" class="action icon-checkmark svg"> <input type="submit" value="" class="action icon-checkmark svg">
<div class="colorselect"> <div class="colorselect">
@@ -34,7 +38,6 @@
</div> </div>
</li> </li>
<!-- Add new Board //--> <!-- Add new Board //-->
<li> <li>
<a ng-click="status.addBoard=!status.addBoard" ng-show="!status.addBoard" class="icon-add"> <a ng-click="status.addBoard=!status.addBoard" ng-show="!status.addBoard" class="icon-add">