TT#4315 ngcp-csc mocked buddylist/chat further implementation

- chat users are now grouped in teams
- user can add/remove chat channels and add/remove users with both
  drag and drop or bulk selection
- message textarea now accepts line breaks (enter + shift)
- added icons to trigger call/videocalls (will be implemented in separat ticket)

Change-Id: Ibc48ff24fbe85c8462ae035970826756d6f56d73
changes/16/9316/1
Carlo 9 years ago
parent 39a2ef8168
commit 6fcfcbfbd7

@ -466,11 +466,25 @@ Ext.define('Ngcp.csc.locales', {
},
chat: {
title: {
en: 'Team',
it: 'Team',
de: 'Team',
fr: 'Team',
sp: 'Team'
en: 'Buddy List',
it: 'Buddy List',
de: 'Buddy List',
fr: 'Buddy List',
sp: 'Buddy List'
},
new_group: {
en: 'Create new team',
it: 'Create new team',
de: 'Create new team',
fr: 'Create new team',
sp: 'Create new team'
},
provide_name: {
en: 'Chat group name',
it: 'Chat group name',
de: 'Chat group name',
fr: 'Chat group name',
sp: 'Chat group name'
},
msg_box:{
empty_text:{
@ -487,6 +501,52 @@ Ext.define('Ngcp.csc.locales', {
de: 'You can start a private conversation with {0} here.',
fr: 'You can start a private conversation with {0} here.',
sp: 'You can start a private conversation with {0} here.'
},
alerts:{
user_ddrop: {
en: 'Only users can be dropped',
it: 'Only users can be dropped',
de: 'Only users can be dropped',
fr: 'Only users can be dropped',
sp: 'Only users can be dropped'
},
user_in_group: {
en: 'User already in group.',
it: 'User already in group.',
de: 'User already in group.',
fr: 'User already in group.',
sp: 'User already in group.'
},
user_added: {
en: '{0} added to {1} channel.',
it: '{0} added to {1} channel.',
de: '{0} added to {1} channel.',
fr: '{0} added to {1} channel.',
sp: '{0} added to {1} channel.'
},
choose_valid_name: {
en: 'Please choose a valid name.',
it: 'Please choose a valid name.',
de: 'Please choose a valid name.',
fr: 'Please choose a valid name.',
sp: 'Please choose a valid name.'
},
channel_created: {
en: 'Channel created',
it: 'Channel created',
de: 'Channel created',
fr: 'Channel created',
sp: 'Channel created'
},
channel_delete: {
en: 'Do you really want to delete {0} channel?',
it: 'Do you really want to delete {0} channel?',
de: 'Do you really want to delete {0} channel?',
fr: 'Do you really want to delete {0} channel?',
sp: 'Do you really want to delete {0} channel?'
}
}
},
common: {
@ -573,6 +633,27 @@ Ext.define('Ngcp.csc.locales', {
de: 'submit',
fr: 'submit',
sp: 'submit'
},
add: {
en: 'add',
it: 'add',
de: 'add',
fr: 'add',
sp: 'add'
},
call: {
en: 'Call',
it: 'Call',
de: 'Call',
fr: 'Call',
sp: 'Call'
},
videocall: {
en: 'Videocall',
it: 'Videocall',
de: 'Videocall',
fr: 'Videocall',
sp: 'Videocall'
}
}

@ -1,25 +1,17 @@
Ext.define('NgcpCsc.store.ChatList', {
extend: 'Ext.data.Store',
extend: 'Ext.data.TreeStore',
alias: 'store.chatlist',
storeId: 'ChatList',
model: 'NgcpCsc.model.ChatList',
autoLoad: true,
proxy: {
type: 'ajax',
url: '/resources/data/chatlist.json',
reader: {
type: 'json',
rootProperty: 'data'
}
url: 'resources/data/chatlist.json'
},
sorters: {
direction: 'DESC',
property: 'online'
}
sorters: [{
property: 'online',
direction: 'DESC'
}]
});

@ -201,6 +201,27 @@
}
.navigation-email {
.x-grid-row:hover {
.x-phone-display:before {
font-family: FontAwesome;
content: "\f095";
margin-left: 5px;
}
.x-video-display:before {
font-family: FontAwesome;
content: "\f03d";
margin-left: 10px;
}
.x-drop-display{
position: relative;
right: 6px;
&:before {
font-family: FontAwesome;
content: "\f00d";
}
}
}
// @include box-shadow(0px,2px,8px,0px,rgba(0,0,0,.15));
@include box-shadow(0, 1px, 2px, 0, rgba(0,0,0,0.2));
@ -278,7 +299,7 @@
}
.new-message-cont {
margin-left: 203px;
margin-right: 10px;
}
.submit-new-message {
@ -293,3 +314,9 @@
.private-conversation-text {
padding: 30px;
}
.online-user {
color: $online-menu-item-color !important;
}
.offline-user {
color: $offline-menu-item-color !important;
}

@ -167,6 +167,7 @@ Ext.define('NgcpCsc.view.main.MainController', {
showMessage: function(success, msg) {
var msgConsole = this.lookupReference('console'),
msgColor = (success) ? 'green-txt' : 'red-txt';
msgConsole.removeCls(['green-txt' , 'red-txt']);
msgConsole.addCls(msgColor);
msgConsole.setText(msg);
msgConsole.getEl().fadeIn();

@ -7,53 +7,46 @@ Ext.define('NgcpCsc.view.pages.chat.Chat', {
controller: 'chat',
layout: 'hbox',
layout: {
type: 'hbox',
align: 'stretch'
},
items: [{
xtype: 'chatlist',
width: 200,
padding: '10 20 20',
height: '100%'
flex:1,
padding: '0 1 0 3',
scrollable:true
}, {
xtype: 'tabpanel',
width: '90%',
height: '100%',
items: [{
title: Ngcp.csc.locales.chat.title[localStorage.getItem('languageSelected')],
xtype: 'chat-notifications',
id: 'chat-notifications',
scrollable: true,
bind: {
store: '{notifications}'
}
}]
}],
dockedItems: [{
xtype: 'toolbar',
cls: 'new-message-cont',
fixed: true,
padding: '0 0 10 0',
dock: 'bottom',
items: [{
xtype: 'textarea',
bind: {
value: '{new_message}'
},
cls: 'new-message',
name: 'new-message',
enableKeyEvents: true,
height: 100,
width: '95%',
listeners: {
keypress: 'onPressEnter'
},
emptyText: Ngcp.csc.locales.chat.msg_box.empty_text[localStorage.getItem('languageSelected')]
}, {
xtype: 'button',
cls: 'submit-new-message',
text: Ngcp.csc.locales.common.submit[localStorage.getItem('languageSelected')],
handler: 'onPressSubmitBtn'
flex: 5,
plugins: 'tabreorderer',
dockedItems: [{
xtype: 'toolbar',
cls: 'new-message-cont',
fixed: true,
padding: '0 0 10 0',
dock: 'bottom',
items: [{
xtype: 'textarea',
bind: {
value: '{new_message}'
},
cls: 'new-message',
name: 'new-message',
enableKeyEvents: true,
height: 100,
width: '95%',
emptyText: Ngcp.csc.locales.chat.msg_box.empty_text[localStorage.getItem('languageSelected')],
listeners: {
keypress: 'onPressEnter'
}
}, {
xtype: 'button',
cls: 'submit-new-message',
text: Ngcp.csc.locales.common.submit[localStorage.getItem('languageSelected')],
handler: 'onPressSubmitBtn'
}]
}]
}]

@ -6,13 +6,15 @@ Ext.define('NgcpCsc.view.pages.chat.ChatController', {
listen: {
controller: {
'#chatlist': {
openpmtab: 'openPM'
openpmtab: 'openPM',
openchanneltab: 'openChat',
destroytab: 'closeChat'
}
}
},
onPressEnter: function(field, e) {
if (e.getKey() == e.ENTER) {
if (!e.shiftKey && e.getKey() == e.ENTER) {
e.preventDefault();
this.submitMessage();
}
@ -24,7 +26,7 @@ Ext.define('NgcpCsc.view.pages.chat.ChatController', {
submitMessage: function(msg, user) {
var message = msg || this.getViewModel().get('new_message');
if (message.length < 1)
if (message.length < 1 || !this.getView().down('tabpanel').getActiveTab())
return;
var chatStore = this.getView().down('tabpanel').getActiveTab().getStore('notifications');
var lastMsg = chatStore.getAt(chatStore.getCount() - 1) || this.getViewModel().getStore('notifications').findRecord('id', this.getView().down('tabpanel').getActiveTab().name);
@ -40,7 +42,7 @@ Ext.define('NgcpCsc.view.pages.chat.ChatController', {
"isActive": true,
"time": Ext.String.format("{0}:{1}", hour, minutes),
"thumbnail": (user) ? user.get('thumbnail') : "resources/images/user-profile/2.png",
"content": message
"content": message.replace(/(?:\r\n|\r|\n)/g, '<br />')
});
chatStore.add(messageModel);
this.clearMsg();
@ -57,7 +59,7 @@ Ext.define('NgcpCsc.view.pages.chat.ChatController', {
},
openPM: function(item, rec) {
var tab = this.getView().down('[name=' + rec.get('id') + ']');
var tab = this.getView().down('[name=' + rec.get('uid') + ']');
if (rec.get('name') == 'administrator') // hardcoded administrator
return;
if (!tab) {
@ -69,12 +71,38 @@ Ext.define('NgcpCsc.view.pages.chat.ChatController', {
cls: 'private-conversation-text',
deferEmptyText: false,
emptyText: Ext.String.format(Ngcp.csc.locales.chat.start_conversation[localStorage.getItem('languageSelected')], rec.get('name')),
name: rec.get('id'),
name: rec.get('uid'),
store: Ext.create('Ext.data.Store', {
model: 'NgcpCsc.model.ChatNotification'
})
});
}
this.getView().down('tabpanel').setActiveTab(tab);
},
openChat: function(rec) {
var tab = this.getView().down('[name=' + rec.get('name') + ']');
if (rec.get('name') == 'Buddies')
return;
if (!tab) {
tab = this.getView().down('tabpanel').add({
xtype: 'chat-notifications',
title: rec.get('name'),
name: rec.get('name'),
closable: true,
scrollable: true,
bind: {
store: '{notifications}'
}
});
}
this.getView().down('tabpanel').setActiveTab(tab);
},
closeChat: function(tabToClose) {
var tabToClose = this.getView().down('[name=' + tabToClose + ']');
var chatList = this.getView().down('#chatlist');
if (tabToClose){
tabToClose.destroy();
}
chatList.getView().refresh();
}
});

@ -1,23 +1,91 @@
Ext.define('NgcpCsc.view.pages.chat.ChatList', {
extend: 'Ext.menu.Menu',
extend: 'Ext.tree.Panel',
alias: 'widget.chatlist',
viewModel: {
type: 'chatlist'
},
controller: 'chatlist',
itemId:'chatlist',
title: Ngcp.csc.locales.chat.title[localStorage.getItem('languageSelected')],
hideHeaders: true,
cls: 'navigation-email',
iconCls: 'x-fa fa-group',
store: 'ChatList',
rootVisible: false,
floating: false,
viewConfig: {
plugins: {
ptype: 'treeviewdragdrop',
sortOnDrop: true,
containerScroll: true
},
listeners: {
beforecellclick: 'preventTabOpen'
}
},
tools: [{
type: 'plus',
tooltip: Ngcp.csc.locales.chat.new_group[localStorage.getItem('languageSelected')],
callback: 'showTabBar'
}],
dockedItems: [{
xtype: 'toolbar',
dock: 'top',
hidden: true,
items: [{
xtype: 'textfield',
name: 'newChatName',
width: '80%',
emptyText: Ngcp.csc.locales.chat.provide_name[localStorage.getItem('languageSelected')],
minLength: 1
}, {
xtype: 'button',
text: Ngcp.csc.locales.common.add[localStorage.getItem('languageSelected')],
handler: 'createNewChannel'
}]
}],
listeners: {
click: 'itemListClicked'
}
beforeitemclick: 'nodeClicked',
beforedrop: 'onBeforeUserDropped'
},
defaults: {
menuDisabled: true
},
columns: [{
xtype: 'treecolumn',
dataIndex: 'name',
renderer: 'renderStatus',
flex: 2
}, {
xtype: 'actioncolumn',
text: 'actions',
flex: 1,
items: [{
tooltip: Ngcp.csc.locales.common.call[localStorage.getItem('languageSelected')],
getClass: function(value, context) {
return (context.record && context.record.get('leaf')) ? 'x-phone-display' : '';
},
handler: 'startCall'
}, {
tooltip: Ngcp.csc.locales.common.videocall[localStorage.getItem('languageSelected')],
getClass: function(value, context) {
return (context.record && context.record.get('leaf')) ? 'x-video-display' : '';
},
handler: 'startVideoCall'
}, {
//tooltip: Ngcp.csc.locales.common.delete[localStorage.getItem('languageSelected')],
getClass: function(value, context) {
return (context.record && !context.record.get('leaf')) ? 'x-drop-display' : '';
},
handler: 'deleteNode'
}]
}]
});

@ -5,47 +5,101 @@ Ext.define('NgcpCsc.view.pages.chat.ChatListController', {
id: 'chatlist', // needed as reference in ChatController listeners
init: function() {
var me = this,
friendsStore = me.getViewModel().getStore('friends');
//Trigger local sorting once new data is available
friendsStore.on('load', function(store) {
store.sort();
renderStatus: function(val, meta, rec) {
if (rec.get('leaf')) {
rec.set('iconCls', 'x-fa fa-circle ' + (rec.get('online') ? 'online-user' : 'offline-user'));
}
return val;
},
onBeforeUserDropped: function(node, data, overModel, dropPosition, dropHandlers) {
var chatListStore = this.getView().getStore('ChatList');
var dropTeam = overModel.get('leaf') ? overModel.parentNode : overModel;
dropHandlers.cancelDrop();
switch (true) {
case !data.records[0].get('leaf'): // happens when a group is dropped
this.fireEvent('showmessage', false, Ngcp.csc.locales.chat.alerts.user_ddrop[localStorage.getItem('languageSelected')]);
break;
case !!dropTeam.findChild('uid', data.records[0].get('uid')): // checks if user is already in team
this.fireEvent('showmessage', false, Ngcp.csc.locales.chat.alerts.user_in_group[localStorage.getItem('languageSelected')]);
break;
default:
dropTeam.insertChild(0, data.records[0].copy(null));
chatListStore.sort('online', 'DESC');
this.fireEvent('showmessage', true, Ext.String.format(Ngcp.csc.locales.chat.alerts.user_added[localStorage.getItem('languageSelected')], data.records[0].get('name'), dropTeam.get('name')));
}
},
showTabBar: function() {
var chatList = this.getView();
chatList.getDockedItems('toolbar[dock="top"]')[0].setVisible(true);
chatList.getStore().each(function(rec) {
if (rec.get('leaf')) {
rec.set('checked', false);
}
});
},
createNewChannel: function() {
var chatList = this.getView();
var tbar = chatList.getDockedItems('toolbar[dock="top"]')[0];
var newChatName = tbar.down('[name=newChatName]');
var selectedUsers = chatList.getChecked();
if (newChatName.getValue().length < 1) {
this.fireEvent('showmessage', false, Ngcp.csc.locales.chat.alerts.choose_valid_name[localStorage.getItem('languageSelected')]);
return;
}
//Sort locally and then update menu
friendsStore.on('sort', function(store) {
me.mutateData(store, store.getRange());
var newNode = chatList.getRootNode().insertChild(chatList.getStore().getCount(), {
"name": newChatName.getValue(),
"iconCls": "x-fa fa-wechat",
"expanded": true,
"children": []
});
me.callParent(arguments);
Ext.each(selectedUsers, function(user) {
newNode.insertChild(0, user.copy(null));
});
chatList.getStore().each(function(rec) {
rec.set('checked', null);
});
chatList.getStore().sort('online', 'DESC');
this.fireEvent('showmessage', true, Ngcp.csc.locales.chat.alerts.channel_created[localStorage.getItem('languageSelected')]);
tbar.hide();
newChatName.reset();
},
mutateData: function(store, records) {
var view = this.getView(),
arr = [],
len = records.length,
i;
for (i = 0; i < len; i++) {
arr.push({
xtype: 'menuitem',
uId: records[i].get('id'),
text: records[i].get('name'),
cls: 'font-icon ' + (records[i].get('online') ? 'online-user' : 'offline-user')
});
preventTabOpen: function(view, cell, cellIdx, record, row, rowIdx, eOpts) {
if (cellIdx === 1) { // prevents tabs to be opened in case user clicked on icons in actioncolumn (startcall/delete/...)
return false;
}
Ext.suspendLayouts();
view.removeAll(true);
view.add(arr);
Ext.resumeLayouts(true);
},
startCall: function(grid, rowIndex, colIndex, item, e) {
this.fireEvent('showmessage', true, 'Todo start call');
},
startVideoCall: function(grid, rowIndex, colIndex) {
this.fireEvent('showmessage', true, 'Todo start videocall');
},
nodeClicked: function(node, record, item, index, e) {
if (record.get('checked') != null)
return;
if (!record.get('leaf'))
this.fireEvent('openchanneltab', record);
else
this.fireEvent('openpmtab', null, record);
return false;
itemListClicked: function(menu, item) {
var selectedUser = Ext.getStore('ChatList').findRecord('id', item.uId, 0, false, true, true);
if (selectedUser && selectedUser.get('online'))
this.fireEvent('openpmtab', null, selectedUser);
},
deleteNode: function(grid, rowIndex, colIndex) {
var nodeToDelete = grid.getStore().getAt(rowIndex);
var me = this;
if (nodeToDelete.get('leaf'))
return;
Ext.Msg.show({
message: Ext.String.format(Ngcp.csc.locales.chat.alerts.channel_delete[localStorage.getItem('languageSelected')], nodeToDelete.get('name')),
buttons: Ext.Msg.YESNO,
icon: Ext.Msg.QUESTION,
fn: function(btn) {
if (btn === 'yes') {
nodeToDelete.remove();
me.fireEvent('destroytab', nodeToDelete.get('name'));
}
}
});
}
});

@ -4,12 +4,8 @@ Ext.define('NgcpCsc.view.pages.chat.ChatListModel', {
alias: 'viewmodel.chatlist',
stores: {
friends: {
//Store reference
type: 'chatlist',
//Auto load
autoLoad: true
buddyList: {
type: 'chatlist'
}
}
});

@ -1,6 +1,6 @@
{
"data": [{
"id": 840,
"uid": 840,
"name": "Jil Sanchez",
"date": "10/27/2016",
"isActive": true,
@ -8,7 +8,7 @@
"thumbnail": "resources/images/user-profile/9.png",
"content": "There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don\'t look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn\'t anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc."
}, {
"id": 252,
"uid": 252,
"name": "Ben Wright",
"date": "10/27/2010",
"isActive": true,
@ -16,7 +16,7 @@
"thumbnail": "resources/images/user-profile/10.png",
"content": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
}, {
"id": 162,
"uid": 162,
"name": "Allen Morris",
"date": "10/27/2016",
"isActive": true,

@ -1,27 +1,76 @@
{
"data": [{
"id": 840,
[{
"name": "Buddies",
"iconCls": "x-fa fa-group",
"expanded": true,
"children": [{
"uid": 840,
"online": true,
"name": "Jil Sanchez"
"name": "Jil Sanchez",
"leaf": true
}, {
"id": 1,
"uid": 1,
"online": false,
"name": "Oneill Franklin"
"name": "Oneill Franklin",
"leaf": true
}, {
"id": 3,
"uid": 3,
"online": false,
"name": "Branch Allison"
"name": "Branch Allison",
"leaf": true
}, {
"id": 252,
"uid": 252,
"online": true,
"name": "Ben Wright"
"name": "Ben Wright",
"leaf": true
}, {
"id": 162,
"uid": 162,
"online": true,
"name": "Allen Morris"
"name": "Allen Morris",
"leaf": true
}, {
"id": 5,
"uid": 5,
"online": false,
"name": "Suzette Powell"
"name": "Suzette Powell",
"leaf": true
}]
}
}, {
"name": "Development",
"iconCls": "x-fa fa-wechat",
"expanded": true,
"children": [{
"uid": 162,
"online": true,
"name": "Allen Morris",
"leaf": true
},{
"uid": 840,
"online": true,
"name": "Jil Sanchez",
"leaf": true
},{
"uid": 252,
"online": true,
"name": "Ben Wright",
"leaf": true
}, {
"uid": 5,
"online": false,
"name": "Suzette Powell",
"leaf": true
}]
}, {
"name": "Operations",
"iconCls": "x-fa fa-wechat",
"expanded": true,
"children": [{
"uid": 162,
"online": true,
"name": "Allen Morris",
"leaf": true
}, {
"uid": 5,
"online": false,
"name": "Suzette Powell",
"leaf": true
}]
}]

Loading…
Cancel
Save