Some more stuff

This commit is contained in:
Julius Haertl
2016-06-05 23:39:15 +02:00
parent e10fe82afb
commit ae9d5da329
18 changed files with 1027 additions and 185 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
js/node_modules/*
js/vendor/

View File

@@ -41,13 +41,13 @@ class StackController extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
*/ */
public function update($id, $title, $color) { public function update($id, $title, $boardId, $order) {
return $this->stackService->update($id, $title, $this->userId, $color); return $this->stackService->update($id, $title, $boardId, $order);
} }
/** /**
* @NoAdminRequired * @NoAdminRequired
*/ */
public function delete($boardId) { public function delete($stackId) {
return $this->stackService->delete($this->userId, $boardId); return $this->stackService->delete($this->userId, $stackId);
} }
} }

View File

@@ -84,6 +84,7 @@ li:hover .app-navigation-entry-utils-counter {
margin: 0; margin: 0;
font-size:12pt; font-size:12pt;
font-weight:700; font-weight:700;
overflow:hidden;
} }
.stack h2 input { .stack h2 input {
padding: 0px; padding: 0px;
@@ -94,16 +95,22 @@ li:hover .app-navigation-entry-utils-counter {
font-weight:700; font-weight:700;
border: 0; border: 0;
background-color: transparent; background-color: transparent;
float:left;
} }
.stack h2 button, .stack h2 button,
.stack .stack-actions{ .stack .stack-actions{
float:right; float:right;
} }
.stack h2 span {
float: left;
margin-bottom:3px;
}
.stack h2 .stack-actions { .stack h2 .stack-actions {
display: none; display: none;
} }
.stack h2:hover .stack-actions { .stack h2:hover .stack-actions {
display: block; display: inline-block;
float:right;
} }
.card { .card {
background-color:#fff; background-color:#fff;

49
js/.jshintrc Normal file
View File

@@ -0,0 +1,49 @@
{
"globals": {
"jasmine" : false,
"spyOn" : false,
"it" : false,
"describe" : false,
"expect" : false,
"beforeEach" : false,
"waits" : false,
"waitsFor" : false,
"runs" : false,
"require" : false,
"module": true
},
"asi" : true,
"boss" : true,
"browser" : true,
"curly" : true,
"debug" : true,
"devel" : true,
"eqeqeq" : true,
"eqnull" : false,
"es5" : true,
"evil" : false,
"forin" : true,
"immed" : true,
"indent" : 4,
"jquery" : true,
"latedef" : true,
"laxbreak" : false,
"newcap" : true,
"noarg" : true,
"node" : false,
"noempty" : false,
"nomen" : false,
"nonew" : true,
"onevar" : true,
"plusplus" : false,
"quotmark" : "single",
"regexp" : false,
"strict" : true,
"sub" : true,
"trailing" : true,
"undef" : true,
"unused" : true,
"white" : false,
"scripturl" : true
}

130
js/Gruntfile.js Normal file
View File

@@ -0,0 +1,130 @@
/**
* ownCloud - Calendar App
*
* @author Raghu Nayyar
* @copyright 2014 Raghu Nayyar <beingminimal@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
module.exports = function(grunt) {
'use strict';
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-wrap');
grunt.loadNpmTasks('grunt-ng-annotate');
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-phpunit');
grunt.initConfig({
meta: {
pkg: grunt.file.readJSON('package.json'),
version: '<%= meta.pkg.version %>',
configJS: 'config/',
buildJS: [
'app/**/*.js',
'controller/**/*.js',
'directive/**/*.js',
'service/**/*.js'
],
productionJS: 'public/',
testsJS: '../tests/js/'
},
concat: {
options: {
stripBanners: true
},
dist: {
src: ['<%= meta.buildJS %>'],
dest: '<%= meta.productionJS %>app.js'
}
},
wrap: {
app: {
src: ['<%= meta.productionJS %>app.js'],
dest: '<%= meta.productionJS %>app.js',
option: {
wrapper: [
'(function(angular, $, oc_requesttoken, undefined){\n\n\'use strict\';\n\n',
'\n})(angular, jQuery, oc_requesttoken);'
]
}
}
},
jshint: {
files: [
'Gruntfile.js',
'<%= meta.buildJS %>**/*.js',
'<%= meta.testsJS %>**/*.js'
],
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
}
},
watch: {
concat: {
files: ['<%=meta.buildJS%>'],
options: {
livereload: true
},
tasks: ['build']
}
},
phpunit: {
classes: {
dir: '../tests/unit'
},
options: {
bootstrap: '../tests/bootstrap.php',
colors: true
}
},
karma: {
unit: {
configFile: '<%= meta.testsJS %>config/karma.js'
},
continuous: {
configFile: '<%= meta.testsJS %>config/karma.js',
browsers: ['Firefox'],
singleRun: true,
reporters: ['progress']
}
},
ngAnnotate: {
app: {
src: ['<%= meta.productionJS %>app.js'],
dest: '<%= meta.productionJS %>app.js'
}
}
});
// make tasks available under simpler commands
grunt.registerTask('build', ['jshint', 'concat', 'wrap', 'ngAnnotate']);
grunt.registerTask('js-unit', ['karma:continuous']);
};

