Sfoglia il codice sorgente

Merge branch '1482-make-it-easier-to-chat-in-different-channels' into 'master'

Resolve "Make it easier to chat in different channels"

Closes #1482

See merge request Isleward/isleward!482
tags/v0.8.0
Big Bad Waffle 4 anni fa
parent
commit
2fd0b958ab
8 ha cambiato i file con 678 aggiunte e 340 eliminazioni
  1. +4
    -4
      src/client/css/loader.less
  2. +2
    -1
      src/client/ui/templates/inventory/inventory.js
  3. +208
    -0
      src/client/ui/templates/messages/channelPicker.js
  4. +124
    -208
      src/client/ui/templates/messages/messages.js
  5. +123
    -0
      src/client/ui/templates/messages/mobile.js
  6. +164
    -66
      src/client/ui/templates/messages/styles.less
  7. +11
    -5
      src/client/ui/templates/messages/template.html
  8. +42
    -56
      src/server/components/social/chat.js

+ 4
- 4
src/client/css/loader.less Vedi File

@@ -1,9 +1,8 @@
@import "colors.less";

@font-face
{
font-family: bitty;
src: url('../fonts/bitty.ttf');
@font-face {
font-family: bitty;
src: url('../fonts/bitty.ttf');
}

.loader-container {
@@ -99,4 +98,5 @@
}

}

}

+ 2
- 1
src/client/ui/templates/inventory/inventory.js Vedi File

@@ -148,7 +148,8 @@ define([
method: 'chat',
data: {
message: '{' + item.name + '}',
item: item
item: item,
type: 'global'
}
});
},


+ 208
- 0
src/client/ui/templates/messages/channelPicker.js Vedi File

