Commit 299dfc77 authored by Vladimir Baranov's avatar Vladimir Baranov

Merge branch 'feature/messaging' into develop

parents 2619b847 145d9e37
......@@ -128,6 +128,7 @@ module.exports = function (grunt) {
"app/zetalib/error_service.js",
"app/zetalib/action_service.js",
"app/zetalib/socket.js",
"app/zetalib/utils_service.js",
"app/shared/directives.js",
"app/components/auth/auth_controller.js",
"app/components/auth/auth_service.js",
......@@ -140,7 +141,8 @@ module.exports = function (grunt) {
"app/components/wf/wf_controller.js",
"app/components/version/version.js",
"app/components/version/interpolate-filter.js",
"app/components/version/version-directive.js"
"app/components/version/version-directive.js",
"app/components/messaging/*.js"
],
dest: 'dist/app.js'
},
......@@ -196,7 +198,8 @@ module.exports = function (grunt) {
'app/shared/scripts/theme.js',
'app/shared/directives.js',
'app/components/**/*controller.js',
'app/components/**/*service.js'
'app/components/**/*service.js',
'app/components/messaging/*.js',
],
dest: 'dist/<%= grunt.branchname %>/app.js'
},
......
......@@ -2160,6 +2160,18 @@ table.dataTable thead .sorting:after {
font-family: 'robotoblack';
}
.chat-app .side-navigation ul li.title .add-action {
display: inline-block;
position: absolute;
right: 21px;
top: 6px;
/*margin-left: 4px;*/
/*top: 2px;*/
/*position: relative;*/
/*display: inline-block;*/
}
.chat-app .side-navigation ul li.compose {
background-color: #6f0d20;
margin: 5px 10px;
......@@ -2191,7 +2203,7 @@ table.dataTable thead .sorting:after {
padding-left: 40px;
}
.chat-app .side-navigation ul.direct-messages li.active {
.chat-app .side-navigation ul.direct-messages li.active, .chat-app .side-navigation ul.channels li.active {
background-color: #B51533;
}
......@@ -2277,7 +2289,7 @@ table.dataTable thead .sorting:after {
margin-top: 15px;
}
.chat-app .conversation-header .close-chat-app {
.chat-app .conversation-header .close-chat-app, .chat-app .conversation-section-empty .close-chat-app {
display: inline-block;
float: left;
width: 40px;
......@@ -2288,6 +2300,21 @@ table.dataTable thead .sorting:after {
margin-left: 10px;
border-radius: 3px;
margin-top:15px;
cursor: pointer;
}
.chat-app .conversation-section-empty .close-chat-app {
display: block;
position: absolute;
right: 15px;
top: 0px;
}
.chat-app .conversation-section-empty .close-chat-app {
display: block;
position: absolute;
right: 15px;
top: 0px;
}
.chat-app .conversation-header .chat-app-actions {
......@@ -2309,6 +2336,10 @@ table.dataTable thead .sorting:after {
overflow-x: hidden;
}
.chat-app .conversation-body.readonly {
height: calc(100% - 100px);
}
.chat-app .conversation-footer {
height: 70px;
width: 560px;
......@@ -2361,7 +2392,7 @@ table.dataTable thead .sorting:after {
border-radius:100%;
}
.chat-app .conversation-section .conversation-body .beginning-of-conversation {
.chat-app .conversation-section .conversation-body .beginning-of-conversation, .chat-app .conversation-section-empty .conversation-body {
text-align: center;
font-family: 'robotobold';
font-size: 20px;
......@@ -2371,6 +2402,10 @@ table.dataTable thead .sorting:after {
border-bottom: 1px solid #f3f3f3;
}
.chat-app .conversation-section-empty .conversation-body {
padding-top: 100px;
}
.chat-app .conversation-section .conversation-body .conversation-block {
display:block;
position:relative;
......@@ -2456,7 +2491,7 @@ table.dataTable thead .sorting:after {
z-index: 11;
background-color: rgba(255,255,255,0.97);
border-radius:3px;
display:none;
/*display:none;*/
}
.chat-app .create-new-message-window input {
......@@ -2490,7 +2525,7 @@ table.dataTable thead .sorting:after {
color:#000000;
}
.chat-app .create-new-message-window .search-results {
.chat-app .create-new-message-window .search-results, .chat-app .add-user-unit .search-results {
width: 50%;
margin-left: 25%;
margin-top: 25px;
......@@ -2498,7 +2533,7 @@ table.dataTable thead .sorting:after {
overflow: auto;
}
.chat-app .create-new-message-window .search-results .user {
.chat-app .create-new-message-window .search-results .user, .chat-app .add-user-unit .search-results .user {
width: 100%;
display: inline-block;
padding: 10px;
......@@ -2506,18 +2541,18 @@ table.dataTable thead .sorting:after {
cursor:pointer;
}
.chat-app .create-new-message-window .search-results .user:hover {
.chat-app .create-new-message-window .search-results .user:hover, .chat-app .add-user-unit .search-results .user:hover{
background-color:#efefef;
}
.chat-app .create-new-message-window .search-results .user img {
.chat-app .create-new-message-window .search-results .user img, .chat-app .add-user-unit .search-results .user img{
width: 45px;
height: 45px;
border-radius: 100%;
float: left;
}
.chat-app .create-new-message-window .search-results .user .user-name {
.chat-app .create-new-message-window .search-results .user .user-name, .chat-app .add-user-unit .search-results .user .user-name {
float: left;
margin-left: 15px;
font-family: 'robotobold';
......@@ -2525,6 +2560,29 @@ table.dataTable thead .sorting:after {
margin-top: 9px;
}
.chat-app-button {
display: block;
position: fixed;
bottom: 20px;
right: 20px;
background: white;
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
padding: 0;
z-index: 1000;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
text-align: center;
cursor: pointer;
}
.chat-app-button i {
top: 16px;
color: #333;
font-size: 20px;
}
.chat-app .create-new-channel-window h3 {
width: 400px;
margin-left: auto;
......@@ -2579,6 +2637,33 @@ table.dataTable thead .sorting:after {
outline: none;
}
.chat-app-close-btn {
display: block;
position: absolute;
right: 5px;
top: 5px;
}
.chat-app-button {
display: block;
position: fixed;
bottom: 20px;
right: 20px;
background: white;
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
padding: 0;
z-index: 9999;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
}
.chat-app-button i {
margin-top: 3px;
font-size: 18px;
}
/* END OF CHAT APPLICATION */
......
......@@ -28,7 +28,7 @@ angular.module(
'ngSanitize',
'ngCookies',
'ulakbus.formService',
'ulakbus.messagingService',
'ulakbus.messaging',
'ulakbus.dashboard',
'ulakbus.auth',
'ulakbus.error_pages',
......
This diff is collapsed.
This diff is collapsed.
<div class="chat-popup-window add-user-unit" style="display:block;">
<div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div>
<h3>{{title}}</h3>
<div class="text-center">
<input type="text" ng-model="query" ng-change="onChange(query)" placeholder="{{placeholder}}">
</div>
<div class="search-results">
<span class="loader" ng-show="loading"></span>
<div class="user" ng-repeat="item in searchResult" ng-click="done(item[1])">
<img ng-src="{{item[2]}}" ng-show="item[2]">
<div class="user-name">{{item[0]}}</div>
</div>
</div>
</div>
<span class="loader" ng-show="loadingChannel"></span>
<div class="conversation-section conversation-section-empty" ng-hide="selectedChannel">
<div class="close-chat-app" ng-click="hideApp()">
<span class="glyphicon glyphicon-remove" ></span>
</div>
<div class="conversation-body" >
Konuşmaya başlamak için bir kanal seçin ya da oluşturun.
</div>
</div>
<div class="conversation-section" ng-hide="loadingChannel || !selectedChannel">
<div class="conversation-header">
<div class="conversation-user">
<div class="user-photo" ng-show="selectedChannel.avatar_url"><img ng-src="{{selectedChannel.avatar_url}}"></div>
<div class="user-name" title="{{selectedChannel.description}}">{{selectedChannel.name}}</div>
</div>
<div class="conversation-search">
<input type="text" placeholder="Arama Yap">
</div>
<div class="dropdown">
<div class="chat-app-actions dropdown-toggle" data-toggle="dropdown" id="chat-app-actions">
<span class="glyphicon glyphicon-option-vertical"></span>
</div>
<ul class="dropdown-menu" ng-show="selectedChannel.actions.length > 0" aria-labelledby="chat-app-actions" style="left: inherit; top: 53px; right: 66px;" >
<li><a ng-click="applyChannelAction(selectedChannel, action)" ng-repeat="action in selectedChannel.actions">{{action[0]}}</a></li>
</ul>
</div>
<div class="close-chat-app" ng-click="hideApp()">
<span class="glyphicon glyphicon-remove"></span>
</div>
</div>
<div class="conversation-body" ng-class="{readonly: selectedChannel.read_only}" scroll-down-when-update="lastMessage">
<div class="conversation-body-inner">
<div class="beginning-of-conversation">
Burası yazışmanın başı!
</div>
<div class="conversation-block clearfix" ng-repeat="msg in selectedChannel.messages">
<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)">
<span class="glyphicon glyphicon-option-horizontal"></span>
</div>
<ul class="dropdown-menu" style="left:-86px;" >
<li ng-repeat="act in msg.actions"><a ng-click="applyMessageAction(msg, act)">{{act[0]}}</a></li>
</ul>
</div>
<div class="user-photo">
<img ng-src="{{msg.avatar_url}}" ng-show="msg.avatar_url">
</div>
<div class="user-message">
<div class="message-header clearfix">
<div class="user-name">{{::msg.sender_name}}</div>
<div class="message-time">{{::msg.moment|fromNow}}</div>
</div>
<div class="message-content">
{{::msg.content}}
</div>
</div>
</div>
</div>
</div>
<div class="conversation-footer" ng-show="!selectedChannel.read_only">
<textarea placeholder="Mesajını buraya yaz..." ng-model="shared.message" on-enter-pressed="sendMessage(shared.message)"></textarea>
<div class="add-attachment">
<span class="glyphicon glyphicon-send" ng-click="sendMessage(shared.message);"></span>
<div class="dropup" style="float:left;">
<span class="glyphicon glyphicon-paperclip dropdown-toggle" data-toggle="dropdown" id="attachment"></span>
<ul class="dropdown-menu" aria-labelledby="attachment" style="left:-104px;">
<li><a >Görsel</a></li>
<li><a >Dosya</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="chat-popup-window create-new-channel-window">
<div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div>
<h3>{{title}}</h3>
<div class="text-center">
<input type="text" placeholder="Channel Name" ng-model="channel.name"><br>
<textarea placeholder="Channel Description" ng-model="channel.description"></textarea>
<button class="btn btn-success" ng-click="done(channel)">{{actionTitle}}</button>
</div>
</div>
<div class="chat-popup-window confirmation-window">
<div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div>
<div class="text-center" style="margin-top: 150px;font-size: 26px;">
<p>{{title}}</p>
<button class="btn btn-success" style="font-size: 20px;" ng-click="done()">Evet</button>
<button class="btn btn-default" style="font-size: 20px;" ng-click="cancel()">Vazgeç</button>
</div>
</div>
<div>
<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-container">
<div class="side-navigation">
<ul class="channels">
<li class="title" ng-click="selectChannel(notificationsChannel)">BİLDİRİMLER <span class="badge" ng-show="notificationsChannel.unread">{{notificationsChannel.unread}}</span></li>
</ul>
<ul class="channels">
<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>
</ul>
<ul class="direct-messages">
<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>
</ul>
</div>
<ng-include src="'components/messaging/templates/conversation.html'"></ng-include>
<div class="popup-placeholder"></div>
</div>
</div>
</div>
<div class="chat-popup-window create-new-message-window">
<div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div>
<input type="text" placeholder="Birini ismi ile ara..." ng-model="query" ng-change="onChange(query)">
<div class="search-results">
<span class="loader" ng-show="loading"></span>
<div class="user" ng-repeat="user in searchResult" ng-click="done(user)">
<img ng-src="{{user[2]}}" ng-show="user[2]">
<div class="user-name">{{user[0]}}</div>
</div>
</div>
</div>
......@@ -113,11 +113,11 @@
<script src="shared/directives.js"></script>
<script src="zetalib/interceptors.js"></script>
<script src="zetalib/form_service.js"></script>
<script src="zetalib/messagingService.js"></script>
<script src="zetalib/form_constraints.js"></script>
<script src="zetalib/action_service.js"></script>
<script src="zetalib/error_service.js"></script>
<script src="zetalib/socket.js"></script>
<script src="zetalib/utils_service.js"></script>
<!-- components -->
......@@ -125,6 +125,8 @@
<script src="components/auth/auth_service.js"></script>
<script src="components/dashboard/dashboard_controller.js"></script>
<script src="components/dashboard/dashboard_widgets_directives.js"></script>
<script src="components/messaging/messaging_service.js"></script>
<script src="components/messaging/messaging.js"></script>
<script src="components/crud/crud_controller.js"></script>
<script src="components/crud/crud_widgets.js"></script>
<script src="components/debug/debug_controller.js"></script>
......@@ -135,5 +137,7 @@
<script src="components/version/version-directive.js"></script>
<script src="components/version/version.js"></script>
</body>
</html>
......@@ -120,11 +120,11 @@
<script src="shared/directives.js"></script>
<script src="zetalib/interceptors.js"></script>
<script src="zetalib/form_service.js"></script>
<script src="zetalib/messagingService.js"></script>
<script src="zetalib/form_constraints.js"></script>
<script src="zetalib/action_service.js"></script>
<script src="zetalib/error_service.js"></script>
<script src="zetalib/socket.js"></script>
<script src="zetalib/utils_service.js"></script>
<!-- components -->
......@@ -132,6 +132,8 @@
<script src="components/auth/auth_service.js"></script>
<script src="components/dashboard/dashboard_controller.js"></script>
<script src="components/dashboard/dashboard_widgets_directives.js"></script>
<script src="components/messaging/messaging_service.js"></script>
<script src="components/messaging/messaging.js"></script>
<script src="components/crud/crud_controller.js"></script>
<script src="components/crud/crud_widgets.js"></script>
<script src="components/debug/debug_controller.js"></script>
......
......@@ -28,7 +28,7 @@ angular.module(
'ngSanitize',
'ngCookies',
'ulakbus.formService',
'ulakbus.messagingService',
'ulakbus.messaging',
'ulakbus.dashboard',
'ulakbus.auth',
'ulakbus.error_pages',
......
......@@ -32,78 +32,28 @@ angular.module('ulakbus')
* @ngdoc directive
* @name headerNotification
* @description This directive is responsible to get and show notification.
* It calls API's /notify path with given interval and broadcasts `notifications` application-wide.
* There are 4 types of notifications:
* 1: tasks, 2: messages, 3: announcements, 4: recents
* It calls API's '_zops_unread_count' view to init its state and updates state when 'message' or 'notifications' broadcast message received *
* - Notifications can be disabled in /dev/settings page
*/
.directive('headerNotification', function (WSOps, $rootScope, $cookies, $interval, RESTURL, $uibModal) {
.directive('headerNotification', function ($rootScope, $uibModal, MessagingService) {
return {
templateUrl: 'shared/templates/directives/header-notification.html',
restrict: 'E',
replace: true,
scope: {},
controller: function ($scope, $log) {
// notification categories:
// 1: tasks, 2: messages, 3: announcements, 4: recents
$scope.notifications = {1: [], 2: [], 3: [], 4: []};
/**
* Group notifications
* @param notifications
*/
$scope.popModal = function(item){
var modalInstance = $uibModal.open({
animation: true,
templateUrl: 'shared/templates/notificationsModalContent.html',
controller: function($scope){
$scope.notification = item;
$scope.cancel = function() {
modalInstance.dismiss('cancel');
};
},
size: 'lg'
});
$scope.count = {
messages: 0,
notifications: 0
};
function initCounters(){
MessagingService.get_unread_messages_count()
.then(function(result){
$scope.count.messages = result.messages;
$scope.count.notifiations = result.notifications;
})
}
$scope.groupNotifications = function (notifications) {
$scope.notifications = {1: [], 2: [], 3: [], 4: []};
angular.forEach(notifications, function (value, key) {
$scope.notifications[value.type].push(value);
});
$scope.$apply();
};
/**
* When "notifications" send via websocket, parse notifications by type.
*/
$scope.$on("notifications", function (event, data) {
$log.debug("Notification!", data);
$scope.groupNotifications(data);
});
/**
* When clicked mark the notification as read.
* @param items
* @todo: do it in detail page of notification
*/
$scope.markAsRead = function (event,item, group, index) {
//Added event parameter to stop propagate, so that behaviour of outsideClick won't be interrupted.
event.stopPropagation();
WSOps.doSend(angular.toJson({data: {view: 'notify', id:item.id}}));
$scope.notifications[group].splice(index,1);
$event.preventDefault();
$event.stopPropagation();
return false;
};
// if markasread triggered outside the directive
// $scope.$on("markasread", function (event, data) {
// $scope.markAsRead(data);
// });
initCounters();
}
};
})
......@@ -663,64 +613,20 @@ angular.module('ulakbus')
}
}
})
// listen for message in directives below
.directive('messaging', function (Generator, MessagingService, $log, $rootScope) {
return {
templateUrl: 'shared/templates/directives/messaging/index.html',
restrict: 'E',
replace: true,
scope: {},
controller: function ($scope) {
$scope.messages = [];
$scope.$on("messages", function (event, data) {
$log.debug("Message List Received", data);
$scope.messages(data);
});
$scope.$on("message", function (event, data) {
$log.debug("Message Received", data);
// do relevant action here
});
}
};
})
.directive('messageDetail', function (Generator, MessagingService, $log, $rootScope) {
return {
templateUrl: 'shared/templates/directives/messaging/detail.html',
restrict: 'E',
replace: true,
scope: {},
controller: function ($scope) {
$scope.messages = [];
$scope.$on("detailMessages", function (event, data) {
$log.debug("Detail Message Received", data);
$scope.messages = data;
});
$scope.$on("message", function (event, data) {
$log.debug("Message Received", data);
// do relevant action here
// if channel_key belongs to detail screen then append msg to the end of the thread
});
}
};
})
.directive('timetableActionSelector', function($timeout){
.directive('timetableActionSelector', function($timeout) {
// Display/hide popover with actions
// global listener used to close popover when user clicks outside of the popover
$('html').on('click', function(e) {
$('html').on('click', function (e) {
var target = $(e.target);
if (target.parents().is('.action-selector')){
if (target.parents().is('.action-selector')) {
target.parents('.action-selector').children('.popover').toggleClass('ng-hide');
return;
}
if (target.hasClass('action-selector')){
if (target.hasClass('action-selector')) {
target.children('.popover').toggleClass('ng-hide');
return;
};
}
;
$('.course-prg-scheduler .action-selector>.popover').toggleClass('ng-hide', true);
});
......@@ -730,29 +636,29 @@ angular.module('ulakbus')
externalModel: '=ngModel',
onChange: "&ngChange"
},
link: function(iScope, iElem, iAttrs){
link: function (iScope, iElem, iAttrs) {
var valueToClassMap = {
1: 'action-indicator_appropriate',
2: 'action-indicator_uncertain',
3: 'action-indicator_busy'
};
if (iAttrs.hasOwnProperty('readonly')){
iAttrs.$observe('readonly', function(v){
if (iAttrs.hasOwnProperty('readonly')) {
iAttrs.$observe('readonly', function (v) {
if (v && v == 'false') v = false;
iScope.readonly = v;
});
}
iScope.$watch('externalModel', function(value){
iScope.$watch('externalModel', function (value) {
iScope.value = valueToClassMap[value];
});
iScope.setModelValue = function(value){
iScope.setModelValue = function (value) {
var oldValue = iScope.externalModel;
iScope.externalModel = value;
// call change in next digest
$timeout(function(){
$timeout(function () {
if (iScope.onChange && value != oldValue) {
iScope.onChange();
}
......@@ -761,4 +667,25 @@ angular.module('ulakbus')
}
}
}
})
/**
* @memberof ulakbus
* @ngdoc directive
* @name onEnterPressed
* @description Fire action when enter pressed on element
*/
.directive("onEnterPressed", function () {
return {
link: function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13 && !event.ctrlKey) {
scope.$apply(function (){
scope.$eval(attrs.onEnterPressed);
});
event.preventDefault();
}
})
}
}
});
......@@ -32,9 +32,9 @@
</li>-->
<li uib-dropdown auto-close="outsideClick">
<a uib-dropdown-toggle>
<div class="badge" ng-show="notifications[2].length > 0">{{notifications[2].length}}</div>
<i class="fa fa-envelope fa-fw" tooltip-placement="bottom" uib-tooltip="Mesajlar"></i> <i
class="fa fa-caret-down"></i>
<div class="badge" ng-show="count.messages > 0">{{count.messages}}</div>
<i class="fa fa-envelope fa-fw" tooltip-placement="bottom" uib-tooltip="Mesajlar"></i>
<!--<i class="fa fa-caret-down"></i>-->
</a>
<ul class="dropdown-messages" uib-dropdown-menu ng-show="notifications[2].length > 0">
<li ng-repeat="notify in notifications[2] | limitTo: '8'">
......@@ -62,47 +62,47 @@
<!-- /.dropdown-messages -->
</li>
<!-- /.dropdown -->
<li uib-dropdown auto-close="outsideClick">
<a uib-dropdown-toggle>
<div class="badge" ng-if="notifications[1].length > 0">{{notifications[1].length}}</div>
<i class="fa fa-tasks fa-fw" tooltip-placement="bottom" uib-tooltip="Görevler"></i> <i
class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-tasks" uib-dropdown-menu ng-if="notifications[1].length > 0">
<li ng-repeat="notify in notifications[1] | limitTo: '8'">
<a href="{{notify.url}}">
<div>
<p>
<strong>{{notify.title}}</strong>
<span class="pull-right text-muted">{{notify.body}}</span>
<span ng-click="markAsRead($event,notify, 1, $index)" class="pull-right fa fa-times"></span>
</p>
<!-- todo: progress bar will be used in future developments-->
<!--<div class="progress progress-striped active">-->
<!--<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">-->
<!--<span class="sr-only">40% Complete (success)</span>-->
<!--</div>-->
<!--</div>-->
<!--<li uib-dropdown auto-close="outsideClick">-->
<!--<a uib-dropdown-toggle>-->
<!--<div class="badge" ng-if="notifications[1].length > 0">{{notifications[1].length}}</div>-->
<!--<i class="fa fa-tasks fa-fw" tooltip-placement="bottom" uib-tooltip="Görevler"></i> <i-->
<!--class="fa fa-caret-down"></i>-->
<!--</a>-->
<!--<ul class="dropdown-tasks" uib-dropdown-menu ng-if="notifications[1].length > 0">-->
<!--<li ng-repeat="notify in notifications[1] | limitTo: '8'">-->
<!--<a href="{{notify.url}}">-->
<!--<div>-->
<!--<p>-->
<!--<strong>{{notify.title}}</strong>-->
<!--<span class="pull-right text-muted">{{notify.body}}</span>-->
<!--<span ng-click="markAsRead($event,notify, 1, $index)" class="pull-right fa fa-times"></span>-->
<!--</p>-->
<!--&lt;!&ndash; todo: progress bar will be used in future developments&ndash;&gt;-->
<!--&lt;!&ndash;<div class="progress progress-striped active">&ndash;&gt;-->
<!--&lt;!&ndash;<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">&ndash;&gt;-->
<!--&lt;!&ndash;<span class="sr-only">40% Complete (success)</span>&ndash;&gt;-->
<!--&lt;!&ndash;</div>&ndash;&gt;-->
<!--&lt;!&ndash;</div>&ndash;&gt;-->
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a class="text-center">
<strong>See All Tasks</strong>
<i class="fa fa-angle-right"></i>
</a>
</li>
</ul>
<!--</div>-->
<!--</a>-->
<!--</li>-->
<!--<li class="divider"></li>-->
<!--<li>-->
<!--<a class="text-center">-->
<!--<strong>See All Tasks</strong>-->
<!--<i class="fa fa-angle-right"></i>-->
<!--</a>-->
<!--</li>-->
<!--</ul>-->
<!-- /.dropdown-tasks -->
</li>
<!-- /.dropdown -->
<li uib-dropdown auto-close="outsideClick">
<a uib-dropdown-toggle>
<div class="badge" ng-if="notifications[3].length > 0">{{notifications[3].length}}</div>
<i class="fa fa-bell fa-fw" tooltip-placement="bottom" uib-tooltip="Duyurular"></i> <i
class="fa fa-caret-down"></i>
<div class="badge" ng-if="count.notifications > 0">{{count.notifications}}</div>
<i class="fa fa-bell fa-fw" tooltip-placement="bottom" uib-tooltip="Duyurular"></i>
<!--<i class="fa fa-caret-down"></i>-->
</a>
<ul class="dropdown-alerts" uib-dropdown-menu ng-if="notifications[3].length > 0">
<li ng-repeat="notify in notifications[3] | limitTo: '8'">
......@@ -114,6 +114,13 @@
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a class="text-center">
<strong>See All Notifications</strong>
<i class="fa fa-angle-right"></i>
</a>
</li>
</ul>
<!-- /.dropdown-alerts -->
</li>
......
......@@ -19,7 +19,7 @@
</ul>
</div>
<div class="close-chat-app">
<span class="glyphicon glyphicon-remove"></span>
<span class="glyphicon glyphicon-remove" ng-click="hideApp()"></span>
</div>
</div>
......
<div class="chat-app">
<div class="chat-app" ng-hide="hidden">
<div class="chat-app-container">
<div class="side-navigation">
......@@ -55,6 +55,5 @@
</div>
</div>
<!-- end of create-new-message-window -->
</div>
</div>
/**
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*
* @author Evren Kutar
*/
angular.module('ulakbus.messagingService', ['ui.bootstrap'])
/**
* @memberof ulakbus.formService
* @ngdoc factory
* @name Generator
* @description form service's Generator factory service handles all generic form operations
*/
.factory('MessagingService', function ($q, $timeout, $sce, $location, $route, $compile, $log, $rootScope, Moment, WSOps) {
var msg = {};
msg.send = function (msg) {
/**
* send the message as following structure;
*
* MSG_TYPES can be follwing;
*
* MSG_TYPES = (
* (2, "Direct Message"),
* (3, "Broadcast Message"),
* (4, "Channel Message")
* )
*
* {
* 'view':'_zops_create_message',
* 'message': {
* 'channel': "code_name of the channel",
* 'receiver': "Key of receiver. Can be blank for non-direct messages",
* 'client_id': "Client side unique id for referencing this message",
* 'title': "Title of the message. Can be blank.",
* 'body': "Message body.",
* 'type': zengine.messaging.model.MSG_TYPES,
* 'attachments': [{
* 'description': "Can be blank.",
* 'name': "File name with extension.",
* 'content': "base64 encoded file content"
* }]
* }
*
* wait for response as
*
* {
* 'msg_key': "Key of the just created message object",
* }
*
*/
function prepMsg(msg) {
var outgoing = {
form_params: {
view: '_zops_create_message',
message: {
'channel': msg.channel, // this can be both channel and direct msg. remember direct msg is channel
'receiver': msg.receiver,
'client_id': msg.client_id, // "Client side unique id for referencing this message",
'title': msg.title, // "Title of the message. Can be blank.",
'body': msg.body, // "Message body.",
'type': msg.TYPE, // type can be one of the above
// 'attachments': [{ // do it with fileread directive
// 'description': "Can be blank.",
// 'name': "File name with extension.",
// 'content': "base64 encoded file content"
// }]
}
}
};
return outgoing;
}
WSOps.request(prepMsg(msg)).then(function (data) {
$log.debug("message sent:", data);
});
};
msg.incoming = function () {
/**
*
*/
};
msg.update = function (msg, action) {
/**
* update / delete a message here
*/
var outgoing = {
form_params: {
view: '_zops_' + action + '_message',
message: {
'channel': msg.channel, // this can be both channel and direct msg. remember direct msg is channel
'receiver': msg.receiver,
'client_id': msg.client_id, // "Client side unique id for referencing this message",
'title': msg.title, // "Title of the message. Can be blank.",
'body': msg.body, // "Message body.",
'type': msg.TYPE // type can be one of the above
}
}
};
return WSOps.request(outgoing).then(function (data) {
$log.debug("update request sent");
return data;
})
};
/**
* use this method to get all messages of channel and direct messages
* REMEMBER; direct messages are also channels, everything is channel on backend!
* @param chnls
* @returns {*}
*/
msg.get_channel = function (chnls) {
/**
* request channels as below;
*
* {
* 'view':'_zops_show_channel',
* 'channel_key': "Key of the requested channel"
* }
*
* wait for response
*
* {
* 'channel_key': "key of channel",
* 'description': string,
* 'no_of_members': int,
* 'member_list': [
* {'name': string,
* 'is_online': bool,
* 'avatar_url': string,
* }],
* 'last_messages': [
* {'content': string,
* 'key': string,
* 'actions':[
* {'title': string,
* 'cmd': string
* }
* ]
* }
* ]
* }
*
*/
var outgoing = {
form_params: {
view: '_zops_show_channel',
channel_key: chnls.key
}
};
return WSOps.request(outgoing).then(function (data) {
$log.debug("message sent:", data);
return data;
});
};
return msg;
});
\ No newline at end of file
......@@ -147,7 +147,9 @@ angular.module('ulakbus')
// this way it broadcasts to relevant listener
// i group messages and notifications into 2 groups
// necessary actions will taken where it is listened
$timeout(function(){
$rootScope.$broadcast(type[msg_data["type"]], msg_data);
});
},
dashboard: function () {
// dashboard consists of menu and user specifications
......
/**
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*
* @author Vladimir Baranov
*/
angular.module("ulakbus")
.service("Utils", function(){
var self = this;
// check if obj1 has properties values equal to corresponding properties in obj2
function hasEqualProperties(obj1, obj2){
var result = true
for (var prop in obj2){
if(obj2.hasOwnProperty(prop)){
result = result && obj2[prop] == obj1[prop];
}
}
return result;
}
/**
* @param list {Array} Array of objects to group
* @param propName {String} property name to group array by
* @returns {Object}
*/
this.groupBy = function (list, propName) {
return list.reduce(function(acc, item) {
(acc[item[propName]] = acc[item[propName]] || []).push(item);
return acc;
}, {});
};
/**
* @param list {Array} Array of objects to group
* @param condition {Object} conditions object. If object in collection has same values as in conditions object it will be removed
* @returns {Object}|undefined removed object or undefined
*/
this.deleteWhere = function(list, condition){
for (var i = 0; i < list.length; i++){
if (hasEqualProperties(list[i], condition)){
list.splice(i, 1);
return list[i];
}
}
}
});
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