diff --git a/openslides/agenda/static/js/agenda/site.js b/openslides/agenda/static/js/agenda/site.js index f9126ab06..574076fae 100644 --- a/openslides/agenda/static/js/agenda/site.js +++ b/openslides/agenda/static/js/agenda/site.js @@ -96,9 +96,10 @@ angular.module('OpenSlidesApp.agenda.site', [ 'osTableFilter', 'AgendaCsvExport', 'PdfCreate', + 'ErrorMessage', function($scope, $filter, $http, $state, DS, operator, ngDialog, Agenda, TopicForm, AgendaTree, Projector, ProjectionDefault, AgendaContentProvider, PdfMakeDocumentProvider, - gettextCatalog, gettext, osTableFilter, AgendaCsvExport, PdfCreate) { + gettextCatalog, gettext, osTableFilter, AgendaCsvExport, PdfCreate, ErrorMessage) { // Bind agenda tree to the scope $scope.$watch(function () { return Agenda.lastModified(); @@ -232,15 +233,11 @@ angular.module('OpenSlidesApp.agenda.site', [ // save changed item $scope.save = function (item) { Agenda.save(item).then( - function(success) { + function (success) { $scope.alert.show = false; }, - function(error){ - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = { type: 'danger', msg: message, show: true }; + function (error) { + $scope.alert = ErrorMessage.forAlert(error); }); }; // delete related item @@ -393,7 +390,8 @@ angular.module('OpenSlidesApp.agenda.site', [ 'itemId', 'Projector', 'ProjectionDefault', - function ($scope, $filter, Agenda, itemId, Projector, ProjectionDefault) { + 'ErrorMessage', + function ($scope, $filter, Agenda, itemId, Projector, ProjectionDefault, ErrorMessage) { $scope.alert = {}; $scope.$watch(function () { @@ -447,16 +445,16 @@ angular.module('OpenSlidesApp.agenda.site', [ // add user to list of speakers $scope.addSpeaker = function (userId) { - $http.post('/rest/agenda/item/' + $scope.item.id + '/manage_speaker/', {'user': userId}) - .success(function (data){ - $scope.alert.show = false; - $scope.speakers = $scope.item.speakers; - $scope.speakerSelectBox = {}; - }) - .error(function (data){ - $scope.alert = {type: 'danger', msg: data.detail, show: true}; - $scope.speakerSelectBox = {}; - }); + $http.post('/rest/agenda/item/' + $scope.item.id + '/manage_speaker/', {'user': userId}).then( + function (success) { + $scope.alert.show = false; + $scope.speakers = $scope.item.speakers; + $scope.speakerSelectBox = {}; + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); + $scope.speakerSelectBox = {}; + } + ); }; // delete speaker(!) from list of speakers @@ -466,11 +464,10 @@ angular.module('OpenSlidesApp.agenda.site', [ {headers: {'Content-Type': 'application/json'}, data: JSON.stringify({speaker: speakerId})} ) - .success(function(data){ + .then(function (success) { $scope.speakers = $scope.item.speakers; - }) - .error(function(data){ - $scope.alert = { type: 'danger', msg: data.detail, show: true }; + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); }); $scope.speakers = $scope.item.speakers; }; @@ -486,11 +483,10 @@ angular.module('OpenSlidesApp.agenda.site', [ {headers: {'Content-Type': 'application/json'}, data: JSON.stringify({speaker: speakersOnList})} ) - .success(function(data){ + .then(function (success) { $scope.speakers = $scope.item.speakers; - }) - .error(function(data){ - $scope.alert = { type: 'danger', msg: data.detail, show: true }; + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); }); $scope.speakers = $scope.item.speakers; }; @@ -529,11 +525,10 @@ angular.module('OpenSlidesApp.agenda.site', [ // begin speech of selected/next speaker $scope.beginSpeech = function (speakerId) { $http.put('/rest/agenda/item/' + $scope.item.id + '/speak/', {'speaker': speakerId}) - .success(function(data){ + .then(function (success) { $scope.alert.show = false; - }) - .error(function(data){ - $scope.alert = { type: 'danger', msg: data.detail, show: true }; + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); }); }; @@ -542,10 +537,12 @@ angular.module('OpenSlidesApp.agenda.site', [ $http.delete( '/rest/agenda/item/' + $scope.item.id + '/speak/', {headers: {'Content-Type': 'application/json'}, data: {}} - ) - .error(function(data){ - $scope.alert = { type: 'danger', msg: data.detail, show: true }; - }); + ).then( + function (success) {}, + function (error) { + $scope.alert = ErrorMessage.forAlert(error); + } + ); }; // gets speech duration of selected speaker in seconds $scope.getDuration = function (speaker) { @@ -576,7 +573,8 @@ angular.module('OpenSlidesApp.agenda.site', [ '$http', 'Agenda', 'AgendaTree', - function($scope, $http, Agenda, AgendaTree) { + 'ErrorMessage', + function($scope, $http, Agenda, AgendaTree, ErrorMessage) { // Bind agenda tree to the scope $scope.$watch(function () { return Agenda.lastModified(); @@ -600,7 +598,7 @@ angular.module('OpenSlidesApp.agenda.site', [ ).then( function(success) {}, function(error){ - $scope.alert = {type: 'danger', msg: error.data.detail, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); } diff --git a/openslides/assignments/static/js/assignments/site.js b/openslides/assignments/static/js/assignments/site.js index 1121966f6..5a4558ab1 100644 --- a/openslides/assignments/static/js/assignments/site.js +++ b/openslides/assignments/static/js/assignments/site.js @@ -422,9 +422,11 @@ angular.module('OpenSlidesApp.assignments.site', [ 'gettextCatalog', 'PdfCreate', 'AssignmentPhases', + 'ErrorMessage', function($scope, $http, $filter, filterFilter, gettext, ngDialog, AssignmentForm, operator, Assignment, User, assignmentId, Projector, ProjectionDefault, AssignmentContentProvider, BallotContentProvider, - PdfMakeDocumentProvider, PdfMakeBallotPaperProvider, gettextCatalog, PdfCreate, AssignmentPhases) { + PdfMakeDocumentProvider, PdfMakeBallotPaperProvider, gettextCatalog, PdfCreate, AssignmentPhases, + ErrorMessage) { var assignment = Assignment.get(assignmentId); User.bindAll({}, $scope, 'users'); Assignment.loadRelations(assignment, 'agenda_item'); @@ -455,12 +457,11 @@ angular.module('OpenSlidesApp.assignments.site', [ // add (nominate) candidate $scope.addCandidate = function (userId) { $http.post('/rest/assignments/assignment/' + assignment.id + '/candidature_other/', {'user': userId}) - .success(function(data){ + .then(function (success){ $scope.alert.show = false; $scope.candidateSelectBox = {}; - }) - .error(function(data){ - $scope.alert = { type: 'danger', msg: data.detail, show: true }; + }, function (error){ + $scope.alert = ErrorMessage.forAlert(error); $scope.candidateSelectBox = {}; }); }; @@ -469,29 +470,31 @@ angular.module('OpenSlidesApp.assignments.site', [ $http.delete('/rest/assignments/assignment/' + assignment.id + '/candidature_other/', {headers: {'Content-Type': 'application/json'}, data: JSON.stringify({user: userId})}) - .error(function(data){ - $scope.alert = { type: 'danger', msg: data.detail, show: true }; - }); + .then(function (success) {}, + function (error) { + $scope.alert = ErrorMessage.forAlert(error); + } + ); }; // add me (nominate self as candidate) $scope.addMe = function () { - $http.post('/rest/assignments/assignment/' + assignment.id + '/candidature_self/', {}) - .success(function(data){ + $http.post('/rest/assignments/assignment/' + assignment.id + '/candidature_self/', {}).then( + function (success) { $scope.alert.show = false; - }) - .error(function(data){ - $scope.alert = { type: 'danger', msg: data.detail, show: true }; - }); + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); + } + ); }; // remove me (withdraw own candidature) $scope.removeMe = function () { - $http.delete('/rest/assignments/assignment/' + assignment.id + '/candidature_self/') - .success(function(data){ + $http.delete('/rest/assignments/assignment/' + assignment.id + '/candidature_self/').then( + function (success) { $scope.alert.show = false; - }) - .error(function(data){ - $scope.alert = { type: 'danger', msg: data.detail, show: true }; - }); + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); + } + ); }; // check if current user is already a candidate (elected==false) $scope.isCandidate = function () { @@ -525,15 +528,14 @@ angular.module('OpenSlidesApp.assignments.site', [ // create new ballot $scope.createBallot = function () { $scope.activeTab = 0; - $http.post('/rest/assignments/assignment/' + assignment.id + '/create_poll/') - .success(function(data){ + $http.post('/rest/assignments/assignment/' + assignment.id + '/create_poll/').then( + function (success) { $scope.alert.show = false; if (assignment.phase === 0) { $scope.updatePhase(1); } - }) - .error(function(data){ - $scope.alert = { type: 'danger', msg: data.detail, show: true }; + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); }); }; // delete ballot @@ -560,15 +562,10 @@ angular.module('OpenSlidesApp.assignments.site', [ assignment_id: assignment.id, published: !poll.published, }) - .then(function(success) { + .then(function (success) { $scope.alert.show = false; - }) - .catch(function(error) { - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = { type: 'danger', msg: message, show: true }; + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); }); }; @@ -637,7 +634,8 @@ angular.module('OpenSlidesApp.assignments.site', [ 'AssignmentForm', 'Agenda', 'AgendaUpdate', - function($scope, $state, Assignment, AssignmentForm, Agenda, AgendaUpdate) { + 'ErrorMessage', + function($scope, $state, Assignment, AssignmentForm, Agenda, AgendaUpdate, ErrorMessage) { $scope.model = {}; // set default value for open posts form field $scope.model.open_posts = 1; @@ -646,7 +644,7 @@ angular.module('OpenSlidesApp.assignments.site', [ // save assignment $scope.save = function(assignment, gotoDetailView) { Assignment.create(assignment).then( - function(success) { + function (success) { // type: Value 1 means a non hidden agenda item, value 2 means a hidden agenda item, // see openslides.agenda.models.Item.ITEM_TYPE. var changes = [{key: 'type', value: (assignment.showAsAgendaItem ? 1 : 2)}, @@ -656,6 +654,9 @@ angular.module('OpenSlidesApp.assignments.site', [ $state.go('assignments.assignment.detail', {id: success.id}); } $scope.closeThisDialog(); + }, + function (error) { + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -670,7 +671,8 @@ angular.module('OpenSlidesApp.assignments.site', [ 'Agenda', 'AgendaUpdate', 'assignmentId', - function($scope, $state, Assignment, AssignmentForm, Agenda, AgendaUpdate, assignmentId) { + 'ErrorMessage', + function($scope, $state, Assignment, AssignmentForm, Agenda, AgendaUpdate, assignmentId, ErrorMessage) { var assignment = Assignment.get(assignmentId); $scope.alert = {}; // set initial values for form model by create deep copy of assignment object @@ -707,11 +709,7 @@ angular.module('OpenSlidesApp.assignments.site', [ // save error: revert all changes by restore // (refresh) original assignment object from server Assignment.refresh(assignment); - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -725,7 +723,8 @@ angular.module('OpenSlidesApp.assignments.site', [ 'AssignmentPoll', 'assignmentpollId', 'ballot', - function($scope, $filter, gettextCatalog, AssignmentPoll, assignmentpollId, ballot) { + 'ErrorMessage', + function($scope, $filter, gettextCatalog, AssignmentPoll, assignmentpollId, ballot, ErrorMessage) { // set initial values for form model by create deep copy of assignmentpoll object // so detail view is not updated while editing poll var assignmentpoll = angular.copy(AssignmentPoll.get(assignmentpollId)); @@ -879,13 +878,8 @@ angular.module('OpenSlidesApp.assignments.site', [ .then(function(success) { $scope.alert.show = false; $scope.closeThisDialog(); - }) - .catch(function(error) { - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = { type: 'danger', msg: message, show: true }; + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); }); }; } diff --git a/openslides/core/static/css/app.css b/openslides/core/static/css/app.css index c082cd255..6bd6f1e90 100644 --- a/openslides/core/static/css/app.css +++ b/openslides/core/static/css/app.css @@ -1156,42 +1156,46 @@ img { font-size: 90%; } -/** Pdf creation status bar **/ -#pdf-status { +/** Messaging status bar **/ +#messaging { position: fixed; bottom: 0; width: 100%; - z-index: 100; + z-index: 100000; } -#pdf-status-container { +#messaging-container { margin: 0 auto 0 auto; padding: 0px 20px; max-width: 1400px; } -#pdf-status-container > div { +#messaging-container > div { margin-bottom: 10px; padding: 10px 20px; border-radius: 6px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); } -#pdf-status .generating { +#messaging .info { color: #222; background-color: #bed4de; border-color: #46b8da; } -#pdf-status .error { +#messaging .error { color: #a94442; background-color: #f2dede; border-color: #ebccd1; } -#pdf-status .finished { +#messaging .success { color: #3c763d; background-color: #dff0d8; border-color: #d6e9c6; } +#messaging .warning { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} /** General helper classes **/ - .disabled { color: #555; cursor: not-allowed !important; diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js index 34d9efa0f..2bd0b6667 100644 --- a/openslides/core/static/js/core/base.js +++ b/openslides/core/static/js/core/base.js @@ -47,7 +47,8 @@ angular.module('OpenSlidesApp.core', [ 'REALM', 'ProjectorID', '$q', - function (DS, REALM, ProjectorID, $q) { + 'ErrorMessage', + function (DS, REALM, ProjectorID, $q, ErrorMessage) { var socket = null; var recInterval = null; @@ -82,11 +83,12 @@ angular.module('OpenSlidesApp.core', [ Autoupdate.newConnect = function () { socket = new WebSocket(websocketProtocol + '//' + location.host + websocketPath); clearInterval(recInterval); - socket.onclose = function () { + socket.onclose = function (event) { socket = null; recInterval = setInterval(function () { Autoupdate.newConnect(); }, 1000); + ErrorMessage.setConnectionError(); }; socket.onmessage = function (event) { _.forEach(Autoupdate.messageReceivers, function (receiver) { @@ -96,6 +98,7 @@ angular.module('OpenSlidesApp.core', [ if (Autoupdate.firstMessageDeferred.promise.$$state.status === 0) { Autoupdate.firstMessageDeferred.resolve(); } + ErrorMessage.clearConnectionError(); }; }; return Autoupdate; @@ -460,6 +463,108 @@ angular.module('OpenSlidesApp.core', [ } ]) +.factory('ErrorMessage', [ + '$timeout', + 'gettextCatalog', + 'Messaging', + function ($timeout, gettextCatalog, Messaging) { + return { + forAlert: function (error) { + var message = gettextCatalog.getString('Error') + ': '; + + if (!error.data) { + message += gettextCatalog.getString("The server didn't respond."); + } else if (error.data.detail) { + message += error.data.detail; + } else { + for (var e in error.data) { + message += e + ': ' + error.data[e] + ' '; + } + } + return { type: 'danger', msg: message, show: true }; + }, + setConnectionError: function () { + $timeout(function () { + Messaging.createOrEditMessage( + 'connectionLostMessage', + gettextCatalog.getString('Connection lost. You are not connected to the server anymore.'), + 'error', + {noClose: true}); + }, 1); + }, + clearConnectionError: function () { + $timeout(function () { + Messaging.deleteMessage('connectionLostMessage'); + }, 1); + }, + }; + } +]) + +/* Messaging factory. The text is html-binded into the document, so you can + * provide also html markup for the messages. There are 4 types: 'info', + * 'success', 'warning', 'error'. The timeout is for autodeleting the message. + * Args that could be provided: + * - timeout: Milliseconds until autoclose the message + * - noClose: Whether to show the close button*/ +.factory('Messaging', [ + '$timeout', + function($timeout) { + var callbackList = [], + messages = {}, + idCounter = 0; + + var onChange = function () { + _.forEach(callbackList, function (callback) { + callback(); + }); + }; + + return { + addMessage: function (text, type, args) { + var id = idCounter++; + return this.createOrEditMessage(id, text, type, args); + }, + createOrEditMessage: function (id, text, type, args) { + if (!args) { + args = {}; + } + if (messages[id] && messages[id].timeout) { + $timeout.cancel(messages[id].timeout); + } + messages[id] = { + text: text, + type: type, + id: id, + args: args, + }; + if (typeof args.timeout === 'number' && args.timeout > 0) { + var self = this; + messages[id].timeout = $timeout(function () { + self.deleteMessage(id); + }, args.timeout); + } + onChange(); + return id; + }, + deleteMessage: function (id) { + delete messages[id]; + onChange(); + }, + getMessages: function () { + return messages; + }, + registerMessageChangeCallback: function (fn) { + if (typeof fn === 'function') { + callbackList.push(fn); + } else { + throw 'fn has to be a function'; + } + }, + }; + } +]) + .factory('Tag', [ 'DS', function(DS) { diff --git a/openslides/core/static/js/core/pdf.js b/openslides/core/static/js/core/pdf.js index b750c6f11..2f3b95749 100644 --- a/openslides/core/static/js/core/pdf.js +++ b/openslides/core/static/js/core/pdf.js @@ -784,8 +784,9 @@ angular.module('OpenSlidesApp.core.pdf', []) .factory('PdfCreate', [ '$timeout', 'FileSaver', - function ($timeout, FileSaver) { - var stateChangeCallbacks = []; + 'Messaging', + function ($timeout, FileSaver, Messaging) { + var filenameMessageMap = {}; var b64toBlob = function(b64Data) { var byteCharacters = atob(b64Data); var byteNumbers = new Array(byteCharacters.length); @@ -797,18 +798,36 @@ angular.module('OpenSlidesApp.core.pdf', []) return blob; }; var stateChange = function (state, filename, error) { - _.forEach(stateChangeCallbacks, function (cb) { - $timeout(function () {cb(state, filename, error);}, 1); - }); + var text, timeout; + switch (state) { + case 'info': + text = '' + + 'Generating PDF file ' + filename + ' ...'; + break; + case 'success': + text = '' + + 'PDF successfully generated.'; + timeout = 3000; + break; + case 'error': + text = '' + + 'Error while generating PDF file ' + filename + ':' + + '{{ pdf.errorMessage | translate }}' ; + break; + } + $timeout(function () { + filenameMessageMap[filename] = Messaging.createOrEditMessage( + filenameMessageMap[filename], text, state, {timeout: timeout}); + }, 1); }; return { download: function (pdfDocument, filename) { - stateChange('generating', filename); + stateChange('info', filename); var pdfWorker = new Worker('/static/js/workers/pdf-worker.js'); pdfWorker.addEventListener('message', function (event) { var blob = b64toBlob(event.data); - stateChange('finished', filename); + stateChange('success', filename); FileSaver.saveAs(blob, filename); }); pdfWorker.addEventListener('error', function (event) { @@ -816,43 +835,6 @@ angular.module('OpenSlidesApp.core.pdf', []) }); pdfWorker.postMessage(JSON.stringify(pdfDocument)); }, - registerStateChangeCallback: function (cb) { - if (cb && typeof cb === 'function') { - stateChangeCallbacks.push(cb); - } - }, - }; - } -]) - -.directive('pdfGenerationStatus', [ - '$timeout', - 'PdfCreate', - function($timeout, PdfCreate) { - return { - restrict: 'E', - templateUrl: 'static/templates/pdf-status.html', - scope: {}, - controller: function ($scope, $element, $attrs, $location) { - $scope.pdfs = {}; - - var createStateChange = function (state, filename, error) { - $scope.pdfs[filename] = { - state: state, - errorMessage: error - }; - if (state === 'finished') { - $timeout(function () { - $scope.close(filename); - }, 3000); - } - }; - PdfCreate.registerStateChangeCallback(createStateChange); - - $scope.close = function (filename) { - delete $scope.pdfs[filename]; - }; - }, }; } ]); diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js index 8774db95a..39de51a4a 100644 --- a/openslides/core/static/js/core/site.js +++ b/openslides/core/static/js/core/site.js @@ -806,6 +806,30 @@ angular.module('OpenSlidesApp.core.site', [ } ]) +.directive('messaging', [ + '$timeout', + 'Messaging', + function ($timeout, Messaging) { + return { + restrict: 'E', + templateUrl: 'static/templates/messaging.html', + scope: {}, + controller: function ($scope, $element, $attrs, $location) { + $scope.messages = {}; + + var update = function () { + $scope.messages = Messaging.getMessages(); + }; + Messaging.registerMessageChangeCallback(update); + + $scope.close = function (id) { + Messaging.deleteMessage(id); + }; + }, + }; + } +]) + .controller('MainMenuCtrl', [ '$scope', 'mainMenu', @@ -893,9 +917,9 @@ angular.module('OpenSlidesApp.core.site', [ '$scope', '$http', function ($scope, $http) { - $http.get('/core/version/').success(function(data) { - $scope.core_version = data.openslides_version; - $scope.plugins = data.plugins; + $http.get('/core/version/').then(function (success) { + $scope.core_version = success.data.openslides_version; + $scope.plugins = success.data.plugins; }); } ]) @@ -1424,7 +1448,8 @@ angular.module('OpenSlidesApp.core.site', [ 'ngDialog', 'TagForm', 'gettext', - function($scope, Tag, ngDialog, TagForm, gettext) { + 'ErrorMessage', + function($scope, Tag, ngDialog, TagForm, gettext, ErrorMessage) { Tag.bindAll({}, $scope, 'tags'); $scope.alert = {}; @@ -1447,11 +1472,7 @@ angular.module('OpenSlidesApp.core.site', [ show: true, }; }, function (error) { - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -1465,7 +1486,8 @@ angular.module('OpenSlidesApp.core.site', [ '$scope', 'Tag', 'TagForm', - function($scope, Tag, TagForm) { + 'ErrorMessage', + function($scope, Tag, TagForm, ErrorMessage) { $scope.model = {}; $scope.alert = {}; $scope.formFields = TagForm.getFormFields(); @@ -1475,11 +1497,7 @@ angular.module('OpenSlidesApp.core.site', [ $scope.closeThisDialog(); }, function (error) { - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -1491,7 +1509,8 @@ angular.module('OpenSlidesApp.core.site', [ 'Tag', 'tagId', 'TagForm', - function($scope, Tag, tagId, TagForm) { + 'ErrorMessage', + function($scope, Tag, tagId, TagForm, ErrorMessage) { $scope.model = angular.copy(Tag.get(tagId)); $scope.alert = {}; $scope.formFields = TagForm.getFormFields(); @@ -1503,11 +1522,7 @@ angular.module('OpenSlidesApp.core.site', [ // save error: revert all changes by restore // the original object Tag.refresh(tag); - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); }); }; } @@ -1541,16 +1556,14 @@ angular.module('OpenSlidesApp.core.site', [ $http.post( '/rest/core/chat-message/', {message: $scope.newMessage} - ) - .success(function () { + ).then(function (success) { $scope.newMessage = ''; angular.element('#messageSendButton').removeClass('disabled'); angular.element('#messageInput').removeAttr('disabled'); $timeout(function () { angular.element('#messageInput').focus(); }, 0); - }) - .error(function () { + }, function (error) { angular.element('#messageSendButton').removeClass('disabled'); angular.element('#messageInput').removeAttr('disabled'); }); diff --git a/openslides/core/static/js/core/start.js b/openslides/core/static/js/core/start.js index 77e8a542e..a780009e4 100644 --- a/openslides/core/static/js/core/start.js +++ b/openslides/core/static/js/core/start.js @@ -14,15 +14,15 @@ angular.module('OpenSlidesApp.core.start', []) 'mainMenu', function($http, $rootScope, $state, autoupdate, operator, Group, mainMenu) { $rootScope.openslidesBootstrapDone = false; - $http.get('/users/whoami/').success(function(data) { - $rootScope.guest_enabled = data.guest_enabled; - if (data.user_id === null && !data.guest_enabled) { + $http.get('/users/whoami/').then(function (success) { + $rootScope.guest_enabled = success.data.guest_enabled; + if (success.data.user_id === null && !success.data.guest_enabled) { // Redirect to login dialog if user is not logged in. - $state.go('login', {guest_enabled: data.guest_enabled}); + $state.go('login', {guest_enabled: success.data.guest_enabled}); } else { autoupdate.newConnect(); autoupdate.firstMessageDeferred.promise.then(function () { - operator.setUser(data.user_id, data.user); + operator.setUser(success.data.user_id, success.data.user); $rootScope.operator = operator; mainMenu.updateMainMenu(); $rootScope.openslidesBootstrapDone = true; diff --git a/openslides/core/static/templates/index.html b/openslides/core/static/templates/index.html index 36353bfee..be535fea0 100644 --- a/openslides/core/static/templates/index.html +++ b/openslides/core/static/templates/index.html @@ -218,7 +218,7 @@ - + diff --git a/openslides/core/static/templates/messaging.html b/openslides/core/static/templates/messaging.html new file mode 100644 index 000000000..f12308dcc --- /dev/null +++ b/openslides/core/static/templates/messaging.html @@ -0,0 +1,10 @@ +
+
+
+ + + + +
+
+
diff --git a/openslides/mediafiles/static/js/mediafiles/create.js b/openslides/mediafiles/static/js/mediafiles/create.js index ec29121ee..8b332db7c 100644 --- a/openslides/mediafiles/static/js/mediafiles/create.js +++ b/openslides/mediafiles/static/js/mediafiles/create.js @@ -9,7 +9,8 @@ angular.module('OpenSlidesApp.mediafiles.create', [ .controller('MediafileCreateCtrl', [ '$scope', 'MediafileForm', - function ($scope, MediafileForm) { + 'ErrorMessage', + function ($scope, MediafileForm, ErrorMessage) { $scope.model = {}; $scope.alert = {}; $scope.formFields = MediafileForm.getFormFields(true); @@ -23,11 +24,7 @@ angular.module('OpenSlidesApp.mediafiles.create', [ }, function (error) { $scope.activeUpload = void 0; - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); }, function (progress) { $scope.progress = parseInt(100.0 * progress.loaded / progress.total); diff --git a/openslides/mediafiles/static/js/mediafiles/update.js b/openslides/mediafiles/static/js/mediafiles/update.js index c2ee31c32..8243753f6 100644 --- a/openslides/mediafiles/static/js/mediafiles/update.js +++ b/openslides/mediafiles/static/js/mediafiles/update.js @@ -14,7 +14,8 @@ angular.module('OpenSlidesApp.mediafiles.update', [ 'Mediafile', 'mediafileId', 'MediafileForm', - function ($scope, operator, User, Mediafile, mediafileId, MediafileForm) { + 'ErrorMessage', + function ($scope, operator, User, Mediafile, mediafileId, MediafileForm, ErrorMessage) { $scope.alert = {}; $scope.formFields = MediafileForm.getFormFields(); @@ -40,11 +41,7 @@ angular.module('OpenSlidesApp.mediafiles.update', [ }, function (error) { Mediafile.refresh(mediafile); - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; diff --git a/openslides/motions/static/js/motions/motion-block.js b/openslides/motions/static/js/motions/motion-block.js index 1aced4f4e..818bf13e9 100644 --- a/openslides/motions/static/js/motions/motion-block.js +++ b/openslides/motions/static/js/motions/motion-block.js @@ -144,7 +144,8 @@ angular.module('OpenSlidesApp.motions.motionBlock', []) 'motionBlockId', 'Projector', 'ProjectionDefault', - function($scope, $http, ngDialog, Motion, MotionBlockForm, MotionBlock, motionBlockId, Projector, ProjectionDefault) { + 'ErrorMessage', + function($scope, $http, ngDialog, Motion, MotionBlockForm, MotionBlock, motionBlockId, Projector, ProjectionDefault, ErrorMessage) { MotionBlock.bindOne(motionBlockId, $scope, 'motionBlock'); Motion.bindAll({}, $scope, 'motions'); $scope.$watch(function () { @@ -159,12 +160,11 @@ angular.module('OpenSlidesApp.motions.motionBlock', []) ngDialog.open(MotionBlockForm.getDialog(motionBlock)); }; $scope.followRecommendations = function () { - $http.post('/rest/motions/motion-block/' + motionBlockId + '/follow_recommendations/') - .success(function(data) { - $scope.alert = { type: 'success', msg: data.detail, show: true }; - }) - .error(function(data) { - $scope.alert = { type: 'danger', msg: data.detail, show: true }; + $http.post('/rest/motions/motion-block/' + motionBlockId + '/follow_recommendations/').then( + function (success) { + $scope.alert = { type: 'success', msg: success.data.detail, show: true }; + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); }); }; $scope.delete = function (motion) { diff --git a/openslides/motions/static/js/motions/motion-services.js b/openslides/motions/static/js/motions/motion-services.js index c728fb46b..5e107c505 100644 --- a/openslides/motions/static/js/motions/motion-services.js +++ b/openslides/motions/static/js/motions/motion-services.js @@ -30,8 +30,8 @@ angular.module('OpenSlidesApp.motions.motionservices', ['OpenSlidesApp.motions', return element.getAttribute("src"); }); - $http.post('/core/encode_media/', JSON.stringify(image_sources)).success(function(data) { - var converter = PdfMakeConverter.createInstance(data.images); + $http.post('/core/encode_media/', JSON.stringify(image_sources)).then(function (success) { + var converter = PdfMakeConverter.createInstance(sucess.data.images); var motionContentProvider = MotionContentProvider.createInstance(converter, $scope.motion, $scope, User, $http); var documentProvider = PdfMakeDocumentProvider.createInstance(motionContentProvider); var identifier = $scope.motion.identifier ? '-' + $scope.motion.identifier : ''; diff --git a/openslides/motions/static/js/motions/site.js b/openslides/motions/static/js/motions/site.js index 068c876fa..45cc09935 100644 --- a/openslides/motions/static/js/motions/site.js +++ b/openslides/motions/static/js/motions/site.js @@ -912,8 +912,8 @@ angular.module('OpenSlidesApp.motions.site', [ }); //post-request to convert the images. Async. - $http.post('/core/encode_media/', JSON.stringify(image_sources)).success(function(data) { - var converter = PdfMakeConverter.createInstance(data.images); + $http.post('/core/encode_media/', JSON.stringify(image_sources)).then(function (success) { + var converter = PdfMakeConverter.createInstance(success.data.images); var motionContentProviderArray = []; //convert the filtered motions to motionContentProviders @@ -1313,7 +1313,8 @@ angular.module('OpenSlidesApp.motions.site', [ 'MotionChangeRecommendation', 'ChangeRecommendationForm', 'change', - function ($scope, MotionChangeRecommendation, ChangeRecommendationForm, change) { + 'ErrorMessage', + function ($scope, MotionChangeRecommendation, ChangeRecommendationForm, change, ErrorMessage) { $scope.alert = {}; $scope.model = angular.copy(change); @@ -1330,11 +1331,7 @@ angular.module('OpenSlidesApp.motions.site', [ }, function (error) { MotionChangeRecommendation.refresh(change); - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -1397,8 +1394,9 @@ angular.module('OpenSlidesApp.motions.site', [ 'Workflow', 'Agenda', 'AgendaUpdate', + 'ErrorMessage', function($scope, $state, gettext, gettextCatalog, operator, Motion, MotionForm, - Category, Config, Mediafile, Tag, User, Workflow, Agenda, AgendaUpdate) { + Category, Config, Mediafile, Tag, User, Workflow, Agenda, AgendaUpdate, ErrorMessage) { Category.bindAll({}, $scope, 'categories'); Mediafile.bindAll({}, $scope, 'mediafiles'); Tag.bindAll({}, $scope, 'tags'); @@ -1445,11 +1443,7 @@ angular.module('OpenSlidesApp.motions.site', [ $scope.closeThisDialog(); }, function (error) { - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -1470,8 +1464,9 @@ angular.module('OpenSlidesApp.motions.site', [ 'Agenda', 'AgendaUpdate', 'motionId', + 'ErrorMessage', function($scope, $state, Motion, Category, Config, Mediafile, MotionForm, Tag, - User, Workflow, Agenda, AgendaUpdate, motionId) { + User, Workflow, Agenda, AgendaUpdate, motionId, ErrorMessage) { Category.bindAll({}, $scope, 'categories'); Mediafile.bindAll({}, $scope, 'mediafiles'); Tag.bindAll({}, $scope, 'tags'); @@ -1547,11 +1542,7 @@ angular.module('OpenSlidesApp.motions.site', [ // save error: revert all changes by restore // (refresh) original motion object from server Motion.refresh(motion); - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -1565,7 +1556,9 @@ angular.module('OpenSlidesApp.motions.site', [ 'MotionPollForm', 'motionpollId', 'voteNumber', - function($scope, gettextCatalog, MotionPoll, MotionPollForm, motionpollId, voteNumber) { + 'ErrorMessage', + function($scope, gettextCatalog, MotionPoll, MotionPollForm, motionpollId, + voteNumber, ErrorMessage) { // set initial values for form model by create deep copy of motionpoll object // so detail view is not updated while editing poll var motionpoll = MotionPoll.get(motionpollId); @@ -1586,13 +1579,8 @@ angular.module('OpenSlidesApp.motions.site', [ .then(function(success) { $scope.alert.show = false; $scope.closeThisDialog(); - }) - .catch(function(error) { - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = { type: 'danger', msg: message, show: true }; + }, function(error) { + $scope.alert = ErrorMessage.forAlert(error); }); }; } @@ -1865,7 +1853,8 @@ angular.module('OpenSlidesApp.motions.site', [ '$scope', 'Category', 'CategoryForm', - function($scope, Category, CategoryForm) { + 'ErrorMessage', + function($scope, Category, CategoryForm, ErrorMessage) { $scope.model = {}; $scope.alert = {}; $scope.formFields = CategoryForm.getFormFields(); @@ -1875,11 +1864,7 @@ angular.module('OpenSlidesApp.motions.site', [ $scope.closeThisDialog(); }, function (error) { - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -1891,7 +1876,8 @@ angular.module('OpenSlidesApp.motions.site', [ 'Category', 'categoryId', 'CategoryForm', - function($scope, Category, categoryId, CategoryForm) { + 'ErrorMessage', + function($scope, Category, categoryId, CategoryForm, ErrorMessage) { $scope.alert = {}; $scope.model = angular.copy(Category.get(categoryId)); $scope.formFields = CategoryForm.getFormFields(); @@ -1905,11 +1891,7 @@ angular.module('OpenSlidesApp.motions.site', [ // save error: revert all changes by restore // (refresh) original category object from server Category.refresh(category); - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -1924,7 +1906,8 @@ angular.module('OpenSlidesApp.motions.site', [ 'Category', 'categoryId', 'Motion', - function($scope, $stateParams, $http, MotionList, Category, categoryId, Motion) { + 'ErrorMessage', + function($scope, $stateParams, $http, MotionList, Category, categoryId, Motion, ErrorMessage) { Category.bindOne(categoryId, $scope, 'category'); Motion.bindAll({}, $scope, 'motions'); $scope.filter = { category_id: categoryId, @@ -1951,12 +1934,11 @@ angular.module('OpenSlidesApp.motions.site', [ // renumber them $http.post('/rest/motions/category/' + $scope.category.id + '/numbering/', - {'motions': sorted_motions} ) - .success(function(data) { - $scope.alert = { type: 'success', msg: data.detail, show: true }; - }) - .error(function(data) { - $scope.alert = { type: 'danger', msg: data.detail, show: true }; + {'motions': sorted_motions} ).then( + function (success) { + $scope.alert = { type: 'success', msg: success.data.detail, show: true }; + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); }); }; } diff --git a/openslides/topics/static/js/topics/site.js b/openslides/topics/static/js/topics/site.js index e88652164..3dd69d2ea 100644 --- a/openslides/topics/static/js/topics/site.js +++ b/openslides/topics/static/js/topics/site.js @@ -178,7 +178,8 @@ angular.module('OpenSlidesApp.topics.site', ['OpenSlidesApp.topics', 'OpenSlides 'TopicForm', 'Agenda', 'AgendaUpdate', - function($scope, $state, Topic, TopicForm, Agenda, AgendaUpdate) { + 'ErrorMessage', + function($scope, $state, Topic, TopicForm, Agenda, AgendaUpdate, ErrorMessage) { $scope.topic = {}; $scope.model = {}; $scope.model.showAsAgendaItem = true; @@ -193,8 +194,11 @@ angular.module('OpenSlidesApp.topics.site', ['OpenSlidesApp.topics', 'OpenSlides var changes = [{key: 'type', value: (topic.showAsAgendaItem ? 1 : 2)}, {key: 'parent_id', value: topic.agenda_parent_item_id}]; AgendaUpdate.saveChanges(success.agenda_item_id,changes); - }); - $scope.closeThisDialog(); + $scope.closeThisDialog(); + }, function (error) { + $scope.alert = ErrorMessage.forAlert(error); + } + ); }; } ]) @@ -207,7 +211,8 @@ angular.module('OpenSlidesApp.topics.site', ['OpenSlidesApp.topics', 'OpenSlides 'Agenda', 'AgendaUpdate', 'topicId', - function($scope, $state, Topic, TopicForm, Agenda, AgendaUpdate, topicId) { + 'ErrorMessage', + function($scope, $state, Topic, TopicForm, Agenda, AgendaUpdate, topicId, ErrorMessage) { var topic = Topic.get(topicId); $scope.alert = {}; // set initial values for form model by create deep copy of topic object @@ -237,11 +242,7 @@ angular.module('OpenSlidesApp.topics.site', ['OpenSlidesApp.topics', 'OpenSlides // save error: revert all changes by restore // (refresh) original topic object from server Topic.refresh(topic); - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; diff --git a/openslides/users/static/js/users/site.js b/openslides/users/static/js/users/site.js index 12783c5a9..d143e7505 100644 --- a/openslides/users/static/js/users/site.js +++ b/openslides/users/static/js/users/site.js @@ -603,11 +603,7 @@ angular.module('OpenSlidesApp.users.site', [ $scope.alert.show = false; }, function(error){ - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = { type: 'danger', msg: message, show: true }; + $scope.alert = ErrorMessage.forAlert(error); }); }; // delete single user @@ -744,7 +740,8 @@ angular.module('OpenSlidesApp.users.site', [ 'User', 'UserForm', 'Group', - function($scope, $state, User, UserForm, Group) { + 'ErrorMessage', + function($scope, $state, User, UserForm, Group, ErrorMessage) { Group.bindAll({where: {id: {'>': 2}}}, $scope, 'groups'); $scope.alert = {}; // get all form fields @@ -756,15 +753,11 @@ angular.module('OpenSlidesApp.users.site', [ user.groups_id = []; } User.create(user).then( - function(success) { + function (success) { $scope.closeThisDialog(); }, function (error) { - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -779,7 +772,8 @@ angular.module('OpenSlidesApp.users.site', [ 'UserForm', 'Group', 'userId', - function($scope, $state, $http, User, UserForm, Group, userId) { + 'ErrorMessage', + function($scope, $state, $http, User, UserForm, Group, userId, ErrorMessage) { Group.bindAll({where: {id: {'>': 2}}}, $scope, 'groups'); $scope.alert = {}; // set initial values for form model by create deep copy of user object @@ -805,11 +799,7 @@ angular.module('OpenSlidesApp.users.site', [ // save error: revert all changes by restore // (refresh) original user object from server User.refresh(user); - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -823,7 +813,8 @@ angular.module('OpenSlidesApp.users.site', [ 'operator', 'UserProfileForm', 'gettext', - function($scope, Editor, User, operator, UserProfileForm, gettext) { + 'ErrorMessage', + function($scope, Editor, User, operator, UserProfileForm, gettext, ErrorMessage) { $scope.model = angular.copy(operator.user); $scope.title = gettext('Edit profile'); $scope.formFields = UserProfileForm.getFormFields(); @@ -837,11 +828,7 @@ angular.module('OpenSlidesApp.users.site', [ // save error: revert all changes by restore // (refresh) original user object from server User.refresh(user); - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -856,7 +843,8 @@ angular.module('OpenSlidesApp.users.site', [ 'userId', 'gettextCatalog', 'PasswordGenerator', - function($scope, $state, $http, User, userId, gettextCatalog, PasswordGenerator) { + 'ErrorMessage', + function($scope, $state, $http, User, userId, gettextCatalog, PasswordGenerator, ErrorMessage) { User.bindOne(userId, $scope, 'user'); $scope.alert = {}; $scope.generatePassword = function () { @@ -873,7 +861,7 @@ angular.module('OpenSlidesApp.users.site', [ $scope.new_password = ''; }, function (error) { - $scope.alert = {type: 'danger', msg: error.data.detail, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); } @@ -887,7 +875,8 @@ angular.module('OpenSlidesApp.users.site', [ '$http', 'gettext', 'UserPasswordForm', - function($scope, $state, $http, gettext, UserPasswordForm) { + 'ErrorMessage', + function($scope, $state, $http, gettext, UserPasswordForm, ErrorMessage) { $scope.title = 'Change password'; $scope.alert = {}; $scope.model = {}; @@ -911,12 +900,7 @@ angular.module('OpenSlidesApp.users.site', [ function (error) { // Error, e. g. wrong old password. $scope.model = {}; - - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = {type: 'danger', msg: message, show: true}; + $scope.alert = ErrorMessage.forAlert(error); } ); } @@ -1362,7 +1346,8 @@ angular.module('OpenSlidesApp.users.site', [ '$scope', 'Group', 'group', - function($scope, Group, group) { + 'ErrorMessage', + function($scope, Group, group, ErrorMessage) { $scope.group = group; $scope.new_name = group.name; @@ -1375,12 +1360,8 @@ angular.module('OpenSlidesApp.users.site', [ $scope.closeThisDialog(); }, function (error) { - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = { msg: message, show: true }; - $scope.group.name = old_name; + $scope.alert = ErrorMessage.forAlert(error); + $scope.group.name = old_name; } ); }; @@ -1390,7 +1371,8 @@ angular.module('OpenSlidesApp.users.site', [ .controller('GroupCreateCtrl', [ '$scope', 'Group', - function($scope, Group) { + 'ErrorMessage', + function($scope, Group, ErrorMessage) { $scope.new_name = ''; $scope.alert = {}; @@ -1405,11 +1387,7 @@ angular.module('OpenSlidesApp.users.site', [ $scope.closeThisDialog(); }, function (error) { - var message = ''; - for (var e in error.data) { - message += e + ': ' + error.data[e] + ' '; - } - $scope.alert = { msg: message, show: true }; + $scope.alert = ErrorMessage.forAlert(error); } ); }; @@ -1469,11 +1447,11 @@ angular.module('OpenSlidesApp.users.site', [ $scope.guestAllowed = $rootScope.guest_enabled; // get login info-text from server - $http.get('/users/login/').success(function(data) { - if(data.info_text) { + $http.get('/users/login/').then(function (success) { + if(success.data.info_text) { $scope.alerts.push({ type: 'success', - msg: data.info_text + msg: success.data.info_text }); } });