Commit 1d5f8f37 authored by Vladimir Baranov's avatar Vladimir Baranov

Merge branch 'feature/advanced-messaging' into develop

parents ce11ec8c f05f250a
...@@ -2087,7 +2087,7 @@ table.dataTable thead .sorting:after { ...@@ -2087,7 +2087,7 @@ table.dataTable thead .sorting:after {
right: 15px; right: 15px;
-moz-box-shadow: 0px 0px 45px rgba(0,0,0,0.4); -moz-box-shadow: 0px 0px 45px rgba(0,0,0,0.4);
box-shadow: 0px 0px 45px rgba(0,0,0,0.4); box-shadow: 0px 0px 45px rgba(0,0,0,0.4);
z-index: 10; z-index: 2100;
border-radius: 3px; border-radius: 3px;
} }
...@@ -2482,6 +2482,11 @@ table.dataTable thead .sorting:after { ...@@ -2482,6 +2482,11 @@ table.dataTable thead .sorting:after {
font-family: 'robotomedium'; font-family: 'robotomedium';
} }
.chat-app .conversation-section .message-content-url {
display: block;
}
.chat-app .conversation-section .user-message .message-content .attachment-message { .chat-app .conversation-section .user-message .message-content .attachment-message {
color: #909090; color: #909090;
} }
...@@ -2966,6 +2971,7 @@ table.dataTable thead .sorting:after { ...@@ -2966,6 +2971,7 @@ table.dataTable thead .sorting:after {
.course-prg-scheduler .action-selector.readonly { .course-prg-scheduler .action-selector.readonly {
right: 0; right: 0;
padding-right: 0; padding-right: 0;
cursor: default;
} }
.course-prg-scheduler .action-selector.readonly:after { .course-prg-scheduler .action-selector.readonly:after {
......
...@@ -551,7 +551,8 @@ angular.module('ulakbus.crud', ['schemaForm', 'ui.bootstrap', 'ulakbus.formServi ...@@ -551,7 +551,8 @@ angular.module('ulakbus.crud', ['schemaForm', 'ui.bootstrap', 'ulakbus.formServi
key: data.oe_key, key: data.oe_key,
name: data.name, name: data.name,
avatar_url: data.avatar_url, avatar_url: data.avatar_url,
totalHours: data.toplam_ders_saati totalHours: data.toplam_ders_saati,
readonly: data.readonly
}; };
iScope.timetable = iScope.prepareTimetable(data.uygunluk_durumu); iScope.timetable = iScope.prepareTimetable(data.uygunluk_durumu);
}; };
...@@ -611,18 +612,19 @@ angular.module('ulakbus.crud', ['schemaForm', 'ui.bootstrap', 'ulakbus.formServi ...@@ -611,18 +612,19 @@ angular.module('ulakbus.crud', ['schemaForm', 'ui.bootstrap', 'ulakbus.formServi
iScope.currentTable = { iScope.currentTable = {
key: data.oe_key, key: data.oe_key,
name: data.name, name: data.name,
avatar_url: data.avatar_url avatar_url: data.avatar_url,
readonly: data.readonly
}; };
iScope.timetable = iScope.prepareTimetable(data.zaman_plani); iScope.timetable = iScope.prepareTimetable(data.zaman_plani);
}; };
iScope.selectTable = function(lecturer){ iScope.selectTable = function(table){
iScope.loadingTable = true; iScope.loadingTable = true;
iScope.get_wf({ iScope.get_wf({
cmd: 'personel_sec', cmd: 'derslik_degistir',
secili_og_elemani: {key: lecturer.key} secili_derslik: {key: table.key}
}).then(function(response){ }).then(function(response){
initLecturer(response); initTable(response);
}).finally(function(){ }).finally(function(){
iScope.loadingTable = false; iScope.loadingTable = false;
}) })
......
This diff is collapsed.
angular.module("ulakbus.messaging") angular.module("ulakbus.messaging")
.directive('messaging', function (Generator, MessagingService, $log, $rootScope, MessagingPopup, Utils) { .directive('messaging', function (Generator, MessagingService, $log, $rootScope, MessagingPopup, Utils, $q) {
// get channel key // get channel key
function getKey (channel) { function getKey (channel) {
...@@ -32,11 +32,24 @@ angular.module("ulakbus.messaging") ...@@ -32,11 +32,24 @@ angular.module("ulakbus.messaging")
link: function(iScope, iElem, iAttrs){ link: function(iScope, iElem, iAttrs){
iScope.chatAppIsHidden = true; iScope.chatAppIsHidden = true;
// reset state when user log in/log out
$rootScope.$watch('loggedInUser', function(v){
iScope.loggedIn = v;
reset();
});
// shared object to populate models through scopes // shared object to populate models through scopes
iScope.shared = {}; iScope.shared = {};
var popupRootElement = $(iElem).find('.popup-placeholder'); var popupRootElement = $(iElem).find('.popup-placeholder');
function reset(){
iScope.selectedChannel = null;
iScope.publicChannels = [];
iScope.notificationsChannel = [];
iScope.directChannels = [];
}
function editChannelPopup(channel){ function editChannelPopup(channel){
return MessagingPopup.show({ return MessagingPopup.show({
templateUrl: "components/messaging/templates/create_channel.html", templateUrl: "components/messaging/templates/create_channel.html",
...@@ -66,8 +79,9 @@ angular.module("ulakbus.messaging") ...@@ -66,8 +79,9 @@ angular.module("ulakbus.messaging")
if (channel.messages){ if (channel.messages){
channel.messages.push(message); channel.messages.push(message);
} }
} };
updateLastMessage(message); updateLastMessage(message);
reportLastSeenMessage();
} }
function updateAndSelect(channelKey){ function updateAndSelect(channelKey){
...@@ -103,10 +117,12 @@ angular.module("ulakbus.messaging") ...@@ -103,10 +117,12 @@ angular.module("ulakbus.messaging")
}; };
iScope.updateChannelsList = function(){ iScope.updateChannelsList = function(){
return MessagingService.list_channels().then(function (groupedChannels) { return MessagingService.list_channels().then(function (channels) {
var groupedChannels = channels.grouped;
iScope.publicChannels = groupedChannels[MessagingService.CHANNEL_TYPE.PUBLIC]; iScope.publicChannels = groupedChannels[MessagingService.CHANNEL_TYPE.PUBLIC];
iScope.notificationsChannel = groupedChannels[MessagingService.CHANNEL_TYPE.NOTIFICATION][0]; iScope.notificationsChannel = groupedChannels[MessagingService.CHANNEL_TYPE.NOTIFICATION][0];
iScope.directChannels = groupedChannels[MessagingService.CHANNEL_TYPE.DIRECT]; iScope.directChannels = groupedChannels[MessagingService.CHANNEL_TYPE.DIRECT];
}); });
} }
...@@ -123,11 +139,13 @@ angular.module("ulakbus.messaging") ...@@ -123,11 +139,13 @@ angular.module("ulakbus.messaging")
iScope.hideApp = function(){ iScope.hideApp = function(){
iScope.chatAppIsHidden = true; iScope.chatAppIsHidden = true;
MessagingService.toggle_messaging_window_visibility(false);
}; };
iScope.showApp = function(){ iScope.showApp = function(){
iScope.chatAppIsHidden = false; iScope.chatAppIsHidden = false;
iScope.updateChannelsList(); MessagingService.toggle_messaging_window_visibility(true);
return iScope.updateChannelsList();
} }
iScope.searchUser = function(){ iScope.searchUser = function(){
...@@ -221,11 +239,10 @@ angular.module("ulakbus.messaging") ...@@ -221,11 +239,10 @@ angular.module("ulakbus.messaging")
function selectChannel(channelKey, silent){ function selectChannel(channelKey, silent){
if (!silent) iScope.loadingChannel = true; if (!silent) iScope.loadingChannel = true;
return MessagingService.show_channel(channelKey).then(function(result){ return MessagingService.show_channel(channelKey)
return result; .finally(function(){
}).finally(function(){ iScope.loadingChannel = false;
iScope.loadingChannel = false; })
})
} }
iScope.selectChannel = function(channel, silent){ iScope.selectChannel = function(channel, silent){
...@@ -308,12 +325,21 @@ angular.module("ulakbus.messaging") ...@@ -308,12 +325,21 @@ angular.module("ulakbus.messaging")
$rootScope.$on("user_ready", function(){ $rootScope.$on("user_ready", function(){
// init service after user logged in // init service after user logged in
iScope.selectedChannel = null; reset();
iScope.publicChannels = [];
iScope.notificationsChannel = [];
iScope.directChannels = []
iScope.hideApp(); iScope.hideApp();
}); });
$rootScope.$on(MessagingService.SHOW_MESSAGING_WINDOW_EVENT, function(e, channelKey){
var showApp = $q.when();
if (iScope.chatAppIsHidden){
showApp = iScope.showApp();
}
if (channelKey && channelKey != getKey(iScope.selectedChannel)){
showApp.then(function(){
iScope.selectChannel(channelKey);
})
}
})
} }
}; };
}) })
......
...@@ -18,6 +18,9 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -18,6 +18,9 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
.factory('MessagingService', function ($q, $timeout, $compile, $log, $rootScope, Moment, WSOps, Utils) { .factory('MessagingService', function ($q, $timeout, $compile, $log, $rootScope, Moment, WSOps, Utils) {
var msg = {}; var msg = {};
var notificationsChannelKey; var notificationsChannelKey;
var channelsMap = {};
// channels loader promise
var channelsLoader;
msg.CHANNEL_TYPE = { msg.CHANNEL_TYPE = {
"PUBLIC": 15, "PUBLIC": 15,
...@@ -25,6 +28,16 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -25,6 +28,16 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
"NOTIFICATION": 5 "NOTIFICATION": 5
}; };
msg.SHOW_MESSAGING_WINDOW_EVENT = "show_messaging_window";
var unread = {
messages: {count: 0},
notifications: {count: 0}
};
var currentChannelKey;
// track messaging app state for proper unread messages count
var messagingAppIsHidden = true;
function wsReady () { function wsReady () {
/** /**
* wait until websocket will be open * wait until websocket will be open
...@@ -52,6 +65,44 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -52,6 +65,44 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
} }
} }
function increaseUnread(message, messageType){
// skip current channel messages. Don't update counters
if (!messagingAppIsHidden && message.channel_key == currentChannelKey){
return;
}
checkIfInitialized().then(function(){
var channel = channelsMap[message.channel_key];
if (channel){
channel.unread += 1;
}
unread[messageType].count += 1;
})
}
function decreaseUnread(channel){
// get channel from channelsMap. Channels in channelMap has unread property
// which is updated when messages arrive
channel = channelsMap[channel.key];
if (channel && channel.unread){
var counter;
if (channel.type == msg.CHANNEL_TYPE.NOTIFICATION){
counter = unread.notifications
} else {
counter = unread.messages;
}
counter.count -= channel.unread;
if (counter.count < 0) counter.count = 0;
channel.unread = 0;
}
}
function checkIfInitialized(){
if (!channelsLoader){
return msg.list_channels()
}
return channelsLoader;
}
// prepare message to show in UI // prepare message to show in UI
msg.prepareMessage = function(message){ msg.prepareMessage = function(message){
if (!message.timestamp){ if (!message.timestamp){
...@@ -64,9 +115,35 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -64,9 +115,35 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
}; };
msg.get_notifications_channel_key = function(){ msg.get_notifications_channel_key = function(){
return notificationsChannelKey; return checkIfInitialized().then(function(){
return notificationsChannelKey;
});
};
msg.get_unread_counters = function(){
return unread;
}; };
msg.reset_state = function(){
currentChannelKey = null;
notificationsChannelKey = null;
channelsMap = {};
unread.messages.count = 0;
unread.notifications.count = 0;
channelsLoader = false;
}
msg.toggle_messaging_window_visibility = function(visibility, resetState){
messagingAppIsHidden = !visibility;
if (resetState){
msg.reset_state();
}
};
msg.show_messaging_window = function(channelKey){
$rootScope.$broadcast(msg.SHOW_MESSAGING_WINDOW_EVENT, channelKey);
}
/** /**
* API * API
* *
...@@ -100,13 +177,21 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -100,13 +177,21 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
var outgoing = { var outgoing = {
view: '_zops_list_channels' view: '_zops_list_channels'
}; };
return wsRequest(outgoing).then(function (data) {
console.error("channels: ", data.channels); channelsLoader = wsRequest(outgoing).then(function (data) {
var grouped = Utils.groupBy(data.channels||[], "type"); var grouped = Utils.groupBy(data.channels||[], "type");
// add all channels to channels map
for (var i = 0; i < data.channels.length; i++){
var channel = data.channels[i];
channelsMap[channel.key] = channel;
}
// save notifications channel key // save notifications channel key
notificationsChannelKey = grouped[msg.CHANNEL_TYPE.NOTIFICATION][0].key; notificationsChannelKey = grouped[msg.CHANNEL_TYPE.NOTIFICATION][0].key;
return grouped;
return {grouped: grouped, channelsMap: channelsMap};
}); });
return channelsLoader;
}; };
msg.search_user = function (query) { msg.search_user = function (query) {
...@@ -226,6 +311,10 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -226,6 +311,10 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
}; };
return wsRequest(outgoing).then(function(result){ return wsRequest(outgoing).then(function(result){
$log.info("Show channel ", channelKey, ": ", result); $log.info("Show channel ", channelKey, ": ", result);
// decrease unread messages for current channel
decreaseUnread(result);
// save current channel key
currentChannelKey = result.key;
prepareMessages(result.last_messages); prepareMessages(result.last_messages);
return result; return result;
}) })
...@@ -249,6 +338,9 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -249,6 +338,9 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
}; };
return wsRequest(outgoing).then(function(result){ return wsRequest(outgoing).then(function(result){
$log.info("Get unread messages count: ", result); $log.info("Get unread messages count: ", result);
// update internal unread messages counters
unread.messages.count = result.messages;
unread.notifications.count = result.notifications;
return result; return result;
}) })
}; };
...@@ -379,6 +471,25 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -379,6 +471,25 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
}); });
}; };
/**
* Event listeners
*/
$rootScope.$on("message", function(e, message){
increaseUnread(message, 'messages');
});
$rootScope.$on("notifications", function(e, message){
increaseUnread(message, 'notifications');
});
// reset state on logout
$rootScope.$watch("loggedInUser", function(value){
if (!value){
msg.reset_state();
};
});
return msg; return msg;
}) })
......
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
<div class="conversation-block clearfix" ng-repeat="msg in selectedChannel.messages"> <div class="conversation-block clearfix" ng-repeat="msg in selectedChannel.messages">
<div class="conversation-actions"> <div class="conversation-actions">
<div class="action"><span class="glyphicon glyphicon-star-empty"></span></div>
<div class="action dropdown-toggle" data-toggle="dropdown" ng-click="getMessageActions(msg)"> <div class="action dropdown-toggle" data-toggle="dropdown" ng-click="getMessageActions(msg)">
<span class="glyphicon glyphicon-option-horizontal"></span> <span class="glyphicon glyphicon-option-horizontal"></span>
</div> </div>
...@@ -59,6 +58,7 @@ ...@@ -59,6 +58,7 @@
</div> </div>
<div class="message-content"> <div class="message-content">
{{::msg.content}} {{::msg.content}}
<a class="message-content-url" href="{{::msg.url}}" ng-if="msg.url">{{msg.url}}</a>
</div> </div>
</div> </div>
</div> </div>
......
<div> <div ng-show="loggedIn">
<a class="chat-app-button" ng-show="chatAppIsHidden" ng-click="showApp()"><i class="glyphicon glyphicon-comment"></i></a> <a class="chat-app-button" ng-show="chatAppIsHidden" ng-click="showApp()"><i class="glyphicon glyphicon-comment"></i></a>
<div class="chat-app" ng-hide="chatAppIsHidden"> <div class="chat-app" ng-hide="chatAppIsHidden">
...@@ -11,12 +11,12 @@ ...@@ -11,12 +11,12 @@
<ul class="channels"> <ul class="channels">
<li class="title">KANALLAR <span class="add-action glyphicon glyphicon-plus-sign" ng-click="createChannel()"></span></li> <li class="title">KANALLAR <span class="add-action glyphicon glyphicon-plus-sign" ng-click="createChannel()"></span></li>
<li ng-class="{'notification': ch.unread, 'active': isChannelSelected(ch)}" title="{{ch.description}}" ng-repeat="ch in publicChannels" ng-click="selectChannel(ch)">{{ch.name}}</li> <li ng-class="{'unread': ch.unread, 'active': isChannelSelected(ch)}" title="{{ch.description}}" ng-repeat="ch in publicChannels" ng-click="selectChannel(ch)">{{ch.name}}</li>
</ul> </ul>
<ul class="direct-messages"> <ul class="direct-messages">
<li class="title">MESAJLAR <span class="add-action glyphicon glyphicon-plus-sign" ng-click="searchUser()"></span></li> <li class="title">MESAJLAR <span class="add-action glyphicon glyphicon-plus-sign" ng-click="searchUser()"></span></li>
<li ng-class="{'notification': userChannel.unread, 'active': isChannelSelected(userChannel), 'online': userChannel.is_online}" ng-repeat="userChannel in directChannels" ng-click="selectChannel(userChannel)">{{userChannel.name}}</li> <li ng-class="{'unread': userChannel.unread, 'active': isChannelSelected(userChannel), 'online': userChannel.is_online}" ng-repeat="userChannel in directChannels" ng-click="selectChannel(userChannel)">{{userChannel.name}}</li>
</ul> </ul>
</div> </div>
......
...@@ -42,18 +42,19 @@ angular.module('ulakbus') ...@@ -42,18 +42,19 @@ angular.module('ulakbus')
replace: true, replace: true,
scope: {}, scope: {},
controller: function ($scope, $log) { controller: function ($scope, $log) {
$scope.count = { $scope.count = MessagingService.get_unread_counters();
messages: 0, // initialize counters
notifications: 0 MessagingService.get_unread_messages_count();
};
function initCounters(){ $scope.showMessagesWindow = function(type){
MessagingService.get_unread_messages_count() if (type == 'notifications'){
.then(function(result){ return MessagingService.get_notifications_channel_key()
$scope.count.messages = result.messages; .then(function(channelKey){
$scope.count.notifiations = result.notifications; return MessagingService.show_messaging_window(channelKey);
}) })
}
MessagingService.show_messaging_window();
} }
initCounters();
} }
}; };
}) })
......
...@@ -31,8 +31,8 @@ ...@@ -31,8 +31,8 @@
&lt;!&ndash; /.dropdown-messages &ndash;&gt; &lt;!&ndash; /.dropdown-messages &ndash;&gt;
</li>--> </li>-->
<li uib-dropdown auto-close="outsideClick"> <li uib-dropdown auto-close="outsideClick">
<a uib-dropdown-toggle> <a uib-dropdown-toggle ng-click="showMessagesWindow('messages')">
<div class="badge" ng-show="count.messages > 0">{{count.messages}}</div> <div class="badge" ng-show="count.messages.count > 0">{{count.messages.count}}</div>
<i class="fa fa-envelope fa-fw" tooltip-placement="bottom" uib-tooltip="Mesajlar"></i> <i class="fa fa-envelope fa-fw" tooltip-placement="bottom" uib-tooltip="Mesajlar"></i>
<!--<i class="fa fa-caret-down"></i>--> <!--<i class="fa fa-caret-down"></i>-->
</a> </a>
...@@ -99,8 +99,8 @@ ...@@ -99,8 +99,8 @@
</li> </li>
<!-- /.dropdown --> <!-- /.dropdown -->
<li uib-dropdown auto-close="outsideClick"> <li uib-dropdown auto-close="outsideClick">
<a uib-dropdown-toggle> <a uib-dropdown-toggle ng-click="showMessagesWindow('notifications')">
<div class="badge" ng-if="count.notifications > 0">{{count.notifications}}</div> <div class="badge" ng-if="count.notifications.count > 0">{{count.notifications.count}}</div>
<i class="fa fa-bell fa-fw" tooltip-placement="bottom" uib-tooltip="Duyurular"></i> <i class="fa fa-bell fa-fw" tooltip-placement="bottom" uib-tooltip="Duyurular"></i>
<!--<i class="fa fa-caret-down"></i>--> <!--<i class="fa fa-caret-down"></i>-->
</a> </a>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment