-
+
-
-
-
-
-
-
-
-
-
-
-
- {{ channel.name }}
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/client/js/libs/handlebars/modes.js b/client/js/libs/handlebars/modes.js
deleted file mode 100644
index 271361f3..00000000
--- a/client/js/libs/handlebars/modes.js
+++ /dev/null
@@ -1,15 +0,0 @@
-"use strict";
-
-const modes = {
- "~": "owner",
- "&": "admin",
- "!": "admin",
- "@": "op",
- "%": "half-op",
- "+": "voice",
- "": "normal",
-};
-
-module.exports = function(mode) {
- return modes[mode];
-};
diff --git a/client/js/lounge.js b/client/js/lounge.js
index 53ce7ec2..1a941ae5 100644
--- a/client/js/lounge.js
+++ b/client/js/lounge.js
@@ -164,6 +164,7 @@ $(function() {
// sidebar specifically. Needs to be done better when window management gets
// refactored.
const inSidebar = self.parents("#sidebar, #footer").length > 0;
+ let channel;
if (inSidebar) {
chat.data(
@@ -175,7 +176,7 @@ $(function() {
self.data("id")
);
- const channel = findChannel(self.data("id"));
+ channel = findChannel(self.data("id"));
vueApp.activeChannel = channel;
@@ -207,11 +208,9 @@ $(function() {
const lastActive = $("#windows > .active");
lastActive
- .removeClass("active")
- .find(".chat")
- .unsticky();
+ .removeClass("active");
- const lastActiveChan = lastActive.find(".chan.active");
+ /*const lastActiveChan = lastActive.find(".chan.active");
if (lastActiveChan.length > 0) {
lastActiveChan
@@ -221,7 +220,7 @@ $(function() {
.appendTo(lastActiveChan.find(".messages"));
render.trimMessageInChannel(lastActiveChan, 100);
- }
+ }*/
const chan = $(target)
.addClass("active")
@@ -231,19 +230,9 @@ $(function() {
utils.updateTitle();
const type = chan.data("type");
- let placeholder = "";
-
- if (type === "channel" || type === "query") {
- placeholder = `Write to ${chan.attr("aria-label")}`;
- }
-
- input
- .prop("placeholder", placeholder)
- .attr("aria-label", placeholder);
if (self.hasClass("chan")) {
$("#chat-container").addClass("active");
- $("#nick").text(self.closest(".network").attr("data-nick"));
}
const chanChat = chan.find(".chat");
@@ -257,9 +246,12 @@ $(function() {
input.trigger("ontouchstart" in window ? "blur" : "focus");
}
- if (chan.data("needsNamesRefresh") === true) {
- chan.data("needsNamesRefresh", false);
- socket.emit("names", {target: self.data("id")});
+ if (channel && channel.channel.usersOutdated) {
+ channel.channel.usersOutdated = false;
+
+ socket.emit("names", {
+ target: channel.channel.id,
+ });
}
// Pushes states to history web API when clicking elements with a data-target attribute.
diff --git a/client/js/render.js b/client/js/render.js
index e65057fc..51b75b9b 100644
--- a/client/js/render.js
+++ b/client/js/render.js
@@ -24,26 +24,18 @@ const historyObserver = window.IntersectionObserver ?
}) : null;
module.exports = {
- appendMessage,
- buildChannelMessages,
renderChannel,
- renderChannelUsers,
renderNetworks,
trimMessageInChannel,
};
-function buildChannelMessages(container, chanId, chanType, messages) {
- return messages.reduce((docFragment, message) => {
- appendMessage(docFragment, chanId, chanType, message);
- return docFragment;
- }, container);
-}
-
function appendMessage(container, chanId, chanType, msg) {
if (utils.lastMessageId < msg.id) {
utils.lastMessageId = msg.id;
}
+ return;
+
let lastChild = container.children(".msg, .date-marker-container").last();
const renderedMessage = buildChatMessage(msg);
@@ -136,80 +128,18 @@ function renderChannel(data) {
renderChannelMessages(data);
if (data.type === "channel") {
- const users = renderChannelUsers(data);
+ //const users = renderChannelUsers(data);
- Userlist.handleKeybinds(users.find(".search"));
+ //Userlist.handleKeybinds(users.find(".search"));
}
if (historyObserver) {
- historyObserver.observe(chat.find("#chan-" + data.id + " .show-more").get(0));
+ //historyObserver.observe(chat.find("#chan-" + data.id + " .show-more").get(0));
}
}
function renderChannelMessages(data) {
- const documentFragment = buildChannelMessages($(document.createDocumentFragment()), data.id, data.type, data.messages);
const channel = chat.find("#chan-" + data.id + " .messages");
-
- renderUnreadMarker($(templates.unread_marker()), data.firstUnread, channel);
-}
-
-function renderUnreadMarker(template, firstUnread, channel) {
- if (firstUnread > 0) {
- let first = channel.find("#msg-" + firstUnread);
-
- if (!first.length) {
- template.data("unread-id", firstUnread);
- channel.prepend(template);
- } else {
- const parent = first.parent();
-
- if (parent.hasClass("condensed")) {
- first = parent;
- }
-
- first.before(template);
- }
- } else {
- channel.append(template);
- }
-}
-
-function renderChannelUsers(data) {
- const users = chat.find("#chan-" + data.id).find(".userlist");
- const nicks = data.users
- .concat() // Make a copy of the user list, sort is applied in-place
- .sort((a, b) => b.lastMessage - a.lastMessage)
- .map((a) => a.nick);
-
- // Before re-rendering the list of names, there might have been an entry
- // marked as active (i.e. that was highlighted by keyboard navigation).
- // It is `undefined` if there was none.
- const previouslyActive = users.find(".active");
-
- const search = users
- .find(".search")
- .prop("placeholder", nicks.length + " " + (nicks.length === 1 ? "user" : "users"));
-
- users
- .data("nicks", nicks)
- .find(".names-original")
- .html(templates.user(data));
-
- // Refresh user search
- if (search.val().length) {
- search.trigger("input");
- }
-
- // If a nick was highlighted before re-rendering the lists, re-highlight it in
- // the newly-rendered list.
- if (previouslyActive.length > 0) {
- // We need to un-highlight everything first because triggering `input` with
- // a value highlights the first entry.
- users.find(".user").removeClass("active");
- users.find(`.user[data-name="${previouslyActive.attr("data-name")}"]`).addClass("active");
- }
-
- return users;
}
function renderNetworks(data, singleNetwork) {
@@ -234,20 +164,12 @@ function renderNetworks(data, singleNetwork) {
const chan = $("#chan-" + channel.id);
if (chan.length > 0) {
- if (chan.data("type") === "channel") {
- chan
- .data("needsNamesRefresh", true)
- .find(".header .topic")
- .html(helpers_parse(channel.topic))
- .prop("title", channel.topic);
+ if (channel.type === "channel") {
+ channel.usersOutdated = true;
}
if (channel.messages.length > 0) {
const container = chan.find(".messages");
- buildChannelMessages(container, channel.id, channel.type, channel.messages);
-
- const unreadMarker = container.find(".unread-marker").data("unread-id", 0);
- renderUnreadMarker(unreadMarker, channel.firstUnread, container);
if (container.find(".msg").length >= 100) {
container.find(".show-more").addClass("show");
@@ -268,7 +190,7 @@ function renderNetworks(data, singleNetwork) {
renderChannel(channel);
if (channel.type === "channel") {
- chat.find("#chan-" + channel.id).data("needsNamesRefresh", true);
+ channel.usersOutdated = true;
}
});
}
diff --git a/client/js/socket-events/more.js b/client/js/socket-events/more.js
index 1fcfd976..e3ab8719 100644
--- a/client/js/socket-events/more.js
+++ b/client/js/socket-events/more.js
@@ -5,6 +5,7 @@ const socket = require("../socket");
const render = require("../render");
const condensed = require("../condensed");
const chat = $("#chat");
+const {Vue, vueApp, findChannel} = require("../vue");
socket.on("more", function(data) {
let chan = chat.find("#chan-" + data.chan);
@@ -21,52 +22,31 @@ socket.on("more", function(data) {
return;
}
- // Remove the date marker at the top if date does not change
- const children = $(chan).children();
+ const channel = findChannel(data.chan);
- // Check the top-most element and the one after because
- // unread and date markers may switch positions
- for (let i = 0; i <= 1; i++) {
- const marker = children.eq(i);
-
- if (marker.hasClass("date-marker-container")) {
- const msgTime = new Date(data.messages[data.messages.length - 1].time);
- const prevMsgTime = new Date(marker.data("time"));
-
- if (prevMsgTime.toDateString() === msgTime.toDateString()) {
- marker.remove();
- }
-
- break;
- }
+ if (!channel) {
+ return;
}
- // Add the older messages
- const documentFragment = render.buildChannelMessages($(document.createDocumentFragment()), data.chan, type, data.messages);
- chan.prepend(documentFragment);
+ channel.channel.messages.unshift(...data.messages);
- // Move unread marker to correct spot if needed
- const unreadMarker = chan.find(".unread-marker");
- const firstUnread = unreadMarker.data("unread-id");
+ Vue.nextTick(() => {
+ // restore scroll position
+ const position = chan.height() - heightOld;
+ scrollable.finish().scrollTop(position);
+ });
- if (firstUnread > 0) {
- let first = chan.find("#msg-" + firstUnread);
-
- if (!first.length) {
- chan.prepend(unreadMarker);
- } else {
- const parent = first.parent();
-
- if (parent.hasClass("condensed")) {
- first = parent;
- }
-
- unreadMarker.data("unread-id", 0);
-
- first.before(unreadMarker);
- }
+ if (data.messages.length !== 100) {
+ 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
const condensedDuplicate = chan.find(".msg.condensed + .msg.condensed");
@@ -81,25 +61,6 @@ socket.on("more", function(data) {
condensedDuplicate.remove();
}
-
- // restore scroll position
- const position = chan.height() - heightOld;
- scrollable.finish().scrollTop(position);
-
- // We have to do this hack due to smooth scrolling in browsers,
- // as scrollTop does not apply correctly
- if (window.requestAnimationFrame) {
- window.requestAnimationFrame(() => scrollable.scrollTop(position));
- }
-
- if (data.messages.length !== 100) {
- 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);
});
chat.on("click", ".show-more button", function() {
diff --git a/client/js/socket-events/msg.js b/client/js/socket-events/msg.js
index ab031a63..3fc1e9e2 100644
--- a/client/js/socket-events/msg.js
+++ b/client/js/socket-events/msg.js
@@ -60,13 +60,7 @@ function processReceivedMessage(data) {
$(container).empty();
}
- // Add message to the container
- render.appendMessage(
- container,
- targetId,
- channelContainer.data("type"),
- data.msg
- );
+ channel.channel.messages.push(data.msg);
if (activeChannelId === targetId) {
scrollContainer.trigger("keepToBottom");
diff --git a/client/js/socket-events/names.js b/client/js/socket-events/names.js
index 4d2036e8..1adf6196 100644
--- a/client/js/socket-events/names.js
+++ b/client/js/socket-events/names.js
@@ -2,5 +2,12 @@
const socket = require("../socket");
const render = require("../render");
+const {vueApp, findChannel} = require("../vue");
-socket.on("names", render.renderChannelUsers);
+socket.on("names", function(data) {
+ const channel = findChannel(data.id);
+
+ if (channel) {
+ channel.channel.users = data.users;
+ }
+});
diff --git a/client/js/socket-events/nick.js b/client/js/socket-events/nick.js
index bb3b1ae5..cda8213c 100644
--- a/client/js/socket-events/nick.js
+++ b/client/js/socket-events/nick.js
@@ -1,14 +1,12 @@
"use strict";
-const $ = require("jquery");
const socket = require("../socket");
+const {vueApp} = require("../vue");
socket.on("nick", function(data) {
- const id = data.network;
- const nick = data.nick;
- const network = $(`#sidebar .network[data-uuid="${id}"]`).attr("data-nick", nick);
+ const network = vueApp.networks.find((n) => n.uuid === data.network);
- if (network.find(".active").length) {
- $("#nick").text(nick);
+ if (network) {
+ network.nick = data.nick;
}
});
diff --git a/client/js/socket-events/users.js b/client/js/socket-events/users.js
index b81a739d..bae3239a 100644
--- a/client/js/socket-events/users.js
+++ b/client/js/socket-events/users.js
@@ -2,16 +2,18 @@
const $ = require("jquery");
const socket = require("../socket");
-const chat = $("#chat");
+const {vueApp, findChannel} = require("../vue");
socket.on("users", function(data) {
- const chan = chat.find("#chan-" + data.chan);
-
- if (chan.hasClass("active")) {
- socket.emit("names", {
+ if (vueApp.activeChannel && vueApp.activeChannel.channel.id === data.chan) {
+ return socket.emit("names", {
target: data.chan,
});
- } else {
- chan.data("needsNamesRefresh", true);
+ }
+
+ const channel = findChannel(data.chan);
+
+ if (channel) {
+ channel.channel.usersOutdated = true;
}
});
diff --git a/client/views/unread_marker.tpl b/client/views/unread_marker.tpl
deleted file mode 100644
index cb952947..00000000
--- a/client/views/unread_marker.tpl
+++ /dev/null
@@ -1,3 +0,0 @@
-
+ class="lt"
+ aria-label="Toggle channel list"/>
+ {{ channel.name }}
+
+
+
+
+
-
+
+
-
-