diff --git a/bower.json b/bower.json
index 20ff31753..dfed8f57a 100644
--- a/bower.json
+++ b/bower.json
@@ -14,6 +14,7 @@
"angular-loading-bar": "~0.7.1",
"angular-ui-router": "~0.2.13",
"angular-ui-select": "~0.12",
+ "angular-ui-switch": "~0.1.0",
"angular-ui-tree": "~2.2.0",
"angular-gettext": "~2.0.2",
"angular-sanitize": "~1.3.15",
diff --git a/openslides/agenda/static/js/agenda/agenda.js b/openslides/agenda/static/js/agenda/agenda.js
index 36b40a59f..217e3c6da 100644
--- a/openslides/agenda/static/js/agenda/agenda.js
+++ b/openslides/agenda/static/js/agenda/agenda.js
@@ -2,44 +2,52 @@
angular.module('OpenSlidesApp.agenda', ['OpenSlidesApp.users'])
-.factory('Speaker', ['DS', function(DS) {
- return DS.defineResource({
- name: 'agenda/speaker',
- relations: {
- belongsTo: {
- 'users/user': {
- localField: 'user',
- localKey: 'user_id',
+.factory('Speaker', [
+ 'DS',
+ function(DS) {
+ return DS.defineResource({
+ name: 'agenda/speaker',
+ relations: {
+ belongsTo: {
+ 'users/user': {
+ localField: 'user',
+ localKey: 'user_id',
+ }
}
}
- }
- });
-}])
+ });
+ }
+])
-.factory('Agenda', ['DS', 'Speaker', 'jsDataModel', function(DS, Speaker, jsDataModel) {
- var name = 'agenda/item'
- return DS.defineResource({
- name: name,
- useClass: jsDataModel,
- methods: {
- getResourceName: function () {
- return name;
- }
- },
- relations: {
- hasMany: {
- 'core/tag': {
- localField: 'tags',
- localKeys: 'tags_id',
- },
- 'agenda/speaker': {
- localField: 'speakers',
- foreignKey: 'item_id',
+.factory('Agenda', [
+ 'DS',
+ 'Speaker',
+ 'jsDataModel',
+ function(DS, Speaker, jsDataModel) {
+ var name = 'agenda/item'
+ return DS.defineResource({
+ name: name,
+ useClass: jsDataModel,
+ methods: {
+ getResourceName: function () {
+ return name;
+ }
+ },
+ relations: {
+ hasMany: {
+ 'core/tag': {
+ localField: 'tags',
+ localKeys: 'tags_id',
+ },
+ 'agenda/speaker': {
+ localField: 'speakers',
+ foreignKey: 'item_id',
+ }
}
}
- }
- });
-}])
+ });
+ }
+])
// Make sure that the Agenda resource is loaded.
.run(['Agenda', function(Agenda) {}]);
@@ -60,79 +68,82 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
}
])
-.config(function($stateProvider) {
- $stateProvider
- .state('agenda', {
- url: '/agenda',
- abstract: true,
- template: "",
- })
- .state('agenda.item', {
- abstract: true,
- template: "",
- })
- .state('agenda.item.list', {
- resolve: {
- items: function(Agenda) {
- return Agenda.findAll();
+.config([
+ '$stateProvider',
+ function($stateProvider) {
+ $stateProvider
+ .state('agenda', {
+ url: '/agenda',
+ abstract: true,
+ template: "",
+ })
+ .state('agenda.item', {
+ abstract: true,
+ template: "",
+ })
+ .state('agenda.item.list', {
+ resolve: {
+ items: function(Agenda) {
+ return Agenda.findAll();
+ }
}
- }
- })
- .state('agenda.item.create', {
- resolve: {
- types: function($http) {
- // get all item types
- return $http({ 'method': 'OPTIONS', 'url': '/rest/agenda/item/' });
+ })
+ .state('agenda.item.create', {
+ resolve: {
+ types: function($http) {
+ // get all item types
+ return $http({ 'method': 'OPTIONS', 'url': '/rest/agenda/item/' });
+ },
+ tags: function(Tag) {
+ return Tag.findAll();
+ }
+ }
+ })
+ .state('agenda.item.detail', {
+ resolve: {
+ item: function(Agenda, $stateParams) {
+ return Agenda.find($stateParams.id);
+ },
+ users: function(User) {
+ return User.findAll();
+ },
+ tags: function(Tag) {
+ return Tag.findAll();
+ }
+ }
+ })
+ .state('agenda.item.detail.update', {
+ views: {
+ '@agenda.item': {}
},
- tags: function(Tag) {
- return Tag.findAll();
+ resolve: {
+ types: function($http) {
+ // get all item types
+ return $http({ 'method': 'OPTIONS', 'url': '/rest/agenda/item/' });
+ }
}
- }
- })
- .state('agenda.item.detail', {
- resolve: {
- item: function(Agenda, $stateParams) {
- return Agenda.find($stateParams.id);
+ })
+ .state('agenda.item.sort', {
+ resolve: {
+ items: function(Agenda) {
+ return Agenda.findAll();
+ }
},
- users: function(User) {
- return User.findAll();
- },
- tags: function(Tag) {
- return Tag.findAll();
- }
- }
- })
- .state('agenda.item.detail.update', {
- views: {
- '@agenda.item': {}
- },
- resolve: {
- types: function($http) {
- // get all item types
- return $http({ 'method': 'OPTIONS', 'url': '/rest/agenda/item/' });
- }
- }
- })
- .state('agenda.item.sort', {
- resolve: {
- items: function(Agenda) {
- return Agenda.findAll();
- }
- },
- url: '/sort',
- controller: 'AgendaSortCtrl',
- })
- .state('agenda.item.import', {
- url: '/import',
- controller: 'AgendaImportCtrl',
- });
-})
+ url: '/sort',
+ controller: 'AgendaSortCtrl',
+ })
+ .state('agenda.item.import', {
+ url: '/import',
+ controller: 'AgendaImportCtrl',
+ });
+ }
+])
.factory('AgendaTree', [
function () {
return {
getTree: function (items) {
- // sortieren nach weight???
+ // TODO: sortieren nach weight???
// Build a dict with all children (dict-value) to a specific
// item id (dict-key).
@@ -190,199 +201,270 @@ angular.module('OpenSlidesApp.agenda.site', ['OpenSlidesApp.agenda'])
}
])
-.controller('ItemListCtrl', function($scope, $http, Agenda, Projector, AgendaTree) {
- // Bind agenda tree to the scope
- $scope.$watch(function () {
- return Agenda.lastModified();
- }, function () {
- $scope.items = AgendaTree.getFlatTree(Agenda.getAll());
- });
-
- // save changed item
- $scope.save = function (item) {
- Agenda.save(item);
- };
- // delete selected item
- $scope.delete = function (id) {
- Agenda.destroy(id);
- };
- // project agenda
- $scope.projectAgenda = function () {
- $http.post('/rest/core/projector/1/prune_elements/',
- [{name: 'agenda/item-list'}]);
- };
- // check if agenda is projected
- $scope.isAgendaProjected = function () {
- // Returns true if there is a projector element with the same
- // name and agenda is active.
- var projector = Projector.get(1);
- if (typeof projector === 'undefined') return false;
- var self = this;
- return _.findIndex(projector.elements, function(element) {
- return element.name == 'agenda/item-list'
- }) > -1;
-
- };
-})
-
-.controller('ItemDetailCtrl', function($scope, $http, Agenda, User, item) {
- Agenda.bindOne(item.id, $scope, 'item');
- User.bindAll({}, $scope, 'users');
- $scope.speaker = {};
- $scope.alert = {};
-
- // close/open list of speakers of current item
- $scope.closeList = function (listClosed) {
- item.speaker_list_closed = listClosed;
- Agenda.save(item);
- };
- // add user to list of speakers
- $scope.addSpeaker = function (userId) {
- $http.post('/rest/agenda/item/' + item.id + '/manage_speaker/', {'user': userId})
- .success(function(data){
- $scope.alert.show = false;
- })
- .error(function(data){
- $scope.alert = { type: 'danger', msg: data.detail, show: true };
- });
- };
- // delete speaker(!) from list of speakers
- $scope.removeSpeaker = function (speakerId) {
- $http.delete('/rest/agenda/item/' + item.id + '/manage_speaker/',
- {headers: {'Content-Type': 'application/json'},
- data: JSON.stringify({speaker: speakerId})})
- .error(function(data){
- $scope.alert = { type: 'danger', msg: data.detail, show: true };
- });
- };
- // begin speech of selected/next speaker
- $scope.beginSpeech = function (speakerId) {
- $http.put('/rest/agenda/item/' + item.id + '/speak/', {'speaker': speakerId})
- .success(function(data){
- $scope.alert.show = false;
- })
- .error(function(data){
- $scope.alert = { type: 'danger', msg: data.detail, show: true };
- });
- };
- // end speech of current speaker
- $scope.endSpeech = function () {
- $http.delete('/rest/agenda/item/' + item.id + '/speak/',
- {headers: {'Content-Type': 'application/json'},
- data: JSON.stringify()})
- .error(function(data){
- $scope.alert = { type: 'danger', msg: data.detail, show: true };
- });
- };
- // project list of speakers
- $scope.projectListOfSpeakers = function () {
- $http.post('/rest/core/projector/1/prune_elements/',
- [{name: 'agenda/item', id: item.id, list_of_speakers: true}]);
- };
-})
-
-.controller('ItemCreateCtrl', function($scope, $state, Agenda, Tag, types) {
- $scope.types = types.data.actions.POST.type.choices; // get all item types
- Tag.bindAll({}, $scope, 'tags');
- $scope.save = function (item) {
- if (!item)
- return null;
- Agenda.create(item).then(
- function(success) {
- $state.go('agenda.item.list');
- }
- );
- };
-})
-
-.controller('ItemUpdateCtrl', function($scope, $state, Agenda, Tag, types, item) {
- $scope.types = types.data.actions.POST.type.choices; // get all item types
- Tag.bindAll({}, $scope, 'tags');
- $scope.item = item;
- $scope.save = function (item) {
- Agenda.save(item).then(
- function(success) {
- $state.go('agenda.item.list');
- }
- );
- };
-})
-
-.controller('AgendaSortCtrl', function($scope, $http, Agenda, AgendaTree) {
- // Bind agenda tree to the scope
- $scope.$watch(function () {
- return Agenda.lastModified();
- }, function () {
- $scope.items = AgendaTree.getTree(Agenda.getAll());
- });
-
- // set changed agenda tree
- $scope.treeOptions = {
- dropped: function() {
- $http.put('/rest/agenda/item/tree/', {tree: $scope.items});
- }
- };
-})
-
-.controller('AgendaImportCtrl', function($scope, $state, Agenda) {
- // import from textarea
- $scope.importByLine = function () {
- $scope.items = $scope.itemlist[0].split("\n");
- $scope.importcounter = 0;
- $scope.items.forEach(function(title) {
- var item = {title: title};
- // TODO: create all items in bulk mode
- Agenda.create(item).then(
- function(success) {
- $scope.importcounter++;
- }
- );
+.controller('ItemListCtrl', [
+ '$scope',
+ '$http',
+ '$state',
+ 'Agenda',
+ 'AgendaTree',
+ 'Projector',
+ function($scope, $http, $state, Agenda, AgendaTree, Projector) {
+ // Bind agenda tree to the scope
+ $scope.$watch(function () {
+ return Agenda.lastModified();
+ }, function () {
+ $scope.items = AgendaTree.getFlatTree(Agenda.getAll());
});
- }
- // import from csv file
- $scope.csv = {
- content: null,
- header: true,
- separator: ',',
- result: null
- };
- $scope.importByCSV = function (result) {
- var obj = JSON.parse(JSON.stringify(result));
- $scope.csvimporting = true;
- $scope.csvlines = Object.keys(obj).length;
- $scope.csvimportcounter = 0;
- for (var i = 0; i < obj.length; i++) {
- var item = {};
- item.title = obj[i].title;
- item.text = obj[i].text;
- item.duration = obj[i].duration;
+ // open detail view link
+ $scope.openDetail = function (id) {
+ $state.go('agenda.item.detail', {id: id});
+ }
+
+ // save changed item
+ $scope.save = function (item) {
+ Agenda.save(item);
+ };
+
+ // *** delete mode functions ***
+ $scope.isDeleteMode = false;
+ // check all checkboxes
+ $scope.checkAll = function () {
+ angular.forEach($scope.items, function (item) {
+ item.selected = $scope.selectedAll;
+ });
+ };
+ // uncheck all checkboxes if isDeleteMode is closed
+ $scope.uncheckAll = function () {
+ if (!$scope.isDeleteMode) {
+ $scope.selectedAll = false;
+ angular.forEach($scope.items, function (item) {
+ item.selected = false;
+ });
+ }
+ };
+ // delete selected item
+ $scope.delete = function () {
+ angular.forEach($scope.items, function (item) {
+ if (item.selected)
+ Agenda.destroy(item.id);
+ });
+ $scope.isDeleteMode = false;
+ $scope.uncheckAll();
+ };
+
+ // project agenda
+ $scope.projectAgenda = function () {
+ $http.post('/rest/core/projector/1/prune_elements/',
+ [{name: 'agenda/item-list'}]);
+ };
+ // check if agenda is projected
+ $scope.isAgendaProjected = function () {
+ // Returns true if there is a projector element with the same
+ // name and agenda is active.
+ var projector = Projector.get(1);
+ if (typeof projector === 'undefined') return false;
+ var self = this;
+ return _.findIndex(projector.elements, function(element) {
+ return element.name == 'agenda/item-list'
+ }) > -1;
+
+ };
+ }
+])
+
+.controller('ItemDetailCtrl', [
+ '$scope',
+ '$http',
+ 'Agenda',
+ 'User',
+ 'item',
+ function ($scope, $http, Agenda, User, item) {
+ Agenda.bindOne(item.id, $scope, 'item');
+ User.bindAll({}, $scope, 'users');
+ $scope.speaker = {};
+ $scope.alert = {};
+
+ // close/open list of speakers of current item
+ $scope.closeList = function (listClosed) {
+ item.speaker_list_closed = listClosed;
+ Agenda.save(item);
+ };
+ // add user to list of speakers
+ $scope.addSpeaker = function (userId) {
+ $http.post('/rest/agenda/item/' + item.id + '/manage_speaker/', {'user': userId})
+ .success(function(data){
+ $scope.alert.show = false;
+ })
+ .error(function(data){
+ $scope.alert = { type: 'danger', msg: data.detail, show: true };
+ });
+ };
+ // delete speaker(!) from list of speakers
+ $scope.removeSpeaker = function (speakerId) {
+ $http.delete('/rest/agenda/item/' + item.id + '/manage_speaker/',
+ {headers: {'Content-Type': 'application/json'},
+ data: JSON.stringify({speaker: speakerId})})
+ .error(function(data){
+ $scope.alert = { type: 'danger', msg: data.detail, show: true };
+ });
+ };
+ // begin speech of selected/next speaker
+ $scope.beginSpeech = function (speakerId) {
+ $http.put('/rest/agenda/item/' + item.id + '/speak/', {'speaker': speakerId})
+ .success(function(data){
+ $scope.alert.show = false;
+ })
+ .error(function(data){
+ $scope.alert = { type: 'danger', msg: data.detail, show: true };
+ });
+ };
+ // end speech of current speaker
+ $scope.endSpeech = function () {
+ $http.delete('/rest/agenda/item/' + item.id + '/speak/',
+ {headers: {'Content-Type': 'application/json'},
+ data: JSON.stringify()})
+ .error(function(data){
+ $scope.alert = { type: 'danger', msg: data.detail, show: true };
+ });
+ };
+ // project list of speakers
+ $scope.projectListOfSpeakers = function () {
+ $http.post('/rest/core/projector/1/prune_elements/',
+ [{name: 'agenda/item', id: item.id, list_of_speakers: true}]);
+ };
+ }
+])
+
+.controller('ItemCreateCtrl', [
+ '$scope',
+ '$state',
+ 'Agenda',
+ 'Tag',
+ 'types',
+ function($scope, $state, Agenda, Tag, types) {
+ $scope.types = types.data.actions.POST.type.choices; // get all item types
+ Tag.bindAll({}, $scope, 'tags');
+ $scope.save = function (item) {
+ if (!item)
+ return null;
Agenda.create(item).then(
function(success) {
- $scope.csvimportcounter++;
+ $state.go('agenda.item.list');
}
);
- }
- $scope.csvimported = true;
+ };
}
+])
- $scope.clear = function () {
- $scope.csv.result = null;
- };
+.controller('ItemUpdateCtrl', [
+ '$scope',
+ '$state',
+ 'Agenda',
+ 'Tag',
+ 'types',
+ 'item',
+ function($scope, $state, Agenda, Tag, types, item) {
+ $scope.types = types.data.actions.POST.type.choices; // get all item types
+ Tag.bindAll({}, $scope, 'tags');
+ $scope.item = item;
+ $scope.save = function (item) {
+ Agenda.save(item).then(
+ function(success) {
+ $state.go('agenda.item.list');
+ }
+ );
+ };
+ }
+])
-});
+.controller('AgendaSortCtrl', [
+ '$scope',
+ '$http',
+ 'Agenda',
+ 'AgendaTree',
+ function($scope, $http, Agenda, AgendaTree) {
+ // Bind agenda tree to the scope
+ $scope.$watch(function () {
+ return Agenda.lastModified();
+ }, function () {
+ $scope.items = AgendaTree.getTree(Agenda.getAll());
+ });
+
+ // set changed agenda tree
+ $scope.treeOptions = {
+ dropped: function() {
+ $http.put('/rest/agenda/item/tree/', {tree: $scope.tree});
+ }
+ };
+ }
+])
+
+.controller('AgendaImportCtrl', [
+ '$scope',
+ '$state',
+ 'Agenda',
+ function($scope, $state, Agenda) {
+ // import from textarea
+ $scope.importByLine = function () {
+ $scope.items = $scope.itemlist[0].split("\n");
+ $scope.importcounter = 0;
+ $scope.items.forEach(function(title) {
+ var item = {title: title};
+ // TODO: create all items in bulk mode
+ Agenda.create(item).then(
+ function(success) {
+ $scope.importcounter++;
+ }
+ );
+ });
+ }
+
+ // import from csv file
+ $scope.csv = {
+ content: null,
+ header: true,
+ separator: ',',
+ result: null
+ };
+ $scope.importByCSV = function (result) {
+ var obj = JSON.parse(JSON.stringify(result));
+ $scope.csvimporting = true;
+ $scope.csvlines = Object.keys(obj).length;
+ $scope.csvimportcounter = 0;
+ for (var i = 0; i < obj.length; i++) {
+ var item = {};
+ item.title = obj[i].title;
+ item.text = obj[i].text;
+ item.duration = obj[i].duration;
+ Agenda.create(item).then(
+ function(success) {
+ $scope.csvimportcounter++;
+ }
+ );
+ }
+ $scope.csvimported = true;
+ }
+ $scope.clear = function () {
+ $scope.csv.result = null;
+ };
+ }
+]);
angular.module('OpenSlidesApp.agenda.projector', ['OpenSlidesApp.agenda'])
-.config(function(slidesProvider) {
- slidesProvider.registerSlide('agenda/item', {
- template: 'static/templates/agenda/slide-item-detail.html',
- });
- slidesProvider.registerSlide('agenda/item-list', {
- template: 'static/templates/agenda/slide-item-list.html',
- });
-})
+.config([
+ 'slidesProvider',
+ function(slidesProvider) {
+ slidesProvider.registerSlide('agenda/item', {
+ template: 'static/templates/agenda/slide-item-detail.html',
+ });
+ slidesProvider.registerSlide('agenda/item-list', {
+ template: 'static/templates/agenda/slide-item-list.html',
+ });
+ }
+])
.controller('SlideItemDetailCtrl', [
'$scope',
@@ -401,18 +483,21 @@ angular.module('OpenSlidesApp.agenda.projector', ['OpenSlidesApp.agenda'])
}
])
-.controller('SlideItemListCtrl', function($scope, $http, Agenda) {
- // Attention! Each object that is used here has to be dealt on server side.
- // Add it to the coresponding get_requirements method of the ProjectorElement
- // class.
- Agenda.findAll();
- Agenda.bindAll({}, $scope, 'items');
- $scope.ids = [];
- var tree = $http.get('/rest/agenda/item/tree/').success(function(data) {
- var ids = [];
- angular.forEach(data,function(element) {
- ids.push(element.id)
+.controller('SlideItemListCtrl', [
+ '$scope',
+ '$http',
+ 'Agenda',
+ 'AgendaTree',
+ function($scope, $http, Agenda, AgendaTree) {
+ // Attention! Each object that is used here has to be dealt on server side.
+ // Add it to the coresponding get_requirements method of the ProjectorElement
+ // class.
+
+ // Bind agenda tree to the scope
+ $scope.$watch(function () {
+ return Agenda.lastModified();
+ }, function () {
+ $scope.items = AgendaTree.getFlatTree(Agenda.getAll());
});
- $scope.ids = ids;
- })
-});
+ }
+]);
diff --git a/openslides/agenda/static/templates/agenda/item-list.html b/openslides/agenda/static/templates/agenda/item-list.html
index 0fbc07f9d..9b2041ffb 100644
--- a/openslides/agenda/static/templates/agenda/item-list.html
+++ b/openslides/agenda/static/templates/agenda/item-list.html
@@ -23,74 +23,93 @@
-
diff --git a/openslides/core/static/css/app.css b/openslides/core/static/css/app.css
index 50b73c41b..82918b547 100644
--- a/openslides/core/static/css/app.css
+++ b/openslides/core/static/css/app.css
@@ -184,7 +184,7 @@ a:hover {
}
/* List tables */
-th.sortable:hover {
+th.sortable:hover, tr.pointer:hover {
cursor: pointer;
}
@@ -246,7 +246,7 @@ tr.offline td, li.offline {
background-color: #EAEAEA !important;
}
tr.activeline td, li.activeline {
- background-color: #bed4de !important;
+ background-color: #bed4de;
}
.nopadding {
padding: 0;
@@ -266,6 +266,19 @@ tr.total td {
.indentation {
margin-left: 12px;
}
+.firstColumn {
+ width: 55px;
+}
+.deleteColumn {
+ text-align: center;
+ background-color: #ff9999 !important;
+}
+.switch.checked {
+ background-color: #ff9999 !important;
+ border-color: #ff9999;
+}
+
+
.minimum, .mini_width {
width: 1px;
}
diff --git a/openslides/core/static/js/core/core.js b/openslides/core/static/js/core/core.js
index d9d08010c..31762348d 100644
--- a/openslides/core/static/js/core/core.js
+++ b/openslides/core/static/js/core/core.js
@@ -8,6 +8,7 @@ angular.module('OpenSlidesApp.core', [
'ngAnimate',
'ui.bootstrap',
'ui.tree',
+ 'uiSwitch',
])
.config(['DSProvider', 'DSHttpAdapterProvider', function(DSProvider, DSHttpAdapterProvider) {