diff --git a/bower.json b/bower.json index c0e9df018..dd08732fd 100644 --- a/bower.json +++ b/bower.json @@ -21,6 +21,7 @@ "angular-ui-tree": "~2.10.0", "angular-gettext": "~2.1.2", "angular-xeditable": "~0.1.9", + "angular-scroll-glue": "~2.0.6", "ngBootbox": "~0.1.2", "sockjs": "~0.3.4", "font-awesome-bower": "~4.4.0", diff --git a/openslides/core/static/css/app.css b/openslides/core/static/css/app.css index 879f6147e..3e030c968 100644 --- a/openslides/core/static/css/app.css +++ b/openslides/core/static/css/app.css @@ -71,6 +71,10 @@ body { margin-top: 5px; } +.inline { + display: inline; +} + /* ngAnimate classes */ .animate-item.ng-enter { @@ -93,8 +97,23 @@ body { 100% { opacity: 1; background: none; } } - - +/* Chatbox */ +#chatbox { + position: fixed; + top: 50px; + right: 0; + width: 40%; + border-color: #dddddd; + border-width: 1px; + box-shadow: -5px 5px 5px rgba(0, 0, 0, 0.2); + height: 200px; + padding: 0 10px 10px 10px; + z-index: 99; +} +#chatbox-text { + overflow-y: scroll; + height: 190px; +} /* Header */ #header { background-color: #333333; diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js index 00282d3da..9e86c1ca5 100644 --- a/openslides/core/static/js/core/base.js +++ b/openslides/core/static/js/core/base.js @@ -101,8 +101,17 @@ angular.module('OpenSlidesApp.core', [ // Loads all projector data Projector.findAll(); - // Loads all chat messages data - ChatMessage.findAll(); + // Loads all chat messages data and their user_ids + // TODO: add permission check if user has required chat permission + // error if include 'operator' here: + // "Circular dependency found: loadGlobalData <- operator <- loadGlobalData" + //if (operator.hasPerms("core.can_use_chat")) { + ChatMessage.findAll().then( function(chatmessages) { + angular.forEach(chatmessages, function (chatmessage) { + ChatMessage.loadRelations(chatmessage, 'user'); + }); + }); + //} // Loads server time and calculates server offset $http.get('/core/servertime/').then(function(data) { @@ -172,32 +181,41 @@ angular.module('OpenSlidesApp.core', [ } ]) -.factory('Tag', ['DS', function(DS) { - return DS.defineResource({ - name: 'core/tag', - }); -}]) +.factory('Tag', [ + 'DS', + function(DS) { + return DS.defineResource({ + name: 'core/tag', + }); + } +]) -.factory('Config', ['DS', function(DS) { - return DS.defineResource({ - name: 'core/config', - idAttribute: 'key', - }); -}]) +.factory('Config', [ + 'DS', + function(DS) { + return DS.defineResource({ + name: 'core/config', + idAttribute: 'key', + }); + } +]) -.factory('ChatMessage', ['DS', function(DS) { - return DS.defineResource({ - name: 'core/chatmessage', - relations: { - belongsTo: { - 'users/user': { - localField: 'user', - localKey: 'user_id', +.factory('ChatMessage', [ + 'DS', + function(DS) { + return DS.defineResource({ + name: 'core/chatmessage', + relations: { + belongsTo: { + 'users/user': { + localField: 'user', + localKey: 'user_id', + } } } - } - }); -}]) + }); + } +]) /* Model for a projector. * diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js index ef1e9c913..97c812706 100644 --- a/openslides/core/static/js/core/site.js +++ b/openslides/core/static/js/core/site.js @@ -13,6 +13,7 @@ angular.module('OpenSlidesApp.core.site', [ 'ngCsvImport', 'ngSanitize', // TODO: only use this in functions that need it. 'ui.select', + 'luegg.directives', 'xeditable', 'ckeditor', ]) @@ -752,22 +753,50 @@ angular.module('OpenSlidesApp.core.site', [ }; }) +// counter of new (unread) chat messages +.value('NewChatMessages', []) + // ChatMessage Controller .controller('ChatMessageCtrl', [ '$scope', '$http', 'ChatMessage', - function ($scope, $http, ChatMessage) { + 'NewChatMessages', + function ($scope, $http, ChatMessage, NewChatMessages) { ChatMessage.bindAll({}, $scope, 'chatmessages'); + $scope.unreadMessages = NewChatMessages.length; + $scope.chatboxIsCollapsed = true; + $scope.openChatbox = function () { + $scope.chatboxIsCollapsed = !$scope.chatboxIsCollapsed; + NewChatMessages = []; + $scope.unreadMessages = NewChatMessages.length; + } $scope.sendMessage = function () { + angular.element('#messageSendButton').addClass('disabled'); + angular.element('#messageInput').attr('disabled', ''); $http.post( '/rest/core/chatmessage/', {message: $scope.newMessage} ) .success(function () { $scope.newMessage = ''; + angular.element('#messageSendButton').removeClass('disabled'); + angular.element('#messageInput').removeAttr('disabled'); + }) + .error(function () { + angular.element('#messageSendButton').removeClass('disabled'); + angular.element('#messageInput').removeAttr('disabled'); }); }; + // increment unread messages counter for each new message + $scope.$watch('chatmessages', function (newVal, oldVal) { + // add new message id if there is really a new message which is not yet tracked + if ((oldVal[oldVal.length-1].id != newVal[newVal.length-1].id) && + ($.inArray(newVal[newVal.length-1].id, NewChatMessages) == -1)) { + NewChatMessages.push(newVal[newVal.length-1].id); + $scope.unreadMessages = NewChatMessages.length; + } + }) } ]) diff --git a/openslides/core/static/templates/index.html b/openslides/core/static/templates/index.html index eee8f230e..ef34563a6 100644 --- a/openslides/core/static/templates/index.html +++ b/openslides/core/static/templates/index.html @@ -21,10 +21,43 @@ {{ config('general_event_name') }}