@@ -0,0 +1,208 @@
define([
'html!ui/templates/messages/tplTab'
], function (
tplTab
) {
const extensionObj = {
processChat: function (msgConfig) {
const { message, event: keyboardEvent } = msgConfig;
const { key } = keyboardEvent;
const { el, currentChannel } = this;

const optionContainer = this.find('.channelOptions');

if (message.length) {
if (el.hasClass('picking'))
msgConfig.cancel = true;
return;
}
if (key === 'Enter') {
const selectedSubPick = optionContainer.find('.option.selected');
if (selectedSubPick.length) {
this.onPickSubChannel(selectedSubPick.html(), currentChannel);
return;
}
}

//If we're busy picking a sub channel, we can use keyboard nav
const isPicking = el.hasClass('picking');
const currentSelection = optionContainer.find('.option.selected');
if (isPicking && currentSelection.length) {
const delta = {
ArrowUp: -1,
ArrowDown: 1
}[key];

if (delta) {
const options = optionContainer.find('.option');
const currentIndex = currentSelection.eq(0).index();
let nextIndex = (currentIndex + delta) % options.length;
currentSelection.removeClass('selected');
options.eq(nextIndex).addClass('selected');
}
}

const pick = {
'%': 'party',
'!': 'global',
$: 'custom',
'@': 'direct'
}[key];

if (!pick) {
if (isPicking)
msgConfig.cancel = true;

return;
}

if (currentChannel === pick) {
if (pick === 'direct')
this.lastPrivateChannel = null;
else if (pick === 'custom')
this.lastCustomChannel = null;
}

this.onPickChannel(pick, true);
msgConfig.cancel = true;
},

onPickChannel: function (channel, autoPickSub) {
this.currentChannel = channel;
this.currentSubChannel = null;

const showSubChannels = (
['direct', 'custom'].includes(channel) &&
(
!autoPickSub ||
(
channel === 'direct' &&
!this.lastPrivateChannel
) ||
(
channel === 'custom' &&
!this.lastCustomChannel
)
)
);

if (!showSubChannels) {
this.find('.channelOptions').removeClass('active');

let showValue = {
direct: this.lastPrivateChannel,
custom: this.lastCustomChannel
}[channel];

if (channel === 'direct' || channel === 'custom')
this.currentSubChannel = showValue;

showValue = showValue || channel;

this.find('.channelPicker').html(showValue);

this.find('input').focus();

this.el.removeClass('picking');
} else
this.onShowChannelOptions(channel);
},

onPickSubChannel: function (subChannel, channel) {
this.currentSubChannel = subChannel;
this.find('.channelOptions').removeClass('active');
this.find('.channelPicker').html(subChannel);

const elInput = this.find('input');

elInput.focus();

if (channel === 'custom') {
if (subChannel === 'join new') {
elInput.val('/join channelName');
elInput[0].setSelectionRange(6, 17);
} else if (subChannel === 'leave') {
elInput.val('/leave channelName');
elInput[0].setSelectionRange(7, 18);
}
}

this.el.removeClass('picking');
},

onShowChannelOptions: function (currentPick) {
const optionContainer = this.find('.channelOptions')
.addClass('active')
.empty();

const options = [];
let handlerOnClick = this.onPickChannel;

this.el.addClass('picking');

if (!currentPick) {
options.push('global', 'custom');

if (this.privateChannels.length)
options.push('direct');

//Hack...surely we can find a more sane way to do this
if ($('.uiParty .member').length)
options.push('party');
} else {
handlerOnClick = this.onPickSubChannel;
if (currentPick === 'direct')
options.push(...this.privateChannels);
else if (currentPick === 'custom')
options.push(...this.customChannels, 'join new', 'leave');
}

if (!options.length) {
this.onPickChannel('global');
return;
}
let addSelectStyleTo = null;
if (currentPick)
addSelectStyleTo = this.currentSubChannel || options[0];
options.forEach(o => {
const shortcut = {
global: ' (!)',
direct: ' (@)',
party: ' (%)',
custom: ' ($)'
}[o] || '';

const html = `<div class='option' shortcut='${shortcut}'>${o}</div>`;

const el = $(html)
.appendTo(optionContainer)
.on('click', handlerOnClick.bind(this, o, currentPick))
.on('hover', this.stopKeyboardNavForOptions.bind(this));

if (o === addSelectStyleTo)
el.addClass('selected');
});
},

stopKeyboardNavForOptions: function () {
this.find('.channelOptions .option.selected').removeClass('selected');
}
};

return {
init: function () {
$.extend(this, extensionObj);

//This whole hoverFilter business is a filthy hack
this.find('.channelPicker, .channelOptions, .filter:not(.channel)')
.on('mouseover', this.onFilterHover.bind(this, true))
.on('mouseleave', this.onFilterHover.bind(this, false));

this.find('.channelPicker').on('click', this.onShowChannelOptions.bind(this, null));
}
};
});

+ 124
- 208
src/client/ui/templates/messages/messages.js Vedi File