6
js/Makefile Normal file
View File

@@ -0,0 +1,6 @@
default:
grunt build
watch:
grunt watch

View File

@@ -1,16 +1,40 @@
app.controller('BoardController', function ($rootScope, $scope, $location, $http, $route, $stateParams, boardFactory, stackFactory, StackService) { app.controller('BoardController', function ($rootScope, $scope, $location, $http, $route, $stateParams, BoardService, StackService) {
$scope.sidebar = $rootScope.sidebar; $scope.sidebar = $rootScope.sidebar;
$scope.newCard = {};
$scope.stackservice = StackService;
$scope.id = $stateParams.boardId; $scope.id = $stateParams.boardId;
$scope.stackservice = StackService;
$scope.boardservice = BoardService;
// fetch data
StackService.clear();
StackService.fetchAll($scope.id).then(function(data) {
console.log($scope.stackservice.data)
$scope.releaseWaiting();
}, function(error) {
$scope.setError('Error occured', error);
});
BoardService.fetchOne($scope.id).then(function(data) {
$scope.releaseWaiting();
}, function(error) {
$scope.setError('Error occured', error);
});
$scope.newStack = { 'boardId': $scope.id};
$scope.newCard = {};
// Status Helper
$scope.status = { $scope.status = {
'active': true, 'active': true,
'icon': 'loading', 'icon': 'loading',
'title': 'Bitte warten', 'title': 'Bitte warten',
'text': 'Es dauert noch einen kleinen Moment' 'text': 'Es dauert noch einen kleinen Moment',
'counter': 2,
}; };
$scope.setStatus = function($icon, $title, $text='') { $scope.setStatus = function($icon, $title, $text='') {
@@ -20,45 +44,38 @@ app.controller('BoardController', function ($rootScope, $scope, $location, $http
$scope.status.text = $text; $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.unsetStatus = function() {
$scope.status = { $scope.status = {
'active': false 'active': false
} }
} }
$scope.getBoard = function() { // Create a new Stack
boardFactory.getBoard($scope.id)
.then(function (response) {
$scope.board = response.data;
$scope.unsetStatus();
}, function (error) {
$scope.setStatus('error','Unable to load board data', error);
});
}
$scope.getStacks = function() {
stackFactory.getStacks($scope.id)
.then(function (response) {
$scope.stacks = response.data;
$scope.unsetStatus();
}, function (error) {
$scope.setStatus('error','Unable to load board data', error);
});
}
$scope.createStack = function () { $scope.createStack = function () {
$scope.newStack.boardId = $scope.id; StackService.create($scope.newStack).then(function (data) {
stackFactory.createStack($scope.newStack) $scope.newStack.title="";
.then(function (response) {
$scope.stacks.push(response.data);
$scope.newStack = {};
$scope.status.addStack=false;
}, function(error) {
$scope.status.createBoard = 'Unable to insert board: ' + error.message;
}); });
}; };
// 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);
var color = result ? { var color = result ? {
@@ -107,40 +124,4 @@ app.controller('BoardController', function ($rootScope, $scope, $location, $http
} }
}; };
$scope.sortStackOptions = {
itemMoved: function (event) {
event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column;
console.log(event.dest.sortableScope.$parent);
},
orderChanged: function (event) {
},
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);
}
}
}
};
$scope.getBoard();
$scope.getStacks();
}); });

View File

