Make history loading work
This commit is contained in:
parent
25840dfef4
commit
0e930c9356
@ -59,7 +59,10 @@
|
||||
</aside>
|
||||
<div id="sidebar-overlay"/>
|
||||
<article id="windows">
|
||||
<Chat v-if="activeChannel" :network="activeChannel.network" :channel="activeChannel.channel"/>
|
||||
<Chat
|
||||
v-if="activeChannel"
|
||||
:network="activeChannel.network"
|
||||
:channel="activeChannel.channel"/>
|
||||
<div
|
||||
id="sign-in"
|
||||
class="window"
|
||||
|
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div id="chat-container" class="window">
|
||||
<div id="chat">
|
||||
<div
|
||||
id="chat-container"
|
||||
class="window">
|
||||
<div
|
||||
id="chat"
|
||||
ref="chat">
|
||||
<div
|
||||
:id="'chan-' + channel.id"
|
||||
:class="[channel.type, 'chan', 'active']"
|
||||
@ -35,11 +39,17 @@
|
||||
<div class="chat">
|
||||
<div
|
||||
v-if="channel.messages.length > 0"
|
||||
class="show-more show">
|
||||
ref="loadMoreButton"
|
||||
:disabled="channel.historyLoading"
|
||||
class="show-more show"
|
||||
@click="onShowMoreClick"
|
||||
>
|
||||
<button
|
||||
:data-id="channel.id"
|
||||
class="btn"
|
||||
data-alt-text="Loading…">Show older messages</button>
|
||||
v-if="channel.historyLoading"
|
||||
class="btn">Loading…</button>
|
||||
<button
|
||||
v-else
|
||||
class="btn">Show older messages</button>
|
||||
</div>
|
||||
<div
|
||||
class="messages"
|
||||
@ -86,8 +96,14 @@
|
||||
tabindex="-1">
|
||||
</div>
|
||||
<div class="names">
|
||||
<div v-for="(users, mode) in groupedUsers" :key="mode" :class="['user-mode', getModeClass(mode)]">
|
||||
<Username v-for="user in users" :key="user.nick" :user="user"/>
|
||||
<div
|
||||
v-for="(users, mode) in groupedUsers"
|
||||
:key="mode"
|
||||
:class="['user-mode', getModeClass(mode)]">
|
||||
<Username
|
||||
v-for="user in users"
|
||||
:key="user.nick"
|
||||
:user="user"/>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
@ -95,34 +111,18 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="connection-error"/>
|
||||
<form
|
||||
id="form"
|
||||
method="post"
|
||||
action="">
|
||||
<span id="nick">{{network.nick}}</span>
|
||||
<textarea
|
||||
id="input"
|
||||
class="mousetrap"
|
||||
v-model="channel.pendingMessage"
|
||||
:placeholder="getInputPlaceholder(channel)"
|
||||
:aria-label="getInputPlaceholder(channel)"
|
||||
/>
|
||||
<span
|
||||
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>
|
||||
<ChatInput
|
||||
:network="network"
|
||||
:channel="channel"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
require("intersection-observer");
|
||||
const socket = require("../js/socket");
|
||||
import Message from "./Message.vue";
|
||||
import Username from "./Username.vue";
|
||||
import ChatInput from "./ChatInput.vue";
|
||||
|
||||
const modes = {
|
||||
"~": "owner",
|
||||
@ -139,6 +139,7 @@ export default {
|
||||
components: {
|
||||
Message,
|
||||
Username,
|
||||
ChatInput,
|
||||
},
|
||||
props: {
|
||||
network: Object,
|
||||
@ -159,6 +160,23 @@ export default {
|
||||
return groups;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (window.IntersectionObserver) {
|
||||
this.historyObserver = new window.IntersectionObserver(loadMoreHistory, {
|
||||
root: this.$refs.chat,
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.historyObserver) {
|
||||
this.historyObserver.observe(this.$refs.loadMoreButton);
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
if (this.historyObserver) {
|
||||
this.historyObserver.unobserve(this.$refs.loadMoreButton);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
shouldDisplayDateMarker(id) {
|
||||
const previousTime = this.channel.messages[id - 1];
|
||||
@ -180,16 +198,30 @@ export default {
|
||||
|
||||
return true;
|
||||
},
|
||||
getInputPlaceholder(channel) {
|
||||
if (channel.type === "channel" || channel.type === "query") {
|
||||
return `Write to ${channel.name}`;
|
||||
}
|
||||
|
||||
return "";
|
||||
},
|
||||
getModeClass(mode) {
|
||||
return modes[mode];
|
||||
},
|
||||
onShowMoreClick() {
|
||||
let lastMessage = this.channel.messages[0];
|
||||
lastMessage = lastMessage ? lastMessage.id : -1;
|
||||
|
||||
this.$set(this.channel, "historyLoading", true);
|
||||
|
||||
socket.emit("more", {
|
||||
target: this.channel.id,
|
||||
lastId: lastMessage,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function loadMoreHistory(entries) {
|
||||
entries.forEach((entry) => {
|
||||
if (!entry.isIntersecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry.target.click();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
43
client/components/ChatInput.vue
Normal file
43
client/components/ChatInput.vue
Normal file
@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<form
|
||||
id="form"
|
||||
method="post"
|
||||
action="">
|
||||
<span id="nick">{{ network.nick }}</span>
|
||||
<textarea
|
||||
id="input"
|
||||
v-model="channel.pendingMessage"
|
||||
:placeholder="getInputPlaceholder(channel)"
|
||||
:aria-label="getInputPlaceholder(channel)"
|
||||
class="mousetrap"
|
||||
/>
|
||||
<span
|
||||
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>
|
||||
export default {
|
||||
name: "ChatInput",
|
||||
props: {
|
||||
network: Object,
|
||||
channel: Object,
|
||||
},
|
||||
methods: {
|
||||
getInputPlaceholder(channel) {
|
||||
if (channel.type === "channel" || channel.type === "query") {
|
||||
return `Write to ${channel.name}`;
|
||||
}
|
||||
|
||||
return "";
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -1,12 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
let diff;
|
||||
|
||||
module.exports = function(a, opt) {
|
||||
if (a !== diff) {
|
||||
diff = a;
|
||||
return opt.fn(this);
|
||||
}
|
||||
|
||||
return opt.inverse(this);
|
||||
};
|
@ -9,7 +9,6 @@ require("./libs/jquery/stickyscroll");
|
||||
const slideoutMenu = require("./slideout");
|
||||
const templates = require("../views");
|
||||
const socket = require("./socket");
|
||||
const render = require("./render");
|
||||
require("./socket-events");
|
||||
const storage = require("./localStorage");
|
||||
const utils = require("./utils");
|
||||
@ -232,7 +231,7 @@ $(function() {
|
||||
const type = chan.data("type");
|
||||
|
||||
if (self.hasClass("chan")) {
|
||||
$("#chat-container").addClass("active");
|
||||
vueApp.$nextTick(() => $("#chat-container").addClass("active"));
|
||||
}
|
||||
|
||||
const chanChat = chan.find(".chat");
|
||||
|
@ -8,23 +8,11 @@ const utils = require("./utils");
|
||||
const constants = require("./constants");
|
||||
const condensed = require("./condensed");
|
||||
const JoinChannel = require("./join-channel");
|
||||
const helpers_parse = require("./libs/handlebars/parse");
|
||||
const Userlist = require("./userlist");
|
||||
const storage = require("./localStorage");
|
||||
const {vueApp} = require("./vue");
|
||||
|
||||
const chat = $("#chat");
|
||||
const sidebar = $("#sidebar");
|
||||
|
||||
require("intersection-observer");
|
||||
|
||||
const historyObserver = window.IntersectionObserver ?
|
||||
new window.IntersectionObserver(loadMoreHistory, {
|
||||
root: chat.get(0),
|
||||
}) : null;
|
||||
|
||||
module.exports = {
|
||||
renderChannel,
|
||||
renderNetworks,
|
||||
trimMessageInChannel,
|
||||
};
|
||||
@ -124,24 +112,6 @@ function buildChatMessage(msg) {
|
||||
return renderedMessage;
|
||||
}
|
||||
|
||||
function renderChannel(data) {
|
||||
renderChannelMessages(data);
|
||||
|
||||
if (data.type === "channel") {
|
||||
//const users = renderChannelUsers(data);
|
||||
|
||||
//Userlist.handleKeybinds(users.find(".search"));
|
||||
}
|
||||
|
||||
if (historyObserver) {
|
||||
//historyObserver.observe(chat.find("#chan-" + data.id + " .show-more").get(0));
|
||||
}
|
||||
}
|
||||
|
||||
function renderChannelMessages(data) {
|
||||
const channel = chat.find("#chan-" + data.id + " .messages");
|
||||
}
|
||||
|
||||
function renderNetworks(data, singleNetwork) {
|
||||
const collapsed = new Set(JSON.parse(storage.get("thelounge.networks.collapsed")));
|
||||
|
||||
@ -187,8 +157,6 @@ function renderNetworks(data, singleNetwork) {
|
||||
|
||||
if (newChannels.length > 0) {
|
||||
newChannels.forEach((channel) => {
|
||||
renderChannel(channel);
|
||||
|
||||
if (channel.type === "channel") {
|
||||
channel.usersOutdated = true;
|
||||
}
|
||||
@ -227,22 +195,6 @@ function trimMessageInChannel(channel, messageLimit) {
|
||||
});
|
||||
}
|
||||
|
||||
function loadMoreHistory(entries) {
|
||||
entries.forEach((entry) => {
|
||||
if (!entry.isIntersecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
const target = $(entry.target).find("button");
|
||||
|
||||
if (target.prop("disabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
target.trigger("click");
|
||||
});
|
||||
}
|
||||
|
||||
sidebar.on("click", "button.collapse-network", (e) => collapseNetwork($(e.target)));
|
||||
|
||||
function collapseNetwork(target) {
|
||||
|
@ -9,7 +9,7 @@ const slideoutMenu = require("../slideout");
|
||||
const sidebar = $("#sidebar");
|
||||
const storage = require("../localStorage");
|
||||
const utils = require("../utils");
|
||||
const {Vue, vueApp} = require("../vue");
|
||||
const {vueApp} = require("../vue");
|
||||
|
||||
socket.on("init", function(data) {
|
||||
$("#loading-page-message, #connection-error").text("Rendering…");
|
||||
@ -24,7 +24,7 @@ socket.on("init", function(data) {
|
||||
vueApp.networks = data.networks;
|
||||
|
||||
if (data.networks.length > 0) {
|
||||
Vue.nextTick(() => render.renderNetworks(data));
|
||||
vueApp.$nextTick(() => render.renderNetworks(data));
|
||||
}
|
||||
|
||||
$("#connection-error").removeClass("shown");
|
||||
@ -66,7 +66,7 @@ socket.on("init", function(data) {
|
||||
}
|
||||
}
|
||||
|
||||
Vue.nextTick(() => openCorrectChannel(previousActive, data.active));
|
||||
vueApp.$nextTick(() => openCorrectChannel(previousActive, data.active));
|
||||
});
|
||||
|
||||
function openCorrectChannel(clientActive, serverActive) {
|
||||
|
@ -2,23 +2,19 @@
|
||||
|
||||
const $ = require("jquery");
|
||||
const socket = require("../socket");
|
||||
const render = require("../render");
|
||||
const templates = require("../../views");
|
||||
const sidebar = $("#sidebar");
|
||||
const {Vue, vueApp} = require("../vue");
|
||||
const {vueApp} = require("../vue");
|
||||
|
||||
socket.on("join", function(data) {
|
||||
vueApp.networks.find((n) => n.uuid === data.network)
|
||||
.channels.splice(data.index || -1, 0, data.chan);
|
||||
|
||||
Vue.nextTick(() => render.renderChannel(data.chan));
|
||||
|
||||
// Queries do not automatically focus, unless the user did a whois
|
||||
if (data.chan.type === "query" && !data.shouldOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vue.nextTick(() => {
|
||||
vueApp.$nextTick(() => {
|
||||
sidebar.find(".chan")
|
||||
.sort(function(a, b) {
|
||||
return $(a).data("id") - $(b).data("id");
|
||||
|
@ -2,13 +2,11 @@
|
||||
|
||||
const $ = require("jquery");
|
||||
const socket = require("../socket");
|
||||
const render = require("../render");
|
||||
const condensed = require("../condensed");
|
||||
const chat = $("#chat");
|
||||
const {Vue, vueApp, findChannel} = require("../vue");
|
||||
const {vueApp, findChannel} = require("../vue");
|
||||
|
||||
socket.on("more", function(data) {
|
||||
let chan = chat.find("#chan-" + data.chan);
|
||||
let chan = $("#chat #chan-" + data.chan);
|
||||
const type = chan.data("type");
|
||||
chan = chan.find(".messages");
|
||||
|
||||
@ -29,8 +27,9 @@ socket.on("more", function(data) {
|
||||
}
|
||||
|
||||
channel.channel.messages.unshift(...data.messages);
|
||||
channel.channel.historyLoading = false;
|
||||
|
||||
Vue.nextTick(() => {
|
||||
vueApp.$nextTick(() => {
|
||||
// restore scroll position
|
||||
const position = chan.height() - heightOld;
|
||||
scrollable.finish().scrollTop(position);
|
||||
@ -40,11 +39,6 @@ socket.on("more", function(data) {
|
||||
scrollable.find(".show-more").removeClass("show");
|
||||
}
|
||||
|
||||
// Swap button text back from its alternative label
|
||||
const showMoreBtn = scrollable.find(".show-more button");
|
||||
swapText(showMoreBtn);
|
||||
showMoreBtn.prop("disabled", false);
|
||||
|
||||
return;
|
||||
|
||||
// Join duplicate condensed messages together
|
||||
@ -62,28 +56,3 @@ socket.on("more", function(data) {
|
||||
condensedDuplicate.remove();
|
||||
}
|
||||
});
|
||||
|
||||
chat.on("click", ".show-more button", function() {
|
||||
const self = $(this);
|
||||
const lastMessage = self.closest(".chat").find(".msg:not(.condensed)").first();
|
||||
let lastMessageId = -1;
|
||||
|
||||
if (lastMessage.length > 0) {
|
||||
lastMessageId = parseInt(lastMessage.prop("id").replace("msg-", ""), 10);
|
||||
}
|
||||
|
||||
// Swap button text with its alternative label
|
||||
swapText(self);
|
||||
self.prop("disabled", true);
|
||||
|
||||
socket.emit("more", {
|
||||
target: self.data("id"),
|
||||
lastId: lastMessageId,
|
||||
});
|
||||
});
|
||||
|
||||
// Given a button, swap its text with the content of `data-alt-text`
|
||||
function swapText(btn) {
|
||||
const altText = btn.data("alt-text");
|
||||
btn.data("alt-text", btn.text()).text(altText);
|
||||
}
|
||||
|
@ -6,12 +6,12 @@ const render = require("../render");
|
||||
const templates = require("../../views");
|
||||
const sidebar = $("#sidebar");
|
||||
const utils = require("../utils");
|
||||
const {Vue, vueApp} = require("../vue");
|
||||
const {vueApp} = require("../vue");
|
||||
|
||||
socket.on("network", function(data) {
|
||||
vueApp.networks.push(data.networks[0]);
|
||||
|
||||
Vue.nextTick(() => {
|
||||
vueApp.$nextTick(() => {
|
||||
render.renderNetworks(data, true);
|
||||
|
||||
sidebar.find(".chan")
|
||||
|
@ -3,12 +3,12 @@
|
||||
const $ = require("jquery");
|
||||
const socket = require("../socket");
|
||||
const sidebar = $("#sidebar");
|
||||
const {Vue, vueApp} = require("../vue");
|
||||
const {vueApp} = require("../vue");
|
||||
|
||||
socket.on("quit", function(data) {
|
||||
vueApp.networks.splice(vueApp.networks.findIndex((n) => n.uuid === data.network), 1);
|
||||
|
||||
Vue.nextTick(() => {
|
||||
vueApp.$nextTick(() => {
|
||||
const chan = sidebar.find(".chan");
|
||||
|
||||
if (chan.length === 0) {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
const $ = require("jquery");
|
||||
const io = require("socket.io-client");
|
||||
const utils = require("./utils");
|
||||
|
||||
const socket = io({
|
||||
transports: $(document.body).data("transports"),
|
||||
@ -51,6 +50,7 @@ function handleDisconnect(data) {
|
||||
// If the server shuts down, socket.io skips reconnection
|
||||
// and we have to manually call connect to start the process
|
||||
if (socket.io.skipReconnect) {
|
||||
const utils = require("./utils");
|
||||
utils.requestIdleCallback(() => socket.connect(), 2000);
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ function findChannel(id) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Vue,
|
||||
vueApp,
|
||||
findChannel,
|
||||
};
|
||||
|
@ -1,5 +0,0 @@
|
||||
<div class="date-marker-container tooltipped tooltipped-s" data-time="{{time}}" aria-label="{{localedate time}}">
|
||||
<div class="date-marker">
|
||||
<span class="date-marker-text" data-label="{{friendlydate time}}"></span>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user