mobidev-thelounge
Version:
The self-hosted Web IRC client
1,521 lines (1,242 loc) • 1.35 MB
JavaScript
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./client/components/MessageTypes sync \\.vue$":
/*!******************************************************************!*\
!*** ./client/components/MessageTypes/ sync nonrecursive \.vue$ ***!
\******************************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
var map = {
"./away.vue": "./client/components/MessageTypes/away.vue",
"./back.vue": "./client/components/MessageTypes/back.vue",
"./chghost.vue": "./client/components/MessageTypes/chghost.vue",
"./ctcp.vue": "./client/components/MessageTypes/ctcp.vue",
"./ctcp_request.vue": "./client/components/MessageTypes/ctcp_request.vue",
"./error.vue": "./client/components/MessageTypes/error.vue",
"./invite.vue": "./client/components/MessageTypes/invite.vue",
"./join.vue": "./client/components/MessageTypes/join.vue",
"./kick.vue": "./client/components/MessageTypes/kick.vue",
"./mc.vue": "./client/components/MessageTypes/mc.vue",
"./mode.vue": "./client/components/MessageTypes/mode.vue",
"./mode_channel.vue": "./client/components/MessageTypes/mode_channel.vue",
"./mode_user.vue": "./client/components/MessageTypes/mode_user.vue",
"./monospace_block.vue": "./client/components/MessageTypes/monospace_block.vue",
"./nick.vue": "./client/components/MessageTypes/nick.vue",
"./part.vue": "./client/components/MessageTypes/part.vue",
"./quit.vue": "./client/components/MessageTypes/quit.vue",
"./raw.vue": "./client/components/MessageTypes/raw.vue",
"./topic.vue": "./client/components/MessageTypes/topic.vue",
"./topic_set_by.vue": "./client/components/MessageTypes/topic_set_by.vue",
"./whois.vue": "./client/components/MessageTypes/whois.vue"
};
function webpackContext(req) {
var id = webpackContextResolve(req);
return __webpack_require__(id);
}
function webpackContextResolve(req) {
if(!__webpack_require__.o(map, req)) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return map[req];
}
webpackContext.keys = function webpackContextKeys() {
return Object.keys(map);
};
webpackContext.resolve = webpackContextResolve;
module.exports = webpackContext;
webpackContext.id = "./client/components/MessageTypes sync \\.vue$";
/***/ }),
/***/ "./client/js/commands sync recursive \\.ts$":
/*!****************************************!*\
!*** ./client/js/commands/ sync \.ts$ ***!
\****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
var map = {
"./collapse.ts": "./client/js/commands/collapse.ts",
"./expand.ts": "./client/js/commands/expand.ts",
"./index.ts": "./client/js/commands/index.ts",
"./join.ts": "./client/js/commands/join.ts",
"./search.ts": "./client/js/commands/search.ts"
};
function webpackContext(req) {
var id = webpackContextResolve(req);
return __webpack_require__(id);
}
function webpackContextResolve(req) {
if(!__webpack_require__.o(map, req)) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return map[req];
}
webpackContext.keys = function webpackContextKeys() {
return Object.keys(map);
};
webpackContext.resolve = webpackContextResolve;
module.exports = webpackContext;
webpackContext.id = "./client/js/commands sync recursive \\.ts$";
/***/ }),
/***/ "./client/components/MessageTypes/index.ts":
/*!*************************************************!*\
!*** ./client/components/MessageTypes/index.ts ***!
\*************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
// 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 = __webpack_require__("./client/components/MessageTypes sync \\.vue$");
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (requireViews.keys().reduce((acc, path) => {
acc["message-" + path.substring(2, path.length - 4)] = requireViews(path).default;
return acc;
}, {}));
/***/ }),
/***/ "./client/js/auth.ts":
/*!***************************!*\
!*** ./client/js/auth.ts ***!
\***************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ Auth)
/* harmony export */ });
/* harmony import */ var _localStorage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./localStorage */ "./client/js/localStorage.ts");
/* harmony import */ var _location__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./location */ "./client/js/location.ts");
class Auth {
static signout() {
_localStorage__WEBPACK_IMPORTED_MODULE_0__["default"].clear();
_location__WEBPACK_IMPORTED_MODULE_1__["default"].reload();
}
}
/***/ }),
/***/ "./client/js/autocompletion.ts":
/*!*************************************!*\
!*** ./client/js/autocompletion.ts ***!
\*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./constants */ "./client/js/constants.ts");
/* harmony import */ var mousetrap__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! mousetrap */ "./node_modules/mousetrap/mousetrap.js");
/* harmony import */ var mousetrap__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(mousetrap__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _textcomplete_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @textcomplete/core */ "./node_modules/@textcomplete/core/dist/index.js");
/* harmony import */ var _textcomplete_core__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_textcomplete_core__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _textcomplete_textarea__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @textcomplete/textarea */ "./node_modules/@textcomplete/textarea/dist/index.js");
/* harmony import */ var fuzzy__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! fuzzy */ "./node_modules/fuzzy/lib/fuzzy.js");
/* harmony import */ var fuzzy__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(fuzzy__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _helpers_simplemap_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./helpers/simplemap.json */ "./client/js/helpers/simplemap.json");
/* harmony import */ var _store__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./store */ "./client/js/store.ts");
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (enableAutocomplete);
const emojiSearchTerms = Object.keys(_helpers_simplemap_json__WEBPACK_IMPORTED_MODULE_5__);
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">${String(_helpers_simplemap_json__WEBPACK_IMPORTED_MODULE_5__[original])}</span> ${string}`;
},
replace([, original]) {
return "$1" + String(_helpers_simplemap_json__WEBPACK_IMPORTED_MODULE_5__[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] === "@") {
// TODO: type
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
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__WEBPACK_IMPORTED_MODULE_0__["default"].colorCodeMap.filter(i => fuzzy__WEBPACK_IMPORTED_MODULE_4___default().test(term, i[0]) || fuzzy__WEBPACK_IMPORTED_MODULE_4___default().test(term, i[1])).map(i => {
if (fuzzy__WEBPACK_IMPORTED_MODULE_4___default().test(term, i[1])) {
return [i[0], fuzzy__WEBPACK_IMPORTED_MODULE_4___default().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__WEBPACK_IMPORTED_MODULE_0__["default"].colorCodeMap.filter(i => fuzzy__WEBPACK_IMPORTED_MODULE_4___default().test(term, i[0]) || fuzzy__WEBPACK_IMPORTED_MODULE_4___default().test(term, i[1])).map(pair => {
if (fuzzy__WEBPACK_IMPORTED_MODULE_4___default().test(term, pair[1])) {
return [pair[0], fuzzy__WEBPACK_IMPORTED_MODULE_4___default().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__WEBPACK_IMPORTED_MODULE_1___default()(input).bind("tab", e => {
if (_store__WEBPACK_IMPORTED_MODULE_6__.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( // TODO: type this properly
String(currentMatches[tabCount % currentMatches.length]), position);
const remainder = text.substring(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 _textcomplete_textarea__WEBPACK_IMPORTED_MODULE_3__.TextareaEditor(input);
const textcomplete = new _textcomplete_core__WEBPACK_IMPORTED_MODULE_2__.Textcomplete(editor, strategies, {
dropdown: {
className: "textcomplete-menu",
placement: "top"
}
});
textcomplete.on("show", () => {
_store__WEBPACK_IMPORTED_MODULE_6__.store.commit("isAutoCompleting", true);
});
textcomplete.on("hidden", () => {
_store__WEBPACK_IMPORTED_MODULE_6__.store.commit("isAutoCompleting", false);
});
return {
hide() {
textcomplete.hide();
},
destroy() {
textcomplete.destroy();
_store__WEBPACK_IMPORTED_MODULE_6__.store.commit("isAutoCompleting", false);
}
};
}
function replaceNick(original, position = 1) {
// If no postfix specified, return autocompleted nick as-is
if (!_store__WEBPACK_IMPORTED_MODULE_6__.store.state.settings.nickPostfix) {
return original;
} // If there is whitespace in the input already, append space to nick
if (position > 0 && /\s/.test(_store__WEBPACK_IMPORTED_MODULE_6__.store.state.activeChannel.channel.pendingMessage || "")) {
return original + " ";
} // If nick is first in the input, append specified postfix
return original + _store__WEBPACK_IMPORTED_MODULE_6__.store.state.settings.nickPostfix;
}
function fuzzyGrep(term, array) {
const results = fuzzy__WEBPACK_IMPORTED_MODULE_4___default().filter(term, array, {
pre: "<b>",
post: "</b>"
});
return results.map(el => [el.string, el.original]);
}
function rawNicks() {
if (!_store__WEBPACK_IMPORTED_MODULE_6__.store.state.activeChannel) {
return [];
}
if (_store__WEBPACK_IMPORTED_MODULE_6__.store.state.activeChannel.channel.users.length > 0) {
const users = _store__WEBPACK_IMPORTED_MODULE_6__.store.state.activeChannel.channel.users.slice();
return users.sort((a, b) => b.lastMessage - a.lastMessage).map(u => u.nick);
}
const me = _store__WEBPACK_IMPORTED_MODULE_6__.store.state.activeChannel.network.nick;
const otherUser = _store__WEBPACK_IMPORTED_MODULE_6__.store.state.activeChannel.channel.name; // If this is a query, add their name to autocomplete
if (me !== otherUser && _store__WEBPACK_IMPORTED_MODULE_6__.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__WEBPACK_IMPORTED_MODULE_0__["default"].commands.slice();
if (!_store__WEBPACK_IMPORTED_MODULE_6__.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 = [];
if (_store__WEBPACK_IMPORTED_MODULE_6__.store.state.activeChannel) {
for (const channel of _store__WEBPACK_IMPORTED_MODULE_6__.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);
}
/***/ }),
/***/ "./client/js/clipboard.ts":
/*!********************************!*\
!*** ./client/js/clipboard.ts ***!
\********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__(chat) {
// Disable in Firefox as it already copies flex text correctly
// @ts-expect-error Property 'InstallTrigger' does not exist on type 'Window & typeof globalThis'.ts(2339)
if (typeof window.InstallTrigger !== "undefined") {
return;
}
const selection = window.getSelection();
if (!selection) {
return;
} // 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);
}
/***/ }),
/***/ "./client/js/commands/collapse.ts":
/*!****************************************!*\
!*** ./client/js/commands/collapse.ts ***!
\****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var _socket__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../socket */ "./client/js/socket.ts");
/* harmony import */ var _store__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../store */ "./client/js/store.ts");
function input() {
if (!_store__WEBPACK_IMPORTED_MODULE_1__.store.state.activeChannel) {
return;
}
const messageIds = [];
for (const message of _store__WEBPACK_IMPORTED_MODULE_1__.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__WEBPACK_IMPORTED_MODULE_0__["default"].emit("msg:preview:toggle", {
target: _store__WEBPACK_IMPORTED_MODULE_1__.store.state.activeChannel.channel.id,
messageIds: messageIds,
shown: false
});
}
return true;
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
input
});
/***/ }),
/***/ "./client/js/commands/expand.ts":
/*!**************************************!*\
!*** ./client/js/commands/expand.ts ***!
\**************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var _socket__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../socket */ "./client/js/socket.ts");
/* harmony import */ var _store__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../store */ "./client/js/store.ts");
function input() {
if (!_store__WEBPACK_IMPORTED_MODULE_1__.store.state.activeChannel) {
return;
}
const messageIds = [];
for (const message of _store__WEBPACK_IMPORTED_MODULE_1__.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__WEBPACK_IMPORTED_MODULE_0__["default"].emit("msg:preview:toggle", {
target: _store__WEBPACK_IMPORTED_MODULE_1__.store.state.activeChannel.channel.id,
messageIds: messageIds,
shown: true
});
}
return true;
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
input
});
/***/ }),
/***/ "./client/js/commands/index.ts":
/*!*************************************!*\
!*** ./client/js/commands/index.ts ***!
\*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
// 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 = __webpack_require__("./client/js/commands sync recursive \\.ts$");
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (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;
}, {}));
/***/ }),
/***/ "./client/js/commands/join.ts":
/*!************************************!*\
!*** ./client/js/commands/join.ts ***!
\************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var _socket__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../socket */ "./client/js/socket.ts");
/* harmony import */ var _store__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../store */ "./client/js/store.ts");
/* harmony import */ var _router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../router */ "./client/js/router.ts");
function input(args) {
if (args.length > 0) {
let channels = args[0];
if (channels.length > 0) {
const chanTypes = _store__WEBPACK_IMPORTED_MODULE_1__.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__WEBPACK_IMPORTED_MODULE_1__.store.getters.findChannelOnCurrentNetwork(channels);
if (chan) {
(0,_router__WEBPACK_IMPORTED_MODULE_2__.switchToChannel)(chan);
} else {
if (_store__WEBPACK_IMPORTED_MODULE_1__.store.state.activeChannel) {
_socket__WEBPACK_IMPORTED_MODULE_0__["default"].emit("input", {
text: `/join ${channels} ${args.length > 1 ? args[1] : ""}`,
target: _store__WEBPACK_IMPORTED_MODULE_1__.store.state.activeChannel.channel.id
});
}
return true;
}
}
} else if (_store__WEBPACK_IMPORTED_MODULE_1__.store.state.activeChannel.channel.type === "channel") {
// If `/join` command is used without any arguments, re-join current channel
_socket__WEBPACK_IMPORTED_MODULE_0__["default"].emit("input", {
target: _store__WEBPACK_IMPORTED_MODULE_1__.store.state.activeChannel.channel.id,
text: `/join ${_store__WEBPACK_IMPORTED_MODULE_1__.store.state.activeChannel.channel.name}`
});
return true;
}
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
input
});
/***/ }),
/***/ "./client/js/commands/search.ts":
/*!**************************************!*\
!*** ./client/js/commands/search.ts ***!
\**************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var _store__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../store */ "./client/js/store.ts");
/* harmony import */ var _router__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../router */ "./client/js/router.ts");
function input(args) {
if (!_store__WEBPACK_IMPORTED_MODULE_0__.store.state.settings.searchEnabled) {
return false;
}
_router__WEBPACK_IMPORTED_MODULE_1__.router.push({
name: "SearchResults",
params: {
id: _store__WEBPACK_IMPORTED_MODULE_0__.store.state.activeChannel.channel.id
},
query: {
q: args.join(" ")
}
}).catch(e => {
// eslint-disable-next-line no-console
console.error(`Failed to push SearchResults route: ${e.message}`);
});
return true;
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
input
});
/***/ }),
/***/ "./client/js/constants.ts":
/*!********************************!*\
!*** ./client/js/constants.ts ***!
\********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
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"
};
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
colorCodeMap,
commands: [],
condensedTypes,
timeFormats,
// Same value as media query in CSS that forces sidebars to become overlays
mobileViewportPixels: 768
});
/***/ }),
/***/ "./client/js/eventbus.ts":
/*!*******************************!*\
!*** ./client/js/eventbus.ts ***!
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
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);
});
}
}
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (new EventBus());
/***/ }),
/***/ "./client/js/helpers/collapseNetwork.ts":
/*!**********************************************!*\
!*** ./client/js/helpers/collapseNetwork.ts ***!
\**********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var _localStorage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../localStorage */ "./client/js/localStorage.ts");
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((network, isCollapsed) => {
const stored = _localStorage__WEBPACK_IMPORTED_MODULE_0__["default"].get("thelounge.networks.collapsed");
const networks = stored ? new Set(JSON.parse(stored)) : new Set();
network.isCollapsed = isCollapsed;
if (isCollapsed) {
networks.add(network.uuid);
} else {
networks.delete(network.uuid);
}
_localStorage__WEBPACK_IMPORTED_MODULE_0__["default"].set("thelounge.networks.collapsed", JSON.stringify([...networks]));
});
/***/ }),
/***/ "./client/js/helpers/colorClass.ts":
/*!*****************************************!*\
!*** ./client/js/helpers/colorClass.ts ***!
\*****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
// Generates a string from "color-1" to "color-32" based on an input string
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (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).toString();
});
/***/ }),
/***/ "./client/js/helpers/contextMenu.ts":
/*!******************************************!*\
!*** ./client/js/helpers/contextMenu.ts ***!
\******************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "generateChannelContextMenu": () => (/* binding */ generateChannelContextMenu),
/* harmony export */ "generateInlineChannelContextMenu": () => (/* binding */ generateInlineChannelContextMenu),
/* harmony export */ "generateUserContextMenu": () => (/* binding */ generateUserContextMenu)
/* harmony export */ });
/* harmony import */ var _socket__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../socket */ "./client/js/socket.ts");
/* harmony import */ var _eventbus__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../eventbus */ "./client/js/eventbus.ts");
/* harmony import */ var _router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../router */ "./client/js/router.ts");
/* harmony import */ var _hooks_use_close_channel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../hooks/use-close-channel */ "./client/js/hooks/use-close-channel.ts");
function generateChannelContextMenu(channel, network) {
const closeChannel = (0,_hooks_use_close_channel__WEBPACK_IMPORTED_MODULE_3__["default"])(channel);
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__WEBPACK_IMPORTED_MODULE_0__["default"].emit("input", {
target: channel.id,
text: "/list"
})
}, {
label: "List ignored users",
type: "item",
class: "list",
action: () => _socket__WEBPACK_IMPORTED_MODULE_0__["default"].emit("input", {
target: channel.id,
text: "/ignorelist"
})
}, network.status.connected ? {
label: "Disconnect",
type: "item",
class: "disconnect",
action: () => _socket__WEBPACK_IMPORTED_MODULE_0__["default"].emit("input", {
target: channel.id,
text: "/disconnect"
})
} : {
label: "Connect",
type: "item",
class: "connect",
action: () => _socket__WEBPACK_IMPORTED_MODULE_0__["default"].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;
(0,_router__WEBPACK_IMPORTED_MODULE_2__.switchToChannel)(channel);
}
});
items.push({
label: "List banned users",
type: "item",
class: "list",
action() {
_socket__WEBPACK_IMPORTED_MODULE_0__["default"].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() {
(0,_router__WEBPACK_IMPORTED_MODULE_2__.switchToChannel)(channel);
_socket__WEBPACK_IMPORTED_MODULE_0__["default"].emit("input", {
target: channel.id,
text: "/whois " + channel.name
});
}
}, {
label: "Ignore user",
type: "item",
class: "action-ignore",
action() {
_socket__WEBPACK_IMPORTED_MODULE_0__["default"].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__WEBPACK_IMPORTED_MODULE_1__["default"].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__WEBPACK_IMPORTED_MODULE_0__["default"].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__WEBPACK_IMPORTED_MODULE_0__["default"].emit("mute:change", {
target: channel.id,
setMutedTo: !channel.muted
});
}
});
} // Add close menu item
items.push({
label: closeMap[channel.type],
type: "item",
class: "close",
action() {
closeChannel();
}
});
return items;
}
function generateInlineChannelContextMenu(store, chan, network) {
const join = () => {
const channel = network.channels.find(c => c.name === chan);
if (channel) {
(0,_router__WEBPACK_IMPORTED_MODULE_2__.switchToChannel)(channel);
}
if (store.state.activeChannel) {
_socket__WEBPACK_IMPORTED_MODULE_0__["default"].emit("input", {
target: store.state.activeChannel.channel.id,
text: "/join " + chan
});
} else {
// eslint-disable-next-line no-console
console.error("Unable to join channel: activeChannel is undefined");
}
};
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
}];
}
function generateUserContextMenu(store, 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) {
(0,_router__WEBPACK_IMPORTED_MODULE_2__.switchToChannel)(chan);
}
_socket__WEBPACK_IMPORTED_MODULE_0__["default"].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__WEBPACK_IMPORTED_MODULE_0__["default"].emit("input", {
target: channel.id,
text: "/ignore " + user.nick
});
}
}, {
label: "Direct messages",
type: "item",
class: "action-query",
action() {
const chan = store.getters.findChannelOnCurrentNetwork(user.nick);
if (chan) {
(0,_router__WEBPACK_IMPORTED_MODULE_2__.switchToChannel)(chan);
}
_socket__WEBPACK_IMPORTED_MODULE_0__["default"].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];
if (typeof name !== "string") {
return "";
}
const res = name ? `Revoke ${name} (-${m.mode})` : `Mode -${m.mode}`;
return res;
},
give(m) {
const name = modeCharToName[m.symbol];
if (typeof name !== "string") {
return "";
}
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__WEBPACK_IMPORTED_MODULE_0__["default"].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__WEBPACK_IMPORTED_MODULE_0__["default"].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__WEBPACK_IMPORTED_MODULE_0__["default"].emit("input", {
target: channel.id,
text: "/kick " + user.nick
});
}
});
}
}
return items;
}
/***/ }),
/***/ "./client/js/helpers/distance.ts":
/*!***************************************!*\
!*** ./client/js/helpers/distance.ts ***!
\***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
function distance([x1, y1], [x2, y2]) {
return Math.hypot(x1 - x2, y1 - y2);
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (distance);
/***/ }),
/***/ "./client/js/helpers/friendlysize.ts":
/*!*******************************************!*\
!*** ./client/js/helpers/friendlysize.ts ***!
\*******************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
const sizes = ["Bytes", "KiB", "MiB", "GiB", "TiB", "PiB"];
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (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]}`;
});
/***/ }),
/***/ "./client/js/helpers/ircmessageparser/anyIntersection.ts":
/*!***************************************************************!*\
!*** ./client/js/helpers/ircmessageparser/anyIntersection.ts ***!
\***************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
// 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;
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (anyIntersection);
/***/ }),
/***/ "./client/js/helpers/ircmessageparser/cleanIrcMessage.ts":
/*!***************************************************************!*\
!*** ./client/js/helpers/ircmessageparser/cleanIrcMessage.ts ***!
\***************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
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;
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (message => message.replace(matchFormatting, "").trim());
/***/ }),
/***/ "./client/js/helpers/ircmessageparser/fill.ts":
/*!****************************************************!*\
!*** ./client/js/helpers/ircmessageparser/fill.ts ***!
\****************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
// 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;
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (fill);
/***/ }),
/***/ "./client/js/helpers/ircmessageparser/findChannels.ts":
/*!************************************************************!*\
!*** ./client/js/helpers/ircmessageparser/findChannels.ts ***!
\************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var lodash_escapeRegExp__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lodash/escapeRegExp */ "./node_modules/lodash/escapeRegExp.js");
/* harmony import */ var lodash_escapeRegExp__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(lodash_escapeRegExp__WEBPACK_IMPORTED_MODULE_0__);
// Escapes the RegExp special characters "^", "$", "", ".", "*", "+", "?", "(",
// ")", "[", "]", "{", "}", and "|" in string.
// See https://lodash.com/docs/#escapeRegExp
// escapes a regex in a way that's compatible to shove it in
// a regex char set (meaning it also escapes -)
function escapeRegExpCharSet(raw) {
const escaped = lodash_escapeRegExp__WEBPACK_IMPORTED_MODULE_0___default()(raw);
return escaped.replace("-", "\\-");
} // 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(escapeRegExpCharSet).join("");
const channelPrefixPattern = channelPrefixes.map(escapeRegExpCharSet).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({