thelounge/client/js/socket-events/init.js

209 lines
6 KiB
JavaScript
Raw Normal View History

2017-05-18 20:08:54 +00:00
"use strict";
const $ = require("jquery");
2017-08-28 20:06:28 +00:00
const escape = require("css.escape");
2017-05-18 20:08:54 +00:00
const socket = require("../socket");
2017-07-10 19:47:03 +00:00
const webpush = require("../webpush");
2017-05-18 20:08:54 +00:00
const sidebar = $("#sidebar");
const storage = require("../localStorage");
2019-10-17 16:56:44 +00:00
const constants = require("../constants");
const {vueApp, initChannel} = require("../vue");
const store = require("../store").default;
2017-05-18 20:08:54 +00:00
socket.on("init", function(data) {
store.commit("currentUserVisibleError", "Rendering…");
2017-08-28 15:03:27 +00:00
$("#loading-page-message").text(store.state.currentUserVisibleError);
2017-05-18 20:08:54 +00:00
const previousActive = store.state.activeChannel && store.state.activeChannel.channel.id;
store.commit("networks", mergeNetworkData(data.networks));
store.commit("isConnected", true);
store.commit("currentUserVisibleError", null);
2018-07-08 17:53:23 +00:00
2018-07-15 20:23:49 +00:00
if (!vueApp.initialized) {
vueApp.onSocketInit();
2018-07-15 20:23:49 +00:00
2017-08-28 15:03:27 +00:00
if (data.token) {
storage.set("token", data.token);
}
2017-05-18 20:08:54 +00:00
2017-08-28 15:03:27 +00:00
webpush.configurePushNotifications(data.pushSubscription, data.applicationServerKey);
2017-07-10 19:47:03 +00:00
const viewportWidth = window.outerWidth;
let isUserlistOpen = storage.get("thelounge.state.userlist");
2019-10-17 16:56:44 +00:00
if (viewportWidth > constants.mobileViewportPixels) {
vueApp.setSidebar(storage.get("thelounge.state.sidebar") !== "false");
}
// If The Lounge is opened on a small screen (less than 1024px), and we don't have stored
// user list state, close it by default
if (viewportWidth >= 1024 && isUserlistOpen !== "true" && isUserlistOpen !== "false") {
isUserlistOpen = "true";
}
vueApp.setUserlist(isUserlistOpen === "true");
$(document.body).removeClass("signed-out");
2017-08-28 15:03:27 +00:00
$("#loading").remove();
2017-12-01 18:04:50 +00:00
if (window.g_LoungeErrorHandler) {
window.removeEventListener("error", window.g_LoungeErrorHandler);
window.g_LoungeErrorHandler = null;
}
2017-08-28 15:03:27 +00:00
}
2017-05-18 20:08:54 +00:00
2018-07-08 13:42:54 +00:00
vueApp.$nextTick(() => openCorrectChannel(previousActive, data.active));
2019-10-17 16:56:44 +00:00
vueApp.synchronizeNotifiedState();
2019-10-20 14:45:38 +00:00
if (document.body.classList.contains("public")) {
window.addEventListener(
"beforeunload",
() => "Are you sure you want to navigate away from this page?"
);
}
2017-05-18 20:08:54 +00:00
});
2017-08-28 20:06:28 +00:00
function openCorrectChannel(clientActive, serverActive) {
let target = $();
2017-08-28 20:06:28 +00:00
// Open last active channel
if (clientActive > 0) {
target = sidebar.find(`.chan[data-id="${clientActive}"]`);
2017-08-28 20:06:28 +00:00
}
// Open window provided in location.hash
if (target.length === 0 && window.location.hash) {
2017-12-25 00:17:26 +00:00
target = $(`[data-target="${escape(window.location.hash)}"]`).first();
2017-08-28 20:06:28 +00:00
}
// Open last active channel according to the server
if (serverActive > 0 && target.length === 0) {
target = sidebar.find(`.chan[data-id="${serverActive}"]`);
2017-08-28 20:06:28 +00:00
}
// Open first available channel
if (target.length === 0) {
target = sidebar.find(".chan").first();
}
2017-08-28 20:06:28 +00:00
// If target channel is found, open it
if (target.length > 0) {
2017-08-28 20:06:28 +00:00
target.trigger("click", {
replaceHistory: true,
2017-08-28 20:06:28 +00:00
});
return;
}
// Open the connect window
$("#footer .connect").trigger("click", {
pushState: false,
2017-08-28 20:06:28 +00:00
});
}
function mergeNetworkData(newNetworks) {
const collapsedNetworks = new Set(JSON.parse(storage.get("thelounge.networks.collapsed")));
for (let n = 0; n < newNetworks.length; n++) {
const network = newNetworks[n];
const currentNetwork = vueApp.findNetwork(network.uuid);
// If this network is new, set some default variables and initalize channel variables
if (!currentNetwork) {
network.isJoinChannelShown = false;
network.isCollapsed = collapsedNetworks.has(network.uuid);
network.channels.forEach(initChannel);
continue;
}
// Merge received network object into existing network object on the client
// so the object reference stays the same (e.g. for vueApp.currentChannel)
for (const key in network) {
if (!Object.prototype.hasOwnProperty.call(network, key)) {
continue;
}
// Channels require extra care to be merged correctly
if (key === "channels") {
2019-07-17 09:33:59 +00:00
currentNetwork.channels = mergeChannelData(
currentNetwork.channels,
network.channels
);
} else {
currentNetwork[key] = network[key];
}
}
newNetworks[n] = currentNetwork;
}
return newNetworks;
}
function mergeChannelData(oldChannels, newChannels) {
for (let c = 0; c < newChannels.length; c++) {
const channel = newChannels[c];
const currentChannel = oldChannels.find((chan) => chan.id === channel.id);
// This is a new channel that was joined while client was disconnected, initialize it
if (!currentChannel) {
initChannel(channel);
continue;
}
// Merge received channel object into existing currentChannel
// so the object references are exactly the same (e.g. in store.state.activeChannel)
for (const key in channel) {
if (!Object.prototype.hasOwnProperty.call(channel, key)) {
continue;
}
// Server sends an empty users array, client requests it whenever needed
if (key === "users") {
if (channel.type === "channel") {
if (
store.state.activeChannel &&
store.state.activeChannel.channel === currentChannel
) {
// For currently open channel, request the user list straight away
socket.emit("names", {
target: channel.id,
});
} else {
// For all other channels, mark the user list as outdated
// so an update will be requested whenever user switches to these channels
currentChannel.usersOutdated = true;
}
}
continue;
}
// Server sends total count of messages in memory, we compare it to amount of messages
// on the client, and decide whether theres more messages to load from server
if (key === "totalMessages") {
currentChannel.moreHistoryAvailable =
channel.totalMessages > currentChannel.messages.length;
continue;
}
// Reconnection only sends new messages, so merge it on the client
// Only concat if server sent us less than 100 messages so we don't introduce gaps
if (key === "messages" && currentChannel.messages && channel.messages.length < 100) {
currentChannel.messages = currentChannel.messages.concat(channel.messages);
} else {
currentChannel[key] = channel[key];
}
}
newChannels[c] = currentChannel;
}
return newChannels;
}