thelounge/client/components/ChatInput.vue

157 lines
3.6 KiB
Vue
Raw Normal View History

2018-07-08 13:42:54 +00:00
<template>
<form
id="form"
method="post"
2018-07-08 15:17:20 +00:00
action=""
@submit.prevent="onSubmit">
2018-07-08 13:42:54 +00:00
<span id="nick">{{ network.nick }}</span>
<textarea
id="input"
2018-07-08 15:17:20 +00:00
ref="input"
2018-07-08 13:42:54 +00:00
v-model="channel.pendingMessage"
:placeholder="getInputPlaceholder(channel)"
:aria-label="getInputPlaceholder(channel)"
2018-07-08 17:53:23 +00:00
:disabled="!$root.connected"
2018-07-08 13:42:54 +00:00
class="mousetrap"
2018-07-10 07:45:54 +00:00
@keypress.enter.prevent="onSubmit"
2018-07-08 13:42:54 +00:00
/>
<span
2018-07-08 17:53:23 +00:00
v-if="$root.connected"
2018-07-08 13:42:54 +00:00
id="submit-tooltip"
class="tooltipped tooltipped-w tooltipped-no-touch"
aria-label="Send message">
<button
id="submit"
type="submit"
aria-label="Send message"/>
</span>
</form>
</template>
<script>
2018-07-08 15:17:20 +00:00
const $ = require("jquery");
const commands = require("../js/commands/index");
2018-07-08 15:17:20 +00:00
const socket = require("../js/socket");
2018-07-09 18:51:27 +00:00
const Mousetrap = require("mousetrap");
const {wrapCursor} = require("undate");
const colorsHotkeys = {
k: "\x03",
b: "\x02",
u: "\x1F",
i: "\x1D",
o: "\x0F",
s: "\x1e",
m: "\x11",
};
// Autocomplete bracket and quote characters like in a modern IDE
// For example, select `text`, press `[` key, and it becomes `[text]`
const bracketWraps = {
'"': '"',
"'": "'",
"(": ")",
"<": ">",
"[": "]",
"{": "}",
"*": "*",
"`": "`",
"~": "~",
"_": "_",
};
2018-07-08 15:17:20 +00:00
2018-07-08 13:42:54 +00:00
export default {
name: "ChatInput",
props: {
network: Object,
channel: Object,
},
2018-07-13 10:24:05 +00:00
watch: {
"channel.pendingMessage"() {
const style = window.getComputedStyle(this.$refs.input);
const lineHeight = parseFloat(style.lineHeight, 10) || 1;
2018-07-13 10:24:05 +00:00
// Start by resetting height before computing as scrollHeight does not
// decrease when deleting characters
resetInputHeight(this);
2018-07-13 10:24:05 +00:00
// Use scrollHeight to calculate how many lines there are in input, and ceil the value
// because some browsers tend to incorrently round the values when using high density
// displays or using page zoom feature
this.$refs.input.style.height = Math.ceil(this.$refs.input.scrollHeight / lineHeight) * lineHeight + "px";
2018-07-13 10:24:05 +00:00
},
},
2018-07-08 14:57:02 +00:00
mounted() {
if (this.$root.settings.autocomplete) {
2018-07-09 18:53:49 +00:00
require("../js/autocompletion").enable(this.$refs.input);
2018-07-08 14:57:02 +00:00
}
2018-07-09 18:51:27 +00:00
const inputTrap = Mousetrap(this.$refs.input);
for (const hotkey in colorsHotkeys) {
inputTrap.bind("mod+" + hotkey, function(e) {
// Key is lowercased because keybinds also get processed if caps lock is on
const modifier = colorsHotkeys[e.key.toLowerCase()];
wrapCursor(
e.target,
modifier,
e.target.selectionStart === e.target.selectionEnd ? "" : modifier
);
return false;
});
}
inputTrap.bind(Object.keys(bracketWraps), function(e) {
if (e.target.selectionStart !== e.target.selectionEnd) {
wrapCursor(e.target, e.key, bracketWraps[e.key]);
return false;
}
});
2018-07-08 14:57:02 +00:00
},
destroyed() {
require("../js/autocompletion").disable();
},
2018-07-08 13:42:54 +00:00
methods: {
getInputPlaceholder(channel) {
if (channel.type === "channel" || channel.type === "query") {
return `Write to ${channel.name}`;
}
return "";
},
2018-07-13 10:24:05 +00:00
resetInputHeight() {
this.$refs.input.style.height = "";
},
2018-07-08 15:17:20 +00:00
onSubmit() {
// Triggering click event opens the virtual keyboard on mobile
// This can only be called from another interactive event (e.g. button click)
$(this.$refs.input).trigger("click").trigger("focus");
const target = this.channel.id;
2018-07-08 18:21:24 +00:00
const text = this.channel.pendingMessage;
2018-07-08 15:17:20 +00:00
if (text.length === 0) {
return false;
}
2018-07-08 18:21:24 +00:00
this.channel.pendingMessage = "";
2018-07-13 10:24:05 +00:00
this.resetInputHeight();
2018-07-08 15:17:20 +00:00
if (text[0] === "/") {
2018-07-08 15:17:20 +00:00
const args = text.substr(1).split(" ");
const cmd = args.shift().toLowerCase();
if (commands[cmd] && commands[cmd].input(args)) {
2018-07-08 15:17:20 +00:00
return false;
}
}
socket.emit("input", {target, text});
},
2018-07-08 13:42:54 +00:00
},
};
</script>