Merge pull request #3872 from thelounge/xpaw/eventbus

Replace vue events with our own event bus
This commit is contained in:
Pavel Djundik 2020-04-24 14:24:29 +03:00 committed by GitHub
commit 480a2576c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 95 additions and 37 deletions

View File

@ -13,6 +13,7 @@
<script> <script>
const constants = require("../js/constants"); const constants = require("../js/constants");
import eventbus from "../js/eventbus";
import Mousetrap from "mousetrap"; import Mousetrap from "mousetrap";
import throttle from "lodash/throttle"; import throttle from "lodash/throttle";
import storage from "../js/localStorage"; import storage from "../js/localStorage";
@ -53,14 +54,14 @@ export default {
// Make a single throttled resize listener available to all components // Make a single throttled resize listener available to all components
this.debouncedResize = throttle(() => { this.debouncedResize = throttle(() => {
this.$root.$emit("resize"); eventbus.emit("resize");
}, 100); }, 100);
window.addEventListener("resize", this.debouncedResize, {passive: true}); window.addEventListener("resize", this.debouncedResize, {passive: true});
// Emit a daychange event every time the day changes so date markers know when to update themselves // Emit a daychange event every time the day changes so date markers know when to update themselves
const emitDayChange = () => { const emitDayChange = () => {
this.$root.$emit("daychange"); eventbus.emit("daychange");
// This should always be 24h later but re-computing exact value just in case // This should always be 24h later but re-computing exact value just in case
this.dayChangeTimeout = setTimeout(emitDayChange, this.msUntilNextDay()); this.dayChangeTimeout = setTimeout(emitDayChange, this.msUntilNextDay());
}; };
@ -77,7 +78,7 @@ export default {
}, },
methods: { methods: {
escapeKey() { escapeKey() {
this.$root.$emit("escapekey"); eventbus.emit("escapekey");
}, },
toggleSidebar(e) { toggleSidebar(e) {
if (isIgnoredKeybind(e)) { if (isIgnoredKeybind(e)) {

View File

@ -30,6 +30,7 @@
</template> </template>
<script> <script>
import eventbus from "../js/eventbus";
import isChannelCollapsed from "../js/helpers/isChannelCollapsed"; import isChannelCollapsed from "../js/helpers/isChannelCollapsed";
export default { export default {
@ -74,7 +75,7 @@ export default {
this.$root.switchToChannel(this.channel); this.$root.switchToChannel(this.channel);
}, },
openContextMenu(event) { openContextMenu(event) {
this.$root.$emit("contextmenu:channel", { eventbus.emit("contextmenu:channel", {
event: event, event: event,
channel: this.channel, channel: this.channel,
network: this.network, network: this.network,

View File

@ -102,6 +102,7 @@
<script> <script>
import socket from "../js/socket"; import socket from "../js/socket";
import eventbus from "../js/eventbus";
import ParsedMessage from "./ParsedMessage.vue"; import ParsedMessage from "./ParsedMessage.vue";
import MessageList from "./MessageList.vue"; import MessageList from "./MessageList.vue";
import ChatInput from "./ChatInput.vue"; import ChatInput from "./ChatInput.vue";
@ -197,14 +198,14 @@ export default {
} }
}, },
openContextMenu(event) { openContextMenu(event) {
this.$root.$emit("contextmenu:channel", { eventbus.emit("contextmenu:channel", {
event: event, event: event,
channel: this.channel, channel: this.channel,
network: this.network, network: this.network,
}); });
}, },
openMentions() { openMentions() {
this.$root.$emit("mentions:toggle", { eventbus.emit("mentions:toggle", {
event: event, event: event,
}); });
}, },

View File

@ -56,6 +56,7 @@ import autocompletion from "../js/autocompletion";
import commands from "../js/commands/index"; import commands from "../js/commands/index";
import socket from "../js/socket"; import socket from "../js/socket";
import upload from "../js/upload"; import upload from "../js/upload";
import eventbus from "../js/eventbus";
const formattingHotkeys = { const formattingHotkeys = {
"mod+k": "\x03", "mod+k": "\x03",
@ -101,7 +102,7 @@ export default {
}, },
}, },
mounted() { mounted() {
this.$root.$on("escapekey", this.blurInput); eventbus.on("escapekey", this.blurInput);
if (this.$store.state.settings.autocomplete) { if (this.$store.state.settings.autocomplete) {
autocompletionRef = autocompletion(this.$refs.input); autocompletionRef = autocompletion(this.$refs.input);
@ -163,7 +164,7 @@ export default {
} }
}, },
destroyed() { destroyed() {
this.$root.$off("escapekey", this.blurInput); eventbus.off("escapekey", this.blurInput);
if (autocompletionRef) { if (autocompletionRef) {
autocompletionRef.destroy(); autocompletionRef.destroy();

View File

@ -51,6 +51,8 @@
</style> </style>
<script> <script>
import eventbus from "../js/eventbus";
export default { export default {
name: "ConfirmDialog", name: "ConfirmDialog",
data() { data() {
@ -60,12 +62,12 @@ export default {
}; };
}, },
mounted() { mounted() {
this.$root.$on("escapekey", this.close); eventbus.on("escapekey", this.close);
this.$root.$on("confirm-dialog", this.open); eventbus.on("confirm-dialog", this.open);
}, },
destroyed() { destroyed() {
this.$root.$off("escapekey", this.close); eventbus.off("escapekey", this.close);
this.$root.$off("confirm-dialog", this.open); eventbus.off("confirm-dialog", this.open);
}, },
methods: { methods: {
open(data, callback) { open(data, callback) {

View File

@ -39,6 +39,7 @@
<script> <script>
import {generateUserContextMenu, generateChannelContextMenu} from "../js/helpers/contextMenu.js"; import {generateUserContextMenu, generateChannelContextMenu} from "../js/helpers/contextMenu.js";
import eventbus from "../js/eventbus";
export default { export default {
name: "ContextMenu", name: "ContextMenu",
@ -58,14 +59,14 @@ export default {
}; };
}, },
mounted() { mounted() {
this.$root.$on("escapekey", this.close); eventbus.on("escapekey", this.close);
this.$root.$on("contextmenu:user", this.openUserContextMenu); eventbus.on("contextmenu:user", this.openUserContextMenu);
this.$root.$on("contextmenu:channel", this.openChannelContextMenu); eventbus.on("contextmenu:channel", this.openChannelContextMenu);
}, },
destroyed() { destroyed() {
this.$root.$off("escapekey", this.close); eventbus.off("escapekey", this.close);
this.$root.$off("contextmenu:user", this.openUserContextMenu); eventbus.off("contextmenu:user", this.openUserContextMenu);
this.$root.$off("contextmenu:channel", this.openChannelContextMenu); eventbus.off("contextmenu:channel", this.openChannelContextMenu);
this.close(); this.close();
}, },

View File

@ -9,6 +9,7 @@
<script> <script>
import dayjs from "dayjs"; import dayjs from "dayjs";
import calendar from "dayjs/plugin/calendar"; import calendar from "dayjs/plugin/calendar";
import eventbus from "../js/eventbus";
dayjs.extend(calendar); dayjs.extend(calendar);
@ -24,11 +25,11 @@ export default {
}, },
mounted() { mounted() {
if (this.hoursPassed() < 48) { if (this.hoursPassed() < 48) {
this.$root.$on("daychange", this.dayChange); eventbus.on("daychange", this.dayChange);
} }
}, },
beforeDestroy() { beforeDestroy() {
this.$root.$off("daychange", this.dayChange); eventbus.off("daychange", this.dayChange);
}, },
methods: { methods: {
hoursPassed() { hoursPassed() {
@ -38,7 +39,7 @@ export default {
this.$forceUpdate(); this.$forceUpdate();
if (this.hoursPassed() >= 48) { if (this.hoursPassed() >= 48) {
this.$root.$off("daychange", this.dayChange); eventbus.off("daychange", this.dayChange);
} }
}, },
friendlyDate() { friendlyDate() {

View File

@ -40,6 +40,7 @@
<script> <script>
import Mousetrap from "mousetrap"; import Mousetrap from "mousetrap";
import eventbus from "../js/eventbus";
export default { export default {
name: "ImageViewer", name: "ImageViewer",
@ -79,8 +80,8 @@ export default {
link(newLink, oldLink) { link(newLink, oldLink) {
// TODO: history.pushState // TODO: history.pushState
if (newLink === null) { if (newLink === null) {
this.$root.$off("escapekey", this.closeViewer); eventbus.off("escapekey", this.closeViewer);
this.$root.$off("resize", this.correctPosition); eventbus.off("resize", this.correctPosition);
Mousetrap.unbind("left", this.previous); Mousetrap.unbind("left", this.previous);
Mousetrap.unbind("right", this.next); Mousetrap.unbind("right", this.next);
return; return;
@ -89,8 +90,8 @@ export default {
this.setPrevNextImages(); this.setPrevNextImages();
if (!oldLink) { if (!oldLink) {
this.$root.$on("escapekey", this.closeViewer); eventbus.on("escapekey", this.closeViewer);
this.$root.$on("resize", this.correctPosition); eventbus.on("resize", this.correctPosition);
Mousetrap.bind("left", this.previous); Mousetrap.bind("left", this.previous);
Mousetrap.bind("right", this.next); Mousetrap.bind("right", this.next);
} }

View File

@ -130,6 +130,7 @@
</template> </template>
<script> <script>
import eventbus from "../js/eventbus";
import friendlysize from "../js/helpers/friendlysize"; import friendlysize from "../js/helpers/friendlysize";
export default { export default {
@ -167,12 +168,12 @@ export default {
this.updateShownState(); this.updateShownState();
}, },
mounted() { mounted() {
this.$root.$on("resize", this.handleResize); eventbus.on("resize", this.handleResize);
this.onPreviewUpdate(); this.onPreviewUpdate();
}, },
beforeDestroy() { beforeDestroy() {
this.$root.$off("resize", this.handleResize); eventbus.off("resize", this.handleResize);
}, },
destroyed() { destroyed() {
// Let this preview go through load/canplay events again, // Let this preview go through load/canplay events again,

View File

@ -125,6 +125,7 @@
import Username from "./Username.vue"; import Username from "./Username.vue";
import ParsedMessage from "./ParsedMessage.vue"; import ParsedMessage from "./ParsedMessage.vue";
import socket from "../js/socket"; import socket from "../js/socket";
import eventbus from "../js/eventbus";
import localetime from "../js/helpers/localetime"; import localetime from "../js/helpers/localetime";
import dayjs from "dayjs"; import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime"; import relativeTime from "dayjs/plugin/relativeTime";
@ -161,10 +162,10 @@ export default {
}, },
}, },
mounted() { mounted() {
this.$root.$on("mentions:toggle", this.openPopup); eventbus.on("mentions:toggle", this.openPopup);
}, },
destroyed() { destroyed() {
this.$root.$off("mentions:toggle", this.openPopup); eventbus.off("mentions:toggle", this.openPopup);
}, },
methods: { methods: {
messageTime(time) { messageTime(time) {

View File

@ -56,6 +56,7 @@
<script> <script>
const constants = require("../js/constants"); const constants = require("../js/constants");
import eventbus from "../js/eventbus";
import clipboard from "../js/clipboard"; import clipboard from "../js/clipboard";
import socket from "../js/socket"; import socket from "../js/socket";
import Message from "./Message.vue"; import Message from "./Message.vue";
@ -173,7 +174,7 @@ export default {
mounted() { mounted() {
this.$refs.chat.addEventListener("scroll", this.handleScroll, {passive: true}); this.$refs.chat.addEventListener("scroll", this.handleScroll, {passive: true});
this.$root.$on("resize", this.handleResize); eventbus.on("resize", this.handleResize);
this.$nextTick(() => { this.$nextTick(() => {
if (this.historyObserver) { if (this.historyObserver) {
@ -185,7 +186,7 @@ export default {
this.unreadMarkerShown = false; this.unreadMarkerShown = false;
}, },
beforeDestroy() { beforeDestroy() {
this.$root.$off("resize", this.handleResize); eventbus.off("resize", this.handleResize);
this.$refs.chat.removeEventListener("scroll", this.handleScroll); this.$refs.chat.removeEventListener("scroll", this.handleScroll);
}, },
destroyed() { destroyed() {

View File

@ -11,6 +11,7 @@
</template> </template>
<script> <script>
import eventbus from "../js/eventbus";
import colorClass from "../js/helpers/colorClass"; import colorClass from "../js/helpers/colorClass";
export default { export default {
@ -30,7 +31,7 @@ export default {
return this.onHover(this.user); return this.onHover(this.user);
}, },
openContextMenu(event) { openContextMenu(event) {
this.$root.$emit("contextmenu:user", { eventbus.emit("contextmenu:user", {
event: event, event: event,
user: this.user, user: this.user,
}); });

43
client/js/eventbus.js Normal file
View File

@ -0,0 +1,43 @@
const events = new Map();
class EventBus {
/**
* Register an event handler for the given type.
*
* @param {String} type Type of event to listen for.
* @param {Function} handler Function to call in response to given event.
*/
on(type, handler) {
if (events.has(type)) {
events[type].push(handler);
} else {
events[type] = [handler];
}
}
/**
* Remove an event handler for the given type.
*
* @param {String} type Type of event to unregister `handler` from.
* @param {Function} handler Handler function to remove.
*/
off(type, handler) {
if (events.has(type)) {
events[type] = events[type].filter((item) => item !== handler);
}
}
/**
* Invoke all handlers for the given type.
*
* @param {String} type The event type to invoke.
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler.
*/
emit(type, evt) {
if (events.has(type)) {
events[type].slice().map((handler) => handler(evt));
}
}
}
export default new EventBus();

View File

@ -1,6 +1,7 @@
"use strict"; "use strict";
import socket from "../socket"; import socket from "../socket";
import eventbus from "../eventbus";
export function generateChannelContextMenu($root, channel, network) { export function generateChannelContextMenu($root, channel, network) {
const typeMap = { const typeMap = {
@ -135,7 +136,7 @@ export function generateChannelContextMenu($root, channel, network) {
type: "item", type: "item",
class: "clear-history", class: "clear-history",
action() { action() {
$root.$emit( eventbus.emit(
"confirm-dialog", "confirm-dialog",
{ {
title: "Clear history", title: "Clear history",

View File

@ -9,6 +9,7 @@ import App from "../components/App.vue";
import storage from "./localStorage"; import storage from "./localStorage";
import {router, navigate} from "./router"; import {router, navigate} from "./router";
import socket from "./socket"; import socket from "./socket";
import eventbus from "./eventbus";
import "./socket-events"; import "./socket-events";
import "./webpush"; import "./webpush";
@ -18,7 +19,7 @@ const favicon = document.getElementById("favicon");
const faviconNormal = favicon.getAttribute("href"); const faviconNormal = favicon.getAttribute("href");
const faviconAlerted = favicon.dataset.other; const faviconAlerted = favicon.dataset.other;
const vueApp = new Vue({ new Vue({
el: "#viewport", el: "#viewport",
router, router,
mounted() { mounted() {
@ -30,7 +31,7 @@ const vueApp = new Vue({
}, },
closeChannel(channel) { closeChannel(channel) {
if (channel.type === "lobby") { if (channel.type === "lobby") {
this.$root.$emit( eventbus.emit(
"confirm-dialog", "confirm-dialog",
{ {
title: "Remove network", title: "Remove network",
@ -75,7 +76,7 @@ store.watch(
(sidebarOpen) => { (sidebarOpen) => {
if (window.innerWidth > constants.mobileViewportPixels) { if (window.innerWidth > constants.mobileViewportPixels) {
storage.set("thelounge.state.sidebar", sidebarOpen); storage.set("thelounge.state.sidebar", sidebarOpen);
vueApp.$emit("resize"); eventbus.emit("resize");
} }
} }
); );
@ -84,7 +85,7 @@ store.watch(
(state) => state.userlistOpen, (state) => state.userlistOpen,
(userlistOpen) => { (userlistOpen) => {
storage.set("thelounge.state.userlist", userlistOpen); storage.set("thelounge.state.userlist", userlistOpen);
vueApp.$emit("resize"); eventbus.emit("resize");
} }
); );