@@ -3,6 +3,8 @@ define([
'html!ui/templates/messages/template',
'html!ui/templates/messages/tplTab',
'css!ui/templates/messages/styles',
'ui/templates/messages/mobile',
'ui/templates/messages/channelPicker',
'js/input',
'js/system/client',
'js/config'
@@ -11,6 +13,8 @@ define([
template,
tplTab,
styles,
messagesMobile,
channelPicker,
input,
client,
config
@@ -18,53 +22,44 @@ define([
return {
tpl: template,

currentFilter: 'info',

messages: [],
maxTtl: 500,

maxChatLength: 255,

hoverItem: null,

hoverFilter: false,

lastChannel: null,
currentChannel: 'global',
currentSubChannel: null,

privateChannels: [],
lastPrivateChannel: null,
customChannels: [],
lastCustomChannel: null,

postRender: function () {
this.onEvent('onGetMessages', this.onGetMessages.bind(this));
this.onEvent('onDoWhisper', this.onDoWhisper.bind(this));
this.onEvent('onJoinChannel', this.onJoinChannel.bind(this));
this.onEvent('onLeaveChannel', this.onLeaveChannel.bind(this));
this.onEvent('onGetCustomChatChannels', this.onGetCustomChatChannels.bind(this));
this.onEvent('onToggleLastChannel', this.onToggleLastChannel.bind(this));

this
.find('.filter:not(.channel)')
.on('mouseover', this.onFilterHover.bind(this, true))
.on('mouseleave', this.onFilterHover.bind(this, false))
.on('click', this.onClickFilter.bind(this));
[
'onGetMessages',
'onDoWhisper',
'onJoinChannel',
'onLeaveChannel',
'onClickFilter',
'onGetCustomChatChannels',
'onKeyDown',
'onKeyUp'
].forEach(e => this.onEvent(e, this[e].bind(this)));

if (isMobile) {
this.kbUpper = 0;
this.find('.filter:not(.channel)').on('click', this.onClickFilter.bind(this));

this.el.on('click', this.toggle.bind(this, true));
this.renderKeyboard();
channelPicker.init.call(this);

$(tplTab)
.appendTo(this.find('.filters'))
.addClass('btnClose')
.html('x')
.on('click', this.toggle.bind(this, false, true));
} else {
if (isMobile)
messagesMobile.init.call(this);
else {
this.find('input')
.on('keydown', this.sendChat.bind(this))
.on('input', this.checkChatLength.bind(this))
.on('input', this.enforceMaxMsgLength.bind(this))
.on('blur', this.toggle.bind(this, false, true));
}

this.onEvent('onKeyDown', this.onKeyDown.bind(this));
this.onEvent('onKeyUp', this.onKeyUp.bind(this));
},

update: function () {
@@ -75,122 +70,17 @@ define([
return;

const time = new Date();
const hours = time.getUTCHours().toString().padStart(2, 0);
const minutes = time.getUTCMinutes().toString().padStart(2, 0);

let elTime = this.find('.time');
const timeString = (
'[ ' +
time.getUTCHours().toString().padStart(2, 0) +
':' +
time.getUTCMinutes().toString().padStart(2, 0) +
' ]'
);
const timeString = `[ ${hours}:${minutes} ]`;

if (elTime.html() !== timeString)
elTime.html(timeString);
},

renderKeyboard: function () {
this.find('.keyboard').remove();

let container = $('<div class="keyboard"></div>')
.appendTo(this.el);

let keyboard = {
0: 'qwertyuiop|asdfghjkl|zxcvbnm',
1: 'QWERTYUIOP|ASDFGHJKL|ZXCVBNM',
2: '1234567890|@#&*-+=()|_$"\';/'
}[this.kbUpper].split('');

//Hacky: Insert control characters in correct positions
//Backspace goes after 'm'
if (this.kbUpper === 0) {
keyboard.splice(keyboard.indexOf('z'), 0, 'caps');
keyboard.splice(keyboard.indexOf('m') + 1, 0, '<<');
} else if (this.kbUpper === 1) {
keyboard.splice(keyboard.indexOf('Z'), 0, 'caps');
keyboard.splice(keyboard.indexOf('M') + 1, 0, '<<');
} else if (this.kbUpper === 2)
keyboard.splice(keyboard.indexOf('/') + 1, 0, '<<');

keyboard.push(...['|', '123', ',', 'space', '.', 'send']);

let row = 0;
keyboard.forEach(k => {
if (k === '|') {
row++;

const postGapCount = row === 4 ? 0 : row - 1;
for (let i = 0; i < postGapCount; i++)
$('<div class="gap" />').appendTo(container);
$('<div class="newline" />').appendTo(container);
const preGapCount = row === 3 ? 0 : row;
for (let i = 0; i < preGapCount; i++)
$('<div class="gap" />').appendTo(container);

return;
}

let className = (k.length === 1) ? 'key' : 'key special';
if (k === ' ') {
k = '.';
className = 'key hidden';
}

className += ' ' + k;

let elKey = $(`<div class="${className}">${k}</div>`)
.appendTo(container);

if (!className.includes('hidden'))
elKey.on('click', this.clickKey.bind(this, k));
});
},

clickKey: function (key) {
window.navigator.vibrate(20);

let elInput = this.find('input');

const handler = {
caps: () => {
this.kbUpper = (this.kbUpper + 1) % 2;
this.renderKeyboard();
},

123: () => {
this.kbUpper = (this.kbUpper === 2) ? 0 : 2;
this.renderKeyboard();
},

space: () => {
this.clickKey(' ');
},

'<<': () => {
elInput.val(elInput.val().slice(0, -1));
this.find('.input').html(elInput.val());
},

send: () => {
this.sendChat({
which: 13
});
this.find('.input').html('');
this.find('input').val('');
}
}[key];
if (handler) {
handler();
return;
}

elInput.val(elInput.val() + key);
this.checkChatLength();

this.find('.input').html(elInput.val());
},

checkChatLength: function () {
enforceMaxMsgLength: function () {
let textbox = this.find('input');
let val = textbox.val();

@@ -202,13 +92,13 @@ define([
},

onGetCustomChatChannels: function (channels) {
channels.forEach(function (c) {
this.onJoinChannel(c);
}, this);
channels.forEach(c => this.onJoinChannel(c));
},

onJoinChannel: function (channel) {
this.find('[filter="' + channel.trim() + '"]').remove();
this.customChannels.push(channel);

this.find(`[filter="${channel.trim()}"]`).remove();

let container = this.find('.filters');
$(tplTab)
@@ -222,7 +112,9 @@ define([
},

onLeaveChannel: function (channel) {
this.find('.filters [filter="' + channel + '"]').remove();
this.customChannels.spliceWhere(c => c === channel);

this.find(`.filters div[filter="${channel}"]`).remove();
},

onFilterHover: function (hover) {
@@ -246,10 +138,9 @@ define([
},

onKeyDown: function (key) {
if (key === 'enter') {
if (key === 'enter')
this.toggle(true);
this.find('input').val(this.lastChannel || '');
} else if (key === 'shift')
else if (key === 'shift')
this.showItemTooltip();
},

@@ -260,11 +151,37 @@ define([

onDoWhisper: function (charName) {
this.toggle(true);
let toName = charName;
if (charName.indexOf(' ') > -1)
toName = "'" + toName + "'";

this.find('input').val('@' + toName + ' ');
this.currentChannel = 'direct';
this.currentSubChannel = charName;

this.find('.channelPicker').html(charName);

const elInput = this.find('input')
.val('message')
.focus();

elInput[0].setSelectionRange(0, 7);
},

//Remember private and custom channels used
trackHistory: function (msg) {
const { subType, source, target, channel } = msg;

if (subType === 'privateIn' || subType === 'privateOut') {
const list = this.privateChannels;
list.spliceWhere(l => l === source || l === target);

//Newest sources are always at the end
list.push(source || target);

if (list.length > 5)
list.splice(0, list.length - 5);

if (subType === 'privateOut' && config.rememberChatChannel)
this.lastPrivateChannel = target;
} else if (subType === 'custom' && config.rememberChatChannel)
this.lastCustomChannel = channel;
},

onGetMessages: function (e) {
@@ -275,10 +192,14 @@ define([
let container = this.find('.list');

messages.forEach(m => {
this.trackHistory(m);

let message = m.message;

if (m.source && window.player.social.isPlayerBlocked(m.source))
return;
if (m.source) {
if (window.player.social.isPlayerBlocked(m.source))
return;
}

if (m.item) {
let source = message.split(':')[0];
@@ -293,6 +214,9 @@ define([
else
el.addClass('info');

if (m.has('channel'))
el.addClass(m.channel);

if (m.item) {
let clickHander = () => {};
let moveHandler = this.showItemTooltip.bind(this, el, m.item);
@@ -318,11 +242,6 @@ define([
});
}
}

this.messages.push({
ttl: this.maxTtl,
el: el
});
});

if (!this.el.hasClass('typing'))
@@ -362,7 +281,7 @@ define([
},

toggle: function (show, isFake, e) {
if ((isFake) && (this.hoverFilter))
if (isFake && this.hoverFilter)
return;

input.resetKeys();
@@ -373,81 +292,78 @@ define([

if (show) {
this.el.addClass('typing');

if (!config.rememberChatChannel) {
this.currentChannel = 'global';
this.currentSubChannel = null;
}

this.find('.channelPicker').html(this.currentSubChannel || this.currentChannel);
textbox.focus();
this.find('.list').scrollTop(9999999);
} else
} else {
this.find('.channelOptions').removeClass('active');
textbox.val('');
this.el.removeClass('picking');

if (['direct', 'custom'].includes(this.currentChannel) && (!this.currentSubChannel || ['join new', 'leave'].includes(this.currentSubChannel))) {
this.currentSubChannel = null;
this.currentChannel = 'global';
}
}

if (e)
e.stopPropagation();
},

sendChat: function (e) {
if (e.which === 27) {
this.toggle(false);
return;
} else if (e.which === 9) {
e.preventDefault();
let textfield = this.find('input');
textfield.val(`${textfield.val()} `);
return;
} else if (e.which !== 13)
return;

if (!this.el.hasClass('typing')) {
this.toggle(true);
return;
}

let textbox = this.find('input');
let msgConfig = {
success: true,
message: textbox.val()
message: textbox.val(),
event: e,
cancel: false
};

this.processChat(msgConfig);
if (msgConfig.cancel || this.el.hasClass('picking'))
return false;

const { which: charCode } = e;

if ([9, 27].includes(charCode) || charCode !== 13) {
if (charCode === 9) {
e.preventDefault();
textbox.val(`${textbox.val()} `);
} else if (charCode === 27)
this.toggle(false);

return;
}

events.emit('onBeforeChat', msgConfig);

let val = msgConfig.message
.split('<')
.join('&lt;')
.split('>')
.join('&gt;');

textbox.blur();
.split('<').join('&lt;')
.split('>').join('&gt;');
if (!msgConfig.success)
return;

if (val.trim() === '')
return;

if (config.rememberChatChannel) {
const firstChar = val[0];
let lastChannel = null;
if ('@$'.includes(firstChar)) {
const firstSpace = val.indexOf(' ');
if (firstSpace === -1)
lastChannel = val + ' ';
else
lastChannel = val.substr(0, firstSpace) + ' ';
} else if (firstChar === '%')
lastChannel = '%';

this.lastChannel = lastChannel;
}

client.request({
cpn: 'social',
method: 'chat',
data: {
message: val
message: val,
type: this.currentChannel,
subType: this.currentSubChannel
}
});
},

onToggleLastChannel: function (isOn) {
if (!isOn)
this.lastChannel = null;
this.toggle();
}
};
});

+ 123
- 0
src/client/ui/templates/messages/mobile.js Vedi File

@@ -0,0 +1,123 @@
define([
'html!ui/templates/messages/tplTab'
], function (
tplTab
) {
const extensionObj = {
renderKeyboard: function () {
this.find('.keyboard').remove();

let container = $('<div class="keyboard"></div>')
.appendTo(this.el);

let keyboard = {
0: 'qwertyuiop|asdfghjkl|zxcvbnm',
1: 'QWERTYUIOP|ASDFGHJKL|ZXCVBNM',
2: '1234567890|@#&*-+=()|_$"\';/'
}[this.kbUpper].split('');

//Hacky: Insert control characters in correct positions
//Backspace goes after 'm'
if (this.kbUpper === 0) {
keyboard.splice(keyboard.indexOf('z'), 0, 'caps');
keyboard.splice(keyboard.indexOf('m') + 1, 0, '<<');
} else if (this.kbUpper === 1) {
keyboard.splice(keyboard.indexOf('Z'), 0, 'caps');
keyboard.splice(keyboard.indexOf('M') + 1, 0, '<<');
} else if (this.kbUpper === 2)
keyboard.splice(keyboard.indexOf('/') + 1, 0, '<<');

keyboard.push(...['|', '123', ',', 'space', '.', 'send']);

let row = 0;
keyboard.forEach(k => {
if (k === '|') {
row++;

const postGapCount = row === 4 ? 0 : row - 1;
for (let i = 0; i < postGapCount; i++)
$('<div class="gap" />').appendTo(container);
$('<div class="newline" />').appendTo(container);
const preGapCount = row === 3 ? 0 : row;
for (let i = 0; i < preGapCount; i++)
$('<div class="gap" />').appendTo(container);

return;
}

let className = (k.length === 1) ? 'key' : 'key special';
if (k === ' ') {
k = '.';
className = 'key hidden';
}

className += ' ' + k;

let elKey = $(`<div class="${className}">${k}</div>`)
.appendTo(container);

if (!className.includes('hidden'))
elKey.on('click', this.clickKey.bind(this, k));
});
},

clickKey: function (key) {
window.navigator.vibrate(20);

let elInput = this.find('input');

const handler = {
caps: () => {
this.kbUpper = (this.kbUpper + 1) % 2;
this.renderKeyboard();
},

123: () => {
this.kbUpper = (this.kbUpper === 2) ? 0 : 2;
this.renderKeyboard();
},

space: () => this.clickKey(' '),

'<<': () => {
elInput.val(elInput.val().slice(0, -1));
this.find('.input').html(elInput.val());
},

send: () => {
this.sendChat({ which: 13 });
this.find('.input').html('');
this.find('input').val('');
}
}[key];
if (handler) {
handler();
return;
}

elInput.val(elInput.val() + key);
this.enforceMaxMsgLength();

this.find('.input').html(elInput.val());
}
};

return {
init: function () {
$.extend(this, extensionObj);

this.kbUpper = 0;

this.el.on('click', this.toggle.bind(this, true));
this.renderKeyboard();

$(tplTab)
.appendTo(this.find('.filters'))
.addClass('btnClose')
.html('x')
.on('click', this.toggle.bind(this, false, true));
}
};
});

+ 164
- 66
src/client/ui/templates/messages/styles.less Vedi File

@@ -7,56 +7,14 @@
left: 10px;
bottom: 10px;
width: 480px;
padding: @pad;
pointer-events: none;

.input {
display: none;
}

&.typing {
pointer-events: all;

.el.textbox {
&.message:not(.input) {
display: block;
}

&.time {
display: none;
}

}

.filters {
pointer-events: all;
display: block;
}

.list {
overflow-y: auto;
background-color: @darkGray;

.list-message {
filter: none;
}

}

}

&.active {
.list-message {
opacity: 1 !important;
}

}
display: flex;
flex-direction: column;

.filters {
display: none;
width: 100%;
height: 26px;
margin-bottom: 10px;
flex-wrap: wrap;

.filter {
height: 100%;
@@ -64,6 +22,7 @@
float: left;
color: @blackA;
margin-right: 10px;
margin-bottom: 10px;
padding: 5px 10px;
cursor: pointer;

@@ -74,7 +33,7 @@

&.active {
background-color: @blackB;
color: @green;
color: @blueB;

&:hover {
background-color: @blackA;
@@ -169,19 +128,53 @@

}

.el {
&.textbox.message {
display: none;
background-color: @gray;
text-align: left;
padding: 5px 10px;
.bottom {
display: none;

.channelPicker {
min-width: 100px;
color: 1;
display: flex;
justify-content: center;
align-items: center;
color: @white;
background-color: @blueC;
cursor: pointer;
padding: 0px 10px;

&:after {
content: '▾';
margin-left: 10px;
}

&:hover {
background-color: @blueD;
}

}

.el {
flex: 1;
width: 100%;
color: @white;

&.textbox.message {
display: none;
background-color: @gray;
text-align: left;
padding: 5px 10px;
}

}

&.time {
display: block;
display: flex;
align-items: center;
padding-left: 10px;
background-color: transparent;
height: 35px;
color: @white;
text-align: left;
padding: 5px 10px;
filter: drop-shadow(0px -2px 0px @blackD)
drop-shadow(0px 2px 0px @blackD)
drop-shadow(2px 0px 0px @blackD)
@@ -192,8 +185,106 @@
drop-shadow(-2px 0px 0px @blackD);
}

width: 100%;
color: @white;
&.channelOptions {
display: none;
flex-direction: column;
position: absolute;
left: 0px;
bottom: 0px;
min-width: 100px;

.option {
height: 35px;
display: flex;
justify-content: center;
align-items: center;
color: @grayB;
background-color: @blackA;
cursor: pointer;
padding: 0px 10px;

&:after {
content: attr(shortcut);
margin-left: 10px;
color: @grayC;
}

&:hover,
&.selected {
background-color: @grayD;
color: @white;
}

}

}

}

&.typing {
pointer-events: all;

.filters {
pointer-events: all;
display: flex;
}

.list {
overflow-y: auto;
background-color: @darkGray;

.list-message {
filter: none;
}

}

.bottom {
display: flex;

.el.textbox {
&.message:not(.input) {
display: block;
}

}

}

.time {
display: none;
}

.channelOptions {
display: none;

&.active {
display: flex;
}

}

}

&.active {
.list-message {
opacity: 1 !important;
}

}

&.picking {
&:before {
position: absolute;
content: '';
left: 0px;
top: 0px;
width: 100%;
height: 100%;
background-color: @blackD;
opacity: 0.7;
}

}

}
@@ -232,22 +323,29 @@
background-color: fade(@darkGray, 90%);
display: flex;
flex-direction: column;
z-index: 999999999;
z-index: 999999998;

.input {
display: block;
height: 26px;
flex-shrink: 0;
.channelPicker {
display: none;
}

.el.textbox:not(.input) {
&.message,
&.time {
display: none;
.channelOptions {
z-index: 999999999;
}

.bottom {
.input {
display: block;
height: 26px;
flex-shrink: 0;
}

}

.el.textbox.message:not(.input),.time {
display: none;
}

.keyboard {
display: flex;
flex-direction: row;
@@ -255,7 +353,7 @@
background-color: @blackC;
justify-content: center;
align-items: center;
height: 128px;
height: 140px;
flex-shrink: 0;

.key {


+ 11
- 5
src/client/ui/templates/messages/template.html Vedi File

@@ -5,10 +5,16 @@
<div class="btn filter active" filter="chat">players</div>
<div class="btn filter active" filter="loot">loot</div>
</div>
<div class="list rep chat info loot">
<div class="list rep chat info loot"></div>
<div class="bottom">
<div class="channelPicker"></div>
<input type="text" class="el textbox message">
<div class="input el textbox message"></div>
</div>
<div class="bottom time"></div>
<div class="bottom channelOptions">
<div class="option">global</div>
<div class="option">party</div>
<div class="option">direct</div>
</div>
<input type="text" class="el textbox message">
<div class="input el textbox message"></div>
<div class="el textbox time"></div>
</div>

+ 42
- 56
src/server/components/social/chat.js Vedi File

@@ -39,7 +39,7 @@ const sendPartyMessage = ({ party, obj }, msg) => {
}

let charname = obj.auth.charname;
let message = msg.data.message.substr(1);
let message = msg.data.message;

party.forEach(p => {
let player = cons.players.find(c => c.id === p);
@@ -60,69 +60,53 @@ const sendPartyMessage = ({ party, obj }, msg) => {
const sendCustomChannelMessage = (cpnSocial, msg) => {
const { obj } = cpnSocial;

let pList = cons.players;
let pLen = pList.length;
let origMessage = msg.data.message.substr(1);
const { data: { message, subType: channel } } = msg;

let channel = origMessage.split(' ')[0];
let message = origMessage.substr(channel.length);

if ((!channel) || (!message)) {
obj.socket.emit('events', {
onGetMessages: [{
messages: [{
class: 'color-redA',
message: 'syntax: $channel message',
type: 'info'
}]
}]
});
if (!channel)
return;
} else if (!cpnSocial.isInChannel(obj, channel)) {

if (!cpnSocial.isInChannel(obj, channel)) {
obj.socket.emit('events', {
onGetMessages: [{
messages: [{
class: 'color-redA',
message: 'you are not currently in channel: ' + channel,
message: 'You are not currently in that channel',
type: 'info'
}]
}]
});
return;
} else if (pLen > 0) {
for (let i = 0; i < pLen; i++) {
if (cpnSocial.isInChannel(pList[i], channel)) {
pList[i].socket.emit('events', {
onGetMessages: [{
messages: [{
class: 'color-grayB',
message: '[' + channel + '] ' + obj.auth.charname + ': ' + message,
type: channel.trim(),
source: obj.name
}]
}]
});
}
}
}
};

const sendPrivateMessage = ({ obj: { name: sourcePlayerName, socket } }, msg) => {
let message = msg.data.message.substr(1);
const sendMessage = `[${channel}] ${obj.auth.charname}: ${message}`;
const eventData = {
onGetMessages: [{
messages: [{
class: 'color-grayB',
message: sendMessage,
type: 'chat',
subType: 'custom',
channel: channel.trim(),
source: obj.name
}]
}]
};

cons.players.forEach(p => {
if (!cpnSocial.isInChannel(p, channel))
return;

let playerName = '';
//Check if there's a space in the name
if (message[0] === "'")
playerName = message.substring(1, message.indexOf("'", 1));
else
playerName = message.substring(0, message.indexOf(' '));
p.socket.emit('events', eventData);
});
};

message = message.substr(playerName.length);
const sendPrivateMessage = ({ obj: { name: sourceName, socket } }, msg) => {
const { data: { message, subType: targetName } } = msg;

if (playerName === sourcePlayerName)
if (targetName === sourceName)
return;

let target = cons.players.find(p => p.name === playerName);
let target = cons.players.find(p => p.name === targetName);
if (!target)
return;

@@ -131,10 +115,10 @@ const sendPrivateMessage = ({ obj: { name: sourcePlayerName, socket } }, msg) =>
data: {
messages: [{
class: 'color-yellowB',
message: '(you to ' + playerName + '): ' + message,
message: '(you to ' + targetName + '): ' + message,
type: 'chat',
subType: 'privateOut',
source: sourcePlayerName
target: targetName
}]
}
});
@@ -144,10 +128,10 @@ const sendPrivateMessage = ({ obj: { name: sourcePlayerName, socket } }, msg) =>
data: {
messages: [{
class: 'color-yellowB',
message: '(' + sourcePlayerName + ' to you): ' + message,
message: '(' + sourceName + ' to you): ' + message,
type: 'chat',
subType: 'privateIn',
source: sourcePlayerName
source: sourceName
}]
}
});
@@ -230,13 +214,15 @@ module.exports = (cpnSocial, msg) => {
};
events.emit('onBeforeSendMessage', msgEvent);

const firstChar = messageString[0];

const messageHandler = {
$: sendCustomChannelMessage,
'@': sendPrivateMessage,
'%': sendPartyMessage
}[firstChar] || sendRegularMessage;
global: sendRegularMessage,
custom: sendCustomChannelMessage,
direct: sendPrivateMessage,
party: sendPartyMessage
}[msgData.type];

if (!messageHandler)
return;

messageHandler(cpnSocial, msg);
};

Caricamento…
Annulla
Salva