diff --git a/openslides/assignments/static/templates/assignments/assignmentpoll-form.html b/openslides/assignments/static/templates/assignments/assignmentpoll-form.html
index 36c7a61f9..90fc67bff 100644
--- a/openslides/assignments/static/templates/assignments/assignmentpoll-form.html
+++ b/openslides/assignments/static/templates/assignments/assignmentpoll-form.html
@@ -1,8 +1,8 @@
Ballot {{ ballot }}
-
+
{{ alert.msg }}
-
+
Special values:
diff --git a/openslides/assignments/static/templates/assignments/slide_assignment.html b/openslides/assignments/static/templates/assignments/slide_assignment.html
index eb870254e..341633bcd 100644
--- a/openslides/assignments/static/templates/assignments/slide_assignment.html
+++ b/openslides/assignments/static/templates/assignments/slide_assignment.html
@@ -1,4 +1,12 @@
{{ assignment.title }}
{{ assignment.description }}
+
+
+
Candidates
+
+ -
+ {{ related_user.user.get_full_name() }}
+
+
diff --git a/openslides/assignments/views.py b/openslides/assignments/views.py
index 44f6eab89..f24d805a5 100644
--- a/openslides/assignments/views.py
+++ b/openslides/assignments/views.py
@@ -172,7 +172,7 @@ class AssignmentViewSet(ModelViewSet):
if not request.user.has_perm('assignments.can_manage'):
self.permission_denied(request)
if assignment.phase == assignment.PHASE_FINISHED:
- detail = _('You can not delete someones candidature to this election because it is finished.')
+ detail = _("You can not delete someone's candidature to this election because it is finished.")
raise ValidationError({'detail': detail})
if not assignment.is_candidate(user) and not assignment.is_elected(user):
raise ValidationError({'detail': _('User %s has no status in this election.') % user})
diff --git a/openslides/core/static/css/app.css b/openslides/core/static/css/app.css
index 596b8e03c..d278a6923 100644
--- a/openslides/core/static/css/app.css
+++ b/openslides/core/static/css/app.css
@@ -458,6 +458,10 @@ img {
padding-right: 10px;
}
+.col2 .countdown_timer.negative {
+ color: #CC0000;
+}
+
.col2 .notNull {
color: red;
font-weight: bold;
@@ -589,6 +593,10 @@ img {
width: 250px;
}
+.loginForm .input-group-addon i {
+ width: 15px;
+}
+
.modal-header {
padding: 5px;
}
@@ -648,23 +656,21 @@ img {
/* ngAnimate classes */
.animate-item.ng-enter {
- -webkit-animation: fade-in 1s linear;
- animation: fade-in 1.5s linear;
+ -webkit-animation: fade-in 0.5s linear;
+ animation: fade-in 0.5s linear;
}
.animate-item.ng-leave {
- -webkit-animation: fade-out 1s linear;
- animation: fade-out 1.5s linear;
+ -webkit-animation: fade-out 0.25s linear;
+ animation: fade-out 0.25s linear;
}
@keyframes fade-out {
0% { opacity: 1; background: none; }
- 25% { opacity: 1; background: #f8efc0; }
100% { opacity: 0; background: none; }
}
@keyframes fade-in {
0% { opacity: 0; background: none; }
- 25% { opacity: 1; background: #dff0d8; }
100% { opacity: 1; background: none; }
}
diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js
index 57d570357..59201377e 100644
--- a/openslides/core/static/js/core/base.js
+++ b/openslides/core/static/js/core/base.js
@@ -12,23 +12,27 @@ angular.module('OpenSlidesApp.core', [
'ui.tree',
])
-.config(['DSProvider', 'DSHttpAdapterProvider', function(DSProvider, DSHttpAdapterProvider) {
- // Reloads everything after 5 minutes.
- // TODO: * find a way only to reload things that are still needed
- DSProvider.defaults.maxAge = 5 * 60 * 1000; // 5 minutes
- DSProvider.defaults.reapAction = 'none';
- DSProvider.defaults.basePath = '/rest';
- DSProvider.defaults.afterReap = function(model, items) {
- if (items.length > 5) {
- model.findAll({}, {bypassCache: true});
- } else {
- _.forEach(items, function (item) {
- model.refresh(item[model.idAttribute]);
- });
- }
- };
- DSHttpAdapterProvider.defaults.forceTrailingSlash = true;
-}])
+.config([
+ 'DSProvider',
+ 'DSHttpAdapterProvider',
+ function(DSProvider, DSHttpAdapterProvider) {
+ // Reloads everything after 5 minutes.
+ // TODO: * find a way only to reload things that are still needed
+ DSProvider.defaults.maxAge = 5 * 60 * 1000; // 5 minutes
+ DSProvider.defaults.reapAction = 'none';
+ DSProvider.defaults.basePath = '/rest';
+ DSProvider.defaults.afterReap = function(model, items) {
+ if (items.length > 5) {
+ model.findAll({}, {bypassCache: true});
+ } else {
+ _.forEach(items, function (item) {
+ model.refresh(item[model.idAttribute]);
+ });
+ }
+ };
+ DSHttpAdapterProvider.defaults.forceTrailingSlash = true;
+ }
+])
.factory('autoupdate', [
'DS',
@@ -129,23 +133,27 @@ angular.module('OpenSlidesApp.core', [
}
])
-.run(['DS', 'autoupdate', function(DS, autoupdate) {
- autoupdate.on_message(function(data) {
- // TODO: when MODEL.find() is called after this
- // a new request is fired. This could be a bug in DS
+.run([
+ 'DS',
+ 'autoupdate',
+ function(DS, autoupdate) {
+ autoupdate.on_message(function(data) {
+ // TODO: when MODEL.find() is called after this
+ // a new request is fired. This could be a bug in DS
- // TODO: Do not send the status code to the client, but make the decission
- // on the server side. It is an implementation detail, that tornado
- // sends request to wsgi, which should not concern the client.
- console.log("Received object: " + data.collection + ", " + data.id);
- if (data.status_code == 200) {
- DS.inject(data.collection, data.data);
- } else if (data.status_code == 404) {
- DS.eject(data.collection, data.id);
- }
- // TODO: handle other statuscodes
- });
-}])
+ // TODO: Do not send the status code to the client, but make the decission
+ // on the server side. It is an implementation detail, that tornado
+ // sends request to wsgi, which should not concern the client.
+ console.log("Received object: " + data.collection + ", " + data.id);
+ if (data.status_code == 200) {
+ DS.inject(data.collection, data.data);
+ } else if (data.status_code == 404) {
+ DS.eject(data.collection, data.id);
+ }
+ // TODO: handle other statuscodes
+ });
+ }
+])
.factory('loadGlobalData', [
'$rootScope',
@@ -310,37 +318,37 @@ angular.module('OpenSlidesApp.core', [
* be removed. See http://www.js-data.io/docs/dsdefaults#onconflict for
* more information.
*/
-.factory('Projector', ['DS', function(DS) {
- return DS.defineResource({
- name: 'core/projector',
- onConflict: 'replace',
- });
-}])
+.factory('Projector', [
+ 'DS',
+ function(DS) {
+ return DS.defineResource({
+ name: 'core/projector',
+ onConflict: 'replace',
+ });
+ }
+])
/* Converts number of seconds into string "hh:mm:ss" or "mm:ss" */
.filter('osSecondsToTime', [
function () {
return function (totalseconds) {
var time;
- var total = Math.abs(totalseconds);
- if (parseInt(totalseconds)) {
- var hh = Math.floor(total / 3600);
- var mm = Math.floor(total % 3600 / 60);
- var ss = Math.floor(total % 60);
- var zero = "0";
- // Add leading "0" for double digit values
- hh = (zero+hh).slice(-2);
- mm = (zero+mm).slice(-2);
- ss = (zero+ss).slice(-2);
- if (hh == "00")
- time = mm + ':' + ss;
- else
- time = hh + ":" + mm + ":" + ss;
- if (totalseconds < 0)
- time = "-"+time;
- } else {
- time = "--:--";
- }
+ // floor returns the largest integer of the absolut value of totalseconds
+ var total = Math.floor(Math.abs(totalseconds));
+ var hh = Math.floor(total / 3600);
+ var mm = Math.floor(total % 3600 / 60);
+ var ss = Math.floor(total % 60);
+ var zero = "0";
+ // Add leading "0" for double digit values
+ hh = (zero+hh).slice(-2);
+ mm = (zero+mm).slice(-2);
+ ss = (zero+ss).slice(-2);
+ if (hh == "00")
+ time = mm + ':' + ss;
+ else
+ time = hh + ":" + mm + ":" + ss;
+ if (totalseconds < 0)
+ time = "-"+time;
return time;
};
}
diff --git a/openslides/core/static/js/core/projector.js b/openslides/core/static/js/core/projector.js
index 7a61df0b8..17207d867 100644
--- a/openslides/core/static/js/core/projector.js
+++ b/openslides/core/static/js/core/projector.js
@@ -6,70 +6,80 @@
angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core'])
// Provider to register slides in a .config() statement.
-.provider('slides', function() {
- var slidesMap = {};
+.provider('slides', [
+ function() {
+ var slidesMap = {};
- this.registerSlide = function(name, config) {
- slidesMap[name] = config;
- return this;
- };
+ this.registerSlide = function(name, config) {
+ slidesMap[name] = config;
+ return this;
+ };
- this.$get = function($templateRequest, $q) {
- var self = this;
- return {
- getElements: function(projector) {
- var elements = [];
- var factory = this;
- _.forEach(projector.elements, function(element) {
- if (element.name in slidesMap) {
- element.template = slidesMap[element.name].template;
- elements.push(element);
+ this.$get = function($templateRequest, $q) {
+ var self = this;
+ return {
+ getElements: function(projector) {
+ var elements = [];
+ var factory = this;
+ _.forEach(projector.elements, function(element) {
+ if (element.name in slidesMap) {
+ element.template = slidesMap[element.name].template;
+ elements.push(element);
+ } else {
+ console.log("Unknown slide: " + element.name);
+ }
+ });
+ return elements;
+ }
+ };
+ };
+ }
+])
+
+.config([
+ 'slidesProvider',
+ function(slidesProvider) {
+ slidesProvider.registerSlide('core/customslide', {
+ template: 'static/templates/core/slide_customslide.html',
+ });
+
+ slidesProvider.registerSlide('core/clock', {
+ template: 'static/templates/core/slide_clock.html',
+ });
+
+ slidesProvider.registerSlide('core/countdown', {
+ template: 'static/templates/core/slide_countdown.html',
+ });
+
+ slidesProvider.registerSlide('core/message', {
+ template: 'static/templates/core/slide_message.html',
+ });
+ }
+])
+
+.controller('ProjectorCtrl', [
+ '$scope',
+ 'Projector',
+ 'slides',
+ function($scope, Projector, slides) {
+ Projector.find(1).then(function() {
+ $scope.$watch(function () {
+ return Projector.lastModified(1);
+ }, function () {
+ $scope.elements = [];
+ _.forEach(slides.getElements(Projector.get(1)), function(element) {
+ if (!element.error) {
+ $scope.elements.push(element);
} else {
- console.log("Unknown slide: " + element.name);
+ console.error("Error for slide " + element.name + ": " + element.error);
}
});
- return elements;
- }
- };
- };
-})
-
-.config(function(slidesProvider) {
- slidesProvider.registerSlide('core/customslide', {
- template: 'static/templates/core/slide_customslide.html',
- });
-
- slidesProvider.registerSlide('core/clock', {
- template: 'static/templates/core/slide_clock.html',
- });
-
- slidesProvider.registerSlide('core/countdown', {
- template: 'static/templates/core/slide_countdown.html',
- });
-
- slidesProvider.registerSlide('core/message', {
- template: 'static/templates/core/slide_message.html',
- });
-})
-
-.controller('ProjectorCtrl', function($scope, Projector, slides) {
- Projector.find(1).then(function() {
- $scope.$watch(function () {
- return Projector.lastModified(1);
- }, function () {
- $scope.elements = [];
- _.forEach(slides.getElements(Projector.get(1)), function(element) {
- if (!element.error) {
- $scope.elements.push(element);
- } else {
- console.error("Error for slide " + element.name + ": " + element.error);
- }
+ $scope.scroll = -5 * Projector.get(1).scroll;
+ $scope.scale = 100 + 20 * Projector.get(1).scale;
});
- $scope.scroll = -5 * Projector.get(1).scroll;
- $scope.scale = 100 + 20 * Projector.get(1).scale;
});
- });
-})
+ }
+])
.controller('SlideCustomSlideCtrl', [
'$scope',
diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js
index 5aa3e5cfb..452c62d8f 100644
--- a/openslides/core/static/js/core/site.js
+++ b/openslides/core/static/js/core/site.js
@@ -84,209 +84,244 @@ angular.module('OpenSlidesApp.core.site', [
}
])
-.config(function($urlRouterProvider, $locationProvider) {
- // define fallback url and html5Mode
- $urlRouterProvider.otherwise('/');
- $locationProvider.html5Mode(true);
-})
+.config([
+ '$urlRouterProvider',
+ '$locationProvider',
+ function($urlRouterProvider, $locationProvider) {
+ // define fallback url and html5Mode
+ $urlRouterProvider.otherwise('/');
+ $locationProvider.html5Mode(true);
+ }
+])
-.config(function($httpProvider) {
- // Combine the django csrf system with the angular csrf system
- $httpProvider.defaults.xsrfCookieName = 'csrftoken';
- $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
-})
+.config([
+ '$httpProvider',
+ function($httpProvider) {
+ // Combine the django csrf system with the angular csrf system
+ $httpProvider.defaults.xsrfCookieName = 'csrftoken';
+ $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
+ }
+])
-.config(function(uiSelectConfig) {
- uiSelectConfig.theme = 'bootstrap';
-})
+.config([
+ 'uiSelectConfig',
+ function(uiSelectConfig) {
+ uiSelectConfig.theme = 'bootstrap';
+ }
+])
-.config(function($stateProvider, $urlMatcherFactoryProvider) {
- // Make the trailing slash optional
- $urlMatcherFactoryProvider.strictMode(false);
+.config([
+ '$stateProvider',
+ '$urlMatcherFactoryProvider',
+ function($stateProvider, $urlMatcherFactoryProvider) {
+ // Make the trailing slash optional
+ $urlMatcherFactoryProvider.strictMode(false);
- // Use stateProvider.decorator to give default values to our states
- $stateProvider.decorator('views', function(state, parent) {
- var result = {},
- views = parent(state);
+ // Use stateProvider.decorator to give default values to our states
+ $stateProvider.decorator('views', function(state, parent) {
+ var result = {},
+ views = parent(state);
- if (state.abstract || state.data && state.data.extern) {
- return views;
- }
+ if (state.abstract || state.data && state.data.extern) {
+ return views;
+ }
- angular.forEach(views, function(config, name) {
+ angular.forEach(views, function(config, name) {
- // Sets default values for templateUrl
- var patterns = state.name.split('.'),
- templateUrl,
- controller,
- defaultControllers = {
- create: 'CreateCtrl',
- update: 'UpdateCtrl',
- list: 'ListCtrl',
- detail: 'DetailCtrl',
- };
+ // Sets default values for templateUrl
+ var patterns = state.name.split('.'),
+ templateUrl,
+ controller,
+ defaultControllers = {
+ create: 'CreateCtrl',
+ update: 'UpdateCtrl',
+ list: 'ListCtrl',
+ detail: 'DetailCtrl',
+ };
- // templateUrl
- if (_.last(patterns).match(/(create|update)/)) {
- // When state_patterns is in the form "app.module.create" or
- // "app.module.update", use the form template.
- templateUrl = 'static/templates/' + patterns[0] + '/' + patterns[1] + '-form.html';
+ // templateUrl
+ if (_.last(patterns).match(/(create|update)/)) {
+ // When state_patterns is in the form "app.module.create" or
+ // "app.module.update", use the form template.
+ templateUrl = 'static/templates/' + patterns[0] + '/' + patterns[1] + '-form.html';
+ } else {
+ // Replaces the first point through a slash (the app name)
+ var appName = state.name.replace('.', '/');
+ // Replaces any folowing points though a -
+ templateUrl = 'static/templates/' + appName.replace(/\./g, '-') + '.html';
+ }
+ config.templateUrl = state.templateUrl || templateUrl;
+
+ // controller
+ if (patterns.length >= 3) {
+ controller = _.capitalize(patterns[1]) + defaultControllers[_.last(patterns)];
+ config.controller = state.controller || controller;
+ }
+ result[name] = config;
+ });
+ return result;
+ })
+
+ .decorator('url', function(state, parent) {
+ var defaultUrl;
+
+ if (state.abstract) {
+ defaultUrl = '';
} else {
- // Replaces the first point through a slash (the app name)
- var appName = state.name.replace('.', '/');
- // Replaces any folowing points though a -
- templateUrl = 'static/templates/' + appName.replace(/\./g, '-') + '.html';
- }
- config.templateUrl = state.templateUrl || templateUrl;
+ var patterns = state.name.split('.'),
+ defaultUrls = {
+ create: '/new',
+ update: '/edit',
+ list: '',
+ // The id is expected to be an integer, if not, the url has to
+ // be defined manually
+ detail: '/{id:int}',
+ };
- // controller
- if (patterns.length >= 3) {
- controller = _.capitalize(patterns[1]) + defaultControllers[_.last(patterns)];
- config.controller = state.controller || controller;
+ defaultUrl = defaultUrls[_.last(patterns)];
}
- result[name] = config;
+
+ state.url = state.url || defaultUrl;
+ return parent(state);
});
- return result;
- })
+ }
+])
- .decorator('url', function(state, parent) {
- var defaultUrl;
-
- if (state.abstract) {
- defaultUrl = '';
- } else {
- var patterns = state.name.split('.'),
- defaultUrls = {
- create: '/new',
- update: '/edit',
- list: '',
- // The id is expected to be an integer, if not, the url has to
- // be defined manually
- detail: '/{id:int}',
- };
-
- defaultUrl = defaultUrls[_.last(patterns)];
- }
-
- state.url = state.url || defaultUrl;
- return parent(state);
- });
-})
-
-.config(function($stateProvider, $locationProvider) {
- // Core urls
- $stateProvider
- .state('dashboard', {
- url: '/',
- templateUrl: 'static/templates/dashboard.html'
- })
- .state('projector', {
- url: '/projector',
- data: {extern: true},
- onEnter: function($window) {
- $window.location.href = this.url;
- }
- })
- .state('core', {
- url: '/core',
- abstract: true,
- template: "
",
- })
- // legal notice and version
- .state('legalnotice', {
- url: '/legalnotice',
- controller: 'LegalNoticeCtrl',
- })
- //config
- .state('config', {
- url: '/config',
- controller: 'ConfigCtrl',
- resolve: {
- configOption: function($http) {
- return $http({ 'method': 'OPTIONS', 'url': '/rest/core/config/' });
- }
- }
- })
- // customslide
- .state('core.customslide', {
- url: '/customslide',
- abstract: true,
- template: "
",
- })
- .state('core.customslide.detail', {
- resolve: {
- customslide: function(Customslide, $stateParams) {
- return Customslide.find($stateParams.id);
- }
- }
- })
- .state('core.customslide.detail.update', {
- onEnter: ['$stateParams', 'ngDialog', 'Customslide', function($stateParams, ngDialog, Customslide) {
- ngDialog.open({
- template: 'static/templates/core/customslide-form.html',
- controller: 'CustomslideUpdateCtrl',
- className: 'ngdialog-theme-default wide-form',
- resolve: { customslide: function() {
- return Customslide.find($stateParams.id) }}
- });
- }]
- })
- // tag
- .state('core.tag', {
- url: '/tag',
- abstract: true,
- template: "
",
- })
- .state('core.tag.list', {
- resolve: {
- tags: function(Tag) {
- return Tag.findAll();
- }
- }
- })
- .state('core.tag.create', {})
- .state('core.tag.detail', {
- resolve: {
- tag: function(Tag, $stateParams) {
- return Tag.find($stateParams.id);
- }
- }
- })
- .state('core.tag.detail.update', {
- views: {
- '@core.tag': {}
- }
- });
-
- $locationProvider.html5Mode(true);
-})
-
-// Helper to add ui.router states at runtime.
-// Needed for the django url_patterns.
-.provider('runtimeStates', function($stateProvider) {
- this.$get = function($q, $timeout, $state) {
- return {
- addState: function(name, state) {
- $stateProvider.state(name, state);
- }
- };
- };
-})
-
-// Load the django url patterns
-.run(function(runtimeStates, $http) {
- $http.get('/core/url_patterns/').then(function(data) {
- for (var pattern in data.data) {
- runtimeStates.addState(pattern, {
- 'url': data.data[pattern],
+.config([
+ '$stateProvider',
+ '$locationProvider',
+ function($stateProvider, $locationProvider) {
+ // Core urls
+ $stateProvider
+ .state('dashboard', {
+ url: '/',
+ templateUrl: 'static/templates/dashboard.html'
+ })
+ .state('projector', {
+ url: '/projector',
data: {extern: true},
onEnter: function($window) {
$window.location.href = this.url;
}
+ })
+ .state('core', {
+ url: '/core',
+ abstract: true,
+ template: "
",
+ })
+ // legal notice and version
+ .state('legalnotice', {
+ url: '/legalnotice',
+ controller: 'LegalNoticeCtrl',
+ })
+ //config
+ .state('config', {
+ url: '/config',
+ controller: 'ConfigCtrl',
+ resolve: {
+ configOption: function($http) {
+ return $http({ 'method': 'OPTIONS', 'url': '/rest/core/config/' });
+ }
+ }
+ })
+ // customslide
+ .state('core.customslide', {
+ url: '/customslide',
+ abstract: true,
+ template: "
",
+ })
+ .state('core.customslide.detail', {
+ resolve: {
+ customslide: function(Customslide, $stateParams) {
+ return Customslide.find($stateParams.id);
+ }
+ }
+ })
+ // redirects to customslide detail and opens customslide edit form dialog, uses edit url,
+ // used by ui-sref links from agenda only
+ // (from customslide controller use CustomSlideForm factory instead to open dialog in front
+ // of current view without redirect)
+ .state('core.customslide.detail.update', {
+ onEnter: ['$stateParams', '$state', 'ngDialog', 'Customslide',
+ function($stateParams, $state, ngDialog, Customslide) {
+ ngDialog.open({
+ template: 'static/templates/core/customslide-form.html',
+ controller: 'CustomslideUpdateCtrl',
+ className: 'ngdialog-theme-default wide-form',
+ resolve: {
+ customslide: function() {return Customslide.find($stateParams.id) }
+ },
+ preCloseCallback: function() {
+ $state.go('core.customslide.detail', {customslide: $stateParams.id});
+ return true;
+ }
+ });
+ }]
+ })
+ // tag
+ .state('core.tag', {
+ url: '/tag',
+ abstract: true,
+ template: "
",
+ })
+ .state('core.tag.list', {
+ resolve: {
+ tags: function(Tag) {
+ return Tag.findAll();
+ }
+ }
+ })
+ .state('core.tag.create', {})
+ .state('core.tag.detail', {
+ resolve: {
+ tag: function(Tag, $stateParams) {
+ return Tag.find($stateParams.id);
+ }
+ }
+ })
+ .state('core.tag.detail.update', {
+ views: {
+ '@core.tag': {}
+ }
});
- }
- });
-})
+
+ $locationProvider.html5Mode(true);
+ }
+])
+
+// Helper to add ui.router states at runtime.
+// Needed for the django url_patterns.
+.provider('runtimeStates', [
+ '$stateProvider',
+ function($stateProvider) {
+ this.$get = function($q, $timeout, $state) {
+ return {
+ addState: function(name, state) {
+ $stateProvider.state(name, state);
+ }
+ };
+ };
+ }
+])
+
+// Load the django url patterns
+.run([
+ 'runtimeStates',
+ '$http',
+ function(runtimeStates, $http) {
+ $http.get('/core/url_patterns/').then(function(data) {
+ for (var pattern in data.data) {
+ runtimeStates.addState(pattern, {
+ 'url': data.data[pattern],
+ data: {extern: true},
+ onEnter: function($window) {
+ $window.location.href = this.url;
+ }
+ });
+ }
+ });
+ }
+])
// angular formly config options
.run([
@@ -311,42 +346,46 @@ angular.module('OpenSlidesApp.core.site', [
// html-tag os-form-field to generate generic from fields
// TODO: make it possible to use other fields then config fields
-.directive('osFormField', function($parse, Config) {
- function getHtmlType(type) {
- return {
- string: 'text',
- text: 'textarea',
- integer: 'number',
- boolean: 'checkbox',
- choice: 'choice',
- }[type];
- }
-
- return {
- restrict: 'E',
- scope: true,
- templateUrl: '/static/templates/config-form-field.html',
- link: function ($scope, iElement, iAttrs, controller, transcludeFn) {
- var field = $parse(iAttrs.field)($scope);
- var config = Config.get(field.key);
- $scope.type = getHtmlType(field.input_type);
- if ($scope.type == 'choice') {
- $scope.choices = field.choices;
- }
- $scope.label = field.label;
- $scope.key = 'field-' + field.key;
- $scope.value = config.value;
- $scope.help_text = field.help_text;
- $scope.default_value = field.default_value;
- $scope.reset = function () {
- $scope.value = $scope.default_value;
- $scope.save(field.key, $scope.value);
- }
+.directive('osFormField', [
+ '$parse',
+ 'Config',
+ function($parse, Config) {
+ function getHtmlType(type) {
+ return {
+ string: 'text',
+ text: 'textarea',
+ integer: 'number',
+ boolean: 'checkbox',
+ choice: 'choice',
+ }[type];
}
- };
-})
-.controller("MainMenuCtrl", [
+ return {
+ restrict: 'E',
+ scope: true,
+ templateUrl: '/static/templates/config-form-field.html',
+ link: function ($scope, iElement, iAttrs, controller, transcludeFn) {
+ var field = $parse(iAttrs.field)($scope);
+ var config = Config.get(field.key);
+ $scope.type = getHtmlType(field.input_type);
+ if ($scope.type == 'choice') {
+ $scope.choices = field.choices;
+ }
+ $scope.label = field.label;
+ $scope.key = 'field-' + field.key;
+ $scope.value = config.value;
+ $scope.help_text = field.help_text;
+ $scope.default_value = field.default_value;
+ $scope.reset = function () {
+ $scope.value = $scope.default_value;
+ $scope.save(field.key, $scope.value);
+ }
+ }
+ };
+ }
+])
+
+.controller('MainMenuCtrl', [
'$scope',
'mainMenu',
function ($scope, mainMenu) {
@@ -354,15 +393,21 @@ angular.module('OpenSlidesApp.core.site', [
}
])
-.controller("LanguageCtrl", function ($scope, gettextCatalog, Languages, filterFilter) {
- $scope.languages = Languages.getLanguages();
- $scope.selectedLanguage = filterFilter($scope.languages, {selected: true});
- // controller to switch app language
- $scope.switchLanguage = function (lang) {
- $scope.languages = Languages.setCurrentLanguage(lang);
+.controller('LanguageCtrl', [
+ '$scope',
+ 'gettextCatalog',
+ 'Languages',
+ 'filterFilter',
+ function ($scope, gettextCatalog, Languages, filterFilter) {
+ $scope.languages = Languages.getLanguages();
$scope.selectedLanguage = filterFilter($scope.languages, {selected: true});
- };
-})
+ // controller to switch app language
+ $scope.switchLanguage = function (lang) {
+ $scope.languages = Languages.setCurrentLanguage(lang);
+ $scope.selectedLanguage = filterFilter($scope.languages, {selected: true});
+ };
+ }
+])
// Projector Sidebar Controller
.controller('ProjectorSidebarCtrl', [
@@ -388,25 +433,46 @@ angular.module('OpenSlidesApp.core.site', [
])
// Config Controller
-.controller('ConfigCtrl', function($scope, Config, configOption) {
- Config.bindAll({}, $scope, 'configs');
- $scope.configGroups = configOption.data.config_groups;
+.controller('ConfigCtrl', [
+ '$scope',
+ 'Config',
+ 'configOption',
+ function($scope, Config, configOption) {
+ Config.bindAll({}, $scope, 'configs');
+ $scope.configGroups = configOption.data.config_groups;
- // save changed config value
- $scope.save = function(key, value) {
- Config.get(key).value = value;
- Config.save(key);
- };
-})
+ // save changed config value
+ $scope.save = function(key, value) {
+ Config.get(key).value = value;
+ Config.save(key);
+ };
+ }
+])
// Provide generic customslide form fields for create and update view
-.factory('CustomslideFormFieldFactory', [
+.factory('CustomslideForm', [
'gettextCatalog',
'CKEditorOptions',
'Mediafile',
function (gettextCatalog, CKEditorOptions, Mediafile) {
return {
+ // ngDialog for customslide form
+ getDialog: function (customslide) {
+ if (customslide) {
+ var resolve = {
+ customslide: function(Customslide) {return Customslide.find(customslide.id);}
+ };
+ }
+ return {
+ template: 'static/templates/core/customslide-form.html',
+ controller: (customslide) ? 'CustomslideUpdateCtrl' : 'CustomslideCreateCtrl',
+ className: 'ngdialog-theme-default wide-form',
+ closeByEscape: false,
+ closeByDocument: false,
+ resolve: (resolve) ? resolve : null
+ }
+ },
getFormFields: function () {
return [
{
@@ -641,20 +707,32 @@ angular.module('OpenSlidesApp.core.site', [
])
// Customslide Controllers
-.controller('CustomslideDetailCtrl', function($scope, Customslide, customslide) {
- Customslide.bindOne(customslide.id, $scope, 'customslide');
- Customslide.loadRelations(customslide, 'agenda_item');
-})
+.controller('CustomslideDetailCtrl', [
+ '$scope',
+ 'ngDialog',
+ 'CustomslideForm',
+ 'Customslide',
+ 'customslide',
+ function($scope, ngDialog, CustomslideForm, Customslide, customslide) {
+ Customslide.bindOne(customslide.id, $scope, 'customslide');
+ Customslide.loadRelations(customslide, 'agenda_item');
+
+ // open edit dialog
+ $scope.openDialog = function (customslide) {
+ ngDialog.open(CustomslideForm.getDialog(customslide));
+ };
+ }
+])
.controller('CustomslideCreateCtrl', [
'$scope',
'$state',
'Customslide',
- 'CustomslideFormFieldFactory',
- function($scope, $state, Customslide, CustomslideFormFieldFactory) {
+ 'CustomslideForm',
+ function($scope, $state, Customslide, CustomslideForm) {
$scope.customslide = {};
// get all form fields
- $scope.formFields = CustomslideFormFieldFactory.getFormFields();
+ $scope.formFields = CustomslideForm.getFormFields();
// save form
$scope.save = function (customslide) {
@@ -671,19 +749,34 @@ angular.module('OpenSlidesApp.core.site', [
'$scope',
'$state',
'Customslide',
- 'CustomslideFormFieldFactory',
+ 'CustomslideForm',
'customslide',
- function($scope, $state, Customslide, CustomslideFormFieldFactory, customslide) {
- // set initial values for form model
- $scope.model = customslide;
+ function($scope, $state, Customslide, CustomslideForm, customslide) {
+ $scope.alert = {};
+ // set initial values for form model by create deep copy of customslide object
+ // so list/detail view is not updated while editing
+ $scope.model = angular.copy(customslide);
// get all form fields
- $scope.formFields = CustomslideFormFieldFactory.getFormFields();
+ $scope.formFields = CustomslideForm.getFormFields();
// save form
$scope.save = function (customslide) {
+ // inject the changed customslide (copy) object back into DS store
+ Customslide.inject(customslide);
+ // save change customslide object on server
Customslide.save(customslide).then(
function(success) {
$scope.closeThisDialog();
+ },
+ function (error) {
+ // save error: revert all changes by restore
+ // (refresh) original customslide object from server
+ Customslide.refresh(customslide);
+ var message = '';
+ for (var e in error.data) {
+ message += e + ': ' + error.data[e] + ' ';
+ }
+ $scope.alert = {type: 'danger', msg: message, show: true};
}
);
};
@@ -691,58 +784,78 @@ angular.module('OpenSlidesApp.core.site', [
])
// Tag Controller
-.controller('TagListCtrl', function($scope, Tag) {
- Tag.bindAll({}, $scope, 'tags');
+.controller('TagListCtrl', [
+ '$scope',
+ 'Tag',
+ function($scope, Tag) {
+ Tag.bindAll({}, $scope, 'tags');
- // setup table sorting
- $scope.sortColumn = 'name';
- $scope.reverse = false;
- // function to sort by clicked column
- $scope.toggleSort = function ( column ) {
- if ( $scope.sortColumn === column ) {
- $scope.reverse = !$scope.reverse;
- }
- $scope.sortColumn = column;
- };
-
- // save changed tag
- $scope.save = function (tag) {
- Tag.save(tag);
- };
- $scope.delete = function (tag) {
- Tag.destroy(tag.id).then(
- function(success) {
- //TODO: success message
+ // setup table sorting
+ $scope.sortColumn = 'name';
+ $scope.reverse = false;
+ // function to sort by clicked column
+ $scope.toggleSort = function ( column ) {
+ if ( $scope.sortColumn === column ) {
+ $scope.reverse = !$scope.reverse;
}
- );
- };
-})
+ $scope.sortColumn = column;
+ };
-.controller('TagDetailCtrl', function($scope, Tag, tag) {
- Tag.bindOne(tag.id, $scope, 'tag');
-})
+ // save changed tag
+ $scope.save = function (tag) {
+ Tag.save(tag);
+ };
+ $scope.delete = function (tag) {
+ Tag.destroy(tag.id).then(
+ function(success) {
+ //TODO: success message
+ }
+ );
+ };
+ }
+])
-.controller('TagCreateCtrl', function($scope, $state, Tag) {
- $scope.tag = {};
- $scope.save = function (tag) {
- Tag.create(tag).then(
- function(success) {
- $state.go('core.tag.list');
- }
- );
- };
-})
+.controller('TagDetailCtrl', [
+ '$scope',
+ 'Tag',
+ 'tag',
+ function($scope, Tag, tag) {
+ Tag.bindOne(tag.id, $scope, 'tag');
+ }
+])
-.controller('TagUpdateCtrl', function($scope, $state, Tag, tag) {
- $scope.tag = tag;
- $scope.save = function (tag) {
- Tag.save(tag).then(
- function(success) {
- $state.go('core.tag.list');
- }
- );
- };
-})
+.controller('TagCreateCtrl', [
+ '$scope',
+ '$state',
+ 'Tag',
+ function($scope, $state, Tag) {
+ $scope.tag = {};
+ $scope.save = function (tag) {
+ Tag.create(tag).then(
+ function(success) {
+ $state.go('core.tag.list');
+ }
+ );
+ };
+ }
+])
+
+.controller('TagUpdateCtrl', [
+ '$scope',
+ '$state',
+ 'Tag',
+ 'tag',
+ function($scope, $state, Tag, tag) {
+ $scope.tag = tag;
+ $scope.save = function (tag) {
+ Tag.save(tag).then(
+ function(success) {
+ $state.go('core.tag.list');
+ }
+ );
+ };
+ }
+])
// counter of new (unread) chat messages
.value('NewChatMessages', [])
@@ -793,14 +906,17 @@ angular.module('OpenSlidesApp.core.site', [
}
])
-.directive('osFocusMe', function ($timeout) {
- return {
- link: function (scope, element, attrs, model) {
- $timeout(function () {
- element[0].focus();
- });
- }
- };
-});
+.directive('osFocusMe', [
+ '$timeout',
+ function ($timeout) {
+ return {
+ link: function (scope, element, attrs, model) {
+ $timeout(function () {
+ element[0].focus();
+ });
+ }
+ };
+ }
+]);
}());
diff --git a/openslides/core/static/templates/core/customslide-detail.html b/openslides/core/static/templates/core/customslide-detail.html
index 383ea335a..4f5ef9dfd 100644
--- a/openslides/core/static/templates/core/customslide-detail.html
+++ b/openslides/core/static/templates/core/customslide-detail.html
@@ -17,6 +17,12 @@
title="{{ 'Project agenda item' | translate }}">
+
+
+
+
diff --git a/openslides/core/static/templates/core/customslide-form.html b/openslides/core/static/templates/core/customslide-form.html
index 2ad1ce6cc..48257ac1a 100644
--- a/openslides/core/static/templates/core/customslide-form.html
+++ b/openslides/core/static/templates/core/customslide-form.html
@@ -1,6 +1,10 @@