Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
U
ulakbus-ui
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ulakbus
ulakbus-ui
Commits
299dfc77
Commit
299dfc77
authored
Jul 27, 2016
by
Vladimir Baranov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature/messaging' into develop
parents
2619b847
145d9e37
Changes
21
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1185 additions
and
342 deletions
+1185
-342
Gruntfile.js
Gruntfile.js
+6
-3
app.css
app/app.css
+95
-10
app.js
app/app.js
+1
-1
messaging.js
app/components/messaging/messaging.js
+344
-0
messaging_service.js
app/components/messaging/messaging_service.js
+423
-0
add_user_unit.html
app/components/messaging/templates/add_user_unit.html
+15
-0
conversation.html
app/components/messaging/templates/conversation.html
+83
-0
create_channel.html
app/components/messaging/templates/create_channel.html
+9
-0
delete_confirmation.html
app/components/messaging/templates/delete_confirmation.html
+9
-0
index.html
app/components/messaging/templates/index.html
+29
-0
search_user.html
app/components/messaging/templates/search_user.html
+11
-0
index.html
app/index.html
+5
-1
main.html
app/main.html
+3
-1
main.js
app/main.js
+1
-1
directives.js
app/shared/directives.js
+46
-119
header-notification.html
app/shared/templates/directives/header-notification.html
+45
-38
detail.html
app/shared/templates/directives/messaging/detail.html
+2
-2
index.html
app/shared/templates/directives/messaging/index.html
+2
-3
messagingService.js
app/zetalib/messagingService.js
+0
-161
socket.js
app/zetalib/socket.js
+4
-2
utils_service.js
app/zetalib/utils_service.js
+52
-0
No files found.
Gruntfile.js
View file @
299dfc77
...
...
@@ -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'
},
...
...
app/app.css
View file @
299dfc77
...
...
@@ -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 */
...
...
app/app.js
View file @
299dfc77
...
...
@@ -28,7 +28,7 @@ angular.module(
'ngSanitize'
,
'ngCookies'
,
'ulakbus.formService'
,
'ulakbus.messaging
Service
'
,
'ulakbus.messaging'
,
'ulakbus.dashboard'
,
'ulakbus.auth'
,
'ulakbus.error_pages'
,
...
...
app/components/messaging/messaging.js
0 → 100644
View file @
299dfc77
angular
.
module
(
"ulakbus.messaging"
)
.
directive
(
'messaging'
,
function
(
Generator
,
MessagingService
,
$log
,
$rootScope
,
MessagingPopup
,
Utils
)
{
// get channel key
function
getKey
(
channel
)
{
if
(
!
channel
)
return
;
if
(
!
angular
.
isObject
(
channel
))
return
channel
;
var
channelKey
=
channel
.
channel_key
;
if
(
!
channelKey
&&
channel
.
hasOwnProperty
(
'key'
)){
channelKey
=
channel
.
key
;
}
return
channelKey
;
}
function
searchWrapper
(
scope
,
promiseWrapper
){
scope
.
loading
=
true
;
scope
.
searchResult
=
[];
promiseWrapper
()
.
then
(
function
(
result
){
scope
.
searchResult
=
result
;
})
.
finally
(
function
(){
scope
.
loading
=
false
;
})
}
return
{
templateUrl
:
'components/messaging/templates/index.html'
,
restrict
:
'E'
,
scope
:
{},
link
:
function
(
iScope
,
iElem
,
iAttrs
){
iScope
.
chatAppIsHidden
=
true
;
// shared object to populate models through scopes
iScope
.
shared
=
{};
var
popupRootElement
=
$
(
iElem
).
find
(
'.popup-placeholder'
);
function
editChannelPopup
(
channel
){
return
MessagingPopup
.
show
({
templateUrl
:
"components/messaging/templates/create_channel.html"
,
rootElement
:
popupRootElement
,
link
:
function
(
scope
){
scope
.
channel
=
channel
||
{};
scope
.
title
=
"Kanalı düzenle"
;
scope
.
actionTitle
=
"Düzenle"
;
if
(
!
channel
){
scope
.
title
=
"Yeni Kanal Oluştur"
;
scope
.
actionTitle
=
"Oluştur"
;
}
}
})
}
function
updateLastMessage
(
message
){
if
(
!
message
&&
iScope
.
selectedChannel
&&
iScope
.
selectedChannel
.
messages
.
length
>
0
){
var
last
=
iScope
.
selectedChannel
.
messages
.
length
-
1
;
return
iScope
.
lastMessage
=
iScope
.
selectedChannel
.
messages
[
last
];
}
return
iScope
.
lastMessage
=
message
;
}
function
appendMessage
(
channel
,
message
){
if
(
channel
&&
getKey
(
message
)
==
getKey
(
channel
)){
if
(
channel
.
messages
){
channel
.
messages
.
push
(
message
);
}
}
updateLastMessage
(
message
);
}
function
updateAndSelect
(
channelKey
){
channelKey
=
getKey
(
channelKey
);
return
iScope
.
updateChannelsList
().
then
(
function
(){
return
iScope
.
selectChannel
(
channelKey
);
})
}
function
deleteMessageLocally
(
messageKey
){
if
(
iScope
.
selectedChannel
){
Utils
.
deleteWhere
(
iScope
.
selectedChannel
.
messages
,
{
'key'
:
messageKey
});
}
}
function
reportLastSeenMessage
(){
if
(
!
iScope
.
lastMessage
||
!
iScope
.
selectedChannel
)
return
;
// instantly received messages haven't timestamp. Use moment
// FIXME: change to proper moment processing
// var ts = iScope.lastMessage.moment.toISOString();
var
ts
=
iScope
.
lastMessage
.
moment
.
format
(
"YYYY-MM-DDTHH:mm:ss"
);
MessagingService
.
report_last_seen_message
(
getKey
(
iScope
.
selectedChannel
),
iScope
.
lastMessage
.
key
,
ts
);
};
iScope
.
deleteConfirmation
=
function
(
title
){
return
MessagingPopup
.
show
({
templateUrl
:
"components/messaging/templates/delete_confirmation.html"
,
link
:
function
(
scope
){
scope
.
title
=
title
||
"Silmek istediğinize emin misiniz?"
;
},
rootElement
:
popupRootElement
})
};
iScope
.
updateChannelsList
=
function
(){
return
MessagingService
.
list_channels
().
then
(
function
(
groupedChannels
)
{
iScope
.
publicChannels
=
groupedChannels
[
MessagingService
.
CHANNEL_TYPE
.
PUBLIC
];
iScope
.
notificationsChannel
=
groupedChannels
[
MessagingService
.
CHANNEL_TYPE
.
NOTIFICATION
][
0
];
iScope
.
directChannels
=
groupedChannels
[
MessagingService
.
CHANNEL_TYPE
.
DIRECT
];
});
}
this
.
createDirectChannel
=
function
(
user
){
// user format is ['username', 'key', 'avatarUrl']
var
key
=
user
[
1
];
MessagingService
.
create_direct_channel
(
key
)
.
then
(
function
(
result
){
updateAndSelect
(
getKey
(
result
));
})
};
iScope
.
createDirectChannel
=
this
.
createDirectChannel
;
iScope
.
hideApp
=
function
(){
iScope
.
chatAppIsHidden
=
true
;
};
iScope
.
showApp
=
function
(){
iScope
.
chatAppIsHidden
=
false
;
iScope
.
updateChannelsList
();
}
iScope
.
searchUser
=
function
(){
MessagingPopup
.
show
({
templateUrl
:
"components/messaging/templates/search_user.html"
,
rootElement
:
popupRootElement
,
link
:
function
(
scope
){
scope
.
onChange
=
function
(
query
){
searchWrapper
(
scope
,
function
(){
return
MessagingService
.
search_user
(
query
);
})
};
scope
.
onChange
(
""
);
}
}).
then
(
function
(
user
){
return
iScope
.
createDirectChannel
(
user
);
});
};
iScope
.
createChannel
=
function
(){
return
editChannelPopup
().
then
(
function
(
channel
){
return
MessagingService
.
create_channel
(
channel
.
name
,
channel
.
description
||
""
)
.
then
(
function
(
newChannel
){
updateAndSelect
(
newChannel
)
});
})
};
iScope
.
applyChannelAction
=
function
(
channel
,
action
){
var
actionView
=
action
[
1
];
switch
(
actionView
)
{
case
'_zops_pin_channel'
:
MessagingService
.
pin_channel
(
getKey
(
channel
));
break
;
case
'_zops_delete_channel'
:
iScope
.
deleteConfirmation
(
'Kanalı silmek istediğinize emin misiniz?'
)
.
then
(
function
(){
MessagingService
.
delete_channel
(
getKey
(
channel
));
});
break
;
case
'_zops_edit_channel'
:
editChannelPopup
(
channel
).
then
(
function
(
channelData
){
return
MessagingService
.
edit_channel
(
getKey
(
channelData
),
channelData
.
name
,
channelData
.
description
||
""
);
});
break
;
case
'_zops_add_members'
:
MessagingPopup
.
show
({
templateUrl
:
"components/messaging/templates/add_user_unit.html"
,
rootElement
:
popupRootElement
,
link
:
function
(
scope
){
scope
.
title
=
"Kanala kullanıcı ekle"
;
scope
.
placeholder
=
"Eklemek için kullanıcı ara"
;
scope
.
onChange
=
function
(
query
){
searchWrapper
(
scope
,
function
(){
return
MessagingService
.
search_user
(
query
);
})
};
scope
.
onChange
(
""
);
}
}).
then
(
function
(
userKey
){
return
MessagingService
.
add_members
(
getKey
(
channel
),
[
userKey
]);
});
break
;
case
"_zops_add_unit_to_channel"
:
MessagingPopup
.
show
({
templateUrl
:
"components/messaging/templates/add_user_unit.html"
,
rootElement
:
popupRootElement
,
link
:
function
(
scope
){
scope
.
title
=
"Birim Ekle"
;
scope
.
placeholder
=
"Kanala eklemek için birim ara"
;
scope
.
onChange
=
function
(
query
){
searchWrapper
(
scope
,
function
(){
return
MessagingService
.
search_unit
(
query
);
})
};
scope
.
onChange
(
""
);
}
}).
then
(
function
(
unitKey
){
var
channelKey
=
getKey
(
iScope
.
selectedChannel
);
return
MessagingService
.
add_members
(
channelKey
,
unitKey
);
});
break
;
}
};
function
selectChannel
(
channelKey
,
silent
){
if
(
!
silent
)
iScope
.
loadingChannel
=
true
;
return
MessagingService
.
show_channel
(
channelKey
).
then
(
function
(
result
){
return
result
;
}).
finally
(
function
(){
iScope
.
loadingChannel
=
false
;
})
}
iScope
.
selectChannel
=
function
(
channel
,
silent
){
var
channelKey
=
getKey
(
channel
);
selectChannel
(
channelKey
,
silent
).
then
(
function
(
result
){
iScope
.
selectedChannel
=
result
;
iScope
.
selectedChannel
.
read_only
=
channel
.
read_only
;
iScope
.
selectedChannel
.
messages
=
result
.
last_messages
;
updateLastMessage
(
channel
.
messages
);
reportLastSeenMessage
();
});
};
iScope
.
isChannelSelected
=
function
(
channel
){
return
iScope
.
selectedChannel
&&
getKey
(
channel
)
==
getKey
(
iScope
.
selectedChannel
);
}
iScope
.
sendMessage
=
function
(
content
){
if
(
!
content
)
return
;
var
channelKey
=
getKey
(
iScope
.
selectedChannel
);
// select message type: 2 - direct message, 4 - channel message;
var
msgType
=
iScope
.
selectedChannel
.
type
==
MessagingService
.
CHANNEL_TYPE
.
DIRECT
?
2
:
4
;
MessagingService
.
create_message
(
channelKey
,
msgType
,
content
).
then
(
function
(){
iScope
.
shared
.
message
=
""
;
});
};
iScope
.
applyMessageAction
=
function
(
message
,
action
){
var
actionView
=
action
[
1
];
switch
(
actionView
)
{
case
"_zops_favorite_message"
:
MessagingService
.
add_to_favorites
(
message
.
key
)
.
then
(
function
(){
// force actions to reload
message
.
actions
=
null
;
});
break
;
case
"_zops_flag_message"
:
MessagingService
.
flag_message
(
message
.
key
,
true
)
.
then
(
function
(){
// force actions to reload
message
.
actions
=
null
;
});
break
;
case
"_zops_unflag_message"
:
MessagingService
.
flag_message
(
message
.
key
,
false
)
.
then
(
function
(){
// force actions to reload
message
.
actions
=
null
;
});
break
;
case
"_zops_delete_message"
:
iScope
.
deleteConfirmation
(
"Mesajı silmek istediğinize emin misiniz?"
)
.
then
(
function
(){
return
MessagingService
.
delete_message
(
message
.
key
).
then
(
function
(){
deleteMessageLocally
(
message
.
key
);
})
});
break
;
case
"_zops_edit_message"
:
break
;
}
};
iScope
.
getMessageActions
=
function
(
message
){
if
(
message
.
actions
)
return
;
MessagingService
.
get_message_actions
(
message
.
key
).
then
(
function
(
result
){
message
.
actions
=
result
.
actions
;
})
};
// listen to new messages and add them to selected channel if any
$rootScope
.
$on
(
"message"
,
function
(
e
,
message
){
appendMessage
(
iScope
.
selectedChannel
,
MessagingService
.
prepareMessage
(
message
));
});
// notifications in messaging window are processed as ordinary messages
$rootScope
.
$on
(
"notifications"
,
function
(
e
,
notification
){
appendMessage
(
iScope
.
selectedChannel
,
MessagingService
.
prepareMessage
(
notification
));
});
$rootScope
.
$on
(
"user_ready"
,
function
(){
// init service after user logged in
iScope
.
selectedChannel
=
null
;
iScope
.
publicChannels
=
[];
iScope
.
notificationsChannel
=
[];
iScope
.
directChannels
=
[]
iScope
.
hideApp
();
});
}
};
})
.
filter
(
'fromNow'
,
function
(
Moment
){
return
function
(
datetime
){
return
Moment
(
datetime
).
fromNow
();
}
})
.
directive
(
"scrollDownWhenUpdate"
,
function
(
$timeout
){
return
{
scope
:
{
changesWatcher
:
"&scrollDownWhenUpdate"
},
link
:
function
(
iScope
,
iElem
,
iAttrs
){
var
elem
=
$
(
iElem
);
iScope
.
$watch
(
iScope
.
changesWatcher
,
function
(
value
){
if
(
value
){
// update on next digest
$timeout
(
function
(){
elem
.
scrollTop
(
elem
[
0
].
scrollHeight
);
},
0
);
}
});
}
}
})
app/components/messaging/messaging_service.js
0 → 100644
View file @
299dfc77
/**
* 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.messaging'
,
[
'ui.bootstrap'
])
/**
* @memberof ulakbus.messaging
* @ngdoc factory
* @name MessagingService
* @description Service handles all stuff related to messaging
*/
.
factory
(
'MessagingService'
,
function
(
$q
,
$timeout
,
$compile
,
$log
,
$rootScope
,
Moment
,
WSOps
,
Utils
)
{
var
msg
=
{};
var
notificationsChannelKey
;
msg
.
CHANNEL_TYPE
=
{
"PUBLIC"
:
15
,
"DIRECT"
:
10
,
"NOTIFICATION"
:
5
};
function
wsReady
()
{
/**
* wait until websocket will be open
*/
var
deferred
=
$q
.
defer
();
var
dismissWatcher
=
$rootScope
.
$watch
(
'websocketIsOpen'
,
function
(
isOpen
){
if
(
isOpen
){
dismissWatcher
();
deferred
.
resolve
();
}
});
return
deferred
.
promise
;
}
function
wsRequest
(
outgoing
){
return
wsReady
().
then
(
function
(){
return
WSOps
.
request
(
outgoing
);
})
}
function
prepareMessages
(
messages
){
for
(
var
i
=
0
;
i
<
messages
.
length
;
i
++
){
var
message
=
messages
[
i
];
msg
.
prepareMessage
(
message
);
}
}
// prepare message to show in UI
msg
.
prepareMessage
=
function
(
message
){
if
(
!
message
.
timestamp
){
message
.
moment
=
Moment
();
}
else
{
var
ts
=
message
.
timestamp
.
replace
(
"Z"
,
""
);
message
.
moment
=
Moment
(
ts
);
}
return
message
;
};
msg
.
get_notifications_channel_key
=
function
(){
return
notificationsChannelKey
;
};
/**
* API
*
* */
msg
.
list_channels
=
function
list_channels
(){
/**
* request channels list as below;
* {
* 'view':'_zops_list_channels',
* }
*
* wait for response
*
* {
* 'channels': [
* {'name': string, // name of channel
* 'key': key, // key of channel
* 'unread': int, // unread message count
* 'type': int, // channel type,
* // 15: public channels (chat room/broadcast channel distinction comes from "read_only" flag)
* // 10: direct channels
* // 5: one and only private channel which can be "Notifications"
* 'read_only': boolean, // true if this is a read-only subscription to a broadcast channel
* // false if it's a public chat room
*
* 'actions':[('action name', 'view name'),]
* }
*
*/
var
outgoing
=
{
view
:
'_zops_list_channels'
};
return
wsRequest
(
outgoing
).
then
(
function
(
data
)
{
console
.
error
(
"channels: "
,
data
.
channels
);
var
grouped
=
Utils
.
groupBy
(
data
.
channels
||
[],
"type"
);
// save notifications channel key
notificationsChannelKey
=
grouped
[
msg
.
CHANNEL_TYPE
.
NOTIFICATION
][
0
].
key
;
return
grouped
;
});
};
msg
.
search_user
=
function
(
query
)
{
var
outgoing
=
{
view
:
'_zops_search_user'
,
query
:
query
};
return
wsRequest
(
outgoing
).
then
(
function
(
data
)
{
return
data
.
results
});
};
msg
.
search_unit
=
function
(
query
)
{
var
outgoing
=
{
view
:
'_zops_search_unit'
,
query
:
query
};
return
wsRequest
(
outgoing
).
then
(
function
(
data
)
{
return
data
.
results
});
};
msg
.
create_direct_channel
=
function
(
key
)
{
var
outgoing
=
{
'view'
:
'_zops_create_direct_channel'
,
'user_key'
:
key
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Create direct channel result: "
,
result
);
return
result
;
})
};
msg
.
create_channel
=
function
(
name
,
desription
)
{
var
outgoing
=
{
view
:
'_zops_create_channel'
,
name
:
name
,
description
:
desription
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Channel "
,
name
,
"created: "
,
result
);
return
result
;
})
};
msg
.
add_members
=
function
(
channelKey
,
members
,
readOnly
)
{
var
outgoing
=
{
view
:
'_zops_add_members'
,
channel_key
:
channelKey
,
read_only
:
!!
readOnly
,
members
:
members
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Members "
,
members
,
" added to channel "
,
channelKey
,
": "
,
result
);
return
result
;
})
};
msg
.
add_unit_to_channel
=
function
(
channelKey
,
unitKey
,
readOnly
)
{
var
outgoing
=
{
view
:
'_zops_add_unit_to_channel'
,
channel_key
:
channelKey
,
unit_key
:
unitKey
,
read_only
:
!!
readOnly
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Unit "
,
unitKey
,
" added to channel "
,
channelKey
,
": "
,
result
);
return
result
;
});
};
msg
.
delete_channel
=
function
(
channelKey
)
{
var
outgoing
=
{
view
:
'_zops_delete_channel'
,
channel_key
:
channelKey
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Channel "
,
channelKey
,
" deleted: "
,
result
);
return
result
;
})
};
msg
.
edit_channel
=
function
(
channelKey
,
name
,
desription
)
{
var
outgoing
=
{
view
:
'_zops_edit_channel'
,
channel_key
:
channelKey
,
name
:
name
,
description
:
desription
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Channel "
,
channelKey
,
" edited: "
,
outgoing
,
result
);
return
result
;
})
};
msg
.
pin_channel
=
function
(
channelKey
)
{
var
outgoing
=
{
view
:
'_zops_pin_channel'
,
channel_key
:
channelKey
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Channel "
,
channelKey
,
" pinned: "
,
result
);
return
result
;
})
};
msg
.
show_channel
=
function
(
channelKey
){
var
outgoing
=
{
view
:
'_zops_show_channel'
,
key
:
channelKey
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Show channel "
,
channelKey
,
": "
,
result
);
prepareMessages
(
result
.
last_messages
);
return
result
;
})
};
msg
.
channel_history
=
function
(
channelKey
,
lastMessageTimestamp
)
{
var
outgoing
=
{
view
:
'_zops_channel_history'
,
channel_key
:
channelKey
,
timestamp
:
lastMessageTimestamp
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Load channel "
,
channelKey
,
"history: "
,
result
);
return
result
;
})
};
msg
.
get_unread_messages_count
=
function
(){
var
outgoing
=
{
'view'
:
'_zops_unread_count'
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Get unread messages count: "
,
result
);
return
result
;
})
};
msg
.
report_last_seen_message
=
function
(
channelKey
,
msgKey
,
timestamp
){
var
outgoing
=
{
view
:
'_zops_report_last_seen_message'
,
channel_key
:
channelKey
,
msg_key
:
msgKey
,
timestamp
:
timestamp
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Report last seen message "
,
channelKey
,
msgKey
,
timestamp
,
": "
,
result
);
return
result
;
})
};
msg
.
create_message
=
function
(
channelKey
,
msgType
,
body
,
attachments
){
var
outgoing
=
{
view
:
'_zops_create_message'
,
message
:
{
channel
:
channelKey
,
type
:
msgType
,
title
:
""
,
receiver
:
""
,
body
:
body
,
attachments
:
attachments
}
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Message sent: "
,
result
);
return
result
;
})
};
msg
.
find_message
=
function
(
channelKey
,
query
,
pageNumber
)
{
var
outgoing
=
{
view
:
'_zops_search_find_message'
,
channel_key
:
channelKey
,
query
:
query
,
page
:
pageNumber
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Find message: "
,
result
);
return
result
;
});
};
msg
.
delete_message
=
function
(
msgKey
)
{
var
outgoing
=
{
view
:
'_zops_delete_message'
,
key
:
msgKey
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Delete message "
,
msgKey
,
":"
,
result
);
return
result
;
});
};
msg
.
edit_message
=
function
(
msgKey
,
body
)
{
var
outgoing
=
{
view
:
'_zops_edit_message'
,
message
:
{
key
:
msgKey
,
body
:
body
}
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Edit message"
,
msgKey
,
":"
,
result
);
return
result
;
});
};
msg
.
flag_message
=
function
(
msgKey
,
flag
)
{
var
outgoing
=
{
view
:
'_zops_flag_message'
,
key
:
msgKey
,
flag
:
flag
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Flag message "
,
msgKey
,
flag
,
":"
,
result
);
return
result
;
});
};
msg
.
get_message_actions
=
function
(
msgKey
)
{
var
outgoing
=
{
view
:
'_zops_get_message_actions'
,
key
:
msgKey
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Get message actions"
,
msgKey
,
":"
,
result
);
return
result
;
});
};
msg
.
add_to_favorites
=
function
(
msgKey
)
{
var
outgoing
=
{
view
:
'_zops_add_to_favorites'
,
key
:
msgKey
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Add message "
,
msgKey
,
" to favorites: "
,
result
);
return
result
;
});
};
msg
.
remove_from_favorites
=
function
(
msgKey
)
{
var
outgoing
=
{
view
:
'_zops_remove_to_favorites'
,
key
:
msgKey
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"Remove message "
,
msgKey
,
" from favorites: "
,
result
);
return
result
;
});
};
msg
.
list_favorites
=
function
(
channelKey
)
{
var
outgoing
=
{
view
:
'_zops_list_favorites'
,
channel_key
:
channelKey
};
return
wsRequest
(
outgoing
).
then
(
function
(
result
){
$log
.
info
(
"List favorites for channel"
,
channelKey
,
": "
,
result
);
return
result
;
});
};
return
msg
;
})
.
service
(
"MessagingPopup"
,
function
(
$q
,
$compile
,
$http
,
$rootScope
){
function
compile
(
template
,
config
){
var
resultDeferred
=
$q
.
defer
();
var
scope
=
config
.
scope
||
$rootScope
.
$new
(
true
);
var
rootElement
=
config
.
rootElement
;
var
element
=
$compile
(
template
)(
scope
);
if
(
config
.
link
){
config
.
link
(
scope
);
}
scope
.
done
=
function
(
result
){
resultDeferred
.
resolve
.
apply
(
this
,
arguments
);
};
scope
.
cancel
=
function
(){
resultDeferred
.
reject
.
apply
(
this
,
arguments
);
};
rootElement
.
empty
();
rootElement
.
append
(
element
);
resultDeferred
.
promise
.
_done
=
scope
.
done
;
resultDeferred
.
promise
.
_cancel
=
scope
.
cancel
;
return
resultDeferred
.
promise
.
finally
(
function
(){
rootElement
.
empty
();
scope
.
$destroy
();
});
}
this
.
show
=
function
(
config
){
if
(
config
.
templateUrl
){
return
$http
({
method
:
'GET'
,
url
:
config
.
templateUrl
,
cache
:
true
}).
then
(
function
(
result
){
return
compile
(
result
.
data
,
config
)
});
}
return
compile
(
config
.
template
,
config
);
};
});
app/components/messaging/templates/add_user_unit.html
0 → 100644
View file @
299dfc77
<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>
app/components/messaging/templates/conversation.html
0 → 100644
View file @
299dfc77
<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>
app/components/messaging/templates/create_channel.html
0 → 100644
View file @
299dfc77
<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>
app/components/messaging/templates/delete_confirmation.html
0 → 100644
View file @
299dfc77
<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>
app/components/messaging/templates/index.html
0 → 100644
View file @
299dfc77
<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>
app/components/messaging/templates/search_user.html
0 → 100644
View file @
299dfc77
<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>
app/index.html
View file @
299dfc77
...
...
@@ -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>
app/main.html
View file @
299dfc77
...
...
@@ -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>
...
...
app/main.js
View file @
299dfc77
...
...
@@ -28,7 +28,7 @@ angular.module(
'ngSanitize'
,
'ngCookies'
,
'ulakbus.formService'
,
'ulakbus.messaging
Service
'
,
'ulakbus.messaging'
,
'ulakbus.dashboard'
,
'ulakbus.auth'
,
'ulakbus.error_pages'
,
...
...
app/shared/directives.js
View file @
299dfc77
...
...
@@ -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
();
}
})
}
}
});
app/shared/templates/directives/header-notification.html
View file @
299dfc77
...
...
@@ -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>--
>
<!--
<!– 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>–>
-->
<
/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>
...
...
app/shared/templates/directives/messaging/detail.html
View file @
299dfc77
...
...
@@ -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>
...
...
app/shared/templates/directives/messaging/index.html
View file @
299dfc77
<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>
app/zetalib/messagingService.js
deleted
100644 → 0
View file @
2619b847
/**
* 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
app/zetalib/socket.js
View file @
299dfc77
...
...
@@ -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
...
...
app/zetalib/utils_service.js
0 → 100644
View file @
299dfc77
/**
* 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
];
}
}
}
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment