ts progress

This commit is contained in:
Max Leiter 2022-05-02 00:50:13 -07:00
parent 291ac3e903
commit 5bb94d6428
No known key found for this signature in database
GPG key ID: A3512F2F2F17EBDA
170 changed files with 5527 additions and 150 deletions

View file

@ -3,7 +3,7 @@ root: true
parserOptions:
ecmaVersion: 2022
parser: "babel-eslint"
parser: "@babel/eslint-parser",
env:
es6: true

View file

@ -0,0 +1,11 @@
"use strict";
// This creates a version of `require()` in the context of the current
// directory, so we iterate over its content, which is a map statically built by
// Webpack.
// Second argument says it's recursive, third makes sure we only load templates.
const requireViews = require.context(".", false, /\.vue$/);
export default requireViews.keys().reduce((acc, path) => {
acc["message-" + path.substring(2, path.length - 4)] = requireViews(path).default;
return acc;
}, {});
//# sourceMappingURL=index.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../components/MessageTypes/index.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,sEAAsE;AACtE,gFAAgF;AAChF,WAAW;AACX,gFAAgF;AAChF,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AAE3D,eAAe,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;IACvD,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;IAElF,OAAO,GAAG,CAAC;AACZ,CAAC,EAAE,EAAE,CAAC,CAAC"}

10
client/dist/js/auth.js vendored Normal file
View file

@ -0,0 +1,10 @@
"use strict";
import storage from "./localStorage";
import location from "./location";
export default class Auth {
static signout() {
storage.clear();
location.reload();
}
}
//# sourceMappingURL=auth.js.map

1
client/dist/js/auth.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../js/auth.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,OAAO,MAAM,gBAAgB,CAAC;AACrC,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,CAAC,OAAO,OAAO,IAAI;IACxB,MAAM,CAAC,OAAO;QACb,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,QAAQ,CAAC,MAAM,EAAE,CAAC;IACnB,CAAC;CACD"}

280
client/dist/js/autocompletion.js vendored Normal file
View file

@ -0,0 +1,280 @@
"use strict";
const constants = require("./constants");
import Mousetrap from "mousetrap";
import {Textcomplete} from "@textcomplete/core/dist/Textcomplete";
import {TextareaEditor} from "@textcomplete/textarea/dist/TextareaEditor";
import fuzzy from "fuzzy";
import emojiMap from "./helpers/simplemap.json";
import store from "./store";
export default enableAutocomplete;
const emojiSearchTerms = Object.keys(emojiMap);
const emojiStrategy = {
id: "emoji",
match: /(^|\s):([-+\w:?]{2,}):?$/,
search(term, callback) {
// Trim colon from the matched term,
// as we are unable to get a clean string from match regex
term = term.replace(/:$/, "");
callback(fuzzyGrep(term, emojiSearchTerms));
},
template([string, original]) {
return `<span class="emoji">${emojiMap[original]}</span> ${string}`;
},
replace([, original]) {
return "$1" + emojiMap[original];
},
index: 2,
};
const nicksStrategy = {
id: "nicks",
match: /(^|\s)(@([a-zA-Z_[\]\\^{}|`@][a-zA-Z0-9_[\]\\^{}|`-]*)?)$/,
search(term, callback) {
term = term.slice(1);
if (term[0] === "@") {
callback(completeNicks(term.slice(1), true).map((val) => ["@" + val[0], "@" + val[1]]));
} else {
callback(completeNicks(term, true));
}
},
template([string]) {
return string;
},
replace([, original]) {
return "$1" + replaceNick(original);
},
index: 2,
};
const chanStrategy = {
id: "chans",
match: /(^|\s)((?:#|\+|&|![A-Z0-9]{5})(?:[^\s]+)?)$/,
search(term, callback) {
callback(completeChans(term));
},
template([string]) {
return string;
},
replace([, original]) {
return "$1" + original;
},
index: 2,
};
const commandStrategy = {
id: "commands",
match: /^\/(\w*)$/,
search(term, callback) {
callback(completeCommands("/" + term));
},
template([string]) {
return string;
},
replace([, original]) {
return original;
},
index: 1,
};
const foregroundColorStrategy = {
id: "foreground-colors",
match: /\x03(\d{0,2}|[A-Za-z ]{0,10})$/,
search(term, callback) {
term = term.toLowerCase();
const matchingColorCodes = constants.colorCodeMap
.filter((i) => fuzzy.test(term, i[0]) || fuzzy.test(term, i[1]))
.map((i) => {
if (fuzzy.test(term, i[1])) {
return [
i[0],
fuzzy.match(term, i[1], {
pre: "<b>",
post: "</b>",
}).rendered,
];
}
return i;
});
callback(matchingColorCodes);
},
template(value) {
return `<span class="irc-fg${parseInt(value[0], 10)}">${value[1]}</span>`;
},
replace(value) {
return "\x03" + value[0];
},
index: 1,
};
const backgroundColorStrategy = {
id: "background-colors",
match: /\x03(\d{2}),(\d{0,2}|[A-Za-z ]{0,10})$/,
search(term, callback, match) {
term = term.toLowerCase();
const matchingColorCodes = constants.colorCodeMap
.filter((i) => fuzzy.test(term, i[0]) || fuzzy.test(term, i[1]))
.map((pair) => {
if (fuzzy.test(term, pair[1])) {
return [
pair[0],
fuzzy.match(term, pair[1], {
pre: "<b>",
post: "</b>",
}).rendered,
];
}
return pair;
})
.map((pair) => pair.concat(match[1])); // Needed to pass fg color to `template`...
callback(matchingColorCodes);
},
template(value) {
return `<span class="irc-fg${parseInt(value[2], 10)} irc-bg irc-bg${parseInt(
value[0],
10
)}">${value[1]}</span>`;
},
replace(value) {
return "\x03$1," + value[0];
},
index: 2,
};
function enableAutocomplete(input) {
let tabCount = 0;
let lastMatch = "";
let currentMatches = [];
input.addEventListener("input", (e) => {
if (e.detail === "autocomplete") {
return;
}
tabCount = 0;
currentMatches = [];
lastMatch = "";
});
Mousetrap(input).bind(
"tab",
(e) => {
if (store.state.isAutoCompleting) {
return;
}
e.preventDefault();
const text = input.value;
if (tabCount === 0) {
lastMatch = text.substring(0, input.selectionStart).split(/\s/).pop();
if (lastMatch.length === 0) {
return;
}
currentMatches = completeNicks(lastMatch, false);
if (currentMatches.length === 0) {
return;
}
}
const position = input.selectionStart - lastMatch.length;
const newMatch = replaceNick(
currentMatches[tabCount % currentMatches.length],
position
);
const remainder = text.substr(input.selectionStart);
input.value = text.substr(0, position) + newMatch + remainder;
input.selectionStart -= remainder.length;
input.selectionEnd = input.selectionStart;
// Propagate change to Vue model
input.dispatchEvent(
new CustomEvent("input", {
detail: "autocomplete",
})
);
lastMatch = newMatch;
tabCount++;
},
"keydown"
);
const strategies = [
emojiStrategy,
nicksStrategy,
chanStrategy,
commandStrategy,
foregroundColorStrategy,
backgroundColorStrategy,
];
const editor = new TextareaEditor(input);
const textcomplete = new Textcomplete(editor, strategies, {
dropdown: {
className: "textcomplete-menu",
placement: "top",
},
});
textcomplete.on("show", () => {
store.commit("isAutoCompleting", true);
});
textcomplete.on("hidden", () => {
store.commit("isAutoCompleting", false);
});
return {
hide() {
textcomplete.hide();
},
destroy() {
textcomplete.destroy();
store.commit("isAutoCompleting", false);
},
};
}
function replaceNick(original, position = 1) {
// If no postfix specified, return autocompleted nick as-is
if (!store.state.settings.nickPostfix) {
return original;
}
// If there is whitespace in the input already, append space to nick
if (position > 0 && /\s/.test(store.state.activeChannel.channel.pendingMessage)) {
return original + " ";
}
// If nick is first in the input, append specified postfix
return original + store.state.settings.nickPostfix;
}
function fuzzyGrep(term, array) {
const results = fuzzy.filter(term, array, {
pre: "<b>",
post: "</b>",
});
return results.map((el) => [el.string, el.original]);
}
function rawNicks() {
if (store.state.activeChannel.channel.users.length > 0) {
const users = store.state.activeChannel.channel.users.slice();
return users.sort((a, b) => b.lastMessage - a.lastMessage).map((u) => u.nick);
}
const me = store.state.activeChannel.network.nick;
const otherUser = store.state.activeChannel.channel.name;
// If this is a query, add their name to autocomplete
if (me !== otherUser && store.state.activeChannel.channel.type === "query") {
return [otherUser, me];
}
// Return our own name by default for anything that isn't a channel or query
return [me];
}
function completeNicks(word, isFuzzy) {
const users = rawNicks();
word = word.toLowerCase();
if (isFuzzy) {
return fuzzyGrep(word, users);
}
return users.filter((w) => !w.toLowerCase().indexOf(word));
}
function getCommands() {
let cmds = constants.commands.slice();
if (!store.state.settings.searchEnabled) {
cmds = cmds.filter((c) => c !== "/search");
}
return cmds;
}
function completeCommands(word) {
const commands = getCommands();
return fuzzyGrep(word, commands);
}
function completeChans(word) {
const words = [];
for (const channel of store.state.activeChannel.network.channels) {
// Push all channels that start with the same CHANTYPE
if (channel.type === "channel" && channel.name[0] === word[0]) {
words.push(channel.name);
}
}
return fuzzyGrep(word, words);
}
//# sourceMappingURL=autocompletion.js.map

1
client/dist/js/autocompletion.js.map vendored Normal file

File diff suppressed because one or more lines are too long

25
client/dist/js/clipboard.js vendored Normal file
View file

@ -0,0 +1,25 @@
"use strict";
export default function (chat) {
// Disable in Firefox as it already copies flex text correctly
if (typeof window.InstallTrigger !== "undefined") {
return;
}
const selection = window.getSelection();
// If selection does not span multiple elements, do nothing
if (selection.anchorNode === selection.focusNode) {
return;
}
const range = selection.getRangeAt(0);
const documentFragment = range.cloneContents();
const div = document.createElement("div");
div.id = "js-copy-hack";
div.appendChild(documentFragment);
chat.appendChild(div);
selection.selectAllChildren(div);
window.setTimeout(() => {
chat.removeChild(div);
selection.removeAllRanges();
selection.addRange(range);
}, 0);
}
//# sourceMappingURL=clipboard.js.map

1
client/dist/js/clipboard.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../js/clipboard.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,MAAM,CAAC,OAAO,WAAW,IAAI;IAC5B,8DAA8D;IAC9D,IAAI,OAAO,MAAM,CAAC,cAAc,KAAK,WAAW,EAAE;QACjD,OAAO;KACP;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IAExC,2DAA2D;IAC3D,IAAI,SAAS,CAAC,UAAU,KAAK,SAAS,CAAC,SAAS,EAAE;QACjD,OAAO;KACP;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,gBAAgB,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC;IAC/C,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAE1C,GAAG,CAAC,EAAE,GAAG,cAAc,CAAC;IACxB,GAAG,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAClC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAEtB,SAAS,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAEjC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE;QACtB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACtB,SAAS,CAAC,eAAe,EAAE,CAAC;QAC5B,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,EAAE,CAAC,CAAC,CAAC;AACP,CAAC"}

29
client/dist/js/commands/collapse.js vendored Normal file
View file

@ -0,0 +1,29 @@
"use strict";
import socket from "../socket";
import store from "../store";
function input() {
const messageIds = [];
for (const message of store.state.activeChannel.channel.messages) {
let toggled = false;
for (const preview of message.previews) {
if (preview.shown) {
preview.shown = false;
toggled = true;
}
}
if (toggled) {
messageIds.push(message.id);
}
}
// Tell the server we're toggling so it remembers at page reload
if (!document.body.classList.contains("public") && messageIds.length > 0) {
socket.emit("msg:preview:toggle", {
target: store.state.activeChannel.channel.id,
messageIds: messageIds,
shown: false,
});
}
return true;
}
export default {input};
//# sourceMappingURL=collapse.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"collapse.js","sourceRoot":"","sources":["../../../js/commands/collapse.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,KAAK,MAAM,UAAU,CAAC;AAE7B,SAAS,KAAK;IACb,MAAM,UAAU,GAAG,EAAE,CAAC;IAEtB,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,EAAE;QACjE,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE;YACvC,IAAI,OAAO,CAAC,KAAK,EAAE;gBAClB,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;gBACtB,OAAO,GAAG,IAAI,CAAC;aACf;SACD;QAED,IAAI,OAAO,EAAE;YACZ,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;SAC5B;KACD;IAED,gEAAgE;IAChE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE;QACzE,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE;YACjC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE;YAC5C,UAAU,EAAE,UAAU;YACtB,KAAK,EAAE,KAAK;SACZ,CAAC,CAAC;KACH;IAED,OAAO,IAAI,CAAC;AACb,CAAC;AAED,eAAe,EAAC,KAAK,EAAC,CAAC"}

29
client/dist/js/commands/expand.js vendored Normal file
View file

@ -0,0 +1,29 @@
"use strict";
import socket from "../socket";
import store from "../store";
function input() {
const messageIds = [];
for (const message of store.state.activeChannel.channel.messages) {
let toggled = false;
for (const preview of message.previews) {
if (!preview.shown) {
preview.shown = true;
toggled = true;
}
}
if (toggled) {
messageIds.push(message.id);
}
}
// Tell the server we're toggling so it remembers at page reload
if (!document.body.classList.contains("public") && messageIds.length > 0) {
socket.emit("msg:preview:toggle", {
target: store.state.activeChannel.channel.id,
messageIds: messageIds,
shown: true,
});
}
return true;
}
export default {input};
//# sourceMappingURL=expand.js.map

1
client/dist/js/commands/expand.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"expand.js","sourceRoot":"","sources":["../../../js/commands/expand.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,KAAK,MAAM,UAAU,CAAC;AAE7B,SAAS,KAAK;IACb,MAAM,UAAU,GAAG,EAAE,CAAC;IAEtB,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,EAAE;QACjE,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE;YACvC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;gBACnB,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;gBACrB,OAAO,GAAG,IAAI,CAAC;aACf;SACD;QAED,IAAI,OAAO,EAAE;YACZ,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;SAC5B;KACD;IAED,gEAAgE;IAChE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE;QACzE,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE;YACjC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE;YAC5C,UAAU,EAAE,UAAU;YACtB,KAAK,EAAE,IAAI;SACX,CAAC,CAAC;KACH;IAED,OAAO,IAAI,CAAC;AACb,CAAC;AAED,eAAe,EAAC,KAAK,EAAC,CAAC"}

16
client/dist/js/commands/index.js vendored Normal file
View file

@ -0,0 +1,16 @@
"use strict";
// Taken from views/index.js
// This creates a version of `require()` in the context of the current
// directory, so we iterate over its content, which is a map statically built by
// Webpack.
// Second argument says it's recursive, third makes sure we only load javascript.
const commands = require.context("./", true, /\.js$/);
export default commands.keys().reduce((acc, path) => {
const command = path.substring(2, path.length - 3);
if (command === "index") {
return acc;
}
acc[command] = commands(path).default;
return acc;
}, {});
//# sourceMappingURL=index.js.map

1
client/dist/js/commands/index.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../js/commands/index.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,4BAA4B;AAE5B,sEAAsE;AACtE,gFAAgF;AAChF,WAAW;AACX,iFAAiF;AACjF,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AAEtD,eAAe,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEnD,IAAI,OAAO,KAAK,OAAO,EAAE;QACxB,OAAO,GAAG,CAAC;KACX;IAED,GAAG,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;IAEtC,OAAO,GAAG,CAAC;AACZ,CAAC,EAAE,EAAE,CAAC,CAAC"}

40
client/dist/js/commands/join.js vendored Normal file
View file

@ -0,0 +1,40 @@
"use strict";
import socket from "../socket";
import store from "../store";
import {switchToChannel} from "../router";
function input(args) {
if (args.length > 0) {
let channels = args[0];
if (channels.length > 0) {
const chanTypes = store.state.activeChannel.network.serverOptions.CHANTYPES;
const channelList = args[0].split(",");
if (chanTypes && chanTypes.length > 0) {
for (let c = 0; c < channelList.length; c++) {
if (!chanTypes.includes(channelList[c][0])) {
channelList[c] = chanTypes[0] + channelList[c];
}
}
}
channels = channelList.join(",");
const chan = store.getters.findChannelOnCurrentNetwork(channels);
if (chan) {
switchToChannel(chan);
} else {
socket.emit("input", {
text: `/join ${channels} ${args.length > 1 ? args[1] : ""}`,
target: store.state.activeChannel.channel.id,
});
return true;
}
}
} else if (store.state.activeChannel.channel.type === "channel") {
// If `/join` command is used without any arguments, re-join current channel
socket.emit("input", {
target: store.state.activeChannel.channel.id,
text: `/join ${store.state.activeChannel.channel.name}`,
});
return true;
}
}
export default {input};
//# sourceMappingURL=join.js.map

1
client/dist/js/commands/join.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"join.js","sourceRoot":"","sources":["../../../js/commands/join.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,KAAK,MAAM,UAAU,CAAC;AAC7B,OAAO,EAAC,eAAe,EAAC,MAAM,WAAW,CAAC;AAE1C,SAAS,KAAK,CAAC,IAAI;IAClB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;QACpB,IAAI,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAEvB,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;YACxB,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC;YAC5E,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAEvC,IAAI,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;gBACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;oBAC5C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;wBAC3C,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;qBAC/C;iBACD;aACD;YAED,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAEjC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAC;YAEjE,IAAI,IAAI,EAAE;gBACT,eAAe,CAAC,IAAI,CAAC,CAAC;aACtB;iBAAM;gBACN,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE;oBACpB,IAAI,EAAE,SAAS,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;oBAC3D,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE;iBAC5C,CAAC,CAAC;gBAEH,OAAO,IAAI,CAAC;aACZ;SACD;KACD;SAAM,IAAI,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE;QAChE,4EAA4E;QAC5E,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE;YACpB,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE;YAC5C,IAAI,EAAE,SAAS,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE;SACvD,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC;KACZ;AACF,CAAC;AAED,eAAe,EAAC,KAAK,EAAC,CAAC"}

20
client/dist/js/commands/search.js vendored Normal file
View file

@ -0,0 +1,20 @@
"use strict";
import store from "../store";
import {router} from "../router";
function input(args) {
if (!store.state.settings.searchEnabled) {
return false;
}
router.push({
name: "SearchResults",
params: {
id: store.state.activeChannel.channel.id,
},
query: {
q: args.join(" "),
},
});
return true;
}
export default {input};
//# sourceMappingURL=search.js.map

1
client/dist/js/commands/search.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../js/commands/search.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,KAAK,MAAM,UAAU,CAAC;AAC7B,OAAO,EAAC,MAAM,EAAC,MAAM,WAAW,CAAC;AAEjC,SAAS,KAAK,CAAC,IAAI;IAClB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,EAAE;QACxC,OAAO,KAAK,CAAC;KACb;IAED,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE;YACP,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE;SACxC;QACD,KAAK,EAAE;YACN,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;SACjB;KACD,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACb,CAAC;AAED,eAAe,EAAC,KAAK,EAAC,CAAC"}

35
client/dist/js/constants.js vendored Normal file
View file

@ -0,0 +1,35 @@
"use strict";
const colorCodeMap = [
["00", "White"],
["01", "Black"],
["02", "Blue"],
["03", "Green"],
["04", "Red"],
["05", "Brown"],
["06", "Magenta"],
["07", "Orange"],
["08", "Yellow"],
["09", "Light Green"],
["10", "Cyan"],
["11", "Light Cyan"],
["12", "Light Blue"],
["13", "Pink"],
["14", "Grey"],
["15", "Light Grey"],
];
const condensedTypes = new Set(["chghost", "join", "part", "quit", "nick", "kick", "mode"]);
const timeFormats = {
msgDefault: "HH:mm",
msgWithSeconds: "HH:mm:ss",
msg12h: "hh:mm A",
msg12hWithSeconds: "hh:mm:ss A",
};
export default {
colorCodeMap,
commands: [],
condensedTypes,
timeFormats,
// Same value as media query in CSS that forces sidebars to become overlays
mobileViewportPixels: 768,
};
//# sourceMappingURL=constants.js.map

1
client/dist/js/constants.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../js/constants.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,MAAM,YAAY,GAAG;IACpB,CAAC,IAAI,EAAE,OAAO,CAAC;IACf,CAAC,IAAI,EAAE,OAAO,CAAC;IACf,CAAC,IAAI,EAAE,MAAM,CAAC;IACd,CAAC,IAAI,EAAE,OAAO,CAAC;IACf,CAAC,IAAI,EAAE,KAAK,CAAC;IACb,CAAC,IAAI,EAAE,OAAO,CAAC;IACf,CAAC,IAAI,EAAE,SAAS,CAAC;IACjB,CAAC,IAAI,EAAE,QAAQ,CAAC;IAChB,CAAC,IAAI,EAAE,QAAQ,CAAC;IAChB,CAAC,IAAI,EAAE,aAAa,CAAC;IACrB,CAAC,IAAI,EAAE,MAAM,CAAC;IACd,CAAC,IAAI,EAAE,YAAY,CAAC;IACpB,CAAC,IAAI,EAAE,YAAY,CAAC;IACpB,CAAC,IAAI,EAAE,MAAM,CAAC;IACd,CAAC,IAAI,EAAE,MAAM,CAAC;IACd,CAAC,IAAI,EAAE,YAAY,CAAC;CACpB,CAAC;AAEF,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE5F,MAAM,WAAW,GAAG;IACnB,UAAU,EAAE,OAAO;IACnB,cAAc,EAAE,UAAU;IAC1B,MAAM,EAAE,SAAS;IACjB,iBAAiB,EAAE,YAAY;CAC/B,CAAC;AAEF,eAAe;IACd,YAAY;IACZ,QAAQ,EAAE,EAAE;IACZ,cAAc;IACd,WAAW;IACX,2EAA2E;IAC3E,oBAAoB,EAAE,GAAG;CACzB,CAAC"}

48
client/dist/js/eventbus.js vendored Normal file
View file

@ -0,0 +1,48 @@
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.get(type).push(handler);
} else {
events.set(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.set(
type,
events.get(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
.get(type)
.slice()
.map((handler) => {
handler(...evt);
});
}
}
}
export default new EventBus();
//# sourceMappingURL=eventbus.js.map

1
client/dist/js/eventbus.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"eventbus.js","sourceRoot":"","sources":["../../js/eventbus.js"],"names":[],"mappings":"AAAA,MAAM,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;AAEzB,MAAM,QAAQ;IACb;;;;;OAKG;IACH,EAAE,CAAC,IAAI,EAAE,OAAO;QACf,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACrB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;SAC/B;aAAM;YACN,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;SAC5B;IACF,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,IAAI,EAAE,OAAO;QAChB,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACrB,MAAM,CAAC,GAAG,CACT,IAAI,EACJ,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC,CACnD,CAAC;SACF;IACF,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG;QAChB,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACrB,MAAM;iBACJ,GAAG,CAAC,IAAI,CAAC;iBACT,KAAK,EAAE;iBACP,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;gBAChB,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;YACjB,CAAC,CAAC,CAAC;SACJ;IACF,CAAC;CACD;AAED,eAAe,IAAI,QAAQ,EAAE,CAAC"}

View file

@ -0,0 +1,13 @@
"use strict";
import storage from "../localStorage";
export default (network, isCollapsed) => {
const networks = new Set(JSON.parse(storage.get("thelounge.networks.collapsed")));
network.isCollapsed = isCollapsed;
if (isCollapsed) {
networks.add(network.uuid);
} else {
networks.delete(network.uuid);
}
storage.set("thelounge.networks.collapsed", JSON.stringify([...networks]));
};
//# sourceMappingURL=collapseNetwork.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"collapseNetwork.js","sourceRoot":"","sources":["../../../js/helpers/collapseNetwork.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,OAAO,MAAM,iBAAiB,CAAC;AAEtC,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE;IACvC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC,CAAC,CAAC;IAClF,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;IAElC,IAAI,WAAW,EAAE;QAChB,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;KAC3B;SAAM;QACN,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;KAC9B;IAED,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC5E,CAAC,CAAC"}

15
client/dist/js/helpers/colorClass.js vendored Normal file
View file

@ -0,0 +1,15 @@
"use strict";
// Generates a string from "color-1" to "color-32" based on an input string
export default (str) => {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash += str.charCodeAt(i);
}
/*
Modulo 32 lets us be case insensitive for ascii
due to A being ascii 65 (100 0001)
while a being ascii 97 (110 0001)
*/
return "color-" + (1 + (hash % 32));
};
//# sourceMappingURL=colorClass.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"colorClass.js","sourceRoot":"","sources":["../../../js/helpers/colorClass.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,2EAA2E;AAC3E,eAAe,CAAC,GAAG,EAAE,EAAE;IACtB,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACpC,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;KAC1B;IAED;;;;MAIE;IACF,OAAO,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;AACrC,CAAC,CAAC"}

378
client/dist/js/helpers/contextMenu.js vendored Normal file
View file

@ -0,0 +1,378 @@
"use strict";
import socket from "../socket";
import eventbus from "../eventbus";
export function generateChannelContextMenu($root, channel, network) {
const typeMap = {
lobby: "network",
channel: "chan",
query: "query",
special: "chan",
};
const closeMap = {
lobby: "Remove",
channel: "Leave",
query: "Close",
special: "Close",
};
let items = [
{
label: channel.name,
type: "item",
class: typeMap[channel.type],
link: `/chan-${channel.id}`,
},
{
type: "divider",
},
];
// Add menu items for lobbies
if (channel.type === "lobby") {
items = [
...items,
{
label: "Edit this network…",
type: "item",
class: "edit",
link: `/edit-network/${network.uuid}`,
},
{
label: "Join a channel…",
type: "item",
class: "join",
action: () => (network.isJoinChannelShown = true),
},
{
label: "List all channels",
type: "item",
class: "list",
action: () =>
socket.emit("input", {
target: channel.id,
text: "/list",
}),
},
{
label: "List ignored users",
type: "item",
class: "list",
action: () =>
socket.emit("input", {
target: channel.id,
text: "/ignorelist",
}),
},
network.status.connected
? {
label: "Disconnect",
type: "item",
class: "disconnect",
action: () =>
socket.emit("input", {
target: channel.id,
text: "/disconnect",
}),
}
: {
label: "Connect",
type: "item",
class: "connect",
action: () =>
socket.emit("input", {
target: channel.id,
text: "/connect",
}),
},
];
}
// Add menu items for channels
if (channel.type === "channel") {
items.push({
label: "Edit topic",
type: "item",
class: "edit",
action() {
channel.editTopic = true;
$root.switchToChannel(channel);
},
});
items.push({
label: "List banned users",
type: "item",
class: "list",
action() {
socket.emit("input", {
target: channel.id,
text: "/banlist",
});
},
});
}
// Add menu items for queries
if (channel.type === "query") {
items.push(
{
label: "User information",
type: "item",
class: "action-whois",
action() {
$root.switchToChannel(channel);
socket.emit("input", {
target: channel.id,
text: "/whois " + channel.name,
});
},
},
{
label: "Ignore user",
type: "item",
class: "action-ignore",
action() {
socket.emit("input", {
target: channel.id,
text: "/ignore " + channel.name,
});
},
}
);
}
if (channel.type === "channel" || channel.type === "query") {
items.push({
label: "Clear history",
type: "item",
class: "clear-history",
action() {
eventbus.emit(
"confirm-dialog",
{
title: "Clear history",
text: `Are you sure you want to clear history for ${channel.name}? This cannot be undone.`,
button: "Clear history",
},
(result) => {
if (!result) {
return;
}
socket.emit("history:clear", {
target: channel.id,
});
}
);
},
});
}
const humanFriendlyChanTypeMap = {
lobby: "network",
channel: "channel",
query: "conversation",
};
// We don't allow the muting of ChanType.SPECIAL channels
const mutableChanTypes = Object.keys(humanFriendlyChanTypeMap);
if (mutableChanTypes.includes(channel.type)) {
const chanType = humanFriendlyChanTypeMap[channel.type];
items.push({
label: channel.muted ? `Unmute ${chanType}` : `Mute ${chanType}`,
type: "item",
class: "mute",
action() {
socket.emit("mute:change", {
target: channel.id,
setMutedTo: !channel.muted,
});
},
});
}
// Add close menu item
items.push({
label: closeMap[channel.type],
type: "item",
class: "close",
action() {
$root.closeChannel(channel);
},
});
return items;
}
export function generateInlineChannelContextMenu($root, chan, network) {
const join = () => {
const channel = network.channels.find((c) => c.name === chan);
if (channel) {
$root.switchToChannel(channel);
}
socket.emit("input", {
target: $root.$store.state.activeChannel.channel.id,
text: "/join " + chan,
});
};
const channel = network.channels.find((c) => c.name === chan);
if (channel) {
return [
{
label: "Go to channel",
type: "item",
class: "chan",
link: `/chan-${channel.id}`,
},
];
}
return [
{
label: "Join channel",
type: "item",
class: "join",
action: join,
},
];
}
export function generateUserContextMenu($root, channel, network, user) {
const currentChannelUser = channel
? channel.users.find((u) => u.nick === network.nick) || {}
: {};
const whois = () => {
const chan = network.channels.find((c) => c.name === user.nick);
if (chan) {
$root.switchToChannel(chan);
}
socket.emit("input", {
target: channel.id,
text: "/whois " + user.nick,
});
};
const items = [
{
label: user.nick,
type: "item",
class: "user",
action: whois,
},
{
type: "divider",
},
{
label: "User information",
type: "item",
class: "action-whois",
action: whois,
},
{
label: "Ignore user",
type: "item",
class: "action-ignore",
action() {
socket.emit("input", {
target: channel.id,
text: "/ignore " + user.nick,
});
},
},
{
label: "Direct messages",
type: "item",
class: "action-query",
action() {
const chan = $root.$store.getters.findChannelOnCurrentNetwork(user.nick);
if (chan) {
$root.switchToChannel(chan);
}
socket.emit("input", {
target: channel.id,
text: "/query " + user.nick,
});
},
},
];
// Bail because we're in a query or we don't have a special mode.
if (!currentChannelUser.modes || currentChannelUser.modes.length < 1) {
return items;
}
// Names of the standard modes we are able to change
const modeCharToName = {
"~": "owner",
"&": "admin",
"@": "operator",
"%": "half-op",
"+": "voice",
};
// Labels for the mode changes. For example .rev({mode: "a", symbol: "&"}) => 'Revoke admin (-a)'
const modeTextTemplate = {
revoke(m) {
const name = modeCharToName[m.symbol];
const res = name ? `Revoke ${name} (-${m.mode})` : `Mode -${m.mode}`;
return res;
},
give(m) {
const name = modeCharToName[m.symbol];
const res = name ? `Give ${name} (+${m.mode})` : `Mode +${m.mode}`;
return res;
},
};
const networkModeSymbols = network.serverOptions.PREFIX.symbols;
/**
* Determine whether the prefix of mode p1 has access to perform actions on p2.
*
* EXAMPLE:
* compare('@', '@') => true
* compare('&', '@') => true
* compare('+', '~') => false
* @param {string} p1 The mode performing an action
* @param {string} p2 The target mode
*
* @return {boolean} whether p1 can perform an action on p2
*/
function compare(p1, p2) {
// The modes ~ and @ can perform actions on their own mode. The others on modes below.
return "~@".indexOf(p1) > -1
? networkModeSymbols.indexOf(p1) <= networkModeSymbols.indexOf(p2)
: networkModeSymbols.indexOf(p1) < networkModeSymbols.indexOf(p2);
}
network.serverOptions.PREFIX.prefix.forEach((mode) => {
if (!compare(currentChannelUser.modes[0], mode.symbol)) {
// Our highest mode is below the current mode. Bail.
return;
}
if (!user.modes.includes(mode.symbol)) {
// The target doesn't already have this mode, therefore we can set it.
items.push({
label: modeTextTemplate.give(mode),
type: "item",
class: "action-set-mode",
action() {
socket.emit("input", {
target: channel.id,
text: "/mode +" + mode.mode + " " + user.nick,
});
},
});
} else {
items.push({
label: modeTextTemplate.revoke(mode),
type: "item",
class: "action-revoke-mode",
action() {
socket.emit("input", {
target: channel.id,
text: "/mode -" + mode.mode + " " + user.nick,
});
},
});
}
});
// Determine if we are half-op or op depending on the network modes so we can kick.
if (!compare(networkModeSymbols.indexOf("%") > -1 ? "%" : "@", currentChannelUser.modes[0])) {
// Check if the target user has no mode or a mode lower than ours.
if (user.modes.length === 0 || compare(currentChannelUser.modes[0], user.modes[0])) {
items.push({
label: "Kick",
type: "item",
class: "action-kick",
action() {
socket.emit("input", {
target: channel.id,
text: "/kick " + user.nick,
});
},
});
}
}
return items;
}
//# sourceMappingURL=contextMenu.js.map

File diff suppressed because one or more lines are too long

5
client/dist/js/helpers/distance.js vendored Normal file
View file

@ -0,0 +1,5 @@
function distance([x1, y1], [x2, y2]) {
return Math.hypot(x1 - x2, y1 - y2);
}
export default distance;
//# sourceMappingURL=distance.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"distance.js","sourceRoot":"","sources":["../../../js/helpers/distance.js"],"names":[],"mappings":"AAAA,SAAS,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IACnC,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,eAAe,QAAQ,CAAC"}

View file

@ -0,0 +1,9 @@
"use strict";
const sizes = ["Bytes", "KiB", "MiB", "GiB", "TiB", "PiB"];
export default (size) => {
// Loosely inspired from https://stackoverflow.com/a/18650828/1935861
const i = size > 0 ? Math.floor(Math.log(size) / Math.log(1024)) : 0;
const fixedSize = parseFloat((size / Math.pow(1024, i)).toFixed(1));
return `${fixedSize} ${sizes[i]}`;
};
//# sourceMappingURL=friendlysize.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"friendlysize.js","sourceRoot":"","sources":["../../../js/helpers/friendlysize.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAE3D,eAAe,CAAC,IAAI,EAAE,EAAE;IACvB,qEAAqE;IACrE,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,OAAO,GAAG,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACnC,CAAC,CAAC"}

View file

@ -0,0 +1,13 @@
"use strict";
// Return true if any section of "a" or "b" parts (defined by their start/end
// markers) intersect each other, false otherwise.
function anyIntersection(a, b) {
return (
(a.start <= b.start && b.start < a.end) ||
(a.start < b.end && b.end <= a.end) ||
(b.start <= a.start && a.start < b.end) ||
(b.start < a.end && a.end <= b.end)
);
}
export default anyIntersection;
//# sourceMappingURL=anyIntersection.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"anyIntersection.js","sourceRoot":"","sources":["../../../../js/helpers/ircmessageparser/anyIntersection.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,6EAA6E;AAC7E,kDAAkD;AAClD,SAAS,eAAe,CAAC,CAAC,EAAE,CAAC;IAC5B,OAAO,CACN,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC;QACvC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC;QACnC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC;QACvC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CACnC,CAAC;AACH,CAAC;AAED,eAAe,eAAe,CAAC"}

View file

@ -0,0 +1,5 @@
"use strict";
const matchFormatting =
/\x02|\x1D|\x1F|\x16|\x0F|\x11|\x1E|\x03(?:[0-9]{1,2}(?:,[0-9]{1,2})?)?|\x04(?:[0-9a-f]{6}(?:,[0-9a-f]{6})?)?/gi;
module.exports = (message) => message.replace(matchFormatting, "").trim();
//# sourceMappingURL=cleanIrcMessage.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"cleanIrcMessage.js","sourceRoot":"","sources":["../../../../js/helpers/ircmessageparser/cleanIrcMessage.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,MAAM,eAAe,GACpB,gHAAgH,CAAC;AAElH,MAAM,CAAC,OAAO,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC"}

View file

@ -0,0 +1,30 @@
"use strict";
// Create plain text entries corresponding to areas of the text that match no
// existing entries. Returns an empty array if all parts of the text have been
// parsed into recognizable entries already.
function fill(existingEntries, text) {
let position = 0;
// Fill inner parts of the text. For example, if text is `foobarbaz` and both
// `foo` and `baz` have matched into an entry, this will return a dummy entry
// corresponding to `bar`.
const result = existingEntries.reduce((acc, textSegment) => {
if (textSegment.start > position) {
acc.push({
start: position,
end: textSegment.start,
});
}
position = textSegment.end;
return acc;
}, []);
// Complete the unmatched end of the text with a dummy entry
if (position < text.length) {
result.push({
start: position,
end: text.length,
});
}
return result;
}
export default fill;
//# sourceMappingURL=fill.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"fill.js","sourceRoot":"","sources":["../../../../js/helpers/ircmessageparser/fill.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,6EAA6E;AAC7E,8EAA8E;AAC9E,4CAA4C;AAC5C,SAAS,IAAI,CAAC,eAAe,EAAE,IAAI;IAClC,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,6EAA6E;IAC7E,6EAA6E;IAC7E,0BAA0B;IAC1B,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE;QAC1D,IAAI,WAAW,CAAC,KAAK,GAAG,QAAQ,EAAE;YACjC,GAAG,CAAC,IAAI,CAAC;gBACR,KAAK,EAAE,QAAQ;gBACf,GAAG,EAAE,WAAW,CAAC,KAAK;aACtB,CAAC,CAAC;SACH;QAED,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC;QAC3B,OAAO,GAAG,CAAC;IACZ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,4DAA4D;IAC5D,IAAI,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE;QAC3B,MAAM,CAAC,IAAI,CAAC;YACX,KAAK,EAAE,QAAQ;YACf,GAAG,EAAE,IAAI,CAAC,MAAM;SAChB,CAAC,CAAC;KACH;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED,eAAe,IAAI,CAAC"}

View file

@ -0,0 +1,37 @@
"use strict";
// Escapes the RegExp special characters "^", "$", "", ".", "*", "+", "?", "(",
// ")", "[", "]", "{", "}", and "|" in string.
// See https://lodash.com/docs/#escapeRegExp
import escapeRegExp from "lodash/escapeRegExp";
// Given an array of channel prefixes (such as "#" and "&") and an array of user
// modes (such as "@" and "+"), this function extracts channels and nicks from a
// text.
// It returns an array of objects for each channel found with their start index,
// end index and channel name.
function findChannels(text, channelPrefixes, userModes) {
// `userModePattern` is necessary to ignore user modes in /whois responses.
// For example, a voiced user in #thelounge will have a /whois response of:
// > foo is on the following channels: +#thelounge
// We need to explicitly ignore user modes to parse such channels correctly.
const userModePattern = userModes.map(escapeRegExp).join("");
const channelPrefixPattern = channelPrefixes.map(escapeRegExp).join("");
const channelPattern = `(?:^|\\s)[${userModePattern}]*([${channelPrefixPattern}][^ \u0007]+)`;
const channelRegExp = new RegExp(channelPattern, "g");
const result = [];
let match;
do {
// With global ("g") regexes, calling `exec` multiple times will find
// successive matches in the same string.
match = channelRegExp.exec(text);
if (match) {
result.push({
start: match.index + match[0].length - match[1].length,
end: match.index + match[0].length,
channel: match[1],
});
}
} while (match);
return result;
}
export default findChannels;
//# sourceMappingURL=findChannels.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"findChannels.js","sourceRoot":"","sources":["../../../../js/helpers/ircmessageparser/findChannels.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,+EAA+E;AAC/E,8CAA8C;AAC9C,4CAA4C;AAC5C,OAAO,YAAY,MAAM,qBAAqB,CAAC;AAE/C,gFAAgF;AAChF,gFAAgF;AAChF,QAAQ;AACR,gFAAgF;AAChF,8BAA8B;AAC9B,SAAS,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,SAAS;IACrD,2EAA2E;IAC3E,2EAA2E;IAC3E,kDAAkD;IAClD,4EAA4E;IAC5E,MAAM,eAAe,GAAG,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,oBAAoB,GAAG,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxE,MAAM,cAAc,GAAG,aAAa,eAAe,OAAO,oBAAoB,eAAe,CAAC;IAC9F,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IAEtD,MAAM,MAAM,GAAG,EAAE,CAAC;IAClB,IAAI,KAAK,CAAC;IAEV,GAAG;QACF,qEAAqE;QACrE,yCAAyC;QACzC,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEjC,IAAI,KAAK,EAAE;YACV,MAAM,CAAC,IAAI,CAAC;gBACX,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM;gBACtD,GAAG,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM;gBAClC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;aACjB,CAAC,CAAC;SACH;KACD,QAAQ,KAAK,EAAE;IAEhB,OAAO,MAAM,CAAC;AACf,CAAC;AAED,eAAe,YAAY,CAAC"}

View file

@ -0,0 +1,16 @@
"use strict";
const emojiRegExp = require("emoji-regex")();
function findEmoji(text) {
const result = [];
let match;
while ((match = emojiRegExp.exec(text))) {
result.push({
start: match.index,
end: match.index + match[0].length,
emoji: match[0],
});
}
return result;
}
export default findEmoji;
//# sourceMappingURL=findEmoji.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"findEmoji.js","sourceRoot":"","sources":["../../../../js/helpers/ircmessageparser/findEmoji.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,MAAM,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;AAE7C,SAAS,SAAS,CAAC,IAAI;IACtB,MAAM,MAAM,GAAG,EAAE,CAAC;IAClB,IAAI,KAAK,CAAC;IAEV,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE;QACxC,MAAM,CAAC,IAAI,CAAC;YACX,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM;YAClC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;SACf,CAAC,CAAC;KACH;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED,eAAe,SAAS,CAAC"}

View file

@ -1,27 +1,23 @@
"use strict";
const LinkifyIt = require("linkify-it");
import LinkifyIt from "linkify-it";
LinkifyIt.prototype.normalize = function normalize(match) {
if (!match.schema) {
match.schema = "http:";
match.url = "http://" + match.url;
//@ts-ignore
match.noschema = true;
}
if (match.schema === "//") {
match.schema = "http:";
match.url = "http:" + match.url;
//@ts-ignore
match.noschema = true;
}
if (match.schema === "mailto:" && !/^mailto:/i.test(match.url)) {
match.url = "mailto:" + match.url;
}
};
const linkify = LinkifyIt().tlds(require("tlds")).tlds("onion", true);
// Known schemes to detect in text
const commonSchemes = [
"sftp",
@ -39,31 +35,23 @@ const commonSchemes = [
"gopher",
"gemini",
];
for (const schema of commonSchemes) {
linkify.add(schema + ":", "http:");
}
function findLinks(text) {
const matches = linkify.match(text);
if (!matches) {
return [];
}
return matches.map(returnUrl);
}
function findLinksWithSchema(text) {
const matches = linkify.match(text);
if (!matches) {
return [];
}
return matches.filter((url) => !url.noschema).map(returnUrl);
}
function returnUrl(url) {
return {
start: url.index,
@ -71,8 +59,5 @@ function returnUrl(url) {
link: url.url,
};
}
module.exports = {
findLinks,
findLinksWithSchema,
};
export {findLinks, findLinksWithSchema};
//# sourceMappingURL=findLinks.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"findLinks.js","sourceRoot":"","sources":["../../../../js/helpers/ircmessageparser/findLinks.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,SAAoB,MAAM,YAAY,CAAA;AAM7C,SAAS,CAAC,SAAS,CAAC,SAAS,GAAG,SAAS,SAAS,CAAC,KAAe;IACjE,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;QAClB,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC;QACvB,KAAK,CAAC,GAAG,GAAG,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC;QAClC,YAAY;QACZ,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;KACtB;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE;QAC1B,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC;QACvB,KAAK,CAAC,GAAG,GAAG,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC;QAChC,YAAY;QACZ,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;KACtB;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;QAC/D,KAAK,CAAC,GAAG,GAAG,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC;KAClC;AACF,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAEtE,kCAAkC;AAClC,MAAM,aAAa,GAAG;IACrB,MAAM;IACN,KAAK;IACL,MAAM;IACN,KAAK;IACL,MAAM;IACN,KAAK;IACL,KAAK;IACL,OAAO;IACP,QAAQ;IACR,WAAW;IACX,SAAS;IACT,KAAK;IACL,QAAQ;IACR,QAAQ;CACR,CAAC;AAEF,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE;IACnC,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,SAAS,SAAS,CAAC,IAAY;IAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;IAElD,IAAI,CAAC,OAAO,EAAE;QACb,OAAO,EAAE,CAAC;KACV;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAY;IACxC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;IAElD,IAAI,CAAC,OAAO,EAAE;QACb,OAAO,EAAE,CAAC;KACV;IAED,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,SAAS,CAAC,GAAa;IAC/B,OAAO;QACN,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,GAAG,EAAE,GAAG,CAAC,SAAS;QAClB,IAAI,EAAE,GAAG,CAAC,GAAG;KACb,CAAC;AACH,CAAC;AAED,OAAO,EACN,SAAS,EACT,mBAAmB,GACnB,CAAC"}

View file

@ -0,0 +1,22 @@
"use strict";
const nickRegExp = /([\w[\]\\`^{|}-]+)/g;
function findNames(text, users) {
const result = [];
// Return early if we don't have any nicknames to find
if (users.length === 0) {
return result;
}
let match;
while ((match = nickRegExp.exec(text))) {
if (users.indexOf(match[1]) > -1) {
result.push({
start: match.index,
end: match.index + match[1].length,
nick: match[1],
});
}
}
return result;
}
export default findNames;
//# sourceMappingURL=findNames.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"findNames.js","sourceRoot":"","sources":["../../../../js/helpers/ircmessageparser/findNames.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,MAAM,UAAU,GAAG,qBAAqB,CAAC;AAEzC,SAAS,SAAS,CAAC,IAAI,EAAE,KAAK;IAC7B,MAAM,MAAM,GAAG,EAAE,CAAC;IAElB,sDAAsD;IACtD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QACvB,OAAO,MAAM,CAAC;KACd;IAED,IAAI,KAAK,CAAC;IAEV,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE;QACvC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE;YACjC,MAAM,CAAC,IAAI,CAAC;gBACX,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,GAAG,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM;gBAClC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;aACd,CAAC,CAAC;SACH;KACD;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED,eAAe,SAAS,CAAC"}

View file

@ -0,0 +1,44 @@
"use strict";
import anyIntersection from "./anyIntersection";
import fill from "./fill";
// Merge text part information within a styling fragment
function assign(textPart, fragment) {
const fragStart = fragment.start;
const start = Math.max(fragment.start, textPart.start);
const end = Math.min(fragment.end, textPart.end);
const text = fragment.text.slice(start - fragStart, end - fragStart);
return Object.assign({}, fragment, {start, end, text});
}
function sortParts(a, b) {
return a.start - b.start || b.end - a.end;
}
// Merge the style fragments within the text parts, taking into account
// boundaries and text sections that have not matched to links or channels.
// For example, given a string "foobar" where "foo" and "bar" have been
// identified as parts (channels, links, etc.) and "fo", "ob" and "ar" have 3
// different styles, the first resulting part will contain fragments "fo" and
// "o", and the second resulting part will contain "b" and "ar". "o" and "b"
// fragments will contain duplicate styling attributes.
function merge(textParts, styleFragments, cleanText) {
// Remove overlapping parts
textParts = textParts.sort(sortParts).reduce((prev, curr) => {
const intersection = prev.some((p) => anyIntersection(p, curr));
if (intersection) {
return prev;
}
return prev.concat([curr]);
}, []);
// Every section of the original text that has not been captured in a "part"
// is filled with "text" parts, dummy objects with start/end but no extra
// metadata.
const allParts = textParts.concat(fill(textParts, cleanText)).sort(sortParts); // Sort all parts identified based on their position in the original text
// Distribute the style fragments within the text parts
return allParts.map((textPart) => {
textPart.fragments = styleFragments
.filter((fragment) => anyIntersection(textPart, fragment))
.map((fragment) => assign(textPart, fragment));
return textPart;
});
}
export default merge;
//# sourceMappingURL=merge.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../../js/helpers/ircmessageparser/merge.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAChD,OAAO,IAAI,MAAM,QAAQ,CAAC;AAE1B,wDAAwD;AACxD,SAAS,MAAM,CAAC,QAAQ,EAAE,QAAQ;IACjC,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,SAAS,EAAE,GAAG,GAAG,SAAS,CAAC,CAAC;IAErE,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAC,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,SAAS,CAAC,CAAC,EAAE,CAAC;IACtB,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;AAC3C,CAAC;AAED,uEAAuE;AACvE,2EAA2E;AAC3E,uEAAuE;AACvE,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,uDAAuD;AACvD,SAAS,KAAK,CAAC,SAAS,EAAE,cAAc,EAAE,SAAS;IAClD,2BAA2B;IAC3B,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QAC3D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QAEhE,IAAI,YAAY,EAAE;YACjB,OAAO,IAAI,CAAC;SACZ;QAED,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,4EAA4E;IAC5E,yEAAyE;IACzE,YAAY;IACZ,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,yEAAyE;IAExJ,uDAAuD;IACvD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;QAChC,QAAQ,CAAC,SAAS,GAAG,cAAc;aACjC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;aACzD,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;QAEhD,OAAO,QAAQ,CAAC;IACjB,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,eAAe,KAAK,CAAC"}

View file

@ -0,0 +1,198 @@
"use strict";
// Styling control codes
const BOLD = "\x02";
const COLOR = "\x03";
const HEX_COLOR = "\x04";
const RESET = "\x0f";
const REVERSE = "\x16";
const ITALIC = "\x1d";
const UNDERLINE = "\x1f";
const STRIKETHROUGH = "\x1e";
const MONOSPACE = "\x11";
// Color code matcher, with format `XX,YY` where both `XX` and `YY` are
// integers, `XX` is the text color and `YY` is an optional background color.
const colorRx = /^(\d{1,2})(?:,(\d{1,2}))?/;
// 6-char Hex color code matcher
const hexColorRx = /^([0-9a-f]{6})(?:,([0-9a-f]{6}))?/i;
// Represents all other control codes that to be ignored/filtered from the text
// This regex allows line feed character
const controlCodesRx = /[\u0000-\u0009\u000B-\u001F]/g;
// Converts a given text into an array of objects, each of them representing a
// similarly styled section of the text. Each object carries the `text`, style
// information (`bold`, `textColor`, `bgcolor`, `italic`,
// `underline`, `strikethrough`, `monospace`), and `start`/`end` cursors.
function parseStyle(text) {
const result = [];
let start = 0;
let position = 0;
// At any given time, these carry style information since last time a styling
// control code was met.
let colorCodes,
bold,
textColor,
bgColor,
hexColor,
hexBgColor,
italic,
underline,
strikethrough,
monospace;
const resetStyle = () => {
bold = false;
textColor = undefined;
bgColor = undefined;
hexColor = undefined;
hexBgColor = undefined;
italic = false;
underline = false;
strikethrough = false;
monospace = false;
};
resetStyle();
// When called, this "closes" the current fragment by adding an entry to the
// `result` array using the styling information set last time a control code
// was met.
const emitFragment = () => {
// Uses the text fragment starting from the last control code position up to
// the current position
const textPart = text.slice(start, position);
// Filters out all non-style related control codes present in this text
const processedText = textPart.replace(controlCodesRx, " ");
if (processedText.length) {
// Current fragment starts where the previous one ends, or at 0 if none
const fragmentStart = result.length ? result[result.length - 1].end : 0;
result.push({
bold,
textColor,
bgColor,
hexColor,
hexBgColor,
italic,
underline,
strikethrough,
monospace,
text: processedText,
start: fragmentStart,
end: fragmentStart + processedText.length,
});
}
// Now that a fragment has been "closed", the next one will start after that
start = position + 1;
};
// This loop goes through each character of the given text one by one by
// bumping the `position` cursor. Every time a new special "styling" character
// is met, an object gets created (with `emitFragment()`)information on text
// encountered since the previous styling character.
while (position < text.length) {
switch (text[position]) {
case RESET:
emitFragment();
resetStyle();
break;
// Meeting a BOLD character means that the ongoing text is either going to
// be in bold or that the previous one was in bold and the following one
// must be reset.
// This same behavior applies to COLOR, REVERSE, ITALIC, and UNDERLINE.
case BOLD:
emitFragment();
bold = !bold;
break;
case COLOR:
emitFragment();
// Go one step further to find the corresponding color
colorCodes = text.slice(position + 1).match(colorRx);
if (colorCodes) {
textColor = Number(colorCodes[1]);
if (colorCodes[2]) {
bgColor = Number(colorCodes[2]);
}
// Color code length is > 1, so bump the current position cursor by as
// much (and reset the start cursor for the current text block as well)
position += colorCodes[0].length;
start = position + 1;
} else {
// If no color codes were found, toggles back to no colors (like BOLD).
textColor = undefined;
bgColor = undefined;
}
break;
case HEX_COLOR:
emitFragment();
colorCodes = text.slice(position + 1).match(hexColorRx);
if (colorCodes) {
hexColor = colorCodes[1].toUpperCase();
if (colorCodes[2]) {
hexBgColor = colorCodes[2].toUpperCase();
}
// Color code length is > 1, so bump the current position cursor by as
// much (and reset the start cursor for the current text block as well)
position += colorCodes[0].length;
start = position + 1;
} else {
// If no color codes were found, toggles back to no colors (like BOLD).
hexColor = undefined;
hexBgColor = undefined;
}
break;
case REVERSE: {
emitFragment();
const tmp = bgColor;
bgColor = textColor;
textColor = tmp;
break;
}
case ITALIC:
emitFragment();
italic = !italic;
break;
case UNDERLINE:
emitFragment();
underline = !underline;
break;
case STRIKETHROUGH:
emitFragment();
strikethrough = !strikethrough;
break;
case MONOSPACE:
emitFragment();
monospace = !monospace;
break;
}
// Evaluate the next character at the next iteration
position += 1;
}
// The entire text has been parsed, so we finalize the current text fragment.
emitFragment();
return result;
}
const properties = [
"bold",
"textColor",
"bgColor",
"hexColor",
"hexBgColor",
"italic",
"underline",
"strikethrough",
"monospace",
];
function prepare(text) {
return (
parseStyle(text)
// This optimizes fragments by combining them together when all their values
// for the properties defined above are equal.
.reduce((prev, curr) => {
if (prev.length) {
const lastEntry = prev[prev.length - 1];
if (properties.every((key) => curr[key] === lastEntry[key])) {
lastEntry.text += curr.text;
lastEntry.end += curr.text.length;
return prev;
}
}
return prev.concat([curr]);
}, [])
);
}
export default prepare;
//# sourceMappingURL=parseStyle.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"parseStyle.js","sourceRoot":"","sources":["../../../../js/helpers/ircmessageparser/parseStyle.js"],"names":[],"mappings":"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"}

View file

@ -0,0 +1,12 @@
"use strict";
import store from "../store";
export default (network, channel) => {
if (!network.isCollapsed || channel.highlight || channel.type === "lobby") {
return false;
}
if (store.state.activeChannel && channel === store.state.activeChannel.channel) {
return false;
}
return true;
};
//# sourceMappingURL=isChannelCollapsed.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"isChannelCollapsed.js","sourceRoot":"","sources":["../../../js/helpers/isChannelCollapsed.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,KAAK,MAAM,UAAU,CAAC;AAE7B,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;IACnC,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE;QAC1E,OAAO,KAAK,CAAC;KACb;IAED,IAAI,KAAK,CAAC,KAAK,CAAC,aAAa,IAAI,OAAO,KAAK,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE;QAC/E,OAAO,KAAK,CAAC;KACb;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC"}

View file

@ -0,0 +1,11 @@
"use strict";
export default (event) => {
if (event.target.tagName !== "TEXTAREA" && event.target.tagName !== "INPUT") {
return false;
}
// If focus is in a textarea, do not handle keybinds if user has typed anything
// This is done to prevent keyboard layout binds conflicting with ours
// For example alt+shift+left on macos selects a word
return !!event.target.value;
};
//# sourceMappingURL=isIgnoredKeybind.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"isIgnoredKeybind.js","sourceRoot":"","sources":["../../../js/helpers/isIgnoredKeybind.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,eAAe,CAAC,KAAK,EAAE,EAAE;IACxB,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,KAAK,UAAU,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,KAAK,OAAO,EAAE;QAC5E,OAAO,KAAK,CAAC;KACb;IAED,+EAA+E;IAC/E,sEAAsE;IACtE,qDAAqD;IACrD,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;AAC7B,CAAC,CAAC"}

View file

@ -0,0 +1,85 @@
"use strict";
import distance from "./distance";
// onTwoFingerSwipe will be called with a cardinal direction ("n", "e", "s" or
// "w") as its only argument.
function listenForTwoFingerSwipes(onTwoFingerSwipe) {
let history = [];
document.body.addEventListener(
"touchmove",
function (event) {
if (event.touches.length !== 2) {
return;
}
const a = event.touches.item(0);
const b = event.touches.item(1);
const timestamp = window.performance.now();
const center = [(a.screenX + b.screenX) / 2, (a.screenY + b.screenY) / 2];
if (history.length > 0) {
const last = history[history.length - 1];
const centersAreEqual =
last.center[0] === center[0] && last.center[1] === center[1];
if (last.timestamp === timestamp || centersAreEqual) {
// Touches with the same timestamps or center don't help us
// see the speed of movement. Ignore them.
return;
}
}
history.push({timestamp, center});
},
{passive: true}
);
document.body.addEventListener(
"touchend",
function (event) {
if (event.touches.length >= 2) {
return;
}
try {
const direction = getSwipe(history);
if (direction) {
onTwoFingerSwipe(direction);
}
} finally {
history = [];
}
},
{passive: true}
);
document.body.addEventListener(
"touchcancel",
function () {
history = [];
},
{passive: true}
);
}
// Returns the cardinal direction of the swipe or null if there is no swipe.
function getSwipe(hist) {
// Speed is in pixels/millisecond. Must be maintained throughout swipe.
const MIN_SWIPE_SPEED = 0.2;
if (hist.length < 2) {
return null;
}
for (let i = 1; i < hist.length; ++i) {
const previous = hist[i - 1];
const current = hist[i];
const speed =
distance(previous.center, current.center) /
Math.abs(previous.timestamp - current.timestamp);
if (speed < MIN_SWIPE_SPEED) {
return null;
}
}
return getCardinalDirection(hist[0].center, hist[hist.length - 1].center);
}
function getCardinalDirection([x1, y1], [x2, y2]) {
// If θ is the angle of the vector then this is tan(θ)
const tangent = (y2 - y1) / (x2 - x1);
// All values of |tan(-45° to 45°)| are less than 1, same for 145° to 225°
if (Math.abs(tangent) < 1) {
return x1 < x2 ? "e" : "w";
}
return y1 < y2 ? "s" : "n";
}
export default listenForTwoFingerSwipes;
//# sourceMappingURL=listenForTwoFingerSwipes.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"listenForTwoFingerSwipes.js","sourceRoot":"","sources":["../../../js/helpers/listenForTwoFingerSwipes.js"],"names":[],"mappings":"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"}

4
client/dist/js/helpers/localetime.js vendored Normal file
View file

@ -0,0 +1,4 @@
"use strict";
import dayjs from "dayjs";
export default (time) => dayjs(time).format("D MMMM YYYY, HH:mm:ss");
//# sourceMappingURL=localetime.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"localetime.js","sourceRoot":"","sources":["../../../js/helpers/localetime.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC"}

177
client/dist/js/helpers/parse.js vendored Normal file
View file

@ -0,0 +1,177 @@
"use strict";
import parseStyle from "./ircmessageparser/parseStyle";
import findChannels from "./ircmessageparser/findChannels";
import {findLinks} from "./ircmessageparser/findLinks";
import findEmoji from "./ircmessageparser/findEmoji";
import findNames from "./ircmessageparser/findNames";
import merge from "./ircmessageparser/merge";
import emojiMap from "./fullnamemap.json";
import LinkPreviewToggle from "../../components/LinkPreviewToggle.vue";
import LinkPreviewFileSize from "../../components/LinkPreviewFileSize.vue";
import InlineChannel from "../../components/InlineChannel.vue";
import Username from "../../components/Username.vue";
const emojiModifiersRegex = /[\u{1f3fb}-\u{1f3ff}]|\u{fe0f}/gu;
// Create an HTML `span` with styling information for a given fragment
function createFragment(fragment, createElement) {
const classes = [];
if (fragment.bold) {
classes.push("irc-bold");
}
if (fragment.textColor !== undefined) {
classes.push("irc-fg" + fragment.textColor);
}
if (fragment.bgColor !== undefined) {
classes.push("irc-bg" + fragment.bgColor);
}
if (fragment.italic) {
classes.push("irc-italic");
}
if (fragment.underline) {
classes.push("irc-underline");
}
if (fragment.strikethrough) {
classes.push("irc-strikethrough");
}
if (fragment.monospace) {
classes.push("irc-monospace");
}
const data = {};
let hasData = false;
if (classes.length > 0) {
hasData = true;
data.class = classes;
}
if (fragment.hexColor) {
hasData = true;
data.style = {
color: `#${fragment.hexColor}`,
};
if (fragment.hexBgColor) {
data.style["background-color"] = `#${fragment.hexBgColor}`;
}
}
return hasData ? createElement("span", data, fragment.text) : fragment.text;
}
// Transform an IRC message potentially filled with styling control codes, URLs,
// nicknames, and channels into a string of HTML elements to display on the client.
function parse(createElement, text, message = undefined, network = undefined) {
// Extract the styling information and get the plain text version from it
const styleFragments = parseStyle(text);
const cleanText = styleFragments.map((fragment) => fragment.text).join("");
// On the plain text, find channels and URLs, returned as "parts". Parts are
// arrays of objects containing start and end markers, as well as metadata
// depending on what was found (channel or link).
const channelPrefixes = network ? network.serverOptions.CHANTYPES : ["#", "&"];
const userModes = network?.serverOptions?.PREFIX.symbols || ["!", "@", "%", "+"];
const channelParts = findChannels(cleanText, channelPrefixes, userModes);
const linkParts = findLinks(cleanText);
const emojiParts = findEmoji(cleanText);
const nameParts = findNames(cleanText, message ? message.users || [] : []);
const parts = channelParts.concat(linkParts).concat(emojiParts).concat(nameParts);
// The channel the message belongs to might not exist if the user isn't joined to it.
const messageChannel = message ? message.channel : null;
// Merge the styling information with the channels / URLs / nicks / text objects and
// generate HTML strings with the resulting fragments
return merge(parts, styleFragments, cleanText).map((textPart) => {
const fragments = textPart.fragments.map((fragment) =>
createFragment(fragment, createElement)
);
// Wrap these potentially styled fragments with links and channel buttons
if (textPart.link) {
const preview =
message &&
message.previews &&
message.previews.find((p) => p.link === textPart.link);
const link = createElement(
"a",
{
attrs: {
href: textPart.link,
dir: preview ? null : "auto",
target: "_blank",
rel: "noopener",
},
},
fragments
);
if (!preview) {
return link;
}
const linkEls = [link];
if (preview.size > 0) {
linkEls.push(
createElement(LinkPreviewFileSize, {
props: {
size: preview.size,
},
})
);
}
linkEls.push(
createElement(LinkPreviewToggle, {
props: {
link: preview,
},
})
);
// We wrap the link, size, and the toggle button into <span dir="auto">
// to correctly keep the left-to-right order of these elements
return createElement(
"span",
{
attrs: {
dir: "auto",
},
},
linkEls
);
} else if (textPart.channel) {
return createElement(
InlineChannel,
{
props: {
channel: textPart.channel,
},
},
fragments
);
} else if (textPart.emoji) {
const emojiWithoutModifiers = textPart.emoji.replace(emojiModifiersRegex, "");
const title = emojiMap[emojiWithoutModifiers]
? `Emoji: ${emojiMap[emojiWithoutModifiers]}`
: null;
return createElement(
"span",
{
class: ["emoji"],
attrs: {
role: "img",
"aria-label": title,
title: title,
},
},
fragments
);
} else if (textPart.nick) {
return createElement(
Username,
{
props: {
user: {
nick: textPart.nick,
},
channel: messageChannel,
network,
},
attrs: {
dir: "auto",
},
},
fragments
);
}
return fragments;
});
}
export default parse;
//# sourceMappingURL=parse.js.map

1
client/dist/js/helpers/parse.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../js/helpers/parse.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,UAAU,MAAM,+BAA+B,CAAC;AACvD,OAAO,YAAY,MAAM,iCAAiC,CAAC;AAC3D,OAAO,EAAC,SAAS,EAAC,MAAM,8BAA8B,CAAC;AACvD,OAAO,SAAS,MAAM,8BAA8B,CAAC;AACrD,OAAO,SAAS,MAAM,8BAA8B,CAAC;AACrD,OAAO,KAAK,MAAM,0BAA0B,CAAC;AAC7C,OAAO,QAAQ,MAAM,oBAAoB,CAAC;AAC1C,OAAO,iBAAiB,MAAM,wCAAwC,CAAC;AACvE,OAAO,mBAAmB,MAAM,0CAA0C,CAAC;AAC3E,OAAO,aAAa,MAAM,oCAAoC,CAAC;AAC/D,OAAO,QAAQ,MAAM,+BAA+B,CAAC;AAErD,MAAM,mBAAmB,GAAG,kCAAkC,CAAC;AAE/D,sEAAsE;AACtE,SAAS,cAAc,CAAC,QAAQ,EAAE,aAAa;IAC9C,MAAM,OAAO,GAAG,EAAE,CAAC;IAEnB,IAAI,QAAQ,CAAC,IAAI,EAAE;QAClB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;KACzB;IAED,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,EAAE;QACrC,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;KAC5C;IAED,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS,EAAE;QACnC,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;KAC1C;IAED,IAAI,QAAQ,CAAC,MAAM,EAAE;QACpB,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;KAC3B;IAED,IAAI,QAAQ,CAAC,SAAS,EAAE;QACvB,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;KAC9B;IAED,IAAI,QAAQ,CAAC,aAAa,EAAE;QAC3B,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;KAClC;IAED,IAAI,QAAQ,CAAC,SAAS,EAAE;QACvB,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;KAC9B;IAED,MAAM,IAAI,GAAG,EAAE,CAAC;IAChB,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;QACvB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;KACrB;IAED,IAAI,QAAQ,CAAC,QAAQ,EAAE;QACtB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,CAAC,KAAK,GAAG;YACZ,KAAK,EAAE,IAAI,QAAQ,CAAC,QAAQ,EAAE;SAC9B,CAAC;QAEF,IAAI,QAAQ,CAAC,UAAU,EAAE;YACxB,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;SAC3D;KACD;IAED,OAAO,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC7E,CAAC;AAED,gFAAgF;AAChF,mFAAmF;AACnF,SAAS,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,GAAG,SAAS,EAAE,OAAO,GAAG,SAAS;IAC3E,yEAAyE;IACzE,MAAM,cAAc,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAE3E,4EAA4E;IAC5E,0EAA0E;IAC1E,iDAAiD;IACjD,MAAM,eAAe,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC/E,MAAM,SAAS,GAAG,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACjF,MAAM,YAAY,GAAG,YAAY,CAAC,SAAS,EAAE,eAAe,EAAE,SAAS,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAE3E,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAElF,qFAAqF;IACrF,MAAM,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAExD,oFAAoF;IACpF,qDAAqD;IACrD,OAAO,KAAK,CAAC,KAAK,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC/D,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CACrD,cAAc,CAAC,QAAQ,EAAE,aAAa,CAAC,CACvC,CAAC;QAEF,yEAAyE;QACzE,IAAI,QAAQ,CAAC,IAAI,EAAE;YAClB,MAAM,OAAO,GACZ,OAAO;gBACP,OAAO,CAAC,QAAQ;gBAChB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC;YACxD,MAAM,IAAI,GAAG,aAAa,CACzB,GAAG,EACH;gBACC,KAAK,EAAE;oBACN,IAAI,EAAE,QAAQ,CAAC,IAAI;oBACnB,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;oBAC5B,MAAM,EAAE,QAAQ;oBAChB,GAAG,EAAE,UAAU;iBACf;aACD,EACD,SAAS,CACT,CAAC;YAEF,IAAI,CAAC,OAAO,EAAE;gBACb,OAAO,IAAI,CAAC;aACZ;YAED,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC;YAEvB,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE;gBACrB,OAAO,CAAC,IAAI,CACX,aAAa,CAAC,mBAAmB,EAAE;oBAClC,KAAK,EAAE;wBACN,IAAI,EAAE,OAAO,CAAC,IAAI;qBAClB;iBACD,CAAC,CACF,CAAC;aACF;YAED,OAAO,CAAC,IAAI,CACX,aAAa,CAAC,iBAAiB,EAAE;gBAChC,KAAK,EAAE;oBACN,IAAI,EAAE,OAAO;iBACb;aACD,CAAC,CACF,CAAC;YAEF,uEAAuE;YACvE,8DAA8D;YAC9D,OAAO,aAAa,CACnB,MAAM,EACN;gBACC,KAAK,EAAE;oBACN,GAAG,EAAE,MAAM;iBACX;aACD,EACD,OAAO,CACP,CAAC;SACF;aAAM,IAAI,QAAQ,CAAC,OAAO,EAAE;YAC5B,OAAO,aAAa,CACnB,aAAa,EACb;gBACC,KAAK,EAAE;oBACN,OAAO,EAAE,QAAQ,CAAC,OAAO;iBACzB;aACD,EACD,SAAS,CACT,CAAC;SACF;aAAM,IAAI,QAAQ,CAAC,KAAK,EAAE;YAC1B,MAAM,qBAAqB,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;YAC9E,MAAM,KAAK,GAAG,QAAQ,CAAC,qBAAqB,CAAC;gBAC5C,CAAC,CAAC,UAAU,QAAQ,CAAC,qBAAqB,CAAC,EAAE;gBAC7C,CAAC,CAAC,IAAI,CAAC;YAER,OAAO,aAAa,CACnB,MAAM,EACN;gBACC,KAAK,EAAE,CAAC,OAAO,CAAC;gBAChB,KAAK,EAAE;oBACN,IAAI,EAAE,KAAK;oBACX,YAAY,EAAE,KAAK;oBACnB,KAAK,EAAE,KAAK;iBACZ;aACD,EACD,SAAS,CACT,CAAC;SACF;aAAM,IAAI,QAAQ,CAAC,IAAI,EAAE;YACzB,OAAO,aAAa,CACnB,QAAQ,EACR;gBACC,KAAK,EAAE;oBACN,IAAI,EAAE;wBACL,IAAI,EAAE,QAAQ,CAAC,IAAI;qBACnB;oBACD,OAAO,EAAE,cAAc;oBACvB,OAAO;iBACP;gBACD,KAAK,EAAE;oBACN,GAAG,EAAE,MAAM;iBACX;aACD,EACD,SAAS,CACT,CAAC;SACF;QAED,OAAO,SAAS,CAAC;IAClB,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,eAAe,KAAK,CAAC"}

43
client/dist/js/helpers/parseIrcUri.js vendored Normal file
View file

@ -0,0 +1,43 @@
"use strict";
export default (stringUri) => {
const data = {};
try {
// https://tools.ietf.org/html/draft-butcher-irc-url-04
const uri = new URL(stringUri);
// Replace protocol with a "special protocol" (that's what it's called in WHATWG spec)
// So that the uri can be properly parsed
if (uri.protocol === "irc:") {
uri.protocol = "http:";
if (!uri.port) {
uri.port = 6667;
}
data.tls = false;
} else if (uri.protocol === "ircs:") {
uri.protocol = "https:";
if (!uri.port) {
uri.port = 6697;
}
data.tls = true;
} else {
return;
}
if (!uri.hostname) {
return {};
}
data.host = data.name = uri.hostname;
data.port = uri.port;
let channel = "";
if (uri.pathname.length > 1) {
channel = uri.pathname.substr(1); // Remove slash
}
if (uri.hash.length > 1) {
channel += uri.hash;
}
// We don't split channels or append # here because the connect window takes care of that
data.join = channel;
} catch (e) {
// do nothing on invalid uri
}
return data;
};
//# sourceMappingURL=parseIrcUri.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"parseIrcUri.js","sourceRoot":"","sources":["../../../js/helpers/parseIrcUri.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,eAAe,CAAC,SAAS,EAAE,EAAE;IAC5B,MAAM,IAAI,GAAG,EAAE,CAAC;IAEhB,IAAI;QACH,uDAAuD;QACvD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QAE/B,sFAAsF;QACtF,yCAAyC;QACzC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE;YAC5B,GAAG,CAAC,QAAQ,GAAG,OAAO,CAAC;YAEvB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;gBACd,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;aAChB;YAED,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC;SACjB;aAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE;YACpC,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAExB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;gBACd,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;aAChB;YAED,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;SAChB;aAAM;YACN,OAAO;SACP;QAED,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE;YAClB,OAAO,EAAE,CAAC;SACV;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QAErB,IAAI,OAAO,GAAG,EAAE,CAAC;QAEjB,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;YAC5B,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe;SACjD;QAED,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;YACxB,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC;SACpB;QAED,yFAAyF;QACzF,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;KACpB;IAAC,OAAO,CAAC,EAAE;QACX,4BAA4B;KAC5B;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC"}

View file

@ -0,0 +1,8 @@
"use strict";
export default (count) => {
if (count < 1000) {
return count.toString();
}
return (count / 1000).toFixed(2).slice(0, -1) + "k";
};
//# sourceMappingURL=roundBadgeNumber.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"roundBadgeNumber.js","sourceRoot":"","sources":["../../../js/helpers/roundBadgeNumber.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,eAAe,CAAC,KAAK,EAAE,EAAE;IACxB,IAAI,KAAK,GAAG,IAAI,EAAE;QACjB,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;KACxB;IAED,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;AACrD,CAAC,CAAC"}

188
client/dist/js/keybinds.js vendored Normal file
View file

@ -0,0 +1,188 @@
"use strict";
import Mousetrap from "mousetrap";
import store from "./store";
import {switchToChannel, router, navigate} from "./router";
import isChannelCollapsed from "./helpers/isChannelCollapsed";
import isIgnoredKeybind from "./helpers/isIgnoredKeybind";
import listenForTwoFingerSwipes from "./helpers/listenForTwoFingerSwipes";
// Switch to the next/previous window in the channel list.
Mousetrap.bind(["alt+up", "alt+down"], function (e, keys) {
if (isIgnoredKeybind(e)) {
return true;
}
navigateWindow(keys.split("+").pop() === "up" ? -1 : 1);
return false;
});
listenForTwoFingerSwipes(function (cardinalDirection) {
if (cardinalDirection === "e" || cardinalDirection === "w") {
navigateWindow(cardinalDirection === "e" ? -1 : 1);
}
});
function navigateWindow(direction) {
if (store.state.networks.length === 0) {
return;
}
const flatChannels = [];
let index = -1;
for (const network of store.state.networks) {
for (const channel of network.channels) {
if (isChannelCollapsed(network, channel)) {
continue;
}
if (
index === -1 &&
store.state.activeChannel &&
store.state.activeChannel.channel === channel
) {
index = flatChannels.length;
}
flatChannels.push(channel);
}
}
// Circular array, and a modulo bug workaround because in JS it stays negative
const length = flatChannels.length;
index = (((index + direction) % length) + length) % length;
jumpToChannel(flatChannels[index]);
}
// Switch to the next/previous lobby in the channel list
Mousetrap.bind(["alt+shift+up", "alt+shift+down"], function (e, keys) {
if (isIgnoredKeybind(e)) {
return true;
}
const length = store.state.networks.length;
if (length === 0) {
return false;
}
const direction = keys.split("+").pop() === "up" ? -1 : 1;
let index = 0;
// If we're in another window, jump to first lobby
if (store.state.activeChannel) {
index = store.state.networks.findIndex((n) => n === store.state.activeChannel.network);
// If we're in a channel, and it's not the lobby, jump to lobby of this network when going up
if (direction !== -1 || store.state.activeChannel.channel.type === "lobby") {
index = (((index + direction) % length) + length) % length;
}
}
jumpToChannel(store.state.networks[index].channels[0]);
return false;
});
// Jump to the first window with a highlight in it, or the first with unread
// activity if there are none with highlights.
Mousetrap.bind(["alt+a"], function (e) {
if (isIgnoredKeybind(e)) {
return true;
}
let targetChannel;
outer_loop: for (const network of store.state.networks) {
for (const chan of network.channels) {
if (chan.highlight) {
targetChannel = chan;
break outer_loop;
}
if (chan.unread && !targetChannel) {
targetChannel = chan;
}
}
}
if (targetChannel) {
jumpToChannel(targetChannel);
}
return false;
});
// Show the help menu.
Mousetrap.bind(["alt+/"], function (e) {
if (isIgnoredKeybind(e)) {
return true;
}
navigate("Help");
return false;
});
function jumpToChannel(targetChannel) {
switchToChannel(targetChannel);
const element = document.querySelector(
`#sidebar .channel-list-item[aria-controls="#chan-${targetChannel.id}"]`
);
if (element) {
scrollIntoViewNicely(element);
}
}
// Ignored keys which should not automatically focus the input bar
const ignoredKeys = {
8: true,
9: true,
12: true,
16: true,
17: true,
18: true,
19: true,
20: true,
27: true,
35: true,
36: true,
37: true,
38: true,
39: true,
40: true,
45: true,
46: true,
112: true,
113: true,
114: true,
115: true,
116: true,
117: true,
118: true,
119: true,
120: true,
121: true,
122: true,
123: true,
144: true,
145: true,
224: true, // Meta
};
document.addEventListener("keydown", (e) => {
// Allow navigating back to the previous page when on the help screen.
if (e.key === "Escape" && router.currentRoute.name === "Help") {
router.go(-1);
return;
}
// Ignore any key that uses alt modifier
// Ignore keys defined above
if (e.altKey || ignoredKeys[e.which]) {
return;
}
// Ignore all ctrl keys except for ctrl+v to allow pasting
if ((e.ctrlKey || e.metaKey) && e.which !== 86) {
return;
}
// Redirect pagedown/pageup keys to messages container so it scrolls
if (e.which === 33 || e.which === 34) {
const chat = document.querySelector(".window .chat-content .chat");
if (chat) {
chat.focus();
}
return;
}
const tagName = e.target.tagName;
// Ignore if we're already typing into <input> or <textarea>
if (tagName === "INPUT" || tagName === "TEXTAREA") {
return;
}
const input = document.getElementById("input");
if (!input) {
return;
}
input.focus();
// On enter, focus the input but do not propagate the event
// This way, a new line is not inserted
if (e.which === 13) {
e.preventDefault();
}
});
function scrollIntoViewNicely(el) {
// Ideally this would use behavior: "smooth", but that does not consistently work in e.g. Chrome
// https://github.com/iamdustan/smoothscroll/issues/28#issuecomment-364061459
el.scrollIntoView({block: "center", inline: "nearest"});
}
//# sourceMappingURL=keybinds.js.map

1
client/dist/js/keybinds.js.map vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,85 @@
/* eslint strict: 0 */
"use strict";
/*
* This is a separate file for two reasons:
* 1. CSP policy does not allow inline javascript
* 2. It has to be a small javascript executed before all other scripts,
* so that the timeout can be triggered while slow JS is loading
*/
(function () {
const msg = document.getElementById("loading-page-message");
msg.textContent = "Loading the app…";
document
.getElementById("loading-reload")
.addEventListener("click", () => location.reload(true));
const displayReload = () => {
const loadingReload = document.getElementById("loading-reload");
if (loadingReload) {
loadingReload.style.visibility = "visible";
}
};
const loadingSlowTimeout = setTimeout(() => {
const loadingSlow = document.getElementById("loading-slow");
loadingSlow.style.visibility = "visible";
displayReload();
}, 5000);
const errorHandler = (e) => {
msg.textContent = "An error has occurred that prevented the client from loading correctly.";
const summary = document.createElement("summary");
summary.textContent = "More details";
const data = document.createElement("pre");
data.textContent = e.message; // e is an ErrorEvent
const info = document.createElement("p");
info.textContent = "Open the developer tools of your browser for more information.";
const details = document.createElement("details");
details.appendChild(summary);
details.appendChild(data);
details.appendChild(info);
msg.parentNode.insertBefore(details, msg.nextSibling);
window.clearTimeout(loadingSlowTimeout);
displayReload();
};
window.addEventListener("error", errorHandler);
window.g_TheLoungeRemoveLoading = () => {
delete window.g_TheLoungeRemoveLoading;
window.clearTimeout(loadingSlowTimeout);
window.removeEventListener("error", errorHandler);
document.getElementById("loading").remove();
};
// Apply user theme as soon as possible, before any other code loads
// This prevents flash of white while other code loads and socket connects
try {
const userSettings = JSON.parse(localStorage.getItem("settings"));
const themeEl = document.getElementById("theme");
if (
typeof userSettings.theme === "string" &&
themeEl.dataset.serverTheme !== userSettings.theme
) {
themeEl.attributes.href.value = `themes/${userSettings.theme}.css`;
}
if (
typeof userSettings.userStyles === "string" &&
!/[?&]nocss/.test(window.location.search)
) {
document.getElementById("user-specified-css").innerHTML = userSettings.userStyles;
}
} catch (e) {
//
}
// Trigger early service worker registration
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("service-worker.js");
// Handler for messages coming from the service worker
const messageHandler = (event) => {
if (event.data.type === "fetch-error") {
errorHandler({
message: `Service worker failed to fetch an url: ${event.data.message}`,
});
// Display only one fetch error
navigator.serviceWorker.removeEventListener("message", messageHandler);
}
};
navigator.serviceWorker.addEventListener("message", messageHandler);
}
})();
//# sourceMappingURL=loading-error-handlers.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"loading-error-handlers.js","sourceRoot":"","sources":["../../js/loading-error-handlers.js"],"names":[],"mappings":"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"}

42
client/dist/js/localStorage.js vendored Normal file
View file

@ -0,0 +1,42 @@
"use strict";
// This is a simple localStorage wrapper because browser can throw errors
// in different situations, including:
// - Unable to store data if storage is full
// - Local storage is blocked if "third-party cookies and site data" is disabled
//
// For more details, see:
// https://stackoverflow.com/q/14555347/1935861
// https://github.com/thelounge/thelounge/issues/2699
// https://www.chromium.org/for-testers/bug-reporting-guidelines/uncaught-securityerror-failed-to-read-the-localstorage-property-from-window-access-is-denied-for-this-document
export default {
set(key, value) {
try {
window.localStorage.setItem(key, value);
} catch (e) {
//
}
},
get(key) {
try {
return window.localStorage.getItem(key);
} catch (e) {
// Return null as if data is not set
return null;
}
},
remove(key) {
try {
window.localStorage.removeItem(key);
} catch (e) {
//
}
},
clear() {
try {
window.localStorage.clear();
} catch (e) {
//
}
},
};
//# sourceMappingURL=localStorage.js.map

1
client/dist/js/localStorage.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"localStorage.js","sourceRoot":"","sources":["../../js/localStorage.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,yEAAyE;AACzE,sCAAsC;AACtC,4CAA4C;AAC5C,gFAAgF;AAChF,EAAE;AACF,yBAAyB;AACzB,+CAA+C;AAC/C,qDAAqD;AACrD,+KAA+K;AAE/K,eAAe;IACd,GAAG,CAAC,GAAW,EAAE,KAAa;QAC7B,IAAI;YACH,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;SACxC;QAAC,OAAO,CAAC,EAAE;YACX,EAAE;SACF;IACF,CAAC;IACD,GAAG,CAAC,GAAW;QACd,IAAI;YACH,OAAO,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;SACxC;QAAC,OAAO,CAAC,EAAE;YACX,oCAAoC;YACpC,OAAO,IAAI,CAAC;SACZ;IACF,CAAC;IACD,MAAM,CAAC,GAAW;QACjB,IAAI;YACH,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SACpC;QAAC,OAAO,CAAC,EAAE;YACX,EAAE;SACF;IACF,CAAC;IACD,KAAK;QACJ,IAAI;YACH,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;SAC5B;QAAC,OAAO,CAAC,EAAE;YACX,EAAE;SACF;IACF,CAAC;CACD,CAAC"}

9
client/dist/js/location.js vendored Normal file
View file

@ -0,0 +1,9 @@
"use strict";
// This is a thin wrapper around `window.location`, in order to contain the
// side-effects. Do not add logic to it as it cannot be tested, only mocked.
export default {
reload() {
window.location.reload();
},
};
//# sourceMappingURL=location.js.map

1
client/dist/js/location.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"location.js","sourceRoot":"","sources":["../../js/location.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,2EAA2E;AAC3E,4EAA4E;AAC5E,eAAe;IACd,MAAM;QACL,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;IAC1B,CAAC;CACD,CAAC"}

180
client/dist/js/router.js vendored Normal file
View file

@ -0,0 +1,180 @@
"use strict";
const constants = require("./constants");
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
import SignIn from "../components/Windows/SignIn.vue";
import Connect from "../components/Windows/Connect.vue";
import Settings from "../components/Windows/Settings.vue";
import Help from "../components/Windows/Help.vue";
import Changelog from "../components/Windows/Changelog.vue";
import NetworkEdit from "../components/Windows/NetworkEdit.vue";
import SearchResults from "../components/Windows/SearchResults.vue";
import RoutedChat from "../components/RoutedChat.vue";
import store from "./store";
import AppearanceSettings from "../components/Settings/Appearance.vue";
import GeneralSettings from "../components/Settings/General.vue";
import AccountSettings from "../components/Settings/Account.vue";
import NotificationSettings from "../components/Settings/Notifications.vue";
const router = new VueRouter({
routes: [
{
name: "SignIn",
path: "/sign-in",
component: SignIn,
beforeEnter(to, from, next) {
// Prevent navigating to sign-in when already signed in
if (store.state.appLoaded) {
next(false);
return;
}
next();
},
},
{
name: "Connect",
path: "/connect",
component: Connect,
props: (route) => ({queryParams: route.query}),
},
{
path: "/settings",
component: Settings,
children: [
{
name: "General",
path: "",
component: GeneralSettings,
},
{
name: "Appearance",
path: "appearance",
component: AppearanceSettings,
},
{
name: "Account",
path: "account",
component: AccountSettings,
},
{
name: "Notifications",
path: "notifications",
component: NotificationSettings,
},
],
},
{
name: "Help",
path: "/help",
component: Help,
},
{
name: "Changelog",
path: "/changelog",
component: Changelog,
},
{
name: "NetworkEdit",
path: "/edit-network/:uuid",
component: NetworkEdit,
},
{
name: "RoutedChat",
path: "/chan-:id",
component: RoutedChat,
},
{
name: "SearchResults",
path: "/chan-:id/search",
component: SearchResults,
},
],
});
router.beforeEach((to, from, next) => {
// If user is not yet signed in, wait for appLoaded state to change
// unless they are trying to open SignIn (which can be triggered in auth.js)
if (!store.state.appLoaded && to.name !== "SignIn") {
store.watch(
(state) => state.appLoaded,
() => next()
);
return;
}
next();
});
router.beforeEach((to, from, next) => {
// Disallow navigating to non-existing routes
if (!to.matched.length) {
next(false);
return;
}
// Disallow navigating to invalid channels
if (to.name === "RoutedChat" && !store.getters.findChannel(Number(to.params.id))) {
next(false);
return;
}
// Disallow navigating to invalid networks
if (to.name === "NetworkEdit" && !store.getters.findNetwork(to.params.uuid)) {
next(false);
return;
}
// Handle closing image viewer with the browser back button
if (!router.app.$refs.app) {
next();
return;
}
const imageViewer = router.app.$root.$refs.app.$refs.imageViewer;
if (imageViewer && imageViewer.link) {
imageViewer.closeViewer();
next(false);
return;
}
next();
});
router.afterEach((to) => {
if (store.state.appLoaded) {
if (window.innerWidth <= constants.mobileViewportPixels) {
store.commit("sidebarOpen", false);
}
}
if (store.state.activeChannel) {
const channel = store.state.activeChannel.channel;
if (to.name !== "RoutedChat") {
store.commit("activeChannel", null);
}
// When switching out of a channel, mark everything as read
if (channel.messages.length > 0) {
channel.firstUnread = channel.messages[channel.messages.length - 1].id;
}
if (channel.messages.length > 100) {
channel.messages.splice(0, channel.messages.length - 100);
channel.moreHistoryAvailable = true;
}
}
});
function navigate(routeName, params = {}) {
if (router.currentRoute.name) {
router.push({name: routeName, params}).catch(() => {});
} else {
// If current route is null, replace the history entry
// This prevents invalid entries from lingering in history,
// and then the route guard preventing proper navigation
router.replace({name: routeName, params}).catch(() => {});
}
}
function switchToChannel(channel) {
return navigate("RoutedChat", {id: channel.id});
}
if ("serviceWorker" in navigator) {
navigator.serviceWorker.addEventListener("message", (event) => {
if (event.data && event.data.type === "open") {
const id = parseInt(event.data.channel.substr(5), 10); // remove "chan-" prefix
const channelTarget = store.getters.findChannel(id);
if (channelTarget) {
switchToChannel(channelTarget.channel);
}
}
});
}
export {router, navigate, switchToChannel};
//# sourceMappingURL=router.js.map