@@ -1,10 +1,17 @@
app.controller('ListController', function ($scope, $location, boardFactory, StackService) { app.controller('ListController', function ($scope, $location, boardFactory, 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.stackservice = StackService;
$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() { $scope.getBoards = function() {
boardFactory.getBoards() boardFactory.getBoards()

88
js/gulpfile.js Normal file
View File

@@ -0,0 +1,88 @@
/**
* ownCloud - News
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @copyright Bernhard Posselt 2012, 2014
*/
/*jslint node: true */
'use strict';
const gulp = require('gulp'),
ngAnnotate = require('gulp-ng-annotate'),
uglify = require('gulp-uglify'),
jshint = require('gulp-jshint'),
KarmaServer = require('karma').Server,
phpunit = require('gulp-phpunit'),
concat = require('gulp-concat'),
sourcemaps = require('gulp-sourcemaps');
// Configuration
const buildTarget = 'app.min.js';
const phpunitConfig = __dirname + '/../phpunit.xml';
const karmaConfig = __dirname + '/karma.conf.js';
const destinationFolder = __dirname + '/build/';
const sources = [
'app/App.js', 'app/Config.js', 'app/Run.js',
'controller/**/*.js',
'filter/**/*.js',
'service/**/*.js',
'gui/**/*.js',
'plugin/**/*.js',
'utility/**/*.js',
'directive/**/*.js'
];
const testSources = ['tests/**/*.js'];
const phpSources = ['../**/*.php', '!../js/**', '!../vendor/**'];
const watchSources = sources.concat(testSources).concat(['*.js']);
const lintSources = watchSources;
// tasks
gulp.task('default', ['lint'], () => {
return gulp.src(sources)
.pipe(ngAnnotate())
.pipe(sourcemaps.init())
.pipe(concat(buildTarget))
.pipe(uglify())
.pipe(sourcemaps.write())
.pipe(gulp.dest(destinationFolder));
});
gulp.task('lint', () => {
return gulp.src(lintSources)
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(jshint.reporter('fail'));
});
gulp.task('watch', () => {
gulp.watch(watchSources, ['default']);
});
gulp.task('karma', (done) => {
new KarmaServer({
configFile: karmaConfig,
singleRun: true
}, done).start();
});
gulp.task('watch-karma', (done) => {
new KarmaServer({
configFile: karmaConfig,
autoWatch: true
}, done).start();
});
gulp.task('phpunit', () => {
return gulp.src(phpSources)
.pipe(phpunit('phpunit', {
configurationFile: phpunitConfig
}));
});
gulp.task('watch-phpunit', () => {
gulp.watch(phpSources, ['phpunit']);
});

34
js/package.json Normal file
View File

@@ -0,0 +1,34 @@
{
"name": "deck",
"description": "Deck owncloud app",
"version": "0.1.0",
"private": true,
"homepage": "https://github.com/juliushaertl/deck",
"repository": {
"type": "git",
"url": "git@github.com:juliushaertl/deck.git"
},
"dependencies": {},
"devDependencies": {
"bower": "*",
"grunt": "*",
"grunt-cli": "*",
"grunt-contrib-concat": "*",
"grunt-contrib-jshint": "*",
"grunt-contrib-watch": "*",
"grunt-karma": "*",
"grunt-ng-annotate": "^1.0.1",
"grunt-phpunit": "*",
"grunt-wrap": "*",
"jasmine-core": "*",
"jshint-stylish": "^2.1.0",
"karma": "*",
"karma-chrome-launcher": "*",
"karma-coverage": "*",
"karma-firefox-launcher": "*",
"karma-jasmine": "*",
"karma-phantomjs-launcher": "*",
"phantomjs": "*"
},
"engine": "node >= 0.8"
}

496
js/public/app.js Normal file
View File

@@ -0,0 +1,496 @@
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;
});
});
app.controller('AppController', function ($scope, $location, $http, $route, $log, $rootScope, $stateParams) {
$rootScope.sidebar = {
show: false
};
$scope.sidebar = $rootScope.sidebar;
});
app.controller('BoardController', function ($rootScope, $scope, $location, $http, $route, $stateParams, BoardService, StackService) {
$scope.sidebar = $rootScope.sidebar;
$scope.id = $stateParams.boardId;
$scope.stackservice = StackService;
$scope.boardservice = BoardService;
// fetch data
StackService.clear();
StackService.fetchAll($scope.id).then(function(data) {
console.log($scope.stackservice.data)
$scope.releaseWaiting();
}, function(error) {
$scope.setError('Error occured', error);
});
BoardService.fetchOne($scope.id).then(function(data) {
$scope.releaseWaiting();
}, function(error) {
$scope.setError('Error occured', error);
});
$scope.newStack = { 'boardId': $scope.id};
$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
$scope.createStack = function () {
StackService.create($scope.newStack).then(function (data) {
$scope.newStack.title="";
});
};
// 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;
}
};
// settings for card sorting
$scope.sortOptions = {
itemMoved: function (event) {
event.source.itemScope.modelValue.status = event.dest.sortableScope.$parent.column;
console.log(event.dest.sortableScope.$parent);
},
orderChanged: function (event) {
},
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('CardController', function ($scope, $rootScope, $routeParams, $location, $stateParams) {
$scope.sidebar = $rootScope.sidebar;
$scope.location = $location;
$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;
console.log($stateParams);
/*var menu = $('#app-content');
menu.click(function(event){
$scope.location.path('/board/'+$scope.boardId);
$scope.$apply();
});*/
});
app.controller('ListController', function ($scope, $location, boardFactory, BoardService) {
$scope.boards = null;
$scope.newBoard = {};
$scope.status = {};
$scope.colors = ['31CC7C', '317CCC', 'FF7A66', 'F1DB50', '7C31CC', 'CC317C', '3A3B3D', 'CACBCD'];
$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() {
boardFactory.getBoards()
.then(function (response) {
$scope.boards = response.data;
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 () {
boardFactory.createBoard($scope.newBoard)
.then(function (response) {
$scope.boards.push(response.data);
$scope.newBoard = {};
$scope.status.addBoard=false;
}, function(error) {
$scope.status.createBoard = 'Unable to insert board: ' + error.message;
});
};
$scope.updateBoard = function(board) {
boardFactory.updateBoard(board)
.then(function (response) {
board = response.data;
}, function(error) {
$scope.status.createBoard = 'Unable to insert board: ' + error.message;
});
board.status.edit = false;
$scope.$apply();
};
$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();
});
app.factory('ApiService', function($http, $q){
var ApiService = function(http, endpoint) {
this.endpoint = endpoint;
this.baseUrl = OC.generateUrl('/apps/deck/' + endpoint);
this.http = http;
this.q = $q;
this.data = {};
this.id = null;
};
// TODO: Unify error messages
ApiService.prototype.fetchAll = function(){
var deferred = $q.defer();
var self = this;
$http.get(this.baseUrl).then(function (response) {
var objects = response.data;
objects.forEach(function (obj) {
self.data[obj.id] = obj;
});
deferred.resolve(self.data);
}, function (error) {
deferred.reject('Error while ' + self.getName() + '.fetchAll() ');
});
return deferred.promise;
}
ApiService.prototype.fetchOne = function (id) {
this.id = id;
var deferred = $q.defer();
var self = this;
$http.get(this.baseUrl + '/' + id).then(function (response) {
data = response.data;
self.data[data.id] = response.data;
deferred.resolve(response.data);
}, function (error) {
deferred.reject('Error in ' + self.endpoint + ' fetchAll() ');
});
return deferred.promise;
};
ApiService.prototype.create = function (entity) {
var deferred = $q.defer();
var self = this;
$http.post(this.baseUrl, entity).then(function (response) {
self.add(response.data);
deferred.resolve(response.data);
}, function (error) {
deferred.reject('Error in ' + self.endpoint + ' create() ');
});
return deferred.promise;
};
ApiService.prototype.update = function (entity) {
var deferred = $q.defer();
var self = this;
$http.put(this.baseUrl, entity).then(function (response) {
self.add(response.data);
deferred.resolve(response.data);
}, function (error) {
deferred.reject('Error while update ' + self.endpoint);
});
return deferred.promise;
};
ApiService.prototype.delete = function (id) {
var deferred = $q.defer();
var self = this;
$http.delete(this.baseUrl + '/' + id).then(function (response) {
self.remove(id);
deferred.resolve(response.data);
}, function (error) {
deferred.reject('Error while delete ' + self.endpoint);
});
return deferred.promise;
};
// methods for managing data
ApiService.prototype.clear = function() {
this.data = {};
}
ApiService.prototype.add = function (entity) {
var element = this.data[entity.id];
if(element===undefined) {
this.data[entity.id] = entity;
} else {
Object.keys(entity).forEach(function (key) {
element[key] = entity[key];
element[key].status = {};
});
}
};
ApiService.prototype.remove = function(id) {
if (this.data[id] !== undefined) {
delete this.data[id];
}
};
ApiService.prototype.addAll = function (entities) {
var self = this;
angular.forEach(entities, function(entity) {
self.add(entity);
});
};
ApiService.prototype.getCurrent = function () {
return this.data[this.id];
}
ApiService.prototype.getAll = function () {
return this.data;
}
ApiService.prototype.getName = function() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((this).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
};
return ApiService;
});
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;
});
app.factory('StackService', function(ApiService, $http, $q){
var StackService = function($http, ep, $q) {
ApiService.call(this, $http, ep, $q);
};
StackService.prototype = angular.copy(ApiService.prototype);
StackService.prototype.fetchAll = function(boardId) {
var deferred = $q.defer();
var self=this;
$http.get(this.baseUrl +'/'+boardId).then(function (response) {
self.addAll(response.data);
deferred.resolve(self.data);
}, function (error) {
deferred.reject('Error while loading stacks');
});
return deferred.promise;
}
service = new StackService($http, 'stacks', $q)
return service;
});

View File

@@ -1,31 +1,126 @@
app.factory('ApiService', function($http){ app.factory('ApiService', function($http, $q){
var ApiService = function(http, BASEURL,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);
this.http = http; this.http = http;
this.hashMap = {}; this.q = $q;
this.values = []; this.data = {};
this.id = null;
}; };
ApiService.prototype.getAll = function(){ // TODO: Unify error messages
return $http.get(baseUrl); ApiService.prototype.fetchAll = function(){
var deferred = $q.defer();
var self = this;
$http.get(this.baseUrl).then(function (response) {
var objects = response.data;
objects.forEach(function (obj) {
self.data[obj.id] = obj;
});
deferred.resolve(self.data);
}, function (error) {
deferred.reject('Error while ' + self.getName() + '.fetchAll() ');
});
return deferred.promise;
} }
ApiService.prototype.getOne = function (id) { ApiService.prototype.fetchOne = function (id) {
return $http.get(baseUrl + '/' + id); this.id = id;
var deferred = $q.defer();
var self = this;
$http.get(this.baseUrl + '/' + id).then(function (response) {
data = response.data;
self.data[data.id] = response.data;
deferred.resolve(response.data);
}, function (error) {
deferred.reject('Error in ' + self.endpoint + ' fetchAll() ');
});
return deferred.promise;
}; };
ApiService.prototype.create = function (entity) { ApiService.prototype.create = function (entity) {
return $http.post(baseUrl, entity); var deferred = $q.defer();
var self = this;
$http.post(this.baseUrl, entity).then(function (response) {
self.add(response.data);
deferred.resolve(response.data);
}, function (error) {
deferred.reject('Error in ' + self.endpoint + ' create() ');
});
return deferred.promise;
}; };
ApiService.prototype.update = function (entity) { ApiService.prototype.update = function (entity) {
return $http.put(baseUrl, entity) var deferred = $q.defer();
var self = this;
$http.put(this.baseUrl, entity).then(function (response) {
self.add(response.data);
deferred.resolve(response.data);
}, function (error) {
deferred.reject('Error while update ' + self.endpoint);
});
return deferred.promise;
}; };
ApiService.prototype.delete = function (id) { ApiService.prototype.delete = function (id) {
return $http.delete(baseUrl + '/' + id); var deferred = $q.defer();
var self = this;
$http.delete(this.baseUrl + '/' + id).then(function (response) {
self.remove(id);
deferred.resolve(response.data);
}, function (error) {
deferred.reject('Error while delete ' + self.endpoint);
});
return deferred.promise;
};
// methods for managing data
ApiService.prototype.clear = function() {
this.data = {};
}
ApiService.prototype.add = function (entity) {
var element = this.data[entity.id];
if(element===undefined) {
this.data[entity.id] = entity;
} else {
Object.keys(entity).forEach(function (key) {
element[key] = entity[key];
element[key].status = {};
});
}
};
ApiService.prototype.remove = function(id) {
if (this.data[id] !== undefined) {
delete this.data[id];
}
};
ApiService.prototype.addAll = function (entities) {
var self = this;
angular.forEach(entities, function(entity) {
self.add(entity);
});
};
ApiService.prototype.getCurrent = function () {
return this.data[this.id];
}
ApiService.prototype.getAll = function () {
return this.data;
}
ApiService.prototype.getName = function() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((this).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
}; };
return ApiService; return ApiService;
}); });

View File

@@ -1,4 +1,4 @@
app.factory('boardFactory', function($http, stackFactory){ app.factory('boardFactory', function($http){
var service = {}; var service = {};
var baseUrl = OC.generateUrl('/apps/deck/boards'); var baseUrl = OC.generateUrl('/apps/deck/boards');
@@ -12,6 +12,7 @@ app.factory('boardFactory', function($http, stackFactory){
}; };
service.createBoard = function (board) { service.createBoard = function (board) {
return $http.post(baseUrl, board); return $http.post(baseUrl, board);
}; };
@@ -25,3 +26,12 @@ app.factory('boardFactory', function($http, stackFactory){
return service; 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;
});

View File

@@ -1,78 +1,21 @@
app.factory('ApiService', function($http){ app.factory('StackService', function(ApiService, $http, $q){
var ApiService = function(http, endpoint) { var StackService = function($http, ep, $q) {
this.endpoint = endpoint; ApiService.call(this, $http, ep, $q);
this.baseUrl = OC.generateUrl('/apps/deck/' + endpoint);
this.http = http;
this.hashMap = {};
this.values = [];
this.once = null;
}; };
StackService.prototype = angular.copy(ApiService.prototype);
ApiService.prototype.getAll = function(){ StackService.prototype.fetchAll = function(boardId) {
return $http.get(this.baseUrl); var deferred = $q.defer();
} var self=this;
$http.get(this.baseUrl +'/'+boardId).then(function (response) {
ApiService.prototype.getOne = function (id) { self.addAll(response.data);
self = this; deferred.resolve(self.data);
$http.get(this.baseUrl + '/' + id).then(function (response) {
self.once = response.data;
return response.data;
}, function (error) { }, function (error) {
deferred.reject('Error while loading stacks');
}); });
return this.once; return deferred.promise;
};
ApiService.prototype.create = function (entity) {
return $http.post(this.baseUrl, entity);
};
ApiService.prototype.update = function (entity) {
return $http.put(this.baseUrl, entity)
};
ApiService.prototype.delete = function (id) {
return $http.delete(this.baseUrl + '/' + id);
};
return ApiService;
});
app.factory('stackFactory', function($http){
var service = {};
var baseUrl = OC.generateUrl('/apps/deck/stacks');
service.getStacks = function(boardId){
return $http.get(baseUrl + '/' + boardId);
} }
service = new StackService($http, 'stacks', $q)
service.getStack = function (id) {
return $http.get(baseUrl + '/' + id);
};
service.createStack = function (stack) {
return $http.post(baseUrl, stack);
};
service.updateStack = function (stack) {
return $http.put(baseUrl, stack)
};
service.deleteStack = function (id) {
return $http.delete(baseUrl + '/' + id);
};
return service; return service;
}); });
app.factory('StackService', function(ApiService, $http){
var StackService = function($http, ep) {
ApiService.call(this, $http, ep);
};
StackService.prototype = ApiService.prototype;
StackService.prototype.getAll = function(boardId) {
return $http.get(this.baseUrl + '/' + boardId);
}
service = new StackService($http, 'stacks')
return service;
});

View File

@@ -39,11 +39,11 @@ class StackService {
} }
public function delete($userId, $id) { public function delete($userId, $id) {
return $this->stackMapper->delete($this->find($userId, $id)); return $this->stackMapper->delete($this->stackMapper->find($id));
} }
public function update($id, $title, $boardId, $order) { public function update($id, $title, $boardId, $order) {
$stack = $this->find($id); $stack = $this->stackMapper->find($id);
$stack->setTitle($title); $stack->setTitle($title);
$stack->setBoardId($boardId); $stack->setBoardId($boardId);
$stack->setOrder($order); $stack->setOrder($order);

View File

@@ -12,15 +12,7 @@ Util::addScript('deck', 'vendor/angular-sanitize/angular-sanitize.min');
Util::addScript('deck', 'vendor/angular-animate/angular-animate.min'); Util::addScript('deck', 'vendor/angular-animate/angular-animate.min');
Util::addScript('deck', 'vendor/angular-ui-router/release/angular-ui-router.min'); Util::addScript('deck', 'vendor/angular-ui-router/release/angular-ui-router.min');
Util::addScript('deck', 'vendor/ng-sortable/dist/ng-sortable.min'); Util::addScript('deck', 'vendor/ng-sortable/dist/ng-sortable.min');
Util::addScript('deck', 'app/App'); Util::addScript('deck', 'public/app');
Util::addScript('deck', 'controller/AppController');
Util::addScript('deck', 'controller/CardController');
Util::addScript('deck', 'controller/BoardController');
Util::addScript('deck', 'controller/ListController');
Util::addScript('deck', 'service/factory.board');
Util::addScript('deck', 'service/factory.stack');
?> ?>

View File

@@ -4,8 +4,8 @@
<h2>{{ status.title }}</h2> <h2>{{ status.title }}</h2>
<p>{{ status.text }}</p></div> <p>{{ status.text }}</p></div>
</div> </div>
<div id="board" class="scroll-container" style="background-color:{{rgblight(board.color)}};"> <div id="board" class="scroll-container" style="background-color:{{rgblight(boardservice.getCurrent().color)}};">
<h1 style="background-color:#{{ board.color }};" ng-click="stackservice.getOne(6)">{{ board.title }} {{ stackservice.once }} <h1 style="background-color:#{{ boardservice.getCurrent().color }};">{{ boardservice.data[id].title }}
</h1> </h1>
<?php /* maybe later <?php /* maybe later
<div class="board-actions"> <div class="board-actions">
@@ -15,11 +15,15 @@
</div> */ ?> </div> */ ?>
<div id="innerBoard" data-ng-model="stacks"> <div id="innerBoard" data-ng-model="stacks">
<div class="stack" ng-repeat="s in stacks" data-columnindex="{{$index}}" id="column{{$index}}" data-ng-model="stacks"> <div class="stack" ng-repeat="s in stackservice.data" data-columnindex="{{$index}}" id="column{{$index}}" data-ng-model="stackservice.data">
<h2>{{ s.title }} <h2><span ng-show="!s.status.editStack">{{ s.title }}</span>
<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/>
<button class="icon icon-save" ng-if="s.status.editStack" type="submit"></button>
</form>
<div class="stack-actions"> <div class="stack-actions">
<button class="icon-rename"></button> <button class="icon-rename" ng-click="s.status.editStack=true"></button>
<button class="icon-delete"></button> <button class="icon-delete" ng-click="stackservice.delete(s.id)"></button>
</div> </div>
</h2> </h2>
<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;">
@@ -41,15 +45,15 @@
</a> </a>
</li> </li>
</ul> </ul>
<div class="card create"> <div class="card create" ng-click="s.status.addCard=!s.status.addCard">
<h3><input type="text" /></h3> <h3 ng-if="s.status.addCard" ><input type="text" autofocus-on-insert/></h3>
<i class="fa fa-plus"></i> <i class="fa fa-plus" ></i>
</div> </div>
</div> </div>
<div class="stack" style="display: inline-block;"> <div class="stack" style="display: inline-block;">
<form class="ng-pristine ng-valid" ng-submit="createStack()"> <form class="ng-pristine ng-valid" ng-submit="createStack()">
<h2> <h2>
<input type="text" placeholder="Add a new stack" ng-focus="status.addStack=true" ng-blur="status.addStack=false" ng-model="newStack.title"> <input type="text" placeholder="Add a new stack" ng-focus="status.addStack=true" ng-blur="status.addStack=false" ng-model="newStack.title" >
<button class="icon icon-add" ng-show="status.addStack" type="submit"></button> <button class="icon icon-add" ng-show="status.addStack" type="submit"></button>
</h2> </h2>
</form> </form>

View File

@@ -1,11 +1,9 @@
<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>{{stackservice.once}}</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 boards">
<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>
<div class="app-navigation-entry-utils" ng-show="!b.status.edit"> <div class="app-navigation-entry-utils" ng-show="!b.status.edit">
@@ -26,7 +24,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="updateBoard(b)"> <form ng-disabled="isAddingList" class="ng-pristine ng-valid" ng-submit="boardservice.update(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">