@@ -1,208 +0,0 @@ | |||||
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)); | |||||
} | |||||
}; | |||||
}); |
@@ -1,382 +0,0 @@ | |||||
define([ | |||||
'js/system/events', | |||||
'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' | |||||
], function ( | |||||
events, | |||||
template, | |||||
tplTab, | |||||
styles, | |||||
messagesMobile, | |||||
channelPicker, | |||||
input, | |||||
client, | |||||
config | |||||
) { | |||||
return { | |||||
tpl: template, | |||||
maxChatLength: 255, | |||||
hoverItem: null, | |||||
hoverFilter: false, | |||||
currentChannel: 'global', | |||||
currentSubChannel: null, | |||||
privateChannels: [], | |||||
lastPrivateChannel: null, | |||||
customChannels: [], | |||||
lastCustomChannel: null, | |||||
postRender: function () { | |||||
[ | |||||
'onGetMessages', | |||||
'onDoWhisper', | |||||
'onJoinChannel', | |||||
'onLeaveChannel', | |||||
'onClickFilter', | |||||
'onGetCustomChatChannels', | |||||
'onKeyDown', | |||||
'onKeyUp' | |||||
].forEach(e => this.onEvent(e, this[e].bind(this))); | |||||
this.find('.filter:not(.channel)').on('click', this.onClickFilter.bind(this)); | |||||
channelPicker.init.call(this); | |||||
if (isMobile) | |||||
messagesMobile.init.call(this); | |||||
else { | |||||
this.find('input') | |||||
.on('keydown', this.sendChat.bind(this)) | |||||
.on('input', this.enforceMaxMsgLength.bind(this)) | |||||
.on('blur', this.toggle.bind(this, false, true)); | |||||
} | |||||
}, | |||||
update: function () { | |||||
if (isMobile) | |||||
return; | |||||
if (this.el.hasClass('typing')) | |||||
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 = `[ ${hours}:${minutes} ]`; | |||||
if (elTime.html() !== timeString) | |||||
elTime.html(timeString); | |||||
}, | |||||
enforceMaxMsgLength: function () { | |||||
let textbox = this.find('input'); | |||||
let val = textbox.val(); | |||||
if (val.length <= this.maxChatLength) | |||||
return; | |||||
val = val.substr(0, this.maxChatLength); | |||||
textbox.val(val); | |||||
}, | |||||
onGetCustomChatChannels: function (channels) { | |||||
channels.forEach(c => this.onJoinChannel(c)); | |||||
}, | |||||
onJoinChannel: function (channel) { | |||||
const container = this.find('.filters'); | |||||
const channelName = channel.trim(); | |||||
this.customChannels.spliceWhere(c => c === channel); | |||||
this.find(`[filter="${channelName}"]`).remove(); | |||||
this.customChannels.push(channel); | |||||
$(tplTab) | |||||
.appendTo(container) | |||||
.addClass('channel') | |||||
.attr('filter', channelName) | |||||
.html(channelName) | |||||
.on('mouseover', this.onFilterHover.bind(this, true)) | |||||
.on('mouseleave', this.onFilterHover.bind(this, false)) | |||||
.on('click', this.onClickFilter.bind(this)); | |||||
}, | |||||
onLeaveChannel: function (channel) { | |||||
this.customChannels.spliceWhere(c => c === channel); | |||||
this.find(`.filters div[filter="${channel}"]`).remove(); | |||||
}, | |||||
onFilterHover: function (hover) { | |||||
this.hoverFilter = hover; | |||||
}, | |||||
onClickFilter: function (e) { | |||||
let el = $(e.target); | |||||
el.toggleClass('active'); | |||||
let filter = el.attr('filter'); | |||||
let method = (el.hasClass('active') ? 'show' : 'hide'); | |||||
if (method === 'show') | |||||
this.find('.list').addClass(filter); | |||||
else | |||||
this.find('.list').removeClass(filter); | |||||
if (el.hasClass('channel')) | |||||
this.find('.list .' + filter)[method](); | |||||
}, | |||||
onKeyDown: function (key) { | |||||
if (key === 'enter') | |||||
this.toggle(true); | |||||
else if (key === 'shift') | |||||
this.showItemTooltip(); | |||||
else if (key === 'esc' && this.el.hasClass('typing')) | |||||
this.toggle(false); | |||||
}, | |||||
onKeyUp: function (key) { | |||||
if (key === 'shift') | |||||
this.showItemTooltip(); | |||||
}, | |||||
onDoWhisper: function (charName) { | |||||
this.toggle(true); | |||||
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) { | |||||
let messages = e.messages; | |||||
if (!messages.length) | |||||
messages = [messages]; | |||||
let container = this.find('.list'); | |||||
const [ { scrollHeight, clientHeight, scrollTop } ] = container; | |||||
const isAtMaxScroll = scrollTop >= (scrollHeight - clientHeight); | |||||
messages.forEach(m => { | |||||
this.trackHistory(m); | |||||
let message = m.message; | |||||
if (m.source) { | |||||
if (window.player.social.isPlayerBlocked(m.source)) | |||||
return; | |||||
} | |||||
if (m.item) { | |||||
let source = message.split(':')[0]; | |||||
message = source + ': <span class="q' + (m.item.quality || 0) + '">' + message.replace(source + ': ', '') + '</span>'; | |||||
} | |||||
let el = $('<div class="list-message ' + m.class + '">' + message + '</div>') | |||||
.appendTo(container); | |||||
if (m.has('type')) | |||||
el.addClass(m.type); | |||||
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); | |||||
if (isMobile) | |||||
[clickHander, moveHandler] = [moveHandler, clickHander]; | |||||
el.find('span') | |||||
.on('mousemove', moveHandler) | |||||
.on('mousedown', clickHander) | |||||
.on('mouseleave', this.hideItemTooltip.bind(this)); | |||||
} | |||||
if (m.type) { | |||||
let isChannel = (['info', 'chat', 'loot', 'rep'].indexOf(m.type) === -1); | |||||
if (isChannel) { | |||||
if (this.find('.filter[filter="' + m.type + '"]').hasClass('active')) | |||||
el.show(); | |||||
} | |||||
if (isMobile && ['loot', 'info'].indexOf(m.type) !== -1) { | |||||
events.emit('onGetAnnouncement', { | |||||
msg: m.message | |||||
}); | |||||
} | |||||
} | |||||
}); | |||||
if (!this.el.hasClass('typing') || isAtMaxScroll) | |||||
container.scrollTop(9999999); | |||||
}, | |||||
hideItemTooltip: function () { | |||||
if (this.dragEl) { | |||||
this.hoverCell = null; | |||||
return; | |||||
} | |||||
events.emit('onHideItemTooltip', this.hoverItem); | |||||
this.hoverItem = null; | |||||
}, | |||||
showItemTooltip: function (el, item, e) { | |||||
if (item) | |||||
this.hoverItem = item; | |||||
else | |||||
item = this.hoverItem; | |||||
if (!item) | |||||
return; | |||||
let ttPos = null; | |||||
if (el) { | |||||
ttPos = { | |||||
x: ~~(e.clientX + 32), | |||||
y: ~~(e.clientY) | |||||
}; | |||||
} | |||||
let bottomAlign = !isMobile; | |||||
events.emit('onShowItemTooltip', item, ttPos, true, bottomAlign); | |||||
}, | |||||
toggle: function (show, isFake, e) { | |||||
if (isFake && this.hoverFilter) | |||||
return; | |||||
input.resetKeys(); | |||||
this.el.removeClass('typing'); | |||||
let textbox = this.find('input'); | |||||
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 { | |||||
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) { | |||||
let textbox = this.find('input'); | |||||
let msgConfig = { | |||||
success: true, | |||||
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('<') | |||||
.split('>').join('>'); | |||||
if (!msgConfig.success) { | |||||
this.toggle(false); | |||||
return; | |||||
} | |||||
if (val.trim() === '') { | |||||
this.toggle(false); | |||||
return; | |||||
} | |||||
client.request({ | |||||
cpn: 'social', | |||||
method: 'chat', | |||||
data: { | |||||
message: val, | |||||
type: this.currentChannel, | |||||
subType: this.currentSubChannel | |||||
} | |||||
}); | |||||
this.toggle(); | |||||
} | |||||
}; | |||||
}); |
@@ -1,123 +0,0 @@ | |||||
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)); | |||||
} | |||||
}; | |||||
}); |
@@ -1,420 +0,0 @@ | |||||
@import "../../../css/colors.less"; | |||||
@pad: 8px; | |||||
@btnSize: 64px; | |||||
.uiMessages { | |||||
position: absolute; | |||||
left: 10px; | |||||
bottom: 10px; | |||||
width: 480px; | |||||
pointer-events: none; | |||||
display: flex; | |||||
flex-direction: column; | |||||
.filters { | |||||
display: none; | |||||
width: 100%; | |||||
flex-wrap: wrap; | |||||
.filter { | |||||
height: 100%; | |||||
background-color: @blackC; | |||||
float: left; | |||||
color: @blackA; | |||||
margin-right: 10px; | |||||
margin-bottom: 10px; | |||||
padding: 5px 10px; | |||||
cursor: pointer; | |||||
&:hover { | |||||
background-color: @blackB; | |||||
color: @grayD; | |||||
} | |||||
&.active { | |||||
background-color: @blackB; | |||||
color: @blueB; | |||||
&:hover { | |||||
background-color: @blackA; | |||||
color: @grayB; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
.list { | |||||
overflow-y: hidden; | |||||
width: 100%; | |||||
max-height: 320px; | |||||
.list-message { | |||||
display: none; | |||||
width: 100%; | |||||
padding: 5px 10px; | |||||
color: white; | |||||
filter: drop-shadow(0px -2px 0px @blackD) | |||||
drop-shadow(0px 2px 0px @blackD) | |||||
drop-shadow(2px 0px 0px @blackD) | |||||
drop-shadow(-2px 0px 0px @blackD); | |||||
-moz-filter: drop-shadow(0px -2px 0px @blackD) | |||||
drop-shadow(0px 2px 0px @blackD) | |||||
drop-shadow(2px 0px 0px @blackD) | |||||
drop-shadow(-2px 0px 0px @blackD); | |||||
word-wrap: break-word; | |||||
line-height: 18px; | |||||
&.q { | |||||
color: @grayB; | |||||
} | |||||
&.q0 { | |||||
color: @white; | |||||
} | |||||
&.q1 { | |||||
color: @greenB; | |||||
} | |||||
a, | |||||
&.q2 { | |||||
color: @blueB; | |||||
} | |||||
&.q3 { | |||||
color: @purpleA; | |||||
} | |||||
&.q4 { | |||||
color: @orangeA; | |||||
} | |||||
&.color-green { | |||||
color: @green; | |||||
} | |||||
&.color-red { | |||||
color: @red; | |||||
} | |||||
&.color-cyan { | |||||
color: @blueA; | |||||
} | |||||
&.color-tealC { | |||||
color: @tealC; | |||||
} | |||||
} | |||||
&.rep .rep { | |||||
display: block; | |||||
} | |||||
&.chat .chat { | |||||
display: block; | |||||
} | |||||
&.info .info { | |||||
display: block; | |||||
} | |||||
&.loot .loot { | |||||
display: block; | |||||
} | |||||
} | |||||
.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: flex; | |||||
align-items: center; | |||||
padding-left: 10px; | |||||
background-color: transparent; | |||||
height: 35px; | |||||
color: @white; | |||||
text-align: left; | |||||
filter: drop-shadow(0px -2px 0px @blackD) | |||||
drop-shadow(0px 2px 0px @blackD) | |||||
drop-shadow(2px 0px 0px @blackD) | |||||
drop-shadow(-2px 0px 0px @blackD); | |||||
-moz-filter: drop-shadow(0px -2px 0px @blackD) | |||||
drop-shadow(0px 2px 0px @blackD) | |||||
drop-shadow(2px 0px 0px @blackD) | |||||
drop-shadow(-2px 0px 0px @blackD); | |||||
} | |||||
&.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 { | |||||
box-shadow: 0 -2px 0 @black, 0 2px 0 @black, 2px 0 0 @black, -2px 0 0 @black; | |||||
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; | |||||
} | |||||
} | |||||
} | |||||
.mobile .uiMessages { | |||||
padding: 0px; | |||||
pointer-events: all; | |||||
.btnClose.active { | |||||
float: right; | |||||
margin-right: 0px; | |||||
padding: 5px 20px; | |||||
color: @redA; | |||||
} | |||||
input { | |||||
display: none; | |||||
} | |||||
.filters { | |||||
margin-bottom: 0px; | |||||
flex-shrink: 0; | |||||
background-color: @darkGray; | |||||
} | |||||
.list { | |||||
height: 100%; | |||||
max-height: 100%; | |||||
} | |||||
&.typing { | |||||
left: 0px; | |||||
top: 0px; | |||||
width: 100%; | |||||
height: 100%; | |||||
background-color: fade(@darkGray, 90%); | |||||
display: flex; | |||||
flex-direction: column; | |||||
z-index: 999999998; | |||||
.channelPicker { | |||||
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; | |||||
flex-wrap: wrap; | |||||
background-color: @blackC; | |||||
justify-content: center; | |||||
align-items: center; | |||||
height: 140px; | |||||
flex-shrink: 0; | |||||
.key { | |||||
flex: 1; | |||||
background-color: @blackA; | |||||
color: @white; | |||||
padding: 8px 10px; | |||||
text-align: center; | |||||
&.special { | |||||
color: @orangeA; | |||||
} | |||||
&.hidden { | |||||
color: @blackC; | |||||
} | |||||
&.space { | |||||
flex: 5; | |||||
} | |||||
} | |||||
.newline { | |||||
width: 100%; | |||||
} | |||||
.gap { | |||||
width: 5%; | |||||
flex-shrink: 0; | |||||
} | |||||
} | |||||
} | |||||
&:not(.typing) { | |||||
top: 10px; | |||||
right: 84px; | |||||
left: auto; | |||||
bottom: auto; | |||||
width: @btnSize; | |||||
height: @btnSize; | |||||
background-color: fade(@darkGray, 90%); | |||||
&:after { | |||||
content: ''; | |||||
position: absolute; | |||||
left: 0px; | |||||
top: 0px; | |||||
background: url('../../../images/uiIcons.png'); | |||||
background-position: -0px -128px; | |||||
width: @btnSize; | |||||
height: @btnSize; | |||||
} | |||||
> * { | |||||
display: none; | |||||
} | |||||
} | |||||
} |
@@ -1,20 +0,0 @@ | |||||
<div class="uiMessages active"> | |||||
<div class="filters"> | |||||
<div class="btn filter active" filter="info">info</div> | |||||
<div class="btn filter active" filter="rep">reputation</div> | |||||
<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> | |||||
<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> | |||||
</div> |
@@ -1 +0,0 @@ | |||||
<div class="filter active" filter="filterName"></div> |
@@ -11,19 +11,19 @@ const sendRegularMessage = ({ obj }, messageInfo) => { | |||||
const msgClass = item ? `q${item.quality}` : 'color-grayB'; | const msgClass = item ? `q${item.quality}` : 'color-grayB'; | ||||
const msgData = { | |||||
type: 'chat', | |||||
source, | |||||
prefix, | |||||
prefixClass, | |||||
msg, | |||||
msgClass, | |||||
item | |||||
}; | |||||
cons.emit('event', { | cons.emit('event', { | ||||
event: 'onGetMessages', | event: 'onGetMessages', | ||||
data: { | |||||
messages: [{ | |||||
type: 'chat', | |||||
source, | |||||
prefix, | |||||
prefixClass, | |||||
msg, | |||||
msgClass, | |||||
item | |||||
}] | |||||
} | |||||
data: { messages: [msgData] } | |||||
}); | }); | ||||
}; | }; | ||||
@@ -8,7 +8,7 @@ module.exports = { | |||||
// sqlite | // sqlite | ||||
// rethink | // rethink | ||||
//eslint-disable-next-line no-process-env | //eslint-disable-next-line no-process-env | ||||
db: process.env.IWD_DB || 'rethink', | |||||
db: process.env.IWD_DB || 'sqlite', | |||||
//eslint-disable-next-line no-process-env | //eslint-disable-next-line no-process-env | ||||
dbHost: process.env.IWD_DB_HOST || 'localhost', | dbHost: process.env.IWD_DB_HOST || 'localhost', | ||||
//eslint-disable-next-line no-process-env | //eslint-disable-next-line no-process-env | ||||
@@ -49,7 +49,7 @@ module.exports = { | |||||
if (mod.disabled) | if (mod.disabled) | ||||
return; | return; | ||||
const isMapThread = !!process.send; | |||||
const isMapThread = global.instancer; | |||||
mod.isMapThread = isMapThread; | mod.isMapThread = isMapThread; | ||||
mod.events = events; | mod.events = events; | ||||