1
client/dist/js/router.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../js/router.js"],"names":[],"mappings":"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"}

125
client/dist/js/settings.js vendored Normal file
View file

@ -0,0 +1,125 @@
import socket from "./socket";
const defaultSettingConfig = {
apply() {},
default: null,
sync: null,
};
export const config = normalizeConfig({
syncSettings: {
default: true,
sync: "never",
apply(store, value, auto = false) {
// If applied by settings/applyAll, do not emit to server
if (value && !auto) {
socket.emit("setting:get");
}
},
},
advanced: {
default: false,
},
autocomplete: {
default: true,
},
nickPostfix: {
default: "",
},
coloredNicks: {
default: true,
},
desktopNotifications: {
default: false,
sync: "never",
apply(store, value) {
store.commit("refreshDesktopNotificationState", null, {root: true});
if ("Notification" in window && value && Notification.permission !== "granted") {
Notification.requestPermission(() =>
store.commit("refreshDesktopNotificationState", null, {root: true})
);
}
},
},
highlights: {
default: "",
sync: "always",
},
highlightExceptions: {
default: "",
sync: "always",
},
awayMessage: {
default: "",
sync: "always",
},
links: {
default: true,
},
motd: {
default: true,
},
notification: {
default: true,
sync: "never",
},
notifyAllMessages: {
default: false,
},
showSeconds: {
default: false,
},
use12hClock: {
default: false,
},
statusMessages: {
default: "condensed",
},
theme: {
default: document.getElementById("theme").dataset.serverTheme,
apply(store, value) {
const themeEl = document.getElementById("theme");
const themeUrl = `themes/${value}.css`;
if (themeEl.attributes.href.value === themeUrl) {
return;
}
themeEl.attributes.href.value = themeUrl;
const newTheme = store.state.serverConfiguration.themes.filter(
(theme) => theme.name === value
)[0];
const themeColor =
newTheme.themeColor || document.querySelector('meta[name="theme-color"]').content;
document.querySelector('meta[name="theme-color"]').content = themeColor;
},
},
media: {
default: true,
},
uploadCanvas: {
default: true,
},
userStyles: {
default: "",
apply(store, value) {
if (!/[?&]nocss/.test(window.location.search)) {
document.getElementById("user-specified-css").innerHTML = value;
}
},
},
searchEnabled: {
default: false,
},
});
export function createState() {
const state = {};
for (const settingName in config) {
state[settingName] = config[settingName].default;
}
return state;
}
function normalizeConfig(obj) {
const newConfig = {};
for (const settingName in obj) {
newConfig[settingName] = {...defaultSettingConfig, ...obj[settingName]};
}
return newConfig;
}
//# sourceMappingURL=settings.js.map

1
client/dist/js/settings.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../js/settings.js"],"names":[],"mappings":"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"}

81
client/dist/js/socket-events/auth.js vendored Normal file
View file

@ -0,0 +1,81 @@
"use strict";
import socket from "../socket";
import storage from "../localStorage";
import {router, navigate} from "../router";
import store from "../store";
import location from "../location";
let lastServerHash = null;
socket.on("auth:success", function () {
store.commit("currentUserVisibleError", "Loading messages…");
updateLoadingMessage();
});
socket.on("auth:failed", function () {
storage.remove("token");
if (store.state.appLoaded) {
return reloadPage("Authentication failed, reloading…");
}
showSignIn();
});
socket.on("auth:start", function (serverHash) {
// If we reconnected and serverHash differs, that means the server restarted
// And we will reload the page to grab the latest version
if (lastServerHash && serverHash !== lastServerHash) {
return reloadPage("Server restarted, reloading…");
}
lastServerHash = serverHash;
const user = storage.get("user");
const token = storage.get("token");
const doFastAuth = user && token;
// If we reconnect and no longer have a stored token, reload the page
if (store.state.appLoaded && !doFastAuth) {
return reloadPage("Authentication failed, reloading…");
}
// If we have user and token stored, perform auth without showing sign-in first
if (doFastAuth) {
store.commit("currentUserVisibleError", "Authorizing…");
updateLoadingMessage();
let lastMessage = -1;
for (const network of store.state.networks) {
for (const chan of network.channels) {
if (chan.messages.length > 0) {
const id = chan.messages[chan.messages.length - 1].id;
if (lastMessage < id) {
lastMessage = id;
}
}
}
}
const openChannel =
(store.state.activeChannel && store.state.activeChannel.channel.id) || null;
socket.emit("auth:perform", {
user,
token,
lastMessage,
openChannel,
hasConfig: store.state.serverConfiguration !== null,
});
} else {
showSignIn();
}
});
function showSignIn() {
// TODO: this flashes grey background because it takes a little time for vue to mount signin
if (window.g_TheLoungeRemoveLoading) {
window.g_TheLoungeRemoveLoading();
}
if (router.currentRoute.name !== "SignIn") {
navigate("SignIn");
}
}
function reloadPage(message) {
socket.disconnect();
store.commit("currentUserVisibleError", message);
location.reload(true);
}
function updateLoadingMessage() {
const loading = document.getElementById("loading-page-message");
if (loading) {
loading.textContent = store.state.currentUserVisibleError;
}
}
//# sourceMappingURL=auth.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../js/socket-events/auth.js"],"names":[],"mappings":"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"}

View file

@ -0,0 +1,32 @@
"use strict";
import socket from "../socket";
import store from "../store";
socket.on("changelog", function (data) {
store.commit("versionData", data);
store.commit("versionDataExpired", false);
let status;
if (data.latest) {
status = "new-version";
} else if (data.packages) {
status = "new-packages";
} else if (data.current.changelog) {
status = "up-to-date";
} else {
status = "error";
}
store.commit("versionStatus", status);
// When there is a button to refresh the checker available, display it when
// data is expired. Before that, server would return same information anyway.
if (data.expiresAt) {
const expires = data.expiresAt - Date.now();
if (expires > 0) {
setTimeout(() => store.commit("versionDataExpired", true), expires);
} else {
store.commit("versionDataExpired", true);
}
}
});
socket.on("changelog:newversion", () => {
store.state.serverConfiguration.isUpdateAvailable = true;
});
//# sourceMappingURL=changelog.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"changelog.js","sourceRoot":"","sources":["../../../js/socket-events/changelog.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,KAAK,MAAM,UAAU,CAAC;AAE7B,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,UAAU,IAAI;IACpC,KAAK,CAAC,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IAClC,KAAK,CAAC,MAAM,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;IAE1C,IAAI,MAAM,CAAC;IAEX,IAAI,IAAI,CAAC,MAAM,EAAE;QAChB,MAAM,GAAG,aAAa,CAAC;KACvB;SAAM,IAAI,IAAI,CAAC,QAAQ,EAAE;QACzB,MAAM,GAAG,cAAc,CAAC;KACxB;SAAM,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;QAClC,MAAM,GAAG,YAAY,CAAC;KACtB;SAAM;QACN,MAAM,GAAG,OAAO,CAAC;KACjB;IAED,KAAK,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAEtC,2EAA2E;IAC3E,6EAA6E;IAC7E,IAAI,IAAI,CAAC,SAAS,EAAE;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE5C,IAAI,OAAO,GAAG,CAAC,EAAE;YAChB,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;SACpE;aAAM;YACN,KAAK,CAAC,MAAM,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC;SACzC;KACD;AACF,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACtC,KAAK,CAAC,KAAK,CAAC,mBAAmB,CAAC,iBAAiB,GAAG,IAAI,CAAC;AAC1D,CAAC,CAAC,CAAC"}

View file

@ -0,0 +1,8 @@
const constants = require("../constants");
import socket from "../socket";
socket.on("commands", function (commands) {
if (commands) {
constants.commands = commands;
}
});
//# sourceMappingURL=commands.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../js/socket-events/commands.js"],"names":[],"mappings":"AAAA,MAAM,SAAS,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;AAC1C,OAAO,MAAM,MAAM,WAAW,CAAC;AAE/B,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,QAAQ;IACvC,IAAI,QAAQ,EAAE;QACb,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;KAC9B;AACF,CAAC,CAAC,CAAC"}

View file

@ -0,0 +1,28 @@
"use strict";
import socket from "../socket";
import upload from "../upload";
import store from "../store";
socket.once("configuration", function (data) {
store.commit("serverConfiguration", data);
// 'theme' setting depends on serverConfiguration.themes so
// settings cannot be applied before this point
store.dispatch("settings/applyAll");
if (data.fileUpload) {
upload.initialize();
}
// If localStorage contains a theme that does not exist on this server, switch
// back to its default theme.
const currentTheme = data.themes.find((t) => t.name === store.state.settings.theme);
if (currentTheme === undefined) {
store.dispatch("settings/update", {name: "theme", value: data.defaultTheme, sync: true});
} else if (currentTheme.themeColor) {
document.querySelector('meta[name="theme-color"]').content = currentTheme.themeColor;
}
if (document.body.classList.contains("public")) {
window.addEventListener("beforeunload", (e) => {
e.preventDefault();
e.returnValue = "Are you sure you want to navigate away from this page?";
});
}
});
//# sourceMappingURL=configuration.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"configuration.js","sourceRoot":"","sources":["../../../js/socket-events/configuration.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,KAAK,MAAM,UAAU,CAAC;AAE7B,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,UAAU,IAAI;IAC1C,KAAK,CAAC,MAAM,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC;IAE1C,2DAA2D;IAC3D,+CAA+C;IAC/C,KAAK,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IAEpC,IAAI,IAAI,CAAC,UAAU,EAAE;QACpB,MAAM,CAAC,UAAU,EAAE,CAAC;KACpB;IAED,8EAA8E;IAC9E,6BAA6B;IAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpF,IAAI,YAAY,KAAK,SAAS,EAAE;QAC/B,KAAK,CAAC,QAAQ,CAAC,iBAAiB,EAAE,EAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;KACzF;SAAM,IAAI,YAAY,CAAC,UAAU,EAAE;QACnC,QAAQ,CAAC,aAAa,CAAC,0BAA0B,CAAC,CAAC,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC;KACrF;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAC/C,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE;YAC7C,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,CAAC,CAAC,WAAW,GAAG,wDAAwD,CAAC;QAC1E,CAAC,CAAC,CAAC;KACH;AACF,CAAC,CAAC,CAAC"}

View file

@ -0,0 +1,57 @@
import store from "../store";
import socket from "../socket";
socket.on("disconnect", handleDisconnect);
socket.on("connect_error", handleDisconnect);
socket.on("error", handleDisconnect);
socket.io.on("reconnect_attempt", function (attempt) {
store.commit("currentUserVisibleError", `Reconnecting… (attempt ${attempt})`);
updateLoadingMessage();
});
socket.on("connecting", function () {
store.commit("currentUserVisibleError", "Connecting…");
updateLoadingMessage();
});
socket.on("connect", function () {
// Clear send buffer when reconnecting, socket.io would emit these
// immediately upon connection and it will have no effect, so we ensure
// nothing is sent to the server that might have happened.
socket.sendBuffer = [];
store.commit("currentUserVisibleError", "Finalizing connection…");
updateLoadingMessage();
});
function handleDisconnect(data) {
const message = data.message || data;
store.commit("isConnected", false);
if (!socket.io.reconnection()) {
store.commit(
"currentUserVisibleError",
`Disconnected from the server (${message}), The Lounge does not reconnect in public mode.`
);
updateLoadingMessage();
return;
}
store.commit("currentUserVisibleError", `Waiting to reconnect… (${message})`);
updateLoadingMessage();
// If the server shuts down, socket.io skips reconnection
// and we have to manually call connect to start the process
// However, do not reconnect if TL client manually closed the connection
if (socket.io.skipReconnect && message !== "io client disconnect") {
requestIdleCallback(() => socket.connect(), 2000);
}
}
function requestIdleCallback(callback, timeout) {
if (window.requestIdleCallback) {
// During an idle period the user agent will run idle callbacks in FIFO order
// until either the idle period ends or there are no more idle callbacks eligible to be run.
window.requestIdleCallback(callback, {timeout});
} else {
callback();
}
}
function updateLoadingMessage() {
const loading = document.getElementById("loading-page-message");
if (loading) {
loading.textContent = store.state.currentUserVisibleError;
}
}
//# sourceMappingURL=connection.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../../js/socket-events/connection.js"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,UAAU,CAAC;AAC7B,OAAO,MAAM,MAAM,WAAW,CAAC;AAE/B,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;AAC1C,MAAM,CAAC,EAAE,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC;AAC7C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;AAErC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,EAAE,UAAU,OAAO;IAClD,KAAK,CAAC,MAAM,CAAC,yBAAyB,EAAE,0BAA0B,OAAO,GAAG,CAAC,CAAC;IAC9E,oBAAoB,EAAE,CAAC;AACxB,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE;IACvB,KAAK,CAAC,MAAM,CAAC,yBAAyB,EAAE,aAAa,CAAC,CAAC;IACvD,oBAAoB,EAAE,CAAC;AACxB,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE;IACpB,kEAAkE;IAClE,uEAAuE;IACvE,0DAA0D;IAC1D,MAAM,CAAC,UAAU,GAAG,EAAE,CAAC;IAEvB,KAAK,CAAC,MAAM,CAAC,yBAAyB,EAAE,wBAAwB,CAAC,CAAC;IAClE,oBAAoB,EAAE,CAAC;AACxB,CAAC,CAAC,CAAC;AAEH,SAAS,gBAAgB,CAAC,IAAI;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;IAErC,KAAK,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IAEnC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE;QAC9B,KAAK,CAAC,MAAM,CACX,yBAAyB,EACzB,iCAAiC,OAAO,kDAAkD,CAC1F,CAAC;QACF,oBAAoB,EAAE,CAAC;QACvB,OAAO;KACP;IAED,KAAK,CAAC,MAAM,CAAC,yBAAyB,EAAE,0BAA0B,OAAO,GAAG,CAAC,CAAC;IAC9E,oBAAoB,EAAE,CAAC;IAEvB,yDAAyD;IACzD,4DAA4D;IAC5D,wEAAwE;IACxE,IAAI,MAAM,CAAC,EAAE,CAAC,aAAa,IAAI,OAAO,KAAK,sBAAsB,EAAE;QAClE,mBAAmB,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC;KAClD;AACF,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAQ,EAAE,OAAO;IAC7C,IAAI,MAAM,CAAC,mBAAmB,EAAE;QAC/B,6EAA6E;QAC7E,4FAA4F;QAC5F,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,EAAC,OAAO,EAAC,CAAC,CAAC;KAChD;SAAM;QACN,QAAQ,EAAE,CAAC;KACX;AACF,CAAC;AAED,SAAS,oBAAoB;IAC5B,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;IAEhE,IAAI,OAAO,EAAE;QACZ,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,uBAAuB,CAAC;KAC1D;AACF,CAAC"}

