diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js index fc60c3396..ee4fd6890 100644 --- a/openslides/core/static/js/core/base.js +++ b/openslides/core/static/js/core/base.js @@ -353,12 +353,12 @@ angular.module('OpenSlidesApp.core', [ * event_name_two: [ {id:2, fn:fn} ], * */ var idCounter = 0; - var eventNameRegex = new RegExp('^[a-zA-Z_-]+$'); - var externIdRegex = new RegExp('^[a-zA-Z_-]+\/[0-9]+$'); + var eventNameRegex = new RegExp('^[a-zA-Z0-9_-]+$'); + var externIdRegex = new RegExp('^[a-zA-Z0-9_-]+\/[0-9]+$'); return { registerCallback: function (eventName, fn) { if (!eventNameRegex.test(eventName)) { - throw 'eventName should only consist of [a-zA-z_-]'; + throw 'eventName should only consist of [a-zA-Z0-9_-]'; } else if (typeof fn === 'function') { var id = idCounter++; @@ -411,7 +411,7 @@ angular.module('OpenSlidesApp.core', [ } autoupdate.send([notifyItem]); } else { - throw 'eventName should only consist of [a-zA-z_-]'; + throw 'eventName should only consist of [a-zA-Z0-9_-]'; } }, }; diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js index d0b144286..321eac017 100644 --- a/openslides/core/static/js/core/site.js +++ b/openslides/core/static/js/core/site.js @@ -581,6 +581,122 @@ angular.module('OpenSlidesApp.core.site', [ } ]) +/* This Factory could be used in any dialog, if the user should be warned, if another user + * also has this dialog open. Use it like in this example in any dialog controller: + var dialogClosedCallback = DialogEditingWarning.dialogOpened('dialog_name' + item.id); + $scope.$on('$destroy', dialogClosedCallback); + */ +.factory('DialogEditingWarning', [ + 'operator', + 'gettextCatalog', + 'Notify', + 'Messaging', + function (operator, gettextCatalog, Notify, Messaging) { + return { + // This returns the callback function that the controller should call, if + // the dialog got closed by the user. Provide a unique dialog name. + dialogOpened: function (dialogName) { + // List of active editors + var editorNames = []; + var messagingId = dialogName + 'EditingWarning'; + // Add an editor (may come from open_request or open_response) + var addActiveEditor = function (editorName) { + editorNames.push(editorName); + updateActiveEditors(); + }; + // Remove an editor, if he closes his dialog (dialog_closed) + var removeActiveEditor = function (editorName) { + var firstIndex = _.indexOf(editorNames, editorName); + editorNames.splice(firstIndex, 1); + updateActiveEditors(); + }; + // Show a warning. + var updateActiveEditors = function () { + if (editorNames.length === 0) { + Messaging.deleteMessage(messagingId); + } else { + // This block is only for getting the message string together... + var editorsWithoutAnonymous = _.filter(editorNames, function (name) { + return name; + }); + var text = gettextCatalog.getString('Warning') + ': '; + if (editorsWithoutAnonymous.length === 0) { // Only anonymous + // Singular vs. plural + if (editorNames.length === 1) { + text += gettextCatalog.getString('One anonymous users is also editing this.'); + } else { + text += editorNames.length + ' ' + gettextCatalog.getString('anonymous users are also editing this.'); + } + } else { + // At least one named user. The max users to display is 5. Anonymous users doesn't get displayed + // by name, but the amount of users is shown. + text += _.slice(editorsWithoutAnonymous, 0, 5).join(', '); + if (editorsWithoutAnonymous.length > 5) { + // More than 5 users with names. + text += ', ... [+' + (editorNames.length - 5) + ']'; + } else if (editorsWithoutAnonymous.length !== editorNames.length) { + // Less than 5 users, so the difference is calculated different. + text += ', ... [+' + (editorNames.length - editorsWithoutAnonymous.length) + ']'; + } + // Singular vs. plural + if (editorNames.length === 1) { + text += ' ' + gettextCatalog.getString('is also editing this.'); + } else { + text += ' ' + gettextCatalog.getString('are also editing this.'); + } + } + Messaging.createOrEditMessage(messagingId, text, 'warning'); + } + }; + + // The stucture of determinating which users are editing this dialog: + // - send an open_query to every user with the name of this operator in the parameter. With + // this information all clients that listen to this request knows that this operator has + // opened the dialog. + // - The clients, which have recieved the query send an answer (open_resonse) to this operator. + // - The operator collects all resonses and fills the editornames list. + // - If the dialog get closed, a dialog_closed is send. All recieven clients remove this + // operato from their editorNames list. + var responseCallbackId = Notify.registerCallback(dialogName + '_open_response', function (notify) { + if (!notify.sendBySelf) { + addActiveEditor(notify.params.name); + } + }); + var queryCallbackId = Notify.registerCallback(dialogName + '_open_query', function (notify) { + if (!notify.sendBySelf) { + addActiveEditor(notify.params.name); + if (notify.senderUserId) { + Notify.notify(dialogName + '_open_response', { + name: operator.user ? operator.user.short_name : '', + }, [notify.senderUserId]); + } else { + Notify.notify(dialogName + '_open_response', { + name: operator.user ? operator.user.short_name : '', + }, null, [notify.senderReplyChannelName]); + } + } + }); + var closeCallbackId = Notify.registerCallback(dialogName + '_dialog_closed', function (notify) { + removeActiveEditor(notify.params.name); + }); + // Send here the open_query to get the notify-chain started. + Notify.notify(dialogName + '_open_query', { + name: operator.user ? operator.user.short_name : '', + }); + // The function returned is to deregister the callbacks and send the dialog_closed notify, if + // the dialog get closed. + return function () { + Notify.deregisterCallbacks(responseCallbackId, queryCallbackId, closeCallbackId); + Messaging.deleteMessage(messagingId); + Notify.notify(dialogName + '_dialog_closed', { + name: operator.user ? operator.user.short_name : '', + }); + }; + }, + }; + } +]) + /* * This filter filters all items in an array. If the filterArray is empty, the * array is passed. The filterArray contains numbers of the multiselect, e. g. [1, 3, 4]. diff --git a/openslides/motions/static/js/motions/site.js b/openslides/motions/static/js/motions/site.js index a97f9634c..003f710d5 100644 --- a/openslides/motions/static/js/motions/site.js +++ b/openslides/motions/static/js/motions/site.js @@ -1681,8 +1681,6 @@ angular.module('OpenSlidesApp.motions.site', [ .controller('MotionUpdateCtrl', [ '$scope', '$state', - 'operator', - 'gettextCatalog', 'Motion', 'Category', 'Config', @@ -1693,12 +1691,11 @@ angular.module('OpenSlidesApp.motions.site', [ 'Workflow', 'Agenda', 'AgendaUpdate', - 'Notify', - 'Messaging', 'motionId', 'ErrorMessage', - function($scope, $state, operator, gettextCatalog, Motion, Category, Config, Mediafile, MotionForm, - Tag, User, Workflow, Agenda, AgendaUpdate, Notify, Messaging, motionId, ErrorMessage) { + 'DialogEditingWarning', + function($scope, $state, Motion, Category, Config, Mediafile, MotionForm, + Tag, User, Workflow, Agenda, AgendaUpdate, motionId, ErrorMessage, DialogEditingWarning) { Category.bindAll({}, $scope, 'categories'); Mediafile.bindAll({}, $scope, 'mediafiles'); Tag.bindAll({}, $scope, 'tags'); @@ -1753,95 +1750,9 @@ angular.module('OpenSlidesApp.motions.site', [ } } - /* Notify for displaying a warning, if other users edit this motion too */ - var editorNames = []; - var messagingId = 'motionEditDialogOtherUsersWarning'; - var addActiveEditor = function (editorName) { - editorNames.push(editorName); - updateActiveEditors(); - }; - var removeActiveEditor = function (editorName) { - var firstIndex = _.indexOf(editorNames, editorName); - editorNames.splice(firstIndex, 1); - updateActiveEditors(); - }; - var updateActiveEditors = function () { - if (editorNames.length === 0) { - Messaging.deleteMessage(messagingId); - } else { - // This block is only for getting the message string together... - var editorsWithoutAnonymous = _.filter(editorNames, function (name) { - return name; - }); - var text = gettextCatalog.getString('Warning') + ': '; - if (editorsWithoutAnonymous.length === 0) { // Only anonymous - // Singular vs. plural - if (editorNames.length === 1) { - text += gettextCatalog.getString('One anonymous users is also editing this motion.'); - } else { - text += editorNames.length + ' ' + gettextCatalog.getString('anonymous users are also editing this motion.'); - } - } else { - // At least one named user. The max users to display is 5. Anonymous users doesn't get displayed - // by name, but the amount of users is shown. - text += _.slice(editorsWithoutAnonymous, 0, 5).join(', '); - if (editorsWithoutAnonymous.length > 5) { - // More than 5 users with names. - text += ', ... [+' + (editorNames.length - 5) + ']'; - } else if (editorsWithoutAnonymous.length !== editorNames.length) { - // Less than 5 users, so the difference is calculated different. - text += ', ... [+' + (editorNames.length - editorsWithoutAnonymous.length) + ']'; - } - // Singular vs. plural - if (editorNames.length === 1) { - text += ' ' + gettextCatalog.getString('is also editing this motion.'); - } else { - text += ' ' + gettextCatalog.getString('are also editing this motion.'); - } - } - Messaging.createOrEditMessage(messagingId, text, 'warning'); - } - }; - - var responseCallbackId = Notify.registerCallback('motion_dialog_open_response', function (notify) { - if (!notify.sendBySelf && notify.params.motionId === motionId) { - addActiveEditor(notify.params.name); - } - }); - var queryCallbackId = Notify.registerCallback('motion_dialog_open_query', function (notify) { - if (!notify.sendBySelf && notify.params.motionId === motionId) { - addActiveEditor(notify.params.name); - if (notify.senderUserId) { - Notify.notify('motion_dialog_open_response', { - name: operator.user ? operator.user.short_name : '', - motionId: motionId, - }, [notify.senderUserId]); - } else { - Notify.notify('motion_dialog_open_response', { - name: operator.user ? operator.user.short_name : '', - motionId: motionId, - }, null, [notify.senderReplyChannelName]); - } - } - }); - var closeCallbackId = Notify.registerCallback('motion_dialog_closed', function (notify) { - if (notify.params.motionId === motionId) { - removeActiveEditor(notify.params.name); - } - }); - - $scope.$on('$destroy', function () { - Notify.deregisterCallbacks(responseCallbackId, queryCallbackId, closeCallbackId); - Messaging.deleteMessage(messagingId); - Notify.notify('motion_dialog_closed', { - name: operator.user ? operator.user.short_name : '', - motionId: motionId - }); - }); - Notify.notify('motion_dialog_open_query', { - name: operator.user ? operator.user.short_name : '', - motionId: motionId, - }); + // Displaying a warning, if other users edit this motion too + var dialogClosedCallback = DialogEditingWarning.dialogOpened('motion_update_dialog_' + motionId); + $scope.$on('$destroy', dialogClosedCallback); // Save motion $scope.save = function (motion, gotoDetailView) {