View file

@ -0,0 +1,12 @@
"use strict";
import socket from "../socket";
import store from "../store";
socket.on("history:clear", function (data) {
const {channel} = store.getters.findChannel(data.target);
channel.messages = [];
channel.unread = 0;
channel.highlight = 0;
channel.firstUnread = 0;
channel.moreHistoryAvailable = false;
});
//# sourceMappingURL=history_clear.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"history_clear.js","sourceRoot":"","sources":["../../../js/socket-events/history_clear.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,KAAK,MAAM,UAAU,CAAC;AAE7B,MAAM,CAAC,EAAE,CAAC,eAAe,EAAE,UAAU,IAAI;IACxC,MAAM,EAAC,OAAO,EAAC,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEzD,OAAO,CAAC,QAAQ,GAAG,EAAE,CAAC;IACtB,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;IACtB,OAAO,CAAC,WAAW,GAAG,CAAC,CAAC;IACxB,OAAO,CAAC,oBAAoB,GAAG,KAAK,CAAC;AACtC,CAAC,CAAC,CAAC"}

29
client/dist/js/socket-events/index.js vendored Normal file
View file

@ -0,0 +1,29 @@
"use strict";
import "./connection";
import "./auth";
import "./commands";
import "./init";
import "./join";
import "./more";
import "./msg";
import "./msg_preview";
import "./msg_special";
import "./names";
import "./network";
import "./nick";
import "./open";
import "./part";
import "./quit";
import "./sync_sort";
import "./topic";
import "./users";
import "./sign_out";
import "./sessions_list";
import "./configuration";
import "./changelog";
import "./setting";
import "./history_clear";
import "./mentions";
import "./search";
import "./mute_changed";
//# sourceMappingURL=index.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../js/socket-events/index.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,cAAc,CAAC;AACtB,OAAO,QAAQ,CAAC;AAChB,OAAO,YAAY,CAAC;AACpB,OAAO,QAAQ,CAAC;AAChB,OAAO,QAAQ,CAAC;AAChB,OAAO,QAAQ,CAAC;AAChB,OAAO,OAAO,CAAC;AACf,OAAO,eAAe,CAAC;AACvB,OAAO,eAAe,CAAC;AACvB,OAAO,SAAS,CAAC;AACjB,OAAO,WAAW,CAAC;AACnB,OAAO,QAAQ,CAAC;AAChB,OAAO,QAAQ,CAAC;AAChB,OAAO,QAAQ,CAAC;AAChB,OAAO,QAAQ,CAAC;AAChB,OAAO,aAAa,CAAC;AACrB,OAAO,SAAS,CAAC;AACjB,OAAO,SAAS,CAAC;AACjB,OAAO,YAAY,CAAC;AACpB,OAAO,iBAAiB,CAAC;AACzB,OAAO,iBAAiB,CAAC;AACzB,OAAO,aAAa,CAAC;AACrB,OAAO,WAAW,CAAC;AACnB,OAAO,iBAAiB,CAAC;AACzB,OAAO,YAAY,CAAC;AACpB,OAAO,UAAU,CAAC;AAClB,OAAO,gBAAgB,CAAC"}

154
client/dist/js/socket-events/init.js vendored Normal file
View file

@ -0,0 +1,154 @@
"use strict";
import Vue from "vue";
import socket from "../socket";
import storage from "../localStorage";
import {router, switchToChannel, navigate} from "../router";
import store from "../store";
import parseIrcUri from "../helpers/parseIrcUri";
socket.on("init", function (data) {
store.commit("networks", mergeNetworkData(data.networks));
store.commit("isConnected", true);
store.commit("currentUserVisibleError", null);
if (data.token) {
storage.set("token", data.token);
}
if (!store.state.appLoaded) {
store.commit("appLoaded");
socket.emit("setting:get");
if (window.g_TheLoungeRemoveLoading) {
window.g_TheLoungeRemoveLoading();
}
Vue.nextTick(() => {
// If we handled query parameters like irc:// links or just general
// connect parameters in public mode, then nothing to do here
if (!handleQueryParams()) {
// If we are on an unknown route or still on SignIn component
// then we can open last known channel on server, or Connect window if none
if (!router.currentRoute.name || router.currentRoute.name === "SignIn") {
const channel = store.getters.findChannel(data.active);
if (channel) {
switchToChannel(channel.channel);
} else if (store.state.networks.length > 0) {
// Server is telling us to open a channel that does not exist
// For example, it can be unset if you first open the page after server start
switchToChannel(store.state.networks[0].channels[0]);
} else {
navigate("Connect");
}
}
}
});
}
});
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 = store.getters.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(store.getters.initChannel);
continue;
}
// Merge received network object into existing network object on the client
// so the object reference stays the same (e.g. for currentChannel state)
for (const key in network) {
if (!Object.prototype.hasOwnProperty.call(network, key)) {
continue;
}
// Channels require extra care to be merged correctly
if (key === "channels") {
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) {
store.getters.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;
}
function handleQueryParams() {
if (!("URLSearchParams" in window)) {
return false;
}
const params = new URLSearchParams(document.location.search);
const cleanParams = () => {
// Remove query parameters from url without reloading the page
const cleanUri = window.location.origin + window.location.pathname + window.location.hash;
window.history.replaceState({}, document.title, cleanUri);
};
if (params.has("uri")) {
// Set default connection settings from IRC protocol links
const uri = params.get("uri");
const queryParams = parseIrcUri(uri);
cleanParams();
router.push({name: "Connect", query: queryParams});
return true;
} else if (document.body.classList.contains("public") && document.location.search) {
// Set default connection settings from url params
const queryParams = Object.fromEntries(params.entries());
cleanParams();
router.push({name: "Connect", query: queryParams});
return true;
}
return false;
}
//# sourceMappingURL=init.js.map

File diff suppressed because one or more lines are too long

18
client/dist/js/socket-events/join.js vendored Normal file
View file

@ -0,0 +1,18 @@
"use strict";
import socket from "../socket";
import store from "../store";
import {switchToChannel} from "../router";
socket.on("join", function (data) {
store.getters.initChannel(data.chan);
const network = store.getters.findNetwork(data.network);
if (!network) {
return;
}
network.channels.splice(data.index || -1, 0, data.chan);
// Queries do not automatically focus, unless the user did a whois
if (data.chan.type === "query" && !data.shouldOpen) {
return;
}
switchToChannel(store.getters.findChannel(data.chan.id).channel);
});
//# sourceMappingURL=join.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"join.js","sourceRoot":"","sources":["../../../js/socket-events/join.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,KAAK,MAAM,UAAU,CAAC;AAC7B,OAAO,EAAC,eAAe,EAAC,MAAM,WAAW,CAAC;AAE1C,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,IAAI;IAC/B,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAErC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAExD,IAAI,CAAC,OAAO,EAAE;QACb,OAAO;KACP;IAED,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAExD,kEAAkE;IAClE,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;QACnD,OAAO;KACP;IAED,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC"}

View file

@ -0,0 +1,7 @@
"use strict";
import socket from "../socket";
import store from "../store";
socket.on("mentions:list", function (data) {
store.commit("mentions", data);
});
//# sourceMappingURL=mentions.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"mentions.js","sourceRoot":"","sources":["../../../js/socket-events/mentions.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,KAAK,MAAM,UAAU,CAAC;AAE7B,MAAM,CAAC,EAAE,CAAC,eAAe,EAAE,UAAU,IAAI;IACxC,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC"}

24
client/dist/js/socket-events/more.js vendored Normal file
View file

@ -0,0 +1,24 @@
"use strict";
import Vue from "vue";
import socket from "../socket";
import store from "../store";
socket.on("more", function (data) {
const channel = store.getters.findChannel(data.chan)?.channel;
if (!channel) {
return;
}
channel.inputHistory = channel.inputHistory.concat(
data.messages
.filter((m) => m.self && m.text && m.type === "message")
.map((m) => m.text)
.reverse()
.slice(null, 100 - channel.inputHistory.length)
);
channel.moreHistoryAvailable =
data.totalMessages > channel.messages.length + data.messages.length;
channel.messages.unshift(...data.messages);
Vue.nextTick(() => {
channel.historyLoading = false;
});
});
//# sourceMappingURL=more.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"more.js","sourceRoot":"","sources":["../../../js/socket-events/more.js"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,KAAK,MAAM,UAAU,CAAC;AAE7B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,IAAI;IAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAE9D,IAAI,CAAC,OAAO,EAAE;QACb,OAAO;KACP;IAED,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CACjD,IAAI,CAAC,QAAQ;SACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;SACvD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SAClB,OAAO,EAAE;SACT,KAAK,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAChD,CAAC;IACF,OAAO,CAAC,oBAAoB;QAC3B,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;IACrE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAE3C,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE;QACjB,OAAO,CAAC,cAAc,GAAG,KAAK,CAAC;IAChC,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}

166
client/dist/js/socket-events/msg.js vendored Normal file
View file

@ -0,0 +1,166 @@
"use strict";
import socket from "../socket";
import cleanIrcMessage from "../helpers/ircmessageparser/cleanIrcMessage";
import store from "../store";
import {switchToChannel} from "../router";
let pop;
try {
pop = new Audio();
pop.src = "audio/pop.wav";
} catch (e) {
pop = {
play() {},
};
}
socket.on("msg", function (data) {
const receivingChannel = store.getters.findChannel(data.chan);
if (!receivingChannel) {
return;
}
let channel = receivingChannel.channel;
let isActiveChannel =
store.state.activeChannel && store.state.activeChannel.channel === channel;
// Display received notices and errors in currently active channel.
// Reloading the page will put them back into the lobby window.
if (data.msg.showInActive) {
// We only want to put errors/notices in active channel if they arrive on the same network
if (
store.state.activeChannel &&
store.state.activeChannel.network === receivingChannel.network
) {
channel = store.state.activeChannel.channel;
// Do not update unread/highlight counters for this channel
// as we are putting this message in the active channel
isActiveChannel = true;
if (data.chan === channel.id) {
// If active channel is the intended channel for this message,
// remove the showInActive flag
delete data.msg.showInActive;
} else {
data.chan = channel.id;
}
} else {
delete data.msg.showInActive;
}
}
// Do not set unread counter for channel if it is currently active on this client
// It may increase on the server before it processes channel open event from this client
if (!isActiveChannel) {
if (typeof data.highlight !== "undefined") {
channel.highlight = data.highlight;
}
if (typeof data.unread !== "undefined") {
channel.unread = data.unread;
}
}
channel.messages.push(data.msg);
if (data.msg.self) {
channel.firstUnread = data.msg.id;
} else {
notifyMessage(data.chan, channel, store.state.activeChannel, data.msg);
}
let messageLimit = 0;
if (!isActiveChannel) {
// If message arrives in non active channel, keep only 100 messages
messageLimit = 100;
} else if (channel.scrolledToBottom) {
// If message arrives in active channel, keep 1500 messages if scroll is currently at the bottom
// One history load may load up to 1000 messages at once if condendesed or hidden events are enabled
messageLimit = 1500;
}
if (messageLimit > 0 && channel.messages.length > messageLimit) {
channel.messages.splice(0, channel.messages.length - messageLimit);
channel.moreHistoryAvailable = true;
}
if (channel.type === "channel") {
updateUserList(channel, data.msg);
}
});
function notifyMessage(targetId, channel, activeChannel, msg) {
if (channel.muted) {
return;
}
if (msg.highlight || (store.state.settings.notifyAllMessages && msg.type === "message")) {
if (!document.hasFocus() || !activeChannel || activeChannel.channel !== channel) {
if (store.state.settings.notification) {
try {
pop.play();
} catch (exception) {
// On mobile, sounds can not be played without user interaction.
}
}
if (
store.state.settings.desktopNotifications &&
"Notification" in window &&
Notification.permission === "granted"
) {
let title;
let body;
if (msg.type === "invite") {
title = "New channel invite:";
body = msg.from.nick + " invited you to " + msg.channel;
} else {
title = msg.from.nick;
if (channel.type !== "query") {
title += ` (${channel.name})`;
}
if (msg.type === "message") {
title += " says:";
}
body = cleanIrcMessage(msg.text);
}
const timestamp = Date.parse(msg.time);
try {
if (store.state.hasServiceWorker) {
navigator.serviceWorker.ready.then((registration) => {
registration.active.postMessage({
type: "notification",
chanId: targetId,
timestamp: timestamp,
title: title,
body: body,
});
});
} else {
const notify = new Notification(title, {
tag: `chan-${targetId}`,
badge: "img/icon-alerted-black-transparent-bg-72x72px.png",
icon: "img/icon-alerted-grey-bg-192x192px.png",
body: body,
timestamp: timestamp,
});
notify.addEventListener("click", function () {
this.close();
window.focus();
const channelTarget = store.getters.findChannel(targetId);
if (channelTarget) {
switchToChannel(channelTarget);
}
});
}
} catch (exception) {
// `new Notification(...)` is not supported and should be silenced.
}
}
}
}
}
function updateUserList(channel, msg) {
if (msg.type === "message" || msg.type === "action") {
const user = channel.users.find((u) => u.nick === msg.from.nick);
if (user) {
user.lastMessage = new Date(msg.time).getTime() || Date.now();
}
} else if (msg.type === "quit" || msg.type === "part") {
const idx = channel.users.findIndex((u) => u.nick === msg.from.nick);
if (idx > -1) {
channel.users.splice(idx, 1);
}
} else if (msg.type === "kick") {
const idx = channel.users.findIndex((u) => u.nick === msg.target.nick);
if (idx > -1) {
channel.users.splice(idx, 1);
}
}
}
//# sourceMappingURL=msg.js.map

Some files were not shown because too many files have changed in this diff Show more