mirror of
https://codeberg.org/emersion/gamja
synced 2025-03-12 23:43:42 +01:00
s/var/let/
This commit is contained in:
parent
4db845a4b1
commit
8972130252
80
commands.js
80
commands.js
@ -2,7 +2,7 @@ import * as irc from "./lib/irc.js";
|
|||||||
import { SERVER_BUFFER, BufferType } from "./state.js";
|
import { SERVER_BUFFER, BufferType } from "./state.js";
|
||||||
|
|
||||||
function getActiveClient(app) {
|
function getActiveClient(app) {
|
||||||
var buf = app.state.buffers.get(app.state.activeBuffer);
|
let buf = app.state.buffers.get(app.state.activeBuffer);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
throw new Error("Not connected to server");
|
throw new Error("Not connected to server");
|
||||||
}
|
}
|
||||||
@ -10,7 +10,7 @@ function getActiveClient(app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getActiveTarget(app) {
|
function getActiveTarget(app) {
|
||||||
var activeBuffer = app.state.buffers.get(app.state.activeBuffer);
|
let activeBuffer = app.state.buffers.get(app.state.activeBuffer);
|
||||||
if (!activeBuffer) {
|
if (!activeBuffer) {
|
||||||
throw new Error("Not in a buffer");
|
throw new Error("Not in a buffer");
|
||||||
}
|
}
|
||||||
@ -18,7 +18,7 @@ function getActiveTarget(app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getActiveChannel(app) {
|
function getActiveChannel(app) {
|
||||||
var activeBuffer = app.state.buffers.get(app.state.activeBuffer);
|
let activeBuffer = app.state.buffers.get(app.state.activeBuffer);
|
||||||
if (!activeBuffer || activeBuffer.type !== BufferType.CHANNEL) {
|
if (!activeBuffer || activeBuffer.type !== BufferType.CHANNEL) {
|
||||||
throw new Error("Not in a channel");
|
throw new Error("Not in a channel");
|
||||||
}
|
}
|
||||||
@ -26,12 +26,12 @@ function getActiveChannel(app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setUserHostMode(app, args, mode) {
|
function setUserHostMode(app, args, mode) {
|
||||||
var nick = args[0];
|
let nick = args[0];
|
||||||
if (!nick) {
|
if (!nick) {
|
||||||
throw new Error("Missing nick");
|
throw new Error("Missing nick");
|
||||||
}
|
}
|
||||||
var activeChannel = getActiveChannel(app);
|
let activeChannel = getActiveChannel(app);
|
||||||
var client = getActiveClient(app);
|
let client = getActiveClient(app);
|
||||||
client.whois(nick).then((whois) => {
|
client.whois(nick).then((whois) => {
|
||||||
const info = whois[irc.RPL_WHOISUSER].params;
|
const info = whois[irc.RPL_WHOISUSER].params;
|
||||||
const user = info[2];
|
const user = info[2];
|
||||||
@ -47,7 +47,7 @@ const join = {
|
|||||||
usage: "<name>",
|
usage: "<name>",
|
||||||
description: "Join a channel",
|
description: "Join a channel",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var channel = args[0];
|
let channel = args[0];
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
throw new Error("Missing channel name");
|
throw new Error("Missing channel name");
|
||||||
}
|
}
|
||||||
@ -59,9 +59,9 @@ const kick = {
|
|||||||
usage: "<nick>",
|
usage: "<nick>",
|
||||||
description: "Remove a user from the channel",
|
description: "Remove a user from the channel",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var nick = args[0];
|
let nick = args[0];
|
||||||
var activeChannel = getActiveChannel(app);
|
let activeChannel = getActiveChannel(app);
|
||||||
var params = [activeChannel, nick];
|
let params = [activeChannel, nick];
|
||||||
if (args.length > 1) {
|
if (args.length > 1) {
|
||||||
params.push(args.slice(1).join(" "));
|
params.push(args.slice(1).join(" "));
|
||||||
}
|
}
|
||||||
@ -71,11 +71,11 @@ const kick = {
|
|||||||
|
|
||||||
function givemode(app, args, mode) {
|
function givemode(app, args, mode) {
|
||||||
// TODO: Handle several users at once
|
// TODO: Handle several users at once
|
||||||
var nick = args[0];
|
let nick = args[0];
|
||||||
if (!nick) {
|
if (!nick) {
|
||||||
throw new Error("Missing nick");
|
throw new Error("Missing nick");
|
||||||
}
|
}
|
||||||
var activeChannel = getActiveChannel(app);
|
let activeChannel = getActiveChannel(app);
|
||||||
getActiveClient(app).send({
|
getActiveClient(app).send({
|
||||||
command: "MODE",
|
command: "MODE",
|
||||||
params: [activeChannel, mode, nick],
|
params: [activeChannel, mode, nick],
|
||||||
@ -88,7 +88,7 @@ export default {
|
|||||||
description: "Ban a user from the channel, or display the current ban list",
|
description: "Ban a user from the channel, or display the current ban list",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
var activeChannel = getActiveChannel(app);
|
let activeChannel = getActiveChannel(app);
|
||||||
getActiveClient(app).send({
|
getActiveClient(app).send({
|
||||||
command: "MODE",
|
command: "MODE",
|
||||||
params: [activeChannel, "+b"],
|
params: [activeChannel, "+b"],
|
||||||
@ -102,8 +102,8 @@ export default {
|
|||||||
usage: "<name>",
|
usage: "<name>",
|
||||||
description: "Switch to a buffer",
|
description: "Switch to a buffer",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var name = args[0];
|
let name = args[0];
|
||||||
for (var buf of app.state.buffers.values()) {
|
for (let buf of app.state.buffers.values()) {
|
||||||
if (buf.name === name) {
|
if (buf.name === name) {
|
||||||
app.switchBuffer(buf);
|
app.switchBuffer(buf);
|
||||||
return;
|
return;
|
||||||
@ -115,7 +115,7 @@ export default {
|
|||||||
"close": {
|
"close": {
|
||||||
description: "Close the current buffer",
|
description: "Close the current buffer",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var activeBuffer = app.state.buffers.get(app.state.activeBuffer);
|
let activeBuffer = app.state.buffers.get(app.state.activeBuffer);
|
||||||
if (!activeBuffer || activeBuffer.type == BufferType.SERVER) {
|
if (!activeBuffer || activeBuffer.type == BufferType.SERVER) {
|
||||||
throw new Error("Not in a user or channel buffer");
|
throw new Error("Not in a user or channel buffer");
|
||||||
}
|
}
|
||||||
@ -148,11 +148,11 @@ export default {
|
|||||||
usage: "<nick>",
|
usage: "<nick>",
|
||||||
description: "Invite a user to the channel",
|
description: "Invite a user to the channel",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var nick = args[0];
|
let nick = args[0];
|
||||||
if (!nick) {
|
if (!nick) {
|
||||||
throw new Error("Missing nick");
|
throw new Error("Missing nick");
|
||||||
}
|
}
|
||||||
var activeChannel = getActiveChannel(app);
|
let activeChannel = getActiveChannel(app);
|
||||||
getActiveClient(app).send({ command: "INVITE", params: [
|
getActiveClient(app).send({ command: "INVITE", params: [
|
||||||
nick, activeChannel,
|
nick, activeChannel,
|
||||||
]});
|
]});
|
||||||
@ -180,9 +180,9 @@ export default {
|
|||||||
usage: "<action>",
|
usage: "<action>",
|
||||||
description: "Send an action message to the current buffer",
|
description: "Send an action message to the current buffer",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var action = args.join(" ");
|
let action = args.join(" ");
|
||||||
var target = getActiveTarget(app);
|
let target = getActiveTarget(app);
|
||||||
var text = `\x01ACTION ${action}\x01`;
|
let text = `\x01ACTION ${action}\x01`;
|
||||||
app.privmsg(target, text);
|
app.privmsg(target, text);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -190,9 +190,9 @@ export default {
|
|||||||
usage: "[target] [modes] [mode args...]",
|
usage: "[target] [modes] [mode args...]",
|
||||||
description: "Query or change a channel or user mode",
|
description: "Query or change a channel or user mode",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var target = args[0];
|
let target = args[0];
|
||||||
if (!target || target.startsWith("+") || target.startsWith("-")) {
|
if (!target || target.startsWith("+") || target.startsWith("-")) {
|
||||||
var activeChannel = getActiveChannel(app);
|
let activeChannel = getActiveChannel(app);
|
||||||
args = [activeChannel, ...args];
|
args = [activeChannel, ...args];
|
||||||
}
|
}
|
||||||
getActiveClient(app).send({ command: "MODE", params: args });
|
getActiveClient(app).send({ command: "MODE", params: args });
|
||||||
@ -209,8 +209,8 @@ export default {
|
|||||||
usage: "<target> <message>",
|
usage: "<target> <message>",
|
||||||
description: "Send a message to a nickname or a channel",
|
description: "Send a message to a nickname or a channel",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var target = args[0];
|
let target = args[0];
|
||||||
var text = args.slice(1).join(" ");
|
let text = args.slice(1).join(" ");
|
||||||
getActiveClient(app).send({ command: "PRIVMSG", params: [target, text] });
|
getActiveClient(app).send({ command: "PRIVMSG", params: [target, text] });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -218,7 +218,7 @@ export default {
|
|||||||
usage: "<nick>",
|
usage: "<nick>",
|
||||||
description: "Change current nickname",
|
description: "Change current nickname",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var newNick = args[0];
|
let newNick = args[0];
|
||||||
getActiveClient(app).send({ command: "NICK", params: [newNick] });
|
getActiveClient(app).send({ command: "NICK", params: [newNick] });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -226,8 +226,8 @@ export default {
|
|||||||
usage: "<target> <message>",
|
usage: "<target> <message>",
|
||||||
description: "Send a notice to a nickname or a channel",
|
description: "Send a notice to a nickname or a channel",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var target = args[0];
|
let target = args[0];
|
||||||
var text = args.slice(1).join(" ");
|
let text = args.slice(1).join(" ");
|
||||||
getActiveClient(app).send({ command: "NOTICE", params: [target, text] });
|
getActiveClient(app).send({ command: "NOTICE", params: [target, text] });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -240,9 +240,9 @@ export default {
|
|||||||
usage: "[reason]",
|
usage: "[reason]",
|
||||||
description: "Leave a channel",
|
description: "Leave a channel",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var reason = args.join(" ");
|
let reason = args.join(" ");
|
||||||
var activeChannel = getActiveChannel(app);
|
let activeChannel = getActiveChannel(app);
|
||||||
var params = [activeChannel];
|
let params = [activeChannel];
|
||||||
if (reason) {
|
if (reason) {
|
||||||
params.push(reason);
|
params.push(reason);
|
||||||
}
|
}
|
||||||
@ -253,7 +253,7 @@ export default {
|
|||||||
usage: "<nick>",
|
usage: "<nick>",
|
||||||
description: "Open a buffer to send messages to a nickname",
|
description: "Open a buffer to send messages to a nickname",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var nick = args[0];
|
let nick = args[0];
|
||||||
if (!nick) {
|
if (!nick) {
|
||||||
throw new Error("Missing nickname");
|
throw new Error("Missing nickname");
|
||||||
}
|
}
|
||||||
@ -270,7 +270,7 @@ export default {
|
|||||||
usage: "<command>",
|
usage: "<command>",
|
||||||
description: "Send a raw IRC command to the server",
|
description: "Send a raw IRC command to the server",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var msg;
|
let msg;
|
||||||
try {
|
try {
|
||||||
msg = irc.parseMessage(args.join(" "));
|
msg = irc.parseMessage(args.join(" "));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -289,8 +289,8 @@ export default {
|
|||||||
usage: "<realname>",
|
usage: "<realname>",
|
||||||
description: "Change current realname",
|
description: "Change current realname",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var newRealname = args.join(" ");
|
let newRealname = args.join(" ");
|
||||||
var client = getActiveClient(app);
|
let client = getActiveClient(app);
|
||||||
if (!client.enabledCaps["setname"]) {
|
if (!client.enabledCaps["setname"]) {
|
||||||
throw new Error("Server doesn't support changing the realname");
|
throw new Error("Server doesn't support changing the realname");
|
||||||
}
|
}
|
||||||
@ -301,11 +301,11 @@ export default {
|
|||||||
usage: "<query> [server]",
|
usage: "<query> [server]",
|
||||||
description: "Request server statistics",
|
description: "Request server statistics",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var query = args[0];
|
let query = args[0];
|
||||||
if (!query) {
|
if (!query) {
|
||||||
throw new Error("Missing query");
|
throw new Error("Missing query");
|
||||||
}
|
}
|
||||||
var params = [query];
|
let params = [query];
|
||||||
if (args.length > 1) {
|
if (args.length > 1) {
|
||||||
params.push(args.slice(1).join(" "));
|
params.push(args.slice(1).join(" "));
|
||||||
}
|
}
|
||||||
@ -316,8 +316,8 @@ export default {
|
|||||||
usage: "<topic>",
|
usage: "<topic>",
|
||||||
description: "Change the topic of the current channel",
|
description: "Change the topic of the current channel",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var activeChannel = getActiveChannel(app);
|
let activeChannel = getActiveChannel(app);
|
||||||
var params = [activeChannel];
|
let params = [activeChannel];
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
params.push(args.join(" "));
|
params.push(args.join(" "));
|
||||||
}
|
}
|
||||||
@ -347,7 +347,7 @@ export default {
|
|||||||
usage: "<nick>",
|
usage: "<nick>",
|
||||||
description: "Retrieve information about a user",
|
description: "Retrieve information about a user",
|
||||||
execute: (app, args) => {
|
execute: (app, args) => {
|
||||||
var nick = args[0];
|
let nick = args[0];
|
||||||
if (!nick) {
|
if (!nick) {
|
||||||
throw new Error("Missing nick");
|
throw new Error("Missing nick");
|
||||||
}
|
}
|
||||||
|
@ -35,28 +35,28 @@ const configPromise = fetch("./config.json")
|
|||||||
|
|
||||||
const CHATHISTORY_MAX_SIZE = 4000;
|
const CHATHISTORY_MAX_SIZE = 4000;
|
||||||
|
|
||||||
var messagesCount = 0;
|
let messagesCount = 0;
|
||||||
|
|
||||||
function parseQueryString() {
|
function parseQueryString() {
|
||||||
var query = window.location.search.substring(1);
|
let query = window.location.search.substring(1);
|
||||||
var params = {};
|
let params = {};
|
||||||
query.split('&').forEach((s) => {
|
query.split('&').forEach((s) => {
|
||||||
if (!s) {
|
if (!s) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var pair = s.split('=');
|
let pair = s.split('=');
|
||||||
params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || "");
|
params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || "");
|
||||||
});
|
});
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillConnectParams(params) {
|
function fillConnectParams(params) {
|
||||||
var host = window.location.host || "localhost:8080";
|
let host = window.location.host || "localhost:8080";
|
||||||
var proto = "wss:";
|
let proto = "wss:";
|
||||||
if (window.location.protocol != "https:") {
|
if (window.location.protocol != "https:") {
|
||||||
proto = "ws:";
|
proto = "ws:";
|
||||||
}
|
}
|
||||||
var path = window.location.pathname || "/";
|
let path = window.location.pathname || "/";
|
||||||
if (!window.location.host) {
|
if (!window.location.host) {
|
||||||
path = "/";
|
path = "/";
|
||||||
}
|
}
|
||||||
@ -78,7 +78,7 @@ function fillConnectParams(params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function debounce(f, delay) {
|
function debounce(f, delay) {
|
||||||
var timeout = null;
|
let timeout = null;
|
||||||
return (...args) => {
|
return (...args) => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
timeout = setTimeout(() => {
|
timeout = setTimeout(() => {
|
||||||
@ -177,7 +177,7 @@ export default class App extends Component {
|
|||||||
handleConfig(config) {
|
handleConfig(config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
|
||||||
var connectParams = {};
|
let connectParams = {};
|
||||||
|
|
||||||
if (config.server) {
|
if (config.server) {
|
||||||
connectParams.url = config.server.url;
|
connectParams.url = config.server.url;
|
||||||
@ -188,7 +188,7 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var autoconnect = store.autoconnect.load();
|
let autoconnect = store.autoconnect.load();
|
||||||
if (autoconnect) {
|
if (autoconnect) {
|
||||||
connectParams = {
|
connectParams = {
|
||||||
...connectParams,
|
...connectParams,
|
||||||
@ -197,7 +197,7 @@ export default class App extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryParams = parseQueryString();
|
let queryParams = parseQueryString();
|
||||||
if (queryParams.server) {
|
if (queryParams.server) {
|
||||||
connectParams.url = queryParams.server;
|
connectParams.url = queryParams.server;
|
||||||
}
|
}
|
||||||
@ -245,10 +245,10 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createBuffer(serverID, name) {
|
createBuffer(serverID, name) {
|
||||||
var id = null;
|
let id = null;
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var client = this.clients.get(serverID);
|
let client = this.clients.get(serverID);
|
||||||
var updated;
|
let updated;
|
||||||
[id, updated] = State.createBuffer(state, name, serverID, client);
|
[id, updated] = State.createBuffer(state, name, serverID, client);
|
||||||
return updated;
|
return updated;
|
||||||
});
|
});
|
||||||
@ -256,7 +256,7 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switchBuffer(id) {
|
switchBuffer(id) {
|
||||||
var buf;
|
let buf;
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
buf = State.getBuffer(state, id);
|
buf = State.getBuffer(state, id);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
@ -268,7 +268,7 @@ export default class App extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastReadReceipt = this.getReceipt(buf.name, ReceiptType.READ);
|
let lastReadReceipt = this.getReceipt(buf.name, ReceiptType.READ);
|
||||||
// TODO: only mark as read if user scrolled at the bottom
|
// TODO: only mark as read if user scrolled at the bottom
|
||||||
this.setBufferState(buf.id, {
|
this.setBufferState(buf.id, {
|
||||||
unread: Unread.NONE,
|
unread: Unread.NONE,
|
||||||
@ -282,7 +282,7 @@ export default class App extends Component {
|
|||||||
if (buf.messages.length == 0) {
|
if (buf.messages.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var lastMsg = buf.messages[buf.messages.length - 1];
|
let lastMsg = buf.messages[buf.messages.length - 1];
|
||||||
this.setReceipt(buf.name, ReceiptType.READ, lastMsg);
|
this.setReceipt(buf.name, ReceiptType.READ, lastMsg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -292,7 +292,7 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getReceipt(target, type) {
|
getReceipt(target, type) {
|
||||||
var receipts = this.receipts.get(target);
|
let receipts = this.receipts.get(target);
|
||||||
if (!receipts) {
|
if (!receipts) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -300,12 +300,12 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasReceipt(target, type, msg) {
|
hasReceipt(target, type, msg) {
|
||||||
var receipt = this.getReceipt(target, type);
|
let receipt = this.getReceipt(target, type);
|
||||||
return receipt && msg.tags.time <= receipt.time;
|
return receipt && msg.tags.time <= receipt.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
setReceipt(target, type, msg) {
|
setReceipt(target, type, msg) {
|
||||||
var receipt = this.getReceipt(target, type);
|
let receipt = this.getReceipt(target, type);
|
||||||
if (this.hasReceipt(target, type, msg)) {
|
if (this.hasReceipt(target, type, msg)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -318,9 +318,9 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
latestReceipt(type) {
|
latestReceipt(type) {
|
||||||
var last = null;
|
let last = null;
|
||||||
this.receipts.forEach((receipts, target) => {
|
this.receipts.forEach((receipts, target) => {
|
||||||
var delivery = receipts[type];
|
let delivery = receipts[type];
|
||||||
if (target == "*" || !delivery || !delivery.time) {
|
if (target == "*" || !delivery || !delivery.time) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -332,7 +332,7 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addMessage(serverID, bufName, msg) {
|
addMessage(serverID, bufName, msg) {
|
||||||
var client = this.clients.get(serverID);
|
let client = this.clients.get(serverID);
|
||||||
|
|
||||||
msg.key = messagesCount;
|
msg.key = messagesCount;
|
||||||
messagesCount++;
|
messagesCount++;
|
||||||
@ -346,15 +346,15 @@ export default class App extends Component {
|
|||||||
msg.tags.time = irc.formatDate(new Date());
|
msg.tags.time = irc.formatDate(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
var isDelivered = this.hasReceipt(bufName, ReceiptType.DELIVERED, msg);
|
let isDelivered = this.hasReceipt(bufName, ReceiptType.DELIVERED, msg);
|
||||||
var isRead = this.hasReceipt(bufName, ReceiptType.READ, msg);
|
let isRead = this.hasReceipt(bufName, ReceiptType.READ, msg);
|
||||||
// TODO: messages coming from infinite scroll shouldn't trigger notifications
|
// TODO: messages coming from infinite scroll shouldn't trigger notifications
|
||||||
|
|
||||||
var msgUnread = Unread.NONE;
|
let msgUnread = Unread.NONE;
|
||||||
if ((msg.command == "PRIVMSG" || msg.command == "NOTICE") && !isRead) {
|
if ((msg.command == "PRIVMSG" || msg.command == "NOTICE") && !isRead) {
|
||||||
var text = msg.params[1];
|
let text = msg.params[1];
|
||||||
|
|
||||||
var kind;
|
let kind;
|
||||||
if (msg.isHighlight) {
|
if (msg.isHighlight) {
|
||||||
msgUnread = Unread.HIGHLIGHT;
|
msgUnread = Unread.HIGHLIGHT;
|
||||||
kind = "highlight";
|
kind = "highlight";
|
||||||
@ -366,11 +366,11 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (msgUnread == Unread.HIGHLIGHT && !isDelivered && !irc.parseCTCP(msg)) {
|
if (msgUnread == Unread.HIGHLIGHT && !isDelivered && !irc.parseCTCP(msg)) {
|
||||||
var title = "New " + kind + " from " + msg.prefix.name;
|
let title = "New " + kind + " from " + msg.prefix.name;
|
||||||
if (client.isChannel(bufName)) {
|
if (client.isChannel(bufName)) {
|
||||||
title += " in " + bufName;
|
title += " in " + bufName;
|
||||||
}
|
}
|
||||||
var notif = showNotification(title, {
|
let notif = showNotification(title, {
|
||||||
body: stripANSI(text),
|
body: stripANSI(text),
|
||||||
requireInteraction: true,
|
requireInteraction: true,
|
||||||
tag: "msg," + msg.prefix.name + "," + bufName,
|
tag: "msg," + msg.prefix.name + "," + bufName,
|
||||||
@ -384,8 +384,8 @@ export default class App extends Component {
|
|||||||
if (msg.command === "INVITE" && client.isMyNick(msg.params[0])) {
|
if (msg.command === "INVITE" && client.isMyNick(msg.params[0])) {
|
||||||
msgUnread = Unread.HIGHLIGHT;
|
msgUnread = Unread.HIGHLIGHT;
|
||||||
|
|
||||||
var channel = msg.params[1];
|
let channel = msg.params[1];
|
||||||
var notif = new Notification("Invitation to " + channel, {
|
let notif = new Notification("Invitation to " + channel, {
|
||||||
body: msg.prefix.name + " has invited you to " + channel,
|
body: msg.prefix.name + " has invited you to " + channel,
|
||||||
requireInteraction: true,
|
requireInteraction: true,
|
||||||
tag: "invite," + msg.prefix.name + "," + channel,
|
tag: "invite," + msg.prefix.name + "," + channel,
|
||||||
@ -411,12 +411,12 @@ export default class App extends Component {
|
|||||||
|
|
||||||
this.setReceipt(bufName, ReceiptType.DELIVERED, msg);
|
this.setReceipt(bufName, ReceiptType.DELIVERED, msg);
|
||||||
|
|
||||||
var bufID = { server: serverID, name: bufName };
|
let bufID = { server: serverID, name: bufName };
|
||||||
this.setState((state) => State.addMessage(state, msg, bufID));
|
this.setState((state) => State.addMessage(state, msg, bufID));
|
||||||
this.setBufferState(bufID, (buf) => {
|
this.setBufferState(bufID, (buf) => {
|
||||||
// TODO: set unread if scrolled up
|
// TODO: set unread if scrolled up
|
||||||
var unread = buf.unread;
|
let unread = buf.unread;
|
||||||
var lastReadReceipt = buf.lastReadReceipt;
|
let lastReadReceipt = buf.lastReadReceipt;
|
||||||
if (this.state.activeBuffer != buf.id) {
|
if (this.state.activeBuffer != buf.id) {
|
||||||
unread = Unread.union(unread, msgUnread);
|
unread = Unread.union(unread, msgUnread);
|
||||||
} else {
|
} else {
|
||||||
@ -428,15 +428,15 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connect(params) {
|
connect(params) {
|
||||||
var serverID = null;
|
let serverID = null;
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var update;
|
let update;
|
||||||
[serverID, update] = State.createServer(state);
|
[serverID, update] = State.createServer(state);
|
||||||
return update;
|
return update;
|
||||||
});
|
});
|
||||||
this.setState({ connectParams: params });
|
this.setState({ connectParams: params });
|
||||||
|
|
||||||
var client = new Client(fillConnectParams(params));
|
let client = new Client(fillConnectParams(params));
|
||||||
this.clients.set(serverID, client);
|
this.clients.set(serverID, client);
|
||||||
this.setServerState(serverID, { status: client.status });
|
this.setServerState(serverID, { status: client.status });
|
||||||
|
|
||||||
@ -474,7 +474,7 @@ export default class App extends Component {
|
|||||||
serverID = State.getActiveServerID(this.state);
|
serverID = State.getActiveServerID(this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
var client = this.clients.get(serverID);
|
let client = this.clients.get(serverID);
|
||||||
if (client) {
|
if (client) {
|
||||||
this.clients.delete(serverID);
|
this.clients.delete(serverID);
|
||||||
client.disconnect();
|
client.disconnect();
|
||||||
@ -486,14 +486,14 @@ export default class App extends Component {
|
|||||||
serverID = State.getActiveServerID(this.state);
|
serverID = State.getActiveServerID(this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
var client = this.clients.get(serverID);
|
let client = this.clients.get(serverID);
|
||||||
if (client) {
|
if (client) {
|
||||||
client.reconnect();
|
client.reconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serverFromBouncerNetwork(bouncerNetworkID) {
|
serverFromBouncerNetwork(bouncerNetworkID) {
|
||||||
for (var [id, client] of this.clients) {
|
for (let [id, client] of this.clients) {
|
||||||
if (client.params.bouncerNetwork === bouncerNetworkID) {
|
if (client.params.bouncerNetwork === bouncerNetworkID) {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -502,11 +502,12 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleMessage(serverID, msg) {
|
handleMessage(serverID, msg) {
|
||||||
var client = this.clients.get(serverID);
|
let client = this.clients.get(serverID);
|
||||||
var chatHistoryBatch = irc.findBatchByType(msg, "chathistory");
|
let chatHistoryBatch = irc.findBatchByType(msg, "chathistory");
|
||||||
|
|
||||||
this.setState((state) => State.handleMessage(state, msg, serverID, client));
|
this.setState((state) => State.handleMessage(state, msg, serverID, client));
|
||||||
|
|
||||||
|
let target, channel, affectedBuffers;
|
||||||
switch (msg.command) {
|
switch (msg.command) {
|
||||||
case irc.RPL_WELCOME:
|
case irc.RPL_WELCOME:
|
||||||
if (this.state.connectParams.autojoin.length > 0) {
|
if (this.state.connectParams.autojoin.length > 0) {
|
||||||
@ -516,23 +517,23 @@ export default class App extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastReceipt = this.latestReceipt(ReceiptType.READ);
|
let lastReceipt = this.latestReceipt(ReceiptType.READ);
|
||||||
if (lastReceipt && lastReceipt.time && client.enabledCaps["draft/chathistory"] && (!client.enabledCaps["soju.im/bouncer-networks"] || client.params.bouncerNetwork)) {
|
if (lastReceipt && lastReceipt.time && client.enabledCaps["draft/chathistory"] && (!client.enabledCaps["soju.im/bouncer-networks"] || client.params.bouncerNetwork)) {
|
||||||
var now = irc.formatDate(new Date());
|
let now = irc.formatDate(new Date());
|
||||||
client.fetchHistoryTargets(now, lastReceipt.time).then((targets) => {
|
client.fetchHistoryTargets(now, lastReceipt.time).then((targets) => {
|
||||||
targets.forEach((target) => {
|
targets.forEach((target) => {
|
||||||
var from = this.getReceipt(target, ReceiptType.READ);
|
let from = this.getReceipt(target, ReceiptType.READ);
|
||||||
if (!from) {
|
if (!from) {
|
||||||
from = lastReceipt;
|
from = lastReceipt;
|
||||||
}
|
}
|
||||||
var to = { time: msg.tags.time || irc.formatDate(new Date()) };
|
let to = { time: msg.tags.time || irc.formatDate(new Date()) };
|
||||||
this.fetchBacklog(client, target.name, from, to);
|
this.fetchBacklog(client, target.name, from, to);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "MODE":
|
case "MODE":
|
||||||
var target = msg.params[0];
|
target = msg.params[0];
|
||||||
if (client.isChannel(target)) {
|
if (client.isChannel(target)) {
|
||||||
this.addMessage(serverID, target, msg);
|
this.addMessage(serverID, target, msg);
|
||||||
}
|
}
|
||||||
@ -542,7 +543,7 @@ export default class App extends Component {
|
|||||||
break;
|
break;
|
||||||
case "NOTICE":
|
case "NOTICE":
|
||||||
case "PRIVMSG":
|
case "PRIVMSG":
|
||||||
var target = msg.params[0];
|
target = msg.params[0];
|
||||||
if (client.isMyNick(target)) {
|
if (client.isMyNick(target)) {
|
||||||
if (client.cm(msg.prefix.name) === client.cm(client.serverPrefix.name)) {
|
if (client.cm(msg.prefix.name) === client.cm(client.serverPrefix.name)) {
|
||||||
target = SERVER_BUFFER;
|
target = SERVER_BUFFER;
|
||||||
@ -555,9 +556,9 @@ export default class App extends Component {
|
|||||||
target = SERVER_BUFFER;
|
target = SERVER_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
var allowedPrefixes = client.isupport.get("STATUSMSG");
|
let allowedPrefixes = client.isupport.get("STATUSMSG");
|
||||||
if (allowedPrefixes) {
|
if (allowedPrefixes) {
|
||||||
var parts = irc.parseTargetPrefix(target, allowedPrefixes);
|
let parts = irc.parseTargetPrefix(target, allowedPrefixes);
|
||||||
if (client.isChannel(parts.name)) {
|
if (client.isChannel(parts.name)) {
|
||||||
target = parts.name;
|
target = parts.name;
|
||||||
}
|
}
|
||||||
@ -566,7 +567,7 @@ export default class App extends Component {
|
|||||||
this.addMessage(serverID, target, msg);
|
this.addMessage(serverID, target, msg);
|
||||||
break;
|
break;
|
||||||
case "JOIN":
|
case "JOIN":
|
||||||
var channel = msg.params[0];
|
channel = msg.params[0];
|
||||||
|
|
||||||
if (!client.isMyNick(msg.prefix.name)) {
|
if (!client.isMyNick(msg.prefix.name)) {
|
||||||
this.addMessage(serverID, channel, msg);
|
this.addMessage(serverID, channel, msg);
|
||||||
@ -577,7 +578,7 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "PART":
|
case "PART":
|
||||||
var channel = msg.params[0];
|
channel = msg.params[0];
|
||||||
|
|
||||||
this.addMessage(serverID, channel, msg);
|
this.addMessage(serverID, channel, msg);
|
||||||
|
|
||||||
@ -587,16 +588,16 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "KICK":
|
case "KICK":
|
||||||
var channel = msg.params[0];
|
channel = msg.params[0];
|
||||||
this.addMessage(serverID, channel, msg);
|
this.addMessage(serverID, channel, msg);
|
||||||
break;
|
break;
|
||||||
case "QUIT":
|
case "QUIT":
|
||||||
var affectedBuffers = [];
|
affectedBuffers = [];
|
||||||
if (chatHistoryBatch) {
|
if (chatHistoryBatch) {
|
||||||
affectedBuffers.push(chatHistoryBatch.params[0]);
|
affectedBuffers.push(chatHistoryBatch.params[0]);
|
||||||
} else {
|
} else {
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var buffers = new Map(state.buffers);
|
let buffers = new Map(state.buffers);
|
||||||
state.buffers.forEach((buf) => {
|
state.buffers.forEach((buf) => {
|
||||||
if (buf.server != serverID) {
|
if (buf.server != serverID) {
|
||||||
return;
|
return;
|
||||||
@ -604,9 +605,9 @@ export default class App extends Component {
|
|||||||
if (!buf.members.has(msg.prefix.name) && client.cm(buf.name) !== client.cm(msg.prefix.name)) {
|
if (!buf.members.has(msg.prefix.name) && client.cm(buf.name) !== client.cm(msg.prefix.name)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var members = new irc.CaseMapMap(buf.members);
|
let members = new irc.CaseMapMap(buf.members);
|
||||||
members.delete(msg.prefix.name);
|
members.delete(msg.prefix.name);
|
||||||
var offline = client.cm(buf.name) === client.cm(msg.prefix.name);
|
let offline = client.cm(buf.name) === client.cm(msg.prefix.name);
|
||||||
buffers.set(buf.id, { ...buf, members, offline });
|
buffers.set(buf.id, { ...buf, members, offline });
|
||||||
affectedBuffers.push(buf.name);
|
affectedBuffers.push(buf.name);
|
||||||
});
|
});
|
||||||
@ -617,14 +618,14 @@ export default class App extends Component {
|
|||||||
affectedBuffers.forEach((name) => this.addMessage(serverID, name, msg));
|
affectedBuffers.forEach((name) => this.addMessage(serverID, name, msg));
|
||||||
break;
|
break;
|
||||||
case "NICK":
|
case "NICK":
|
||||||
var newNick = msg.params[0];
|
let newNick = msg.params[0];
|
||||||
|
|
||||||
var affectedBuffers = [];
|
affectedBuffers = [];
|
||||||
if (chatHistoryBatch) {
|
if (chatHistoryBatch) {
|
||||||
affectedBuffers.push(chatHistoryBatch.params[0]);
|
affectedBuffers.push(chatHistoryBatch.params[0]);
|
||||||
} else {
|
} else {
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var buffers = new Map(state.buffers);
|
let buffers = new Map(state.buffers);
|
||||||
state.buffers.forEach((buf) => {
|
state.buffers.forEach((buf) => {
|
||||||
if (buf.server != serverID) {
|
if (buf.server != serverID) {
|
||||||
return;
|
return;
|
||||||
@ -632,7 +633,7 @@ export default class App extends Component {
|
|||||||
if (!buf.members.has(msg.prefix.name)) {
|
if (!buf.members.has(msg.prefix.name)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var members = new irc.CaseMapMap(buf.members);
|
let members = new irc.CaseMapMap(buf.members);
|
||||||
members.set(newNick, members.get(msg.prefix.name));
|
members.set(newNick, members.get(msg.prefix.name));
|
||||||
members.delete(msg.prefix.name);
|
members.delete(msg.prefix.name);
|
||||||
buffers.set(buf.id, { ...buf, members });
|
buffers.set(buf.id, { ...buf, members });
|
||||||
@ -645,14 +646,14 @@ export default class App extends Component {
|
|||||||
affectedBuffers.forEach((name) => this.addMessage(serverID, name, msg));
|
affectedBuffers.forEach((name) => this.addMessage(serverID, name, msg));
|
||||||
break;
|
break;
|
||||||
case "TOPIC":
|
case "TOPIC":
|
||||||
var channel = msg.params[0];
|
channel = msg.params[0];
|
||||||
this.addMessage(serverID, channel, msg);
|
this.addMessage(serverID, channel, msg);
|
||||||
break;
|
break;
|
||||||
case "INVITE":
|
case "INVITE":
|
||||||
var channel = msg.params[1];
|
channel = msg.params[1];
|
||||||
|
|
||||||
// TODO: find a more reliable way to do this
|
// TODO: find a more reliable way to do this
|
||||||
var bufName = channel;
|
let bufName = channel;
|
||||||
if (!State.getBuffer(this.state, { server: serverID, name: channel })) {
|
if (!State.getBuffer(this.state, { server: serverID, name: channel })) {
|
||||||
bufName = SERVER_BUFFER;
|
bufName = SERVER_BUFFER;
|
||||||
}
|
}
|
||||||
@ -670,19 +671,19 @@ export default class App extends Component {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var id = msg.params[1];
|
let id = msg.params[1];
|
||||||
var attrs = null;
|
let attrs = null;
|
||||||
if (msg.params[2] !== "*") {
|
if (msg.params[2] !== "*") {
|
||||||
attrs = irc.parseTags(msg.params[2]);
|
attrs = irc.parseTags(msg.params[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var isNew = false;
|
let isNew = false;
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var bouncerNetworks = new Map(state.bouncerNetworks);
|
let bouncerNetworks = new Map(state.bouncerNetworks);
|
||||||
if (!attrs) {
|
if (!attrs) {
|
||||||
bouncerNetworks.delete(id);
|
bouncerNetworks.delete(id);
|
||||||
} else {
|
} else {
|
||||||
var prev = bouncerNetworks.get(id);
|
let prev = bouncerNetworks.get(id);
|
||||||
isNew = prev === undefined;
|
isNew = prev === undefined;
|
||||||
attrs = { ...prev, ...attrs };
|
attrs = { ...prev, ...attrs };
|
||||||
bouncerNetworks.set(id, attrs);
|
bouncerNetworks.set(id, attrs);
|
||||||
@ -690,7 +691,7 @@ export default class App extends Component {
|
|||||||
return { bouncerNetworks };
|
return { bouncerNetworks };
|
||||||
}, () => {
|
}, () => {
|
||||||
if (!attrs) {
|
if (!attrs) {
|
||||||
var serverID = this.serverFromBouncerNetwork(id);
|
let serverID = this.serverFromBouncerNetwork(id);
|
||||||
if (serverID) {
|
if (serverID) {
|
||||||
this.close({ server: serverID, name: SERVER_BUFFER });
|
this.close({ server: serverID, name: SERVER_BUFFER });
|
||||||
}
|
}
|
||||||
@ -710,7 +711,7 @@ export default class App extends Component {
|
|||||||
case irc.RPL_ENDOFEXCEPTLIST:
|
case irc.RPL_ENDOFEXCEPTLIST:
|
||||||
case irc.RPL_BANLIST:
|
case irc.RPL_BANLIST:
|
||||||
case irc.RPL_ENDOFBANLIST:
|
case irc.RPL_ENDOFBANLIST:
|
||||||
var channel = msg.params[1];
|
channel = msg.params[1];
|
||||||
this.addMessage(serverID, channel, msg);
|
this.addMessage(serverID, channel, msg);
|
||||||
break;
|
break;
|
||||||
case irc.RPL_MYINFO:
|
case irc.RPL_MYINFO:
|
||||||
@ -734,7 +735,7 @@ export default class App extends Component {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (irc.isError(msg.command) && msg.command != irc.ERR_NOMOTD) {
|
if (irc.isError(msg.command) && msg.command != irc.ERR_NOMOTD) {
|
||||||
var description = msg.params[msg.params.length - 1];
|
let description = msg.params[msg.params.length - 1];
|
||||||
this.setState({ error: description });
|
this.setState({ error: description });
|
||||||
}
|
}
|
||||||
this.addMessage(serverID, SERVER_BUFFER, msg);
|
this.addMessage(serverID, SERVER_BUFFER, msg);
|
||||||
@ -754,8 +755,8 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleChannelClick(channel) {
|
handleChannelClick(channel) {
|
||||||
var serverID = State.getActiveServerID(this.state);
|
let serverID = State.getActiveServerID(this.state);
|
||||||
var buf = State.getBuffer(this.state, { server: serverID, name: channel });
|
let buf = State.getBuffer(this.state, { server: serverID, name: channel });
|
||||||
if (buf) {
|
if (buf) {
|
||||||
this.switchBuffer(buf.id);
|
this.switchBuffer(buf.id);
|
||||||
} else {
|
} else {
|
||||||
@ -780,7 +781,7 @@ export default class App extends Component {
|
|||||||
serverID = State.getActiveServerID(this.state);
|
serverID = State.getActiveServerID(this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
var client = this.clients.get(serverID);
|
let client = this.clients.get(serverID);
|
||||||
if (client.isServer(target)) {
|
if (client.isServer(target)) {
|
||||||
this.switchBuffer({ server: serverID });
|
this.switchBuffer({ server: serverID });
|
||||||
} else if (client.isChannel(target)) {
|
} else if (client.isChannel(target)) {
|
||||||
@ -794,22 +795,23 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
close(id) {
|
close(id) {
|
||||||
var buf = State.getBuffer(this.state, id);
|
let buf = State.getBuffer(this.state, id);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let client = this.clients.get(buf.server);
|
||||||
switch (buf.type) {
|
switch (buf.type) {
|
||||||
case BufferType.SERVER:
|
case BufferType.SERVER:
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var buffers = new Map(state.buffers);
|
let buffers = new Map(state.buffers);
|
||||||
for (var [id, b] of state.buffers) {
|
for (let [id, b] of state.buffers) {
|
||||||
if (b.server === buf.server) {
|
if (b.server === buf.server) {
|
||||||
buffers.delete(id);
|
buffers.delete(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var activeBuffer = state.activeBuffer;
|
let activeBuffer = state.activeBuffer;
|
||||||
if (activeBuffer && state.buffers.get(activeBuffer).server === buf.server) {
|
if (activeBuffer && state.buffers.get(activeBuffer).server === buf.server) {
|
||||||
if (buffers.size > 0) {
|
if (buffers.size > 0) {
|
||||||
activeBuffer = buffers.keys().next().value;
|
activeBuffer = buffers.keys().next().value;
|
||||||
@ -821,16 +823,15 @@ export default class App extends Component {
|
|||||||
return { buffers, activeBuffer };
|
return { buffers, activeBuffer };
|
||||||
});
|
});
|
||||||
|
|
||||||
var client = this.clients.get(buf.server);
|
let disconnectAll = client && !client.params.bouncerNetwork && client.enabledCaps["soju.im/bouncer-networks"];
|
||||||
var disconnectAll = client && !client.params.bouncerNetwork && client.enabledCaps["soju.im/bouncer-networks"];
|
|
||||||
|
|
||||||
this.disconnect(buf.server);
|
this.disconnect(buf.server);
|
||||||
|
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var servers = new Map(state.servers);
|
let servers = new Map(state.servers);
|
||||||
servers.delete(buf.server);
|
servers.delete(buf.server);
|
||||||
|
|
||||||
var connectForm = state.connectForm;
|
let connectForm = state.connectForm;
|
||||||
if (servers.size == 0) {
|
if (servers.size == 0) {
|
||||||
connectForm = true;
|
connectForm = true;
|
||||||
}
|
}
|
||||||
@ -839,7 +840,7 @@ export default class App extends Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (disconnectAll) {
|
if (disconnectAll) {
|
||||||
for (var serverID of this.clients.keys()) {
|
for (let serverID of this.clients.keys()) {
|
||||||
this.close({ server: serverID, name: SERVER_BUFFER });
|
this.close({ server: serverID, name: SERVER_BUFFER });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -850,13 +851,12 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BufferType.CHANNEL:
|
case BufferType.CHANNEL:
|
||||||
var client = this.clients.get(buf.server);
|
|
||||||
client.send({ command: "PART", params: [buf.name] });
|
client.send({ command: "PART", params: [buf.name] });
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case BufferType.NICK:
|
case BufferType.NICK:
|
||||||
this.switchBuffer({ name: SERVER_BUFFER });
|
this.switchBuffer({ name: SERVER_BUFFER });
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var buffers = new Map(state.buffers);
|
let buffers = new Map(state.buffers);
|
||||||
buffers.delete(buf.id);
|
buffers.delete(buf.id);
|
||||||
return { buffers };
|
return { buffers };
|
||||||
});
|
});
|
||||||
@ -868,11 +868,11 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
executeCommand(s) {
|
executeCommand(s) {
|
||||||
var parts = s.split(" ");
|
let parts = s.split(" ");
|
||||||
var name = parts[0].toLowerCase().slice(1);
|
let name = parts[0].toLowerCase().slice(1);
|
||||||
var args = parts.slice(1);
|
let args = parts.slice(1);
|
||||||
|
|
||||||
var cmd = commands[name];
|
let cmd = commands[name];
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
this.setState({ error: `Unknown command "${name}" (run "/help" to get a command list)` });
|
this.setState({ error: `Unknown command "${name}" (run "/help" to get a command list)` });
|
||||||
return;
|
return;
|
||||||
@ -892,10 +892,10 @@ export default class App extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var serverID = State.getActiveServerID(this.state);
|
let serverID = State.getActiveServerID(this.state);
|
||||||
var client = this.clients.get(serverID);
|
let client = this.clients.get(serverID);
|
||||||
|
|
||||||
var msg = { command: "PRIVMSG", params: [target, text] };
|
let msg = { command: "PRIVMSG", params: [target, text] };
|
||||||
client.send(msg);
|
client.send(msg);
|
||||||
|
|
||||||
if (!client.enabledCaps["echo-message"]) {
|
if (!client.enabledCaps["echo-message"]) {
|
||||||
@ -916,7 +916,7 @@ export default class App extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf = this.state.buffers.get(this.state.activeBuffer);
|
let buf = this.state.buffers.get(this.state.activeBuffer);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -931,7 +931,7 @@ export default class App extends Component {
|
|||||||
|
|
||||||
toggleBufferList() {
|
toggleBufferList() {
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var openPanels = {
|
let openPanels = {
|
||||||
...state.openPanels,
|
...state.openPanels,
|
||||||
bufferList: !state.openPanels.bufferList,
|
bufferList: !state.openPanels.bufferList,
|
||||||
};
|
};
|
||||||
@ -941,7 +941,7 @@ export default class App extends Component {
|
|||||||
|
|
||||||
toggleMemberList() {
|
toggleMemberList() {
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var openPanels = {
|
let openPanels = {
|
||||||
...state.openPanels,
|
...state.openPanels,
|
||||||
memberList: !state.openPanels.memberList,
|
memberList: !state.openPanels.memberList,
|
||||||
};
|
};
|
||||||
@ -951,7 +951,7 @@ export default class App extends Component {
|
|||||||
|
|
||||||
closeBufferList() {
|
closeBufferList() {
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var openPanels = {
|
let openPanels = {
|
||||||
...state.openPanels,
|
...state.openPanels,
|
||||||
bufferList: false,
|
bufferList: false,
|
||||||
};
|
};
|
||||||
@ -961,7 +961,7 @@ export default class App extends Component {
|
|||||||
|
|
||||||
closeMemberList() {
|
closeMemberList() {
|
||||||
this.setState((state) => {
|
this.setState((state) => {
|
||||||
var openPanels = {
|
let openPanels = {
|
||||||
...state.openPanels,
|
...state.openPanels,
|
||||||
memberList: false,
|
memberList: false,
|
||||||
};
|
};
|
||||||
@ -974,7 +974,7 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleJoinSubmit(data) {
|
handleJoinSubmit(data) {
|
||||||
var client = this.clients.get(this.state.joinDialog.server);
|
let client = this.clients.get(this.state.joinDialog.server);
|
||||||
|
|
||||||
this.switchToChannel = data.channel;
|
this.switchToChannel = data.channel;
|
||||||
client.send({ command: "JOIN", params: [data.channel] });
|
client.send({ command: "JOIN", params: [data.channel] });
|
||||||
@ -985,8 +985,8 @@ export default class App extends Component {
|
|||||||
autocomplete(prefix) {
|
autocomplete(prefix) {
|
||||||
function fromList(l, prefix) {
|
function fromList(l, prefix) {
|
||||||
prefix = prefix.toLowerCase();
|
prefix = prefix.toLowerCase();
|
||||||
var repl = null;
|
let repl = null;
|
||||||
for (var item of l) {
|
for (let item of l) {
|
||||||
if (item.toLowerCase().startsWith(prefix)) {
|
if (item.toLowerCase().startsWith(prefix)) {
|
||||||
if (repl) {
|
if (repl) {
|
||||||
return null;
|
return null;
|
||||||
@ -998,14 +998,14 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (prefix.startsWith("/")) {
|
if (prefix.startsWith("/")) {
|
||||||
var repl = fromList(Object.keys(commands), prefix.slice(1));
|
let repl = fromList(Object.keys(commands), prefix.slice(1));
|
||||||
if (repl) {
|
if (repl) {
|
||||||
repl = "/" + repl;
|
repl = "/" + repl;
|
||||||
}
|
}
|
||||||
return repl;
|
return repl;
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf = this.state.buffers.get(this.state.activeBuffer);
|
let buf = this.state.buffers.get(this.state.activeBuffer);
|
||||||
if (!buf || !buf.members) {
|
if (!buf || !buf.members) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -1017,12 +1017,12 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleBufferScrollTop() {
|
handleBufferScrollTop() {
|
||||||
var buf = this.state.buffers.get(this.state.activeBuffer);
|
let buf = this.state.buffers.get(this.state.activeBuffer);
|
||||||
if (!buf || buf.type == BufferType.SERVER) {
|
if (!buf || buf.type == BufferType.SERVER) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var client = this.clients.get(buf.server);
|
let client = this.clients.get(buf.server);
|
||||||
|
|
||||||
if (!client || !client.enabledCaps["draft/chathistory"] || !client.enabledCaps["server-time"]) {
|
if (!client || !client.enabledCaps["draft/chathistory"] || !client.enabledCaps["server-time"]) {
|
||||||
return;
|
return;
|
||||||
@ -1031,7 +1031,7 @@ export default class App extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var before;
|
let before;
|
||||||
if (buf.messages.length > 0) {
|
if (buf.messages.length > 0) {
|
||||||
before = buf.messages[0].tags["time"];
|
before = buf.messages[0].tags["time"];
|
||||||
} else {
|
} else {
|
||||||
@ -1055,9 +1055,9 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleManageNetworkClick(serverID) {
|
handleManageNetworkClick(serverID) {
|
||||||
var server = this.state.servers.get(serverID);
|
let server = this.state.servers.get(serverID);
|
||||||
var bouncerNetID = server.isupport.get("BOUNCER_NETID");
|
let bouncerNetID = server.isupport.get("BOUNCER_NETID");
|
||||||
var bouncerNetwork = this.state.bouncerNetworks.get(bouncerNetID);
|
let bouncerNetwork = this.state.bouncerNetworks.get(bouncerNetID);
|
||||||
this.setState({
|
this.setState({
|
||||||
dialog: "network",
|
dialog: "network",
|
||||||
networkDialog: {
|
networkDialog: {
|
||||||
@ -1068,7 +1068,7 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleNetworkSubmit(attrs) {
|
handleNetworkSubmit(attrs) {
|
||||||
var client = this.clients.values().next().value;
|
let client = this.clients.values().next().value;
|
||||||
|
|
||||||
if (this.state.networkDialog && this.state.networkDialog.id) {
|
if (this.state.networkDialog && this.state.networkDialog.id) {
|
||||||
if (Object.keys(attrs).length == 0) {
|
if (Object.keys(attrs).length == 0) {
|
||||||
@ -1092,7 +1092,7 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleNetworkRemove() {
|
handleNetworkRemove() {
|
||||||
var client = this.clients.values().next().value;
|
let client = this.clients.values().next().value;
|
||||||
|
|
||||||
client.send({
|
client.send({
|
||||||
command: "BOUNCER",
|
command: "BOUNCER",
|
||||||
@ -1103,29 +1103,29 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleMode(serverID, msg) {
|
handleMode(serverID, msg) {
|
||||||
var client = this.clients.get(serverID);
|
let client = this.clients.get(serverID);
|
||||||
var chanmodes = client.isupport.get("CHANMODES") || irc.STD_CHANMODES;
|
let chanmodes = client.isupport.get("CHANMODES") || irc.STD_CHANMODES;
|
||||||
var prefix = client.isupport.get("PREFIX") || "";
|
let prefix = client.isupport.get("PREFIX") || "";
|
||||||
|
|
||||||
var prefixByMode = new Map(irc.parseMembershipModes(prefix).map((membership) => {
|
let prefixByMode = new Map(irc.parseMembershipModes(prefix).map((membership) => {
|
||||||
return [membership.mode, membership.prefix];
|
return [membership.mode, membership.prefix];
|
||||||
}));
|
}));
|
||||||
|
|
||||||
var typeByMode = new Map();
|
let typeByMode = new Map();
|
||||||
var [a, b, c, d] = chanmodes.split(",");
|
let [a, b, c, d] = chanmodes.split(",");
|
||||||
Array.from(a).forEach((mode) => typeByMode.set(mode, "A"));
|
Array.from(a).forEach((mode) => typeByMode.set(mode, "A"));
|
||||||
Array.from(b).forEach((mode) => typeByMode.set(mode, "B"));
|
Array.from(b).forEach((mode) => typeByMode.set(mode, "B"));
|
||||||
Array.from(c).forEach((mode) => typeByMode.set(mode, "C"));
|
Array.from(c).forEach((mode) => typeByMode.set(mode, "C"));
|
||||||
Array.from(d).forEach((mode) => typeByMode.set(mode, "D"));
|
Array.from(d).forEach((mode) => typeByMode.set(mode, "D"));
|
||||||
prefixByMode.forEach((prefix, mode) => typeByMode.set(mode, "B"));
|
prefixByMode.forEach((prefix, mode) => typeByMode.set(mode, "B"));
|
||||||
|
|
||||||
var channel = msg.params[0];
|
let channel = msg.params[0];
|
||||||
var change = msg.params[1];
|
let change = msg.params[1];
|
||||||
var args = msg.params.slice(2);
|
let args = msg.params.slice(2);
|
||||||
|
|
||||||
var plusMinus = null;
|
let plusMinus = null;
|
||||||
var j = 0;
|
let j = 0;
|
||||||
for (var i = 0; i < change.length; i++) {
|
for (let i = 0; i < change.length; i++) {
|
||||||
if (change[i] === "+" || change[i] === "-") {
|
if (change[i] === "+" || change[i] === "-") {
|
||||||
plusMinus = change[i];
|
plusMinus = change[i];
|
||||||
continue;
|
continue;
|
||||||
@ -1134,15 +1134,15 @@ export default class App extends Component {
|
|||||||
throw new Error("malformed mode string: missing plus/minus");
|
throw new Error("malformed mode string: missing plus/minus");
|
||||||
}
|
}
|
||||||
|
|
||||||
var mode = change[i];
|
let mode = change[i];
|
||||||
var add = plusMinus === "+";
|
let add = plusMinus === "+";
|
||||||
|
|
||||||
var modeType = typeByMode.get(mode);
|
let modeType = typeByMode.get(mode);
|
||||||
if (!modeType) {
|
if (!modeType) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var arg = null;
|
let arg = null;
|
||||||
if (modeType === "A" || modeType === "B" || (modeType === "C" && add)) {
|
if (modeType === "A" || modeType === "B" || (modeType === "C" && add)) {
|
||||||
arg = args[j];
|
arg = args[j];
|
||||||
j++;
|
j++;
|
||||||
@ -1159,18 +1159,18 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handlePrefixChange(serverID, channel, nick, letter, add) {
|
handlePrefixChange(serverID, channel, nick, letter, add) {
|
||||||
var client = this.clients.get(serverID);
|
let client = this.clients.get(serverID);
|
||||||
var prefix = client.isupport.get("PREFIX") || "";
|
let prefix = client.isupport.get("PREFIX") || "";
|
||||||
|
|
||||||
var prefixPrivs = new Map(irc.parseMembershipModes(prefix).map((membership, i) => {
|
let prefixPrivs = new Map(irc.parseMembershipModes(prefix).map((membership, i) => {
|
||||||
return [membership.prefix, i];
|
return [membership.prefix, i];
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.setBufferState({ server: serverID, name: channel }, (buf) => {
|
this.setBufferState({ server: serverID, name: channel }, (buf) => {
|
||||||
var members = new irc.CaseMapMap(buf.members);
|
let members = new irc.CaseMapMap(buf.members);
|
||||||
var membership = members.get(nick);
|
let membership = members.get(nick);
|
||||||
if (add) {
|
if (add) {
|
||||||
var i = membership.indexOf(letter);
|
let i = membership.indexOf(letter);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
membership += letter;
|
membership += letter;
|
||||||
}
|
}
|
||||||
@ -1190,24 +1190,24 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var activeBuffer = null, activeServer = null, activeBouncerNetwork = null;
|
let activeBuffer = null, activeServer = null, activeBouncerNetwork = null;
|
||||||
var isBouncer = false;
|
let isBouncer = false;
|
||||||
if (this.state.buffers.get(this.state.activeBuffer)) {
|
if (this.state.buffers.get(this.state.activeBuffer)) {
|
||||||
activeBuffer = this.state.buffers.get(this.state.activeBuffer);
|
activeBuffer = this.state.buffers.get(this.state.activeBuffer);
|
||||||
activeServer = this.state.servers.get(activeBuffer.server);
|
activeServer = this.state.servers.get(activeBuffer.server);
|
||||||
|
|
||||||
var activeClient = this.clients.get(activeBuffer.server);
|
let activeClient = this.clients.get(activeBuffer.server);
|
||||||
isBouncer = activeClient && activeClient.enabledCaps["soju.im/bouncer-networks"];
|
isBouncer = activeClient && activeClient.enabledCaps["soju.im/bouncer-networks"];
|
||||||
|
|
||||||
var bouncerNetID = activeServer.isupport.get("BOUNCER_NETID");
|
let bouncerNetID = activeServer.isupport.get("BOUNCER_NETID");
|
||||||
if (bouncerNetID) {
|
if (bouncerNetID) {
|
||||||
activeBouncerNetwork = this.state.bouncerNetworks.get(bouncerNetID);
|
activeBouncerNetwork = this.state.bouncerNetworks.get(bouncerNetID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.connectForm) {
|
if (this.state.connectForm) {
|
||||||
var status = activeServer ? activeServer.status : ServerStatus.DISCONNECTED;
|
let status = activeServer ? activeServer.status : ServerStatus.DISCONNECTED;
|
||||||
var connecting = status === ServerStatus.CONNECTING || status === ServerStatus.REGISTERING;
|
let connecting = status === ServerStatus.CONNECTING || status === ServerStatus.REGISTERING;
|
||||||
// TODO: using key=connectParams trashes the ConnectForm state on update
|
// TODO: using key=connectParams trashes the ConnectForm state on update
|
||||||
return html`
|
return html`
|
||||||
<section id="connect">
|
<section id="connect">
|
||||||
@ -1223,7 +1223,7 @@ export default class App extends Component {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bufferHeader = null;
|
let bufferHeader = null;
|
||||||
if (activeBuffer) {
|
if (activeBuffer) {
|
||||||
bufferHeader = html`
|
bufferHeader = html`
|
||||||
<section id="buffer-header">
|
<section id="buffer-header">
|
||||||
@ -1242,7 +1242,7 @@ export default class App extends Component {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var memberList = null;
|
let memberList = null;
|
||||||
if (activeBuffer && activeBuffer.type == BufferType.CHANNEL) {
|
if (activeBuffer && activeBuffer.type == BufferType.CHANNEL) {
|
||||||
memberList = html`
|
memberList = html`
|
||||||
<section
|
<section
|
||||||
@ -1269,10 +1269,10 @@ export default class App extends Component {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var dialog = null;
|
let dialog = null;
|
||||||
switch (this.state.dialog) {
|
switch (this.state.dialog) {
|
||||||
case "network":
|
case "network":
|
||||||
var title = this.state.networkDialog ? "Edit network" : "Add network";
|
let title = this.state.networkDialog ? "Edit network" : "Add network";
|
||||||
dialog = html`
|
dialog = html`
|
||||||
<${Dialog} title=${title} onDismiss=${this.handleDialogDismiss}>
|
<${Dialog} title=${title} onDismiss=${this.handleDialogDismiss}>
|
||||||
<${NetworkForm}
|
<${NetworkForm}
|
||||||
@ -1299,7 +1299,7 @@ export default class App extends Component {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var error = null;
|
let error = null;
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
error = html`
|
error = html`
|
||||||
<p id="error-msg">
|
<p id="error-msg">
|
||||||
@ -1310,7 +1310,7 @@ export default class App extends Component {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var composerReadOnly = false;
|
let composerReadOnly = false;
|
||||||
if (activeBuffer && activeBuffer.type === BufferType.SERVER) {
|
if (activeBuffer && activeBuffer.type === BufferType.SERVER) {
|
||||||
composerReadOnly = true;
|
composerReadOnly = true;
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,12 @@ const UserStatus = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function NickStatus(props) {
|
function NickStatus(props) {
|
||||||
var textMap = {
|
let textMap = {
|
||||||
[UserStatus.HERE]: "User is online",
|
[UserStatus.HERE]: "User is online",
|
||||||
[UserStatus.GONE]: "User is away",
|
[UserStatus.GONE]: "User is away",
|
||||||
[UserStatus.OFFLINE]: "User is offline",
|
[UserStatus.OFFLINE]: "User is offline",
|
||||||
};
|
};
|
||||||
var text = textMap[props.status];
|
let text = textMap[props.status];
|
||||||
return html`<span class="status status-${props.status}" title=${text}>●</span>`;
|
return html`<span class="status status-${props.status}" title=${text}>●</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ export default function BufferHeader(props) {
|
|||||||
props.onManageNetwork();
|
props.onManageNetwork();
|
||||||
}
|
}
|
||||||
|
|
||||||
var description = null, actions = null;
|
let description = null, actions = null;
|
||||||
switch (props.buffer.type) {
|
switch (props.buffer.type) {
|
||||||
case BufferType.SERVER:
|
case BufferType.SERVER:
|
||||||
switch (props.server.status) {
|
switch (props.server.status) {
|
||||||
@ -65,7 +65,7 @@ export default function BufferHeader(props) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (props.buffer.serverInfo) {
|
} else if (props.buffer.serverInfo) {
|
||||||
var serverInfo = props.buffer.serverInfo;
|
let serverInfo = props.buffer.serverInfo;
|
||||||
description = `Connected to ${serverInfo.name}`;
|
description = `Connected to ${serverInfo.name}`;
|
||||||
} else {
|
} else {
|
||||||
description = "Connected";
|
description = "Connected";
|
||||||
@ -126,11 +126,11 @@ export default function BufferHeader(props) {
|
|||||||
break;
|
break;
|
||||||
case BufferType.NICK:
|
case BufferType.NICK:
|
||||||
if (props.buffer.who) {
|
if (props.buffer.who) {
|
||||||
var who = props.buffer.who;
|
let who = props.buffer.who;
|
||||||
|
|
||||||
var realname = stripANSI(who.realname || "");
|
let realname = stripANSI(who.realname || "");
|
||||||
|
|
||||||
var status = UserStatus.HERE;
|
let status = UserStatus.HERE;
|
||||||
if (who.away) {
|
if (who.away) {
|
||||||
status = UserStatus.GONE;
|
status = UserStatus.GONE;
|
||||||
}
|
}
|
||||||
@ -154,7 +154,7 @@ export default function BufferHeader(props) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = props.buffer.name;
|
let name = props.buffer.name;
|
||||||
if (props.buffer.type == BufferType.SERVER) {
|
if (props.buffer.type == BufferType.SERVER) {
|
||||||
name = getServerName(props.server, props.bouncerNetwork, props.isBouncer);
|
name = getServerName(props.server, props.bouncerNetwork, props.isBouncer);
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,12 @@ function BufferItem(props) {
|
|||||||
props.onClick();
|
props.onClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = props.buffer.name;
|
let name = props.buffer.name;
|
||||||
if (props.buffer.type == BufferType.SERVER) {
|
if (props.buffer.type == BufferType.SERVER) {
|
||||||
name = getServerName(props.server, props.bouncerNetwork, props.isBouncer);
|
name = getServerName(props.server, props.bouncerNetwork, props.isBouncer);
|
||||||
}
|
}
|
||||||
|
|
||||||
var classes = ["type-" + props.buffer.type];
|
let classes = ["type-" + props.buffer.type];
|
||||||
if (props.active) {
|
if (props.active) {
|
||||||
classes.push("active");
|
classes.push("active");
|
||||||
}
|
}
|
||||||
@ -30,11 +30,11 @@ function BufferItem(props) {
|
|||||||
|
|
||||||
|
|
||||||
export default function BufferList(props) {
|
export default function BufferList(props) {
|
||||||
var items = Array.from(props.buffers.values()).map((buf) => {
|
let items = Array.from(props.buffers.values()).map((buf) => {
|
||||||
var server = props.servers.get(buf.server);
|
let server = props.servers.get(buf.server);
|
||||||
|
|
||||||
var bouncerNetwork = null;
|
let bouncerNetwork = null;
|
||||||
var bouncerNetID = server.isupport.get("BOUNCER_NETID");
|
let bouncerNetID = server.isupport.get("BOUNCER_NETID");
|
||||||
if (bouncerNetID) {
|
if (bouncerNetID) {
|
||||||
bouncerNetwork = props.bouncerNetworks.get(bouncerNetID);
|
bouncerNetwork = props.bouncerNetworks.get(bouncerNetID);
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ import { strip as stripANSI } from "../lib/ansi.js";
|
|||||||
import { BufferType, getNickURL, getChannelURL, getMessageURL } from "../state.js";
|
import { BufferType, getNickURL, getChannelURL, getMessageURL } from "../state.js";
|
||||||
|
|
||||||
function djb2(s) {
|
function djb2(s) {
|
||||||
var hash = 5381;
|
let hash = 5381;
|
||||||
for (var i = 0; i < s.length; i++) {
|
for (let i = 0; i < s.length; i++) {
|
||||||
hash = (hash << 5) + hash + s.charCodeAt(i);
|
hash = (hash << 5) + hash + s.charCodeAt(i);
|
||||||
hash = hash >>> 0; // convert to uint32
|
hash = hash >>> 0; // convert to uint32
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ function Nick(props) {
|
|||||||
props.onClick();
|
props.onClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
var colorIndex = djb2(props.nick) % 16 + 1;
|
let colorIndex = djb2(props.nick) % 16 + 1;
|
||||||
return html`
|
return html`
|
||||||
<a href=${getNickURL(props.nick)} class="nick nick-${colorIndex}" onClick=${handleClick}>${props.nick}</a>
|
<a href=${getNickURL(props.nick)} class="nick nick-${colorIndex}" onClick=${handleClick}>${props.nick}</a>
|
||||||
`;
|
`;
|
||||||
@ -30,10 +30,10 @@ function Timestamp({ date, url }) {
|
|||||||
return html`<spam class="timestamp">--:--:--</span>`;
|
return html`<spam class="timestamp">--:--:--</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hh = date.getHours().toString().padStart(2, "0");
|
let hh = date.getHours().toString().padStart(2, "0");
|
||||||
var mm = date.getMinutes().toString().padStart(2, "0");
|
let mm = date.getMinutes().toString().padStart(2, "0");
|
||||||
var ss = date.getSeconds().toString().padStart(2, "0");
|
let ss = date.getSeconds().toString().padStart(2, "0");
|
||||||
var timestamp = `${hh}:${mm}:${ss}`;
|
let timestamp = `${hh}:${mm}:${ss}`;
|
||||||
return html`
|
return html`
|
||||||
<a href=${url} class="timestamp" onClick=${(event) => event.preventDefault()}>${timestamp}</a>
|
<a href=${url} class="timestamp" onClick=${(event) => event.preventDefault()}>${timestamp}</a>
|
||||||
`;
|
`;
|
||||||
@ -62,10 +62,10 @@ class LogLine extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var msg = this.props.message;
|
let msg = this.props.message;
|
||||||
|
|
||||||
var onNickClick = this.props.onNickClick;
|
let onNickClick = this.props.onNickClick;
|
||||||
var onChannelClick = this.props.onChannelClick;
|
let onChannelClick = this.props.onChannelClick;
|
||||||
function createNick(nick) {
|
function createNick(nick) {
|
||||||
return html`
|
return html`
|
||||||
<${Nick} nick=${nick} onClick=${() => onNickClick(nick)}/>
|
<${Nick} nick=${nick} onClick=${() => onNickClick(nick)}/>
|
||||||
@ -83,14 +83,14 @@ class LogLine extends Component {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var lineClass = "";
|
let lineClass = "";
|
||||||
var content;
|
let content;
|
||||||
switch (msg.command) {
|
switch (msg.command) {
|
||||||
case "NOTICE":
|
case "NOTICE":
|
||||||
case "PRIVMSG":
|
case "PRIVMSG":
|
||||||
var text = msg.params[1];
|
let text = msg.params[1];
|
||||||
|
|
||||||
var ctcp = irc.parseCTCP(msg);
|
let ctcp = irc.parseCTCP(msg);
|
||||||
if (ctcp) {
|
if (ctcp) {
|
||||||
if (ctcp.command == "ACTION") {
|
if (ctcp.command == "ACTION") {
|
||||||
lineClass = "me-tell";
|
lineClass = "me-tell";
|
||||||
@ -102,7 +102,7 @@ class LogLine extends Component {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lineClass = "talk";
|
lineClass = "talk";
|
||||||
var prefix = "<", suffix = ">";
|
let prefix = "<", suffix = ">";
|
||||||
if (msg.command == "NOTICE") {
|
if (msg.command == "NOTICE") {
|
||||||
prefix = suffix = "-";
|
prefix = suffix = "-";
|
||||||
}
|
}
|
||||||
@ -129,7 +129,7 @@ class LogLine extends Component {
|
|||||||
`;
|
`;
|
||||||
break;
|
break;
|
||||||
case "NICK":
|
case "NICK":
|
||||||
var newNick = msg.params[0];
|
let newNick = msg.params[0];
|
||||||
content = html`
|
content = html`
|
||||||
${createNick(msg.prefix.name)} is now known as ${createNick(newNick)}
|
${createNick(msg.prefix.name)} is now known as ${createNick(newNick)}
|
||||||
`;
|
`;
|
||||||
@ -145,14 +145,14 @@ class LogLine extends Component {
|
|||||||
`;
|
`;
|
||||||
break;
|
break;
|
||||||
case "TOPIC":
|
case "TOPIC":
|
||||||
var topic = msg.params[1];
|
let topic = msg.params[1];
|
||||||
content = html`
|
content = html`
|
||||||
${createNick(msg.prefix.name)} changed the topic to: ${linkify(stripANSI(topic), onChannelClick)}
|
${createNick(msg.prefix.name)} changed the topic to: ${linkify(stripANSI(topic), onChannelClick)}
|
||||||
`;
|
`;
|
||||||
break;
|
break;
|
||||||
case "INVITE":
|
case "INVITE":
|
||||||
var invitee = msg.params[0];
|
let invitee = msg.params[0];
|
||||||
var channel = msg.params[1];
|
let channel = msg.params[1];
|
||||||
// TODO: instead of checking buffer type, check if invitee is our nick
|
// TODO: instead of checking buffer type, check if invitee is our nick
|
||||||
if (this.props.buffer.type === BufferType.SERVER) {
|
if (this.props.buffer.type === BufferType.SERVER) {
|
||||||
lineClass = "talk";
|
lineClass = "talk";
|
||||||
@ -193,7 +193,7 @@ function createNickList(nicks, createNick) {
|
|||||||
return createNick(nicks[0]);
|
return createNick(nicks[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var l = nicks.slice(0, nicks.length - 1).map((nick, i) => {
|
let l = nicks.slice(0, nicks.length - 1).map((nick, i) => {
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
return createNick(nick);
|
return createNick(nick);
|
||||||
} else {
|
} else {
|
||||||
@ -214,17 +214,17 @@ class FoldGroup extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var msgs = this.props.messages;
|
let msgs = this.props.messages;
|
||||||
var buf = this.props.buffer;
|
let buf = this.props.buffer;
|
||||||
|
|
||||||
var onNickClick = this.props.onNickClick;
|
let onNickClick = this.props.onNickClick;
|
||||||
function createNick(nick) {
|
function createNick(nick) {
|
||||||
return html`
|
return html`
|
||||||
<${Nick} nick=${nick} onClick=${() => onNickClick(nick)}/>
|
<${Nick} nick=${nick} onClick=${() => onNickClick(nick)}/>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var byCommand = {
|
let byCommand = {
|
||||||
"JOIN": [],
|
"JOIN": [],
|
||||||
"PART": [],
|
"PART": [],
|
||||||
"QUIT": [],
|
"QUIT": [],
|
||||||
@ -234,15 +234,15 @@ class FoldGroup extends Component {
|
|||||||
byCommand[msg.command].push(msg);
|
byCommand[msg.command].push(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
var first = true;
|
let first = true;
|
||||||
var content = [];
|
let content = [];
|
||||||
["JOIN", "PART", "QUIT"].forEach((cmd) => {
|
["JOIN", "PART", "QUIT"].forEach((cmd) => {
|
||||||
if (byCommand[cmd].length === 0) {
|
if (byCommand[cmd].length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var plural = byCommand[cmd].length > 1;
|
let plural = byCommand[cmd].length > 1;
|
||||||
var action;
|
let action;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case "JOIN":
|
case "JOIN":
|
||||||
action = plural ? "have joined" : "has joined";
|
action = plural ? "have joined" : "has joined";
|
||||||
@ -261,7 +261,7 @@ class FoldGroup extends Component {
|
|||||||
content.push(", ");
|
content.push(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
var nicks = byCommand[cmd].map((msg) => msg.prefix.name);
|
let nicks = byCommand[cmd].map((msg) => msg.prefix.name);
|
||||||
|
|
||||||
content.push(createNickList(nicks, createNick));
|
content.push(createNickList(nicks, createNick));
|
||||||
content.push(" " + action);
|
content.push(" " + action);
|
||||||
@ -274,16 +274,16 @@ class FoldGroup extends Component {
|
|||||||
content.push(", ");
|
content.push(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
var newNick = msg.params[0];
|
let newNick = msg.params[0];
|
||||||
content.push(html`
|
content.push(html`
|
||||||
${createNick(msg.prefix.name)} is now known as ${createNick(newNick)}
|
${createNick(msg.prefix.name)} is now known as ${createNick(newNick)}
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
var lastMsg = msgs[msgs.length - 1];
|
let lastMsg = msgs[msgs.length - 1];
|
||||||
var firstDate = new Date(msgs[0].tags.time);
|
let firstDate = new Date(msgs[0].tags.time);
|
||||||
var lastDate = new Date(lastMsg.tags.time);
|
let lastDate = new Date(lastMsg.tags.time);
|
||||||
var timestamp = html`
|
let timestamp = html`
|
||||||
<${Timestamp} date=${firstDate} url=${getMessageURL(buf, msgs[0])}/>
|
<${Timestamp} date=${firstDate} url=${getMessageURL(buf, msgs[0])}/>
|
||||||
`;
|
`;
|
||||||
if (lastDate - firstDate > 60 * 100) {
|
if (lastDate - firstDate > 60 * 100) {
|
||||||
@ -307,7 +307,7 @@ class FoldGroup extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=481856
|
// Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=481856
|
||||||
var notificationsSupported = false;
|
let notificationsSupported = false;
|
||||||
if (window.Notification) {
|
if (window.Notification) {
|
||||||
notificationsSupported = true;
|
notificationsSupported = true;
|
||||||
if (Notification.permission === "default") {
|
if (Notification.permission === "default") {
|
||||||
@ -369,11 +369,11 @@ class DateSeparator extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var date = this.props.date;
|
let date = this.props.date;
|
||||||
var YYYY = date.getFullYear().toString().padStart(4, "0");
|
let YYYY = date.getFullYear().toString().padStart(4, "0");
|
||||||
var MM = (date.getMonth() + 1).toString().padStart(2, "0");
|
let MM = (date.getMonth() + 1).toString().padStart(2, "0");
|
||||||
var DD = date.getDate().toString().padStart(2, "0");
|
let DD = date.getDate().toString().padStart(2, "0");
|
||||||
var text = `${YYYY}-${MM}-${DD}`;
|
let text = `${YYYY}-${MM}-${DD}`;
|
||||||
return html`
|
return html`
|
||||||
<div class="separator date-separator">
|
<div class="separator date-separator">
|
||||||
${text}
|
${text}
|
||||||
@ -396,18 +396,18 @@ export default class Buffer extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var buf = this.props.buffer;
|
let buf = this.props.buffer;
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var children = [];
|
let children = [];
|
||||||
if (buf.type == BufferType.SERVER) {
|
if (buf.type == BufferType.SERVER) {
|
||||||
children.push(html`<${NotificationNagger}/>`);
|
children.push(html`<${NotificationNagger}/>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
var onChannelClick = this.props.onChannelClick;
|
let onChannelClick = this.props.onChannelClick;
|
||||||
var onNickClick = this.props.onNickClick;
|
let onNickClick = this.props.onNickClick;
|
||||||
function createLogLine(msg) {
|
function createLogLine(msg) {
|
||||||
return html`
|
return html`
|
||||||
<${LogLine}
|
<${LogLine}
|
||||||
@ -421,8 +421,8 @@ export default class Buffer extends Component {
|
|||||||
}
|
}
|
||||||
function createFoldGroup(msgs) {
|
function createFoldGroup(msgs) {
|
||||||
// Filter out PART → JOIN pairs
|
// Filter out PART → JOIN pairs
|
||||||
var partIndexes = new Map();
|
let partIndexes = new Map();
|
||||||
var keep = [];
|
let keep = [];
|
||||||
msgs.forEach((msg, i) => {
|
msgs.forEach((msg, i) => {
|
||||||
if (msg.command === "PART" || msg.command === "QUIT") {
|
if (msg.command === "PART" || msg.command === "QUIT") {
|
||||||
partIndexes.set(msg.prefix.name, i);
|
partIndexes.set(msg.prefix.name, i);
|
||||||
@ -452,18 +452,18 @@ export default class Buffer extends Component {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasUnreadSeparator = false;
|
let hasUnreadSeparator = false;
|
||||||
var prevDate = new Date();
|
let prevDate = new Date();
|
||||||
var foldMessages = [];
|
let foldMessages = [];
|
||||||
buf.messages.forEach((msg) => {
|
buf.messages.forEach((msg) => {
|
||||||
var sep = [];
|
let sep = [];
|
||||||
|
|
||||||
if (!hasUnreadSeparator && buf.type != BufferType.SERVER && buf.lastReadReceipt && msg.tags.time > buf.lastReadReceipt.time) {
|
if (!hasUnreadSeparator && buf.type != BufferType.SERVER && buf.lastReadReceipt && msg.tags.time > buf.lastReadReceipt.time) {
|
||||||
sep.push(html`<${UnreadSeparator} key="unread"/>`);
|
sep.push(html`<${UnreadSeparator} key="unread"/>`);
|
||||||
hasUnreadSeparator = true;
|
hasUnreadSeparator = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var date = new Date(msg.tags.time);
|
let date = new Date(msg.tags.time);
|
||||||
if (!sameDate(prevDate, date)) {
|
if (!sameDate(prevDate, date)) {
|
||||||
sep.push(html`<${DateSeparator} key=${"date-" + date} date=${date}/>`);
|
sep.push(html`<${DateSeparator} key=${"date-" + date} date=${date}/>`);
|
||||||
}
|
}
|
||||||
|
@ -34,21 +34,21 @@ export default class Composer extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var text = this.state.text;
|
let text = this.state.text;
|
||||||
var i;
|
let i;
|
||||||
for (i = text.length - 1; i >= 0; i--) {
|
for (i = text.length - 1; i >= 0; i--) {
|
||||||
if (text[i] === " ") {
|
if (text[i] === " ") {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var prefix = text.slice(i + 1);
|
let prefix = text.slice(i + 1);
|
||||||
if (!prefix) {
|
if (!prefix) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
var repl = this.props.autocomplete(prefix);
|
let repl = this.props.autocomplete(prefix);
|
||||||
if (!repl) {
|
if (!repl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,8 @@ export default class ConnectForm extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleChange(event) {
|
handleChange(event) {
|
||||||
var target = event.target;
|
let target = event.target;
|
||||||
var value = target.type == "checkbox" ? target.checked : target.value;
|
let value = target.type == "checkbox" ? target.checked : target.value;
|
||||||
this.setState({ [target.name]: value });
|
this.setState({ [target.name]: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ export default class ConnectForm extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var params = {
|
let params = {
|
||||||
url: this.state.url,
|
url: this.state.url,
|
||||||
pass: this.state.pass,
|
pass: this.state.pass,
|
||||||
nick: this.state.nick,
|
nick: this.state.nick,
|
||||||
@ -74,9 +74,9 @@ export default class ConnectForm extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var disabled = this.props.connecting;
|
let disabled = this.props.connecting;
|
||||||
|
|
||||||
var serverURL = null;
|
let serverURL = null;
|
||||||
if (!this.props.params || !this.props.params.url) {
|
if (!this.props.params || !this.props.params.url) {
|
||||||
serverURL = html`
|
serverURL = html`
|
||||||
<label>
|
<label>
|
||||||
@ -87,7 +87,7 @@ export default class ConnectForm extends Component {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var status = null;
|
let status = null;
|
||||||
if (this.props.connecting) {
|
if (this.props.connecting) {
|
||||||
status = html`
|
status = html`
|
||||||
<p>Connecting...</p>
|
<p>Connecting...</p>
|
||||||
@ -98,7 +98,7 @@ export default class ConnectForm extends Component {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var auth = null;
|
let auth = null;
|
||||||
if (this.props.auth !== "disabled") {
|
if (this.props.auth !== "disabled") {
|
||||||
auth = html`
|
auth = html`
|
||||||
<label>
|
<label>
|
||||||
|
@ -35,7 +35,7 @@ export default class Dialog extends Component {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.addEventListener("keydown", this.handleKeyDown);
|
window.addEventListener("keydown", this.handleKeyDown);
|
||||||
|
|
||||||
var autofocus = this.body.current.querySelector("input[autofocus]");
|
let autofocus = this.body.current.querySelector("input[autofocus]");
|
||||||
if (autofocus) {
|
if (autofocus) {
|
||||||
autofocus.focus();
|
autofocus.focus();
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ import { keybindings } from "../keybindings.js";
|
|||||||
import commands from "../commands.js";
|
import commands from "../commands.js";
|
||||||
|
|
||||||
function KeyBindingsHelp() {
|
function KeyBindingsHelp() {
|
||||||
var l = keybindings.map((binding) => {
|
let l = keybindings.map((binding) => {
|
||||||
var keys = [];
|
let keys = [];
|
||||||
if (binding.ctrlKey) {
|
if (binding.ctrlKey) {
|
||||||
keys.psuh("Ctrl");
|
keys.psuh("Ctrl");
|
||||||
}
|
}
|
||||||
@ -37,10 +37,10 @@ function KeyBindingsHelp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function CommandsHelp() {
|
function CommandsHelp() {
|
||||||
var l = Object.keys(commands).map((name) => {
|
let l = Object.keys(commands).map((name) => {
|
||||||
var cmd = commands[name];
|
let cmd = commands[name];
|
||||||
|
|
||||||
var usage = "/" + name;
|
let usage = "/" + name;
|
||||||
if (cmd.usage) {
|
if (cmd.usage) {
|
||||||
usage += " " + cmd.usage;
|
usage += " " + cmd.usage;
|
||||||
}
|
}
|
||||||
|
@ -13,15 +13,15 @@ export default class JoinForm extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleChange(event) {
|
handleChange(event) {
|
||||||
var target = event.target;
|
let target = event.target;
|
||||||
var value = target.type == "checkbox" ? target.checked : target.value;
|
let value = target.type == "checkbox" ? target.checked : target.value;
|
||||||
this.setState({ [target.name]: value });
|
this.setState({ [target.name]: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(event) {
|
handleSubmit(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
var params = {
|
let params = {
|
||||||
channel: this.state.channel,
|
channel: this.state.channel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,10 +50,10 @@ class MemberItem extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sortMembers(a, b) {
|
function sortMembers(a, b) {
|
||||||
var [nickA, membA] = a, [nickB, membB] = b;
|
let [nickA, membA] = a, [nickB, membB] = b;
|
||||||
|
|
||||||
const prefixPrivs = ["~", "&", "@", "%", "+"]; // TODO: grab it from ISUPPORT PREFIX
|
const prefixPrivs = ["~", "&", "@", "%", "+"]; // TODO: grab it from ISUPPORT PREFIX
|
||||||
var i = prefixPrivs.indexOf(membA[0]), j = prefixPrivs.indexOf(membB[0]);
|
let i = prefixPrivs.indexOf(membA[0]), j = prefixPrivs.indexOf(membB[0]);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
i = prefixPrivs.length;
|
i = prefixPrivs.length;
|
||||||
}
|
}
|
||||||
|
@ -38,15 +38,15 @@ export default class NetworkForm extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleChange(event) {
|
handleChange(event) {
|
||||||
var target = event.target;
|
let target = event.target;
|
||||||
var value = target.type == "checkbox" ? target.checked : target.value;
|
let value = target.type == "checkbox" ? target.checked : target.value;
|
||||||
this.setState({ [target.name]: value });
|
this.setState({ [target.name]: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(event) {
|
handleSubmit(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
var params = {};
|
let params = {};
|
||||||
Object.keys(defaultParams).forEach((k) => {
|
Object.keys(defaultParams).forEach((k) => {
|
||||||
if (this.prevParams[k] == this.state[k]) {
|
if (this.prevParams[k] == this.state[k]) {
|
||||||
return;
|
return;
|
||||||
@ -58,7 +58,7 @@ export default class NetworkForm extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var removeNetwork = null;
|
let removeNetwork = null;
|
||||||
if (!this.state.isNew) {
|
if (!this.state.isNew) {
|
||||||
removeNetwork = html`
|
removeNetwork = html`
|
||||||
<button type="button" onClick=${() => this.props.onRemove()}>
|
<button type="button" onClick=${() => this.props.onRemove()}>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { html, Component } from "../lib/index.js";
|
import { html, Component } from "../lib/index.js";
|
||||||
|
|
||||||
var store = new Map();
|
let store = new Map();
|
||||||
|
|
||||||
export default class ScrollManager extends Component {
|
export default class ScrollManager extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -10,18 +10,18 @@ export default class ScrollManager extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isAtBottom() {
|
isAtBottom() {
|
||||||
var target = this.props.target.current;
|
let target = this.props.target.current;
|
||||||
return target.scrollTop >= target.scrollHeight - target.offsetHeight;
|
return target.scrollTop >= target.scrollHeight - target.offsetHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveScrollPosition() {
|
saveScrollPosition() {
|
||||||
var target = this.props.target.current;
|
let target = this.props.target.current;
|
||||||
|
|
||||||
var sticky = target.querySelectorAll(this.props.stickTo);
|
let sticky = target.querySelectorAll(this.props.stickTo);
|
||||||
var stickToKey = null;
|
let stickToKey = null;
|
||||||
if (!this.isAtBottom()) {
|
if (!this.isAtBottom()) {
|
||||||
for (var i = 0; i < sticky.length; i++) {
|
for (let i = 0; i < sticky.length; i++) {
|
||||||
var el = sticky[i];
|
let el = sticky[i];
|
||||||
if (el.offsetTop >= target.scrollTop + target.offsetTop) {
|
if (el.offsetTop >= target.scrollTop + target.offsetTop) {
|
||||||
stickToKey = el.dataset.key;
|
stickToKey = el.dataset.key;
|
||||||
break;
|
break;
|
||||||
@ -33,13 +33,13 @@ export default class ScrollManager extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
restoreScrollPosition() {
|
restoreScrollPosition() {
|
||||||
var target = this.props.target.current;
|
let target = this.props.target.current;
|
||||||
|
|
||||||
var stickToKey = store.get(this.props.scrollKey);
|
let stickToKey = store.get(this.props.scrollKey);
|
||||||
if (!stickToKey) {
|
if (!stickToKey) {
|
||||||
target.firstChild.scrollIntoView({ block: "end" });
|
target.firstChild.scrollIntoView({ block: "end" });
|
||||||
} else {
|
} else {
|
||||||
var stickTo = target.querySelector("[data-key=\"" + stickToKey + "\"]");
|
let stickTo = target.querySelector("[data-key=\"" + stickToKey + "\"]");
|
||||||
if (stickTo) {
|
if (stickTo) {
|
||||||
stickTo.scrollIntoView();
|
stickTo.scrollIntoView();
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { ReceiptType, Unread, BufferType, SERVER_BUFFER } from "./state.js";
|
import { ReceiptType, Unread, BufferType, SERVER_BUFFER } from "./state.js";
|
||||||
|
|
||||||
function getSiblingBuffer(buffers, bufID, delta) {
|
function getSiblingBuffer(buffers, bufID, delta) {
|
||||||
var bufList = Array.from(buffers.values());
|
let bufList = Array.from(buffers.values());
|
||||||
var i = bufList.findIndex((buf) => buf.id === bufID);
|
let i = bufList.findIndex((buf) => buf.id === bufID);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -17,10 +17,10 @@ export const keybindings = [
|
|||||||
description: "Mark all messages as read",
|
description: "Mark all messages as read",
|
||||||
execute: (app) => {
|
execute: (app) => {
|
||||||
app.setState((state) => {
|
app.setState((state) => {
|
||||||
var buffers = new Map();
|
let buffers = new Map();
|
||||||
state.buffers.forEach((buf) => {
|
state.buffers.forEach((buf) => {
|
||||||
if (buf.messages.length > 0) {
|
if (buf.messages.length > 0) {
|
||||||
var lastMsg = buf.messages[buf.messages.length - 1];
|
let lastMsg = buf.messages[buf.messages.length - 1];
|
||||||
app.setReceipt(buf.name, ReceiptType.READ, lastMsg);
|
app.setReceipt(buf.name, ReceiptType.READ, lastMsg);
|
||||||
}
|
}
|
||||||
buffers.set(buf.id, {
|
buffers.set(buf.id, {
|
||||||
@ -38,9 +38,9 @@ export const keybindings = [
|
|||||||
description: "Jump to next buffer with activity",
|
description: "Jump to next buffer with activity",
|
||||||
execute: (app) => {
|
execute: (app) => {
|
||||||
// TODO: order by age if same priority
|
// TODO: order by age if same priority
|
||||||
var firstServerBuffer = null;
|
let firstServerBuffer = null;
|
||||||
var target = null;
|
let target = null;
|
||||||
for (var buf of app.state.buffers.values()) {
|
for (let buf of app.state.buffers.values()) {
|
||||||
if (!firstServerBuffer && buf.type === BufferType.SERVER) {
|
if (!firstServerBuffer && buf.type === BufferType.SERVER) {
|
||||||
firstServerBuffer = buf;
|
firstServerBuffer = buf;
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ export const keybindings = [
|
|||||||
altKey: true,
|
altKey: true,
|
||||||
description: "Jump to the previous buffer",
|
description: "Jump to the previous buffer",
|
||||||
execute: (app) => {
|
execute: (app) => {
|
||||||
var prev = getSiblingBuffer(app.state.buffers, app.state.activeBuffer, -1);
|
let prev = getSiblingBuffer(app.state.buffers, app.state.activeBuffer, -1);
|
||||||
if (prev) {
|
if (prev) {
|
||||||
app.switchBuffer(prev);
|
app.switchBuffer(prev);
|
||||||
}
|
}
|
||||||
@ -77,7 +77,7 @@ export const keybindings = [
|
|||||||
altKey: true,
|
altKey: true,
|
||||||
description: "Jump to the next buffer",
|
description: "Jump to the next buffer",
|
||||||
execute: (app) => {
|
execute: (app) => {
|
||||||
var next = getSiblingBuffer(app.state.buffers, app.state.activeBuffer, 1);
|
let next = getSiblingBuffer(app.state.buffers, app.state.activeBuffer, 1);
|
||||||
if (next) {
|
if (next) {
|
||||||
app.switchBuffer(next);
|
app.switchBuffer(next);
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ export const keybindings = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export function setup(app) {
|
export function setup(app) {
|
||||||
var byKey = {};
|
let byKey = {};
|
||||||
keybindings.forEach((binding) => {
|
keybindings.forEach((binding) => {
|
||||||
if (!byKey[binding.key]) {
|
if (!byKey[binding.key]) {
|
||||||
byKey[binding.key] = [];
|
byKey[binding.key] = [];
|
||||||
@ -95,7 +95,7 @@ export function setup(app) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener("keydown", (event) => {
|
window.addEventListener("keydown", (event) => {
|
||||||
var candidates = byKey[event.key];
|
let candidates = byKey[event.key];
|
||||||
if (!candidates) {
|
if (!candidates) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,9 @@ function isDigit(ch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function strip(text) {
|
export function strip(text) {
|
||||||
var out = "";
|
let out = "";
|
||||||
for (var i = 0; i < text.length; i++) {
|
for (let i = 0; i < text.length; i++) {
|
||||||
var ch = text[i];
|
let ch = text[i];
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case BOLD:
|
case BOLD:
|
||||||
case ITALIC:
|
case ITALIC:
|
||||||
|
107
lib/client.js
107
lib/client.js
@ -21,7 +21,7 @@ const permanentCaps = [
|
|||||||
|
|
||||||
const RECONNECT_DELAY_SEC = 10;
|
const RECONNECT_DELAY_SEC = 10;
|
||||||
|
|
||||||
var lastLabel = 0;
|
let lastLabel = 0;
|
||||||
|
|
||||||
export default class Client extends EventTarget {
|
export default class Client extends EventTarget {
|
||||||
static Status = {
|
static Status = {
|
||||||
@ -65,7 +65,7 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reconnect() {
|
reconnect() {
|
||||||
var autoReconnect = this.autoReconnect;
|
let autoReconnect = this.autoReconnect;
|
||||||
this.disconnect();
|
this.disconnect();
|
||||||
this.autoReconnect = autoReconnect;
|
this.autoReconnect = autoReconnect;
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleMessage(event) {
|
handleMessage(event) {
|
||||||
var msg = irc.parseMessage(event.data);
|
let msg = irc.parseMessage(event.data);
|
||||||
console.debug("Received:", msg);
|
console.debug("Received:", msg);
|
||||||
|
|
||||||
// If the prefix is missing, assume it's coming from the server on the
|
// If the prefix is missing, assume it's coming from the server on the
|
||||||
@ -159,7 +159,7 @@ export default class Client extends EventTarget {
|
|||||||
msg.prefix = this.serverPrefix;
|
msg.prefix = this.serverPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
var msgBatch = null;
|
let msgBatch = null;
|
||||||
if (msg.tags["batch"]) {
|
if (msg.tags["batch"]) {
|
||||||
msgBatch = this.batches.get(msg.tags["batch"]);
|
msgBatch = this.batches.get(msg.tags["batch"]);
|
||||||
if (msgBatch) {
|
if (msgBatch) {
|
||||||
@ -167,7 +167,7 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var deleteBatch = null;
|
let deleteBatch = null;
|
||||||
switch (msg.command) {
|
switch (msg.command) {
|
||||||
case irc.RPL_WELCOME:
|
case irc.RPL_WELCOME:
|
||||||
if (this.params.saslPlain && this.availableCaps["sasl"] === undefined) {
|
if (this.params.saslPlain && this.availableCaps["sasl"] === undefined) {
|
||||||
@ -184,8 +184,8 @@ export default class Client extends EventTarget {
|
|||||||
this.setStatus(Client.Status.REGISTERED);
|
this.setStatus(Client.Status.REGISTERED);
|
||||||
break;
|
break;
|
||||||
case irc.RPL_ISUPPORT:
|
case irc.RPL_ISUPPORT:
|
||||||
var tokens = msg.params.slice(1, -1);
|
let tokens = msg.params.slice(1, -1);
|
||||||
var changed = irc.parseISUPPORT(tokens, this.isupport);
|
let changed = irc.parseISUPPORT(tokens, this.isupport);
|
||||||
if (changed.indexOf("CASEMAPPING") >= 0) {
|
if (changed.indexOf("CASEMAPPING") >= 0) {
|
||||||
this.setCaseMapping(this.isupport.get("CASEMAPPING"));
|
this.setCaseMapping(this.isupport.get("CASEMAPPING"));
|
||||||
}
|
}
|
||||||
@ -225,7 +225,7 @@ export default class Client extends EventTarget {
|
|||||||
case irc.RPL_WHOISIDLE:
|
case irc.RPL_WHOISIDLE:
|
||||||
case irc.RPL_WHOISCHANNELS:
|
case irc.RPL_WHOISCHANNELS:
|
||||||
case irc.RPL_ENDOFWHOIS:
|
case irc.RPL_ENDOFWHOIS:
|
||||||
var nick = msg.params[1];
|
let nick = msg.params[1];
|
||||||
if (!this.whoisDB.has(nick)) {
|
if (!this.whoisDB.has(nick)) {
|
||||||
this.whoisDB.set(nick, {});
|
this.whoisDB.set(nick, {});
|
||||||
}
|
}
|
||||||
@ -243,16 +243,16 @@ export default class Client extends EventTarget {
|
|||||||
this.send({ command: "PONG", params: [msg.params[0]] });
|
this.send({ command: "PONG", params: [msg.params[0]] });
|
||||||
break;
|
break;
|
||||||
case "NICK":
|
case "NICK":
|
||||||
var newNick = msg.params[0];
|
let newNick = msg.params[0];
|
||||||
if (msg.prefix.name == this.nick) {
|
if (msg.prefix.name == this.nick) {
|
||||||
this.nick = newNick;
|
this.nick = newNick;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "BATCH":
|
case "BATCH":
|
||||||
var enter = msg.params[0].startsWith("+");
|
let enter = msg.params[0].startsWith("+");
|
||||||
var name = msg.params[0].slice(1);
|
let name = msg.params[0].slice(1);
|
||||||
if (enter) {
|
if (enter) {
|
||||||
var batch = {
|
let batch = {
|
||||||
name,
|
name,
|
||||||
type: msg.params[1],
|
type: msg.params[1],
|
||||||
params: msg.params.slice(2),
|
params: msg.params.slice(2),
|
||||||
@ -302,8 +302,8 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
who(mask) {
|
who(mask) {
|
||||||
var msg = { command: "WHO", params: [mask] };
|
let msg = { command: "WHO", params: [mask] };
|
||||||
var l = [];
|
let l = [];
|
||||||
return this.roundtrip(msg, (msg) => {
|
return this.roundtrip(msg, (msg) => {
|
||||||
switch (msg.command) {
|
switch (msg.command) {
|
||||||
case irc.RPL_WHOREPLY:
|
case irc.RPL_WHOREPLY:
|
||||||
@ -320,18 +320,19 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
whois(target) {
|
whois(target) {
|
||||||
var targetCM = this.cm(target);
|
let targetCM = this.cm(target);
|
||||||
var msg = { command: "WHOIS", params: [target] };
|
let msg = { command: "WHOIS", params: [target] };
|
||||||
return this.roundtrip(msg, (msg) => {
|
return this.roundtrip(msg, (msg) => {
|
||||||
|
let nick;
|
||||||
switch (msg.command) {
|
switch (msg.command) {
|
||||||
case irc.RPL_ENDOFWHOIS:
|
case irc.RPL_ENDOFWHOIS:
|
||||||
var nick = msg.params[1];
|
nick = msg.params[1];
|
||||||
if (this.cm(nick) === targetCM) {
|
if (this.cm(nick) === targetCM) {
|
||||||
return this.whoisDB.get(nick);
|
return this.whoisDB.get(nick);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case irc.ERR_NOSUCHNICK:
|
case irc.ERR_NOSUCHNICK:
|
||||||
var nick = msg.params[1];
|
nick = msg.params[1];
|
||||||
if (this.cm(nick) === targetCM) {
|
if (this.cm(nick) === targetCM) {
|
||||||
throw msg;
|
throw msg;
|
||||||
}
|
}
|
||||||
@ -341,11 +342,11 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addAvailableCaps(s) {
|
addAvailableCaps(s) {
|
||||||
var l = s.split(" ");
|
let l = s.split(" ");
|
||||||
l.forEach((s) => {
|
l.forEach((s) => {
|
||||||
var parts = s.split("=");
|
let parts = s.split("=");
|
||||||
var k = parts[0].toLowerCase();
|
let k = parts[0].toLowerCase();
|
||||||
var v = "";
|
let v = "";
|
||||||
if (parts.length > 1) {
|
if (parts.length > 1) {
|
||||||
v = parts[1];
|
v = parts[1];
|
||||||
}
|
}
|
||||||
@ -354,7 +355,7 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
supportsSASL(mech) {
|
supportsSASL(mech) {
|
||||||
var saslCap = this.availableCaps["sasl"];
|
let saslCap = this.availableCaps["sasl"];
|
||||||
if (saslCap === undefined) {
|
if (saslCap === undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -362,7 +363,7 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
requestCaps(extra) {
|
requestCaps(extra) {
|
||||||
var reqCaps = extra || [];
|
let reqCaps = extra || [];
|
||||||
|
|
||||||
permanentCaps.forEach((cap) => {
|
permanentCaps.forEach((cap) => {
|
||||||
if (this.availableCaps[cap] !== undefined && !this.enabledCaps[cap]) {
|
if (this.availableCaps[cap] !== undefined && !this.enabledCaps[cap]) {
|
||||||
@ -376,16 +377,16 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleCap(msg) {
|
handleCap(msg) {
|
||||||
var subCmd = msg.params[1];
|
let subCmd = msg.params[1];
|
||||||
var args = msg.params.slice(2);
|
let args = msg.params.slice(2);
|
||||||
switch (subCmd) {
|
switch (subCmd) {
|
||||||
case "LS":
|
case "LS":
|
||||||
this.addAvailableCaps(args[args.length - 1]);
|
this.addAvailableCaps(args[args.length - 1]);
|
||||||
if (args[0] != "*") {
|
if (args[0] != "*") {
|
||||||
console.log("Available server caps:", this.availableCaps);
|
console.log("Available server caps:", this.availableCaps);
|
||||||
|
|
||||||
var reqCaps = [];
|
let reqCaps = [];
|
||||||
var capEnd = true;
|
let capEnd = true;
|
||||||
if (this.params.saslPlain && this.supportsSASL("PLAIN")) {
|
if (this.params.saslPlain && this.supportsSASL("PLAIN")) {
|
||||||
// CAP END is deferred after authentication finishes
|
// CAP END is deferred after authentication finishes
|
||||||
reqCaps.push("sasl");
|
reqCaps.push("sasl");
|
||||||
@ -438,7 +439,7 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleAuthenticate(msg) {
|
handleAuthenticate(msg) {
|
||||||
var challengeStr = msg.params[0];
|
let challengeStr = msg.params[0];
|
||||||
|
|
||||||
// For now only PLAIN is supported
|
// For now only PLAIN is supported
|
||||||
if (challengeStr != "+") {
|
if (challengeStr != "+") {
|
||||||
@ -447,7 +448,7 @@ export default class Client extends EventTarget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var respStr = btoa("\0" + this.params.saslPlain.username + "\0" + this.params.saslPlain.password);
|
let respStr = btoa("\0" + this.params.saslPlain.username + "\0" + this.params.saslPlain.password);
|
||||||
this.send({ command: "AUTHENTICATE", params: [respStr] });
|
this.send({ command: "AUTHENTICATE", params: [respStr] });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,7 +479,7 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isChannel(name) {
|
isChannel(name) {
|
||||||
var chanTypes = this.isupport.get("CHANTYPES") || irc.STD_CHANTYPES;
|
let chanTypes = this.isupport.get("CHANTYPES") || irc.STD_CHANTYPES;
|
||||||
return chanTypes.indexOf(name[0]) >= 0;
|
return chanTypes.indexOf(name[0]) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,7 +501,7 @@ export default class Client extends EventTarget {
|
|||||||
/* Execute a command that expects a response. `done` is called with message
|
/* Execute a command that expects a response. `done` is called with message
|
||||||
* events until it returns a truthy value. */
|
* events until it returns a truthy value. */
|
||||||
roundtrip(msg, done) {
|
roundtrip(msg, done) {
|
||||||
var label;
|
let label;
|
||||||
if (this.enabledCaps["labeled-response"]) {
|
if (this.enabledCaps["labeled-response"]) {
|
||||||
lastLabel++;
|
lastLabel++;
|
||||||
label = String(lastLabel);
|
label = String(lastLabel);
|
||||||
@ -508,15 +509,15 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var handleMessage = (event) => {
|
let handleMessage = (event) => {
|
||||||
var msg = event.detail.message;
|
let msg = event.detail.message;
|
||||||
|
|
||||||
var msgLabel = irc.getMessageLabel(msg);
|
let msgLabel = irc.getMessageLabel(msg);
|
||||||
if (msgLabel && msgLabel != label) {
|
if (msgLabel && msgLabel != label) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result;
|
let result;
|
||||||
try {
|
try {
|
||||||
result = done(msg);
|
result = done(msg);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -537,11 +538,11 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fetchBatch(msg, batchType) {
|
fetchBatch(msg, batchType) {
|
||||||
var batchName = null;
|
let batchName = null;
|
||||||
var messages = [];
|
let messages = [];
|
||||||
return this.roundtrip(msg, (msg) => {
|
return this.roundtrip(msg, (msg) => {
|
||||||
if (batchName) {
|
if (batchName) {
|
||||||
var batch = msg.batch;
|
let batch = msg.batch;
|
||||||
while (batch) {
|
while (batch) {
|
||||||
if (batch.name === batchName) {
|
if (batch.name === batchName) {
|
||||||
messages.push(msg);
|
messages.push(msg);
|
||||||
@ -553,8 +554,8 @@ export default class Client extends EventTarget {
|
|||||||
|
|
||||||
switch (msg.command) {
|
switch (msg.command) {
|
||||||
case "BATCH":
|
case "BATCH":
|
||||||
var enter = msg.params[0].startsWith("+");
|
let enter = msg.params[0].startsWith("+");
|
||||||
var name = msg.params[0].slice(1);
|
let name = msg.params[0].slice(1);
|
||||||
if (enter && msg.params[1] === batchType) {
|
if (enter && msg.params[1] === batchType) {
|
||||||
batchName = name;
|
batchName = name;
|
||||||
break;
|
break;
|
||||||
@ -576,7 +577,7 @@ export default class Client extends EventTarget {
|
|||||||
// Don't send multiple CHATHISTORY commands in parallel, we can't
|
// Don't send multiple CHATHISTORY commands in parallel, we can't
|
||||||
// properly handle batches and errors.
|
// properly handle batches and errors.
|
||||||
this.pendingHistory = this.pendingHistory.catch(() => {}).then(() => {
|
this.pendingHistory = this.pendingHistory.catch(() => {}).then(() => {
|
||||||
var msg = {
|
let msg = {
|
||||||
command: "CHATHISTORY",
|
command: "CHATHISTORY",
|
||||||
params,
|
params,
|
||||||
};
|
};
|
||||||
@ -587,7 +588,7 @@ export default class Client extends EventTarget {
|
|||||||
|
|
||||||
chatHistoryPageSize() {
|
chatHistoryPageSize() {
|
||||||
if (this.isupport.has("CHATHISTORY")) {
|
if (this.isupport.has("CHATHISTORY")) {
|
||||||
var pageSize = parseInt(this.isupport.get("CHATHISTORY"), 10);
|
let pageSize = parseInt(this.isupport.get("CHATHISTORY"), 10);
|
||||||
if (pageSize > 0) {
|
if (pageSize > 0) {
|
||||||
return pageSize;
|
return pageSize;
|
||||||
}
|
}
|
||||||
@ -597,8 +598,8 @@ export default class Client extends EventTarget {
|
|||||||
|
|
||||||
/* Fetch one page of history before the given date. */
|
/* Fetch one page of history before the given date. */
|
||||||
fetchHistoryBefore(target, before, limit) {
|
fetchHistoryBefore(target, before, limit) {
|
||||||
var max = Math.min(limit, this.chatHistoryPageSize());
|
let max = Math.min(limit, this.chatHistoryPageSize());
|
||||||
var params = ["BEFORE", target, "timestamp=" + before, max];
|
let params = ["BEFORE", target, "timestamp=" + before, max];
|
||||||
return this.roundtripChatHistory(params).then((messages) => {
|
return this.roundtripChatHistory(params).then((messages) => {
|
||||||
return { more: messages.length >= max };
|
return { more: messages.length >= max };
|
||||||
});
|
});
|
||||||
@ -606,8 +607,8 @@ export default class Client extends EventTarget {
|
|||||||
|
|
||||||
/* Fetch history in ascending order. */
|
/* Fetch history in ascending order. */
|
||||||
fetchHistoryBetween(target, after, before, limit) {
|
fetchHistoryBetween(target, after, before, limit) {
|
||||||
var max = Math.min(limit, this.chatHistoryPageSize());
|
let max = Math.min(limit, this.chatHistoryPageSize());
|
||||||
var params = ["AFTER", target, "timestamp=" + after.time, max];
|
let params = ["AFTER", target, "timestamp=" + after.time, max];
|
||||||
return this.roundtripChatHistory(params).then((messages) => {
|
return this.roundtripChatHistory(params).then((messages) => {
|
||||||
limit -= messages.length;
|
limit -= messages.length;
|
||||||
if (limit <= 0) {
|
if (limit <= 0) {
|
||||||
@ -623,7 +624,7 @@ export default class Client extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fetchHistoryTargets(t1, t2) {
|
fetchHistoryTargets(t1, t2) {
|
||||||
var msg = {
|
let msg = {
|
||||||
command: "CHATHISTORY",
|
command: "CHATHISTORY",
|
||||||
params: ["TARGETS", "timestamp=" + t1, "timestamp=" + t2, 1000],
|
params: ["TARGETS", "timestamp=" + t1, "timestamp=" + t2, 1000],
|
||||||
};
|
};
|
||||||
@ -645,13 +646,13 @@ export default class Client extends EventTarget {
|
|||||||
return Promise.reject(new Error("Server doesn't support the BOUNCER extension"));
|
return Promise.reject(new Error("Server doesn't support the BOUNCER extension"));
|
||||||
}
|
}
|
||||||
|
|
||||||
var req = { command: "BOUNCER", params: ["LISTNETWORKS"] };
|
let req = { command: "BOUNCER", params: ["LISTNETWORKS"] };
|
||||||
return this.fetchBatch(req, "soju.im/bouncer-networks").then((batch) => {
|
return this.fetchBatch(req, "soju.im/bouncer-networks").then((batch) => {
|
||||||
var networks = new Map();
|
let networks = new Map();
|
||||||
for (var msg of batch.messages) {
|
for (let msg of batch.messages) {
|
||||||
console.assert(msg.command === "BOUNCER" && msg.params[0] === "NETWORK");
|
console.assert(msg.command === "BOUNCER" && msg.params[0] === "NETWORK");
|
||||||
var id = msg.params[1];
|
let id = msg.params[1];
|
||||||
var params = irc.parseTags(msg.params[2]);
|
let params = irc.parseTags(msg.params[2]);
|
||||||
networks.set(id, params);
|
networks.set(id, params);
|
||||||
}
|
}
|
||||||
return networks;
|
return networks;
|
||||||
|
116
lib/irc.js
116
lib/irc.js
@ -71,14 +71,14 @@ function unescapeTag(s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function parseTags(s) {
|
export function parseTags(s) {
|
||||||
var tags = {};
|
let tags = {};
|
||||||
s.split(";").forEach((s) => {
|
s.split(";").forEach((s) => {
|
||||||
if (!s) {
|
if (!s) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var parts = s.split("=", 2);
|
let parts = s.split("=", 2);
|
||||||
var k = parts[0];
|
let k = parts[0];
|
||||||
var v = null;
|
let v = null;
|
||||||
if (parts.length == 2) {
|
if (parts.length == 2) {
|
||||||
v = unescapeTag(parts[1]);
|
v = unescapeTag(parts[1]);
|
||||||
if (v.endsWith("\\")) {
|
if (v.endsWith("\\")) {
|
||||||
@ -91,26 +91,26 @@ export function parseTags(s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function formatTags(tags) {
|
export function formatTags(tags) {
|
||||||
var l = [];
|
let l = [];
|
||||||
for (var k in tags) {
|
for (let k in tags) {
|
||||||
if (tags[k] === undefined || tags[k] === null) {
|
if (tags[k] === undefined || tags[k] === null) {
|
||||||
l.push(k);
|
l.push(k);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var v = escapeTag(tags[k]);
|
let v = escapeTag(tags[k]);
|
||||||
l.push(k + "=" + v);
|
l.push(k + "=" + v);
|
||||||
}
|
}
|
||||||
return l.join(";");
|
return l.join(";");
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePrefix(s) {
|
function parsePrefix(s) {
|
||||||
var prefix = {
|
let prefix = {
|
||||||
name: null,
|
name: null,
|
||||||
user: null,
|
user: null,
|
||||||
host: null,
|
host: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
var i = s.indexOf("@");
|
let i = s.indexOf("@");
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
prefix.name = s;
|
prefix.name = s;
|
||||||
return prefix;
|
return prefix;
|
||||||
@ -118,7 +118,7 @@ function parsePrefix(s) {
|
|||||||
prefix.host = s.slice(i + 1);
|
prefix.host = s.slice(i + 1);
|
||||||
s = s.slice(0, i);
|
s = s.slice(0, i);
|
||||||
|
|
||||||
var i = s.indexOf("!");
|
i = s.indexOf("!");
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
prefix.name = s;
|
prefix.name = s;
|
||||||
return prefix;
|
return prefix;
|
||||||
@ -143,7 +143,7 @@ export function parseMessage(s) {
|
|||||||
s = s.slice(0, s.length - 2);
|
s = s.slice(0, s.length - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
var msg = {
|
let msg = {
|
||||||
tags: {},
|
tags: {},
|
||||||
prefix: null,
|
prefix: null,
|
||||||
command: null,
|
command: null,
|
||||||
@ -151,7 +151,7 @@ export function parseMessage(s) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (s.startsWith("@")) {
|
if (s.startsWith("@")) {
|
||||||
var i = s.indexOf(" ");
|
let i = s.indexOf(" ");
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
throw new Error("expected a space after tags");
|
throw new Error("expected a space after tags");
|
||||||
}
|
}
|
||||||
@ -160,7 +160,7 @@ export function parseMessage(s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (s.startsWith(":")) {
|
if (s.startsWith(":")) {
|
||||||
var i = s.indexOf(" ");
|
let i = s.indexOf(" ");
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
throw new Error("expected a space after prefix");
|
throw new Error("expected a space after prefix");
|
||||||
}
|
}
|
||||||
@ -168,7 +168,7 @@ export function parseMessage(s) {
|
|||||||
s = s.slice(i + 1);
|
s = s.slice(i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var i = s.indexOf(" ");
|
let i = s.indexOf(" ");
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
msg.command = s;
|
msg.command = s;
|
||||||
return msg;
|
return msg;
|
||||||
@ -196,7 +196,7 @@ export function parseMessage(s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function formatMessage(msg) {
|
export function formatMessage(msg) {
|
||||||
var s = "";
|
let s = "";
|
||||||
if (msg.tags && Object.keys(msg.tags).length > 0) {
|
if (msg.tags && Object.keys(msg.tags).length > 0) {
|
||||||
s += "@" + formatTags(msg.tags) + " ";
|
s += "@" + formatTags(msg.tags) + " ";
|
||||||
}
|
}
|
||||||
@ -205,7 +205,7 @@ export function formatMessage(msg) {
|
|||||||
}
|
}
|
||||||
s += msg.command;
|
s += msg.command;
|
||||||
if (msg.params && msg.params.length > 0) {
|
if (msg.params && msg.params.length > 0) {
|
||||||
var last = msg.params[msg.params.length - 1];
|
let last = msg.params[msg.params.length - 1];
|
||||||
if (msg.params.length > 1) {
|
if (msg.params.length > 1) {
|
||||||
s += " " + msg.params.slice(0, -1).join(" ");
|
s += " " + msg.params.slice(0, -1).join(" ");
|
||||||
}
|
}
|
||||||
@ -217,7 +217,7 @@ export function formatMessage(msg) {
|
|||||||
|
|
||||||
/** Split a prefix and a name out of a target. */
|
/** Split a prefix and a name out of a target. */
|
||||||
export function parseTargetPrefix(s, allowedPrefixes = STD_MEMBERSHIPS) {
|
export function parseTargetPrefix(s, allowedPrefixes = STD_MEMBERSHIPS) {
|
||||||
var i;
|
let i;
|
||||||
for (i = 0; i < s.length; i++) {
|
for (i = 0; i < s.length; i++) {
|
||||||
if (allowedPrefixes.indexOf(s[i]) < 0) {
|
if (allowedPrefixes.indexOf(s[i]) < 0) {
|
||||||
break;
|
break;
|
||||||
@ -262,15 +262,15 @@ export function isHighlight(msg, nick, cm) {
|
|||||||
return false; // Our own messages aren't highlights
|
return false; // Our own messages aren't highlights
|
||||||
}
|
}
|
||||||
|
|
||||||
var text = cm(msg.params[1]);
|
let text = cm(msg.params[1]);
|
||||||
while (true) {
|
while (true) {
|
||||||
var i = text.indexOf(nick);
|
let i = text.indexOf(nick);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect word boundaries
|
// Detect word boundaries
|
||||||
var left = "\x00", right = "\x00";
|
let left = "\x00", right = "\x00";
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
left = text[i - 1];
|
left = text[i - 1];
|
||||||
}
|
}
|
||||||
@ -305,13 +305,13 @@ export function isError(cmd) {
|
|||||||
|
|
||||||
export function formatDate(date) {
|
export function formatDate(date) {
|
||||||
// ISO 8601
|
// ISO 8601
|
||||||
var YYYY = date.getUTCFullYear().toString().padStart(4, "0");
|
let YYYY = date.getUTCFullYear().toString().padStart(4, "0");
|
||||||
var MM = (date.getUTCMonth() + 1).toString().padStart(2, "0");
|
let MM = (date.getUTCMonth() + 1).toString().padStart(2, "0");
|
||||||
var DD = date.getUTCDate().toString().padStart(2, "0");
|
let DD = date.getUTCDate().toString().padStart(2, "0");
|
||||||
var hh = date.getUTCHours().toString().padStart(2, "0");
|
let hh = date.getUTCHours().toString().padStart(2, "0");
|
||||||
var mm = date.getUTCMinutes().toString().padStart(2, "0");
|
let mm = date.getUTCMinutes().toString().padStart(2, "0");
|
||||||
var ss = date.getUTCSeconds().toString().padStart(2, "0");
|
let ss = date.getUTCSeconds().toString().padStart(2, "0");
|
||||||
var sss = date.getUTCMilliseconds().toString().padStart(3, "0");
|
let sss = date.getUTCMilliseconds().toString().padStart(3, "0");
|
||||||
return `${YYYY}-${MM}-${DD}T${hh}:${mm}:${ss}.${sss}Z`;
|
return `${YYYY}-${MM}-${DD}T${hh}:${mm}:${ss}.${sss}Z`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ export function parseCTCP(msg) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var text = msg.params[1];
|
let text = msg.params[1];
|
||||||
if (!text.startsWith("\x01")) {
|
if (!text.startsWith("\x01")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -329,8 +329,8 @@ export function parseCTCP(msg) {
|
|||||||
text = text.slice(0, -1);
|
text = text.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var ctcp;
|
let ctcp;
|
||||||
var i = text.indexOf(" ");
|
let i = text.indexOf(" ");
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
ctcp = { command: text.slice(0, i), param: text.slice(i + 1) };
|
ctcp = { command: text.slice(0, i), param: text.slice(i + 1) };
|
||||||
} else {
|
} else {
|
||||||
@ -341,16 +341,16 @@ export function parseCTCP(msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function parseISUPPORT(tokens, params) {
|
export function parseISUPPORT(tokens, params) {
|
||||||
var changed = [];
|
let changed = [];
|
||||||
tokens.forEach((tok) => {
|
tokens.forEach((tok) => {
|
||||||
if (tok.startsWith("-")) {
|
if (tok.startsWith("-")) {
|
||||||
var k = tok.slice(1);
|
let k = tok.slice(1);
|
||||||
params.delete(k.toUpperCase());
|
params.delete(k.toUpperCase());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var i = tok.indexOf("=");
|
let i = tok.indexOf("=");
|
||||||
var k = tok, v = "";
|
let k = tok, v = "";
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
k = tok.slice(0, i);
|
k = tok.slice(0, i);
|
||||||
v = tok.slice(i + 1);
|
v = tok.slice(i + 1);
|
||||||
@ -366,9 +366,9 @@ export function parseISUPPORT(tokens, params) {
|
|||||||
|
|
||||||
export const CaseMapping = {
|
export const CaseMapping = {
|
||||||
ASCII(str) {
|
ASCII(str) {
|
||||||
var out = "";
|
let out = "";
|
||||||
for (var i = 0; i < str.length; i++) {
|
for (let i = 0; i < str.length; i++) {
|
||||||
var ch = str[i];
|
let ch = str[i];
|
||||||
if ("A" <= ch && ch <= "Z") {
|
if ("A" <= ch && ch <= "Z") {
|
||||||
ch = ch.toLowerCase();
|
ch = ch.toLowerCase();
|
||||||
}
|
}
|
||||||
@ -378,9 +378,9 @@ export const CaseMapping = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
RFC1459(str) {
|
RFC1459(str) {
|
||||||
var out = "";
|
let out = "";
|
||||||
for (var i = 0; i < str.length; i++) {
|
for (let i = 0; i < str.length; i++) {
|
||||||
var ch = str[i];
|
let ch = str[i];
|
||||||
if ("A" <= ch && ch <= "Z") {
|
if ("A" <= ch && ch <= "Z") {
|
||||||
ch = ch.toLowerCase();
|
ch = ch.toLowerCase();
|
||||||
} else if (ch == "{") {
|
} else if (ch == "{") {
|
||||||
@ -398,9 +398,9 @@ export const CaseMapping = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
RFC1459Strict(str) {
|
RFC1459Strict(str) {
|
||||||
var out = "";
|
let out = "";
|
||||||
for (var i = 0; i < str.length; i++) {
|
for (let i = 0; i < str.length; i++) {
|
||||||
var ch = str[i];
|
let ch = str[i];
|
||||||
if ("A" <= ch && ch <= "Z") {
|
if ("A" <= ch && ch <= "Z") {
|
||||||
ch = ch.toLowerCase();
|
ch = ch.toLowerCase();
|
||||||
} else if (ch == "{") {
|
} else if (ch == "{") {
|
||||||
@ -429,7 +429,7 @@ export const CaseMapping = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function createIterator(next) {
|
function createIterator(next) {
|
||||||
var it = { next };
|
let it = { next };
|
||||||
// Not defining this can lead to surprises when feeding the iterator
|
// Not defining this can lead to surprises when feeding the iterator
|
||||||
// to e.g. Array.from
|
// to e.g. Array.from
|
||||||
it[Symbol.iterator] = () => it;
|
it[Symbol.iterator] = () => it;
|
||||||
@ -438,7 +438,7 @@ function createIterator(next) {
|
|||||||
|
|
||||||
function mapIterator(it, f) {
|
function mapIterator(it, f) {
|
||||||
return createIterator(() => {
|
return createIterator(() => {
|
||||||
var { value, done } = it.next();
|
let { value, done } = it.next();
|
||||||
if (done) {
|
if (done) {
|
||||||
return { done: true };
|
return { done: true };
|
||||||
}
|
}
|
||||||
@ -464,7 +464,7 @@ export class CaseMapMap {
|
|||||||
this.map = new Map();
|
this.map = new Map();
|
||||||
|
|
||||||
if (iterable) {
|
if (iterable) {
|
||||||
for (var [key, value] of iterable) {
|
for (let [key, value] of iterable) {
|
||||||
this.set(key, value);
|
this.set(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -480,7 +480,7 @@ export class CaseMapMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get(key) {
|
get(key) {
|
||||||
var kv = this.map.get(this.caseMap(key));
|
let kv = this.map.get(this.caseMap(key));
|
||||||
if (kv) {
|
if (kv) {
|
||||||
return kv.value;
|
return kv.value;
|
||||||
}
|
}
|
||||||
@ -496,21 +496,21 @@ export class CaseMapMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entries() {
|
entries() {
|
||||||
var it = this.map.values();
|
let it = this.map.values();
|
||||||
return mapIterator(it, (kv) => {
|
return mapIterator(it, (kv) => {
|
||||||
return [kv.key, kv.value];
|
return [kv.key, kv.value];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
keys() {
|
keys() {
|
||||||
var it = this.map.values();
|
let it = this.map.values();
|
||||||
return mapIterator(it, (kv) => {
|
return mapIterator(it, (kv) => {
|
||||||
return kv.key;
|
return kv.key;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
values() {
|
values() {
|
||||||
var it = this.map.values();
|
let it = this.map.values();
|
||||||
return mapIterator(it, (kv) => {
|
return mapIterator(it, (kv) => {
|
||||||
return kv.value;
|
return kv.value;
|
||||||
});
|
});
|
||||||
@ -527,23 +527,23 @@ export function parseMembershipModes(str) {
|
|||||||
throw new Error("malformed ISUPPORT PREFIX value: expected opening parenthesis");
|
throw new Error("malformed ISUPPORT PREFIX value: expected opening parenthesis");
|
||||||
}
|
}
|
||||||
|
|
||||||
var sep = str.indexOf(")");
|
let sep = str.indexOf(")");
|
||||||
if (sep < 0) {
|
if (sep < 0) {
|
||||||
throw new Error("malformed ISUPPORT PREFIX value: expected closing parenthesis");
|
throw new Error("malformed ISUPPORT PREFIX value: expected closing parenthesis");
|
||||||
}
|
}
|
||||||
|
|
||||||
var n = str.length - sep - 1;
|
let n = str.length - sep - 1;
|
||||||
var memberships = [];
|
let memberships = [];
|
||||||
for (var i = 0; i < n; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
var mode = str[i + 1];
|
let mode = str[i + 1];
|
||||||
var prefix = str[sep + i + 1];
|
let prefix = str[sep + i + 1];
|
||||||
memberships.push({ mode, prefix });
|
memberships.push({ mode, prefix });
|
||||||
}
|
}
|
||||||
return memberships;
|
return memberships;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findBatchByType(msg, type) {
|
export function findBatchByType(msg, type) {
|
||||||
var batch = msg.batch;
|
let batch = msg.batch;
|
||||||
while (batch) {
|
while (batch) {
|
||||||
if (batch.type === type) {
|
if (batch.type === type) {
|
||||||
return batch;
|
return batch;
|
||||||
@ -558,7 +558,7 @@ export function getMessageLabel(msg) {
|
|||||||
return msg.tags.label;
|
return msg.tags.label;
|
||||||
}
|
}
|
||||||
|
|
||||||
var batch = msg.batch;
|
let batch = msg.batch;
|
||||||
while (batch) {
|
while (batch) {
|
||||||
if (batch.tags.label) {
|
if (batch.tags.label) {
|
||||||
return batch.tags.label;
|
return batch.tags.label;
|
||||||
|
@ -4,12 +4,12 @@ function linkifyChannel(text, transformChannel) {
|
|||||||
// Don't match punctuation at the end of the channel name
|
// Don't match punctuation at the end of the channel name
|
||||||
const channelRegex = /(?:^|\s)(#[^\s]+[^\s.?!…():;,])/gid;
|
const channelRegex = /(?:^|\s)(#[^\s]+[^\s.?!…():;,])/gid;
|
||||||
|
|
||||||
var children = [];
|
let children = [];
|
||||||
var match;
|
let match;
|
||||||
var last = 0;
|
let last = 0;
|
||||||
while ((match = channelRegex.exec(text)) !== null) {
|
while ((match = channelRegex.exec(text)) !== null) {
|
||||||
var channel = match[1];
|
let channel = match[1];
|
||||||
var [start, end] = match.indices[1];
|
let [start, end] = match.indices[1];
|
||||||
|
|
||||||
children.push(text.substring(last, start));
|
children.push(text.substring(last, start));
|
||||||
children.push(transformChannel(channel));
|
children.push(transformChannel(channel));
|
||||||
@ -34,20 +34,20 @@ export default function linkify(text, onChannelClick) {
|
|||||||
>${channel}</a>`;
|
>${channel}</a>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var links = anchorme.list(text);
|
let links = anchorme.list(text);
|
||||||
|
|
||||||
var children = [];
|
let children = [];
|
||||||
var last = 0;
|
let last = 0;
|
||||||
links.forEach((match) => {
|
links.forEach((match) => {
|
||||||
const prefix = text.substring(last, match.start)
|
const prefix = text.substring(last, match.start)
|
||||||
children.push(...linkifyChannel(prefix, transformChannel));
|
children.push(...linkifyChannel(prefix, transformChannel));
|
||||||
|
|
||||||
var proto = match.protocol || "https://";
|
let proto = match.protocol || "https://";
|
||||||
if (match.isEmail) {
|
if (match.isEmail) {
|
||||||
proto = "mailto:";
|
proto = "mailto:";
|
||||||
}
|
}
|
||||||
|
|
||||||
var url = match.string;
|
let url = match.string;
|
||||||
if (!url.startsWith(proto)) {
|
if (!url.startsWith(proto)) {
|
||||||
url = proto + url;
|
url = proto + url;
|
||||||
}
|
}
|
||||||
|
111
state.js
111
state.js
@ -55,7 +55,7 @@ export function getBufferURL(buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getMessageURL(buf, msg) {
|
export function getMessageURL(buf, msg) {
|
||||||
var bufURL = getBufferURL(buf);
|
let bufURL = getBufferURL(buf);
|
||||||
if (msg.tags.msgid) {
|
if (msg.tags.msgid) {
|
||||||
return bufURL + "?msgid=" + encodeURIComponent(msg.tags.msgid);
|
return bufURL + "?msgid=" + encodeURIComponent(msg.tags.msgid);
|
||||||
} else {
|
} else {
|
||||||
@ -71,7 +71,7 @@ export function getServerName(server, bouncerNetwork, isBouncer) {
|
|||||||
return "bouncer";
|
return "bouncer";
|
||||||
}
|
}
|
||||||
|
|
||||||
var netName = server.isupport.get("NETWORK");
|
let netName = server.isupport.get("NETWORK");
|
||||||
if (netName) {
|
if (netName) {
|
||||||
return netName;
|
return netName;
|
||||||
}
|
}
|
||||||
@ -80,7 +80,7 @@ export function getServerName(server, bouncerNetwork, isBouncer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateState(state, updater) {
|
function updateState(state, updater) {
|
||||||
var updated;
|
let updated;
|
||||||
if (typeof updater === "function") {
|
if (typeof updater === "function") {
|
||||||
updated = updater(state, state);
|
updated = updater(state, state);
|
||||||
} else {
|
} else {
|
||||||
@ -119,9 +119,9 @@ function insertMessage(list, msg) {
|
|||||||
return list.concat(msg);
|
return list.concat(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
var insertBefore = -1;
|
let insertBefore = -1;
|
||||||
for (var i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
var other = list[i];
|
let other = list[i];
|
||||||
if (msg.tags.time < other.tags.time) {
|
if (msg.tags.time < other.tags.time) {
|
||||||
insertBefore = i;
|
insertBefore = i;
|
||||||
break;
|
break;
|
||||||
@ -134,42 +134,42 @@ function insertMessage(list, msg) {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastServerID = 0;
|
let lastServerID = 0;
|
||||||
var lastBufferID = 0;
|
let lastBufferID = 0;
|
||||||
|
|
||||||
export const State = {
|
export const State = {
|
||||||
updateServer(state, id, updater) {
|
updateServer(state, id, updater) {
|
||||||
var server = state.servers.get(id);
|
let server = state.servers.get(id);
|
||||||
if (!server) {
|
if (!server) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var updated = updateState(server, updater);
|
let updated = updateState(server, updater);
|
||||||
if (!updated) {
|
if (!updated) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var servers = new Map(state.servers);
|
let servers = new Map(state.servers);
|
||||||
servers.set(id, updated);
|
servers.set(id, updated);
|
||||||
return { servers };
|
return { servers };
|
||||||
},
|
},
|
||||||
updateBuffer(state, id, updater) {
|
updateBuffer(state, id, updater) {
|
||||||
var buf = State.getBuffer(state, id);
|
let buf = State.getBuffer(state, id);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var updated = updateState(buf, updater);
|
let updated = updateState(buf, updater);
|
||||||
if (!updated) {
|
if (!updated) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffers = new Map(state.buffers);
|
let buffers = new Map(state.buffers);
|
||||||
buffers.set(buf.id, updated);
|
buffers.set(buf.id, updated);
|
||||||
return { buffers };
|
return { buffers };
|
||||||
},
|
},
|
||||||
getActiveServerID(state) {
|
getActiveServerID(state) {
|
||||||
var buf = state.buffers.get(state.activeBuffer);
|
let buf = state.buffers.get(state.activeBuffer);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -184,7 +184,7 @@ export const State = {
|
|||||||
return state.buffers.get(id.id);
|
return state.buffers.get(id.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
var serverID = id.server, name = id.name;
|
let serverID = id.server, name = id.name;
|
||||||
if (!serverID) {
|
if (!serverID) {
|
||||||
serverID = State.getActiveServerID(state);
|
serverID = State.getActiveServerID(state);
|
||||||
}
|
}
|
||||||
@ -192,14 +192,14 @@ export const State = {
|
|||||||
name = SERVER_BUFFER;
|
name = SERVER_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cm = irc.CaseMapping.RFC1459;
|
let cm = irc.CaseMapping.RFC1459;
|
||||||
var server = state.servers.get(serverID);
|
let server = state.servers.get(serverID);
|
||||||
if (server) {
|
if (server) {
|
||||||
cm = irc.CaseMapping.byName(server.isupport.get("CASEMAPPING")) || cm;
|
cm = irc.CaseMapping.byName(server.isupport.get("CASEMAPPING")) || cm;
|
||||||
}
|
}
|
||||||
|
|
||||||
var nameCM = cm(name);
|
let nameCM = cm(name);
|
||||||
for (var buf of state.buffers.values()) {
|
for (let buf of state.buffers.values()) {
|
||||||
if (buf.server === serverID && cm(buf.name) === nameCM) {
|
if (buf.server === serverID && cm(buf.name) === nameCM) {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
@ -211,9 +211,9 @@ export const State = {
|
|||||||
},
|
},
|
||||||
createServer(state) {
|
createServer(state) {
|
||||||
lastServerID++;
|
lastServerID++;
|
||||||
var id = lastServerID;
|
let id = lastServerID;
|
||||||
|
|
||||||
var servers = new Map(state.servers);
|
let servers = new Map(state.servers);
|
||||||
servers.set(id, {
|
servers.set(id, {
|
||||||
id,
|
id,
|
||||||
status: ServerStatus.DISCONNECTED,
|
status: ServerStatus.DISCONNECTED,
|
||||||
@ -222,15 +222,15 @@ export const State = {
|
|||||||
return [id, { servers }];
|
return [id, { servers }];
|
||||||
},
|
},
|
||||||
createBuffer(state, name, serverID, client) {
|
createBuffer(state, name, serverID, client) {
|
||||||
var buf = State.getBuffer(state, { server: serverID, name });
|
let buf = State.getBuffer(state, { server: serverID, name });
|
||||||
if (buf) {
|
if (buf) {
|
||||||
return [buf.id, null];
|
return [buf.id, null];
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBufferID++;
|
lastBufferID++;
|
||||||
var id = lastBufferID;
|
let id = lastBufferID;
|
||||||
|
|
||||||
var type;
|
let type;
|
||||||
if (name == SERVER_BUFFER) {
|
if (name == SERVER_BUFFER) {
|
||||||
type = BufferType.SERVER;
|
type = BufferType.SERVER;
|
||||||
} else if (client.isChannel(name)) {
|
} else if (client.isChannel(name)) {
|
||||||
@ -239,7 +239,7 @@ export const State = {
|
|||||||
type = BufferType.NICK;
|
type = BufferType.NICK;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bufferList = Array.from(state.buffers.values());
|
let bufferList = Array.from(state.buffers.values());
|
||||||
bufferList.push({
|
bufferList.push({
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
@ -254,7 +254,7 @@ export const State = {
|
|||||||
unread: Unread.NONE,
|
unread: Unread.NONE,
|
||||||
});
|
});
|
||||||
bufferList = bufferList.sort(compareBuffers);
|
bufferList = bufferList.sort(compareBuffers);
|
||||||
var buffers = new Map(bufferList.map((buf) => [buf.id, buf]));
|
let buffers = new Map(bufferList.map((buf) => [buf.id, buf]));
|
||||||
return [id, { buffers }];
|
return [id, { buffers }];
|
||||||
},
|
},
|
||||||
handleMessage(state, msg, serverID, client) {
|
handleMessage(state, msg, serverID, client) {
|
||||||
@ -270,21 +270,22 @@ export const State = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let channel, topic;
|
||||||
switch (msg.command) {
|
switch (msg.command) {
|
||||||
case irc.RPL_MYINFO:
|
case irc.RPL_MYINFO:
|
||||||
// TODO: parse available modes
|
// TODO: parse available modes
|
||||||
var serverInfo = {
|
let serverInfo = {
|
||||||
name: msg.params[1],
|
name: msg.params[1],
|
||||||
version: msg.params[2],
|
version: msg.params[2],
|
||||||
};
|
};
|
||||||
return updateBuffer(SERVER_BUFFER, { serverInfo });
|
return updateBuffer(SERVER_BUFFER, { serverInfo });
|
||||||
case irc.RPL_ISUPPORT:
|
case irc.RPL_ISUPPORT:
|
||||||
var buffers = new Map(state.buffers);
|
let buffers = new Map(state.buffers);
|
||||||
state.buffers.forEach((buf) => {
|
state.buffers.forEach((buf) => {
|
||||||
if (buf.server != serverID) {
|
if (buf.server != serverID) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var members = new irc.CaseMapMap(buf.members, client.cm);
|
let members = new irc.CaseMapMap(buf.members, client.cm);
|
||||||
buffers.set(buf.id, { ...buf, members });
|
buffers.set(buf.id, { ...buf, members });
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
@ -292,23 +293,23 @@ export const State = {
|
|||||||
...updateServer({ isupport: new Map(client.isupport) }),
|
...updateServer({ isupport: new Map(client.isupport) }),
|
||||||
};
|
};
|
||||||
case irc.RPL_NOTOPIC:
|
case irc.RPL_NOTOPIC:
|
||||||
var channel = msg.params[1];
|
channel = msg.params[1];
|
||||||
return updateBuffer(channel, { topic: null });
|
return updateBuffer(channel, { topic: null });
|
||||||
case irc.RPL_TOPIC:
|
case irc.RPL_TOPIC:
|
||||||
var channel = msg.params[1];
|
channel = msg.params[1];
|
||||||
var topic = msg.params[2];
|
topic = msg.params[2];
|
||||||
return updateBuffer(channel, { topic });
|
return updateBuffer(channel, { topic });
|
||||||
case irc.RPL_TOPICWHOTIME:
|
case irc.RPL_TOPICWHOTIME:
|
||||||
// Ignore
|
// Ignore
|
||||||
break;
|
break;
|
||||||
case irc.RPL_NAMREPLY:
|
case irc.RPL_NAMREPLY:
|
||||||
var channel = msg.params[2];
|
channel = msg.params[2];
|
||||||
var membersList = msg.params[3].split(" ");
|
let membersList = msg.params[3].split(" ");
|
||||||
|
|
||||||
return updateBuffer(channel, (buf) => {
|
return updateBuffer(channel, (buf) => {
|
||||||
var members = new irc.CaseMapMap(buf.members);
|
let members = new irc.CaseMapMap(buf.members);
|
||||||
membersList.forEach((s) => {
|
membersList.forEach((s) => {
|
||||||
var member = irc.parseTargetPrefix(s);
|
let member = irc.parseTargetPrefix(s);
|
||||||
members.set(member.name, member.prefix);
|
members.set(member.name, member.prefix);
|
||||||
});
|
});
|
||||||
return { members };
|
return { members };
|
||||||
@ -316,8 +317,8 @@ export const State = {
|
|||||||
case irc.RPL_ENDOFNAMES:
|
case irc.RPL_ENDOFNAMES:
|
||||||
break;
|
break;
|
||||||
case irc.RPL_WHOREPLY:
|
case irc.RPL_WHOREPLY:
|
||||||
var last = msg.params[msg.params.length - 1];
|
let last = msg.params[msg.params.length - 1];
|
||||||
var who = {
|
let who = {
|
||||||
username: msg.params[2],
|
username: msg.params[2],
|
||||||
hostname: msg.params[3],
|
hostname: msg.params[3],
|
||||||
server: msg.params[4],
|
server: msg.params[4],
|
||||||
@ -327,7 +328,7 @@ export const State = {
|
|||||||
};
|
};
|
||||||
return updateBuffer(who.nick, { who, offline: false });
|
return updateBuffer(who.nick, { who, offline: false });
|
||||||
case irc.RPL_ENDOFWHO:
|
case irc.RPL_ENDOFWHO:
|
||||||
var target = msg.params[1];
|
let target = msg.params[1];
|
||||||
if (!client.isChannel(target) && target.indexOf("*") < 0) {
|
if (!client.isChannel(target) && target.indexOf("*") < 0) {
|
||||||
// Not a channel nor a mask, likely a nick
|
// Not a channel nor a mask, likely a nick
|
||||||
return updateBuffer(target, (buf) => {
|
return updateBuffer(target, (buf) => {
|
||||||
@ -341,57 +342,57 @@ export const State = {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "JOIN":
|
case "JOIN":
|
||||||
var channel = msg.params[0];
|
channel = msg.params[0];
|
||||||
|
|
||||||
if (client.isMyNick(msg.prefix.name)) {
|
if (client.isMyNick(msg.prefix.name)) {
|
||||||
var [id, update] = State.createBuffer(state, channel, serverID, client);
|
let [id, update] = State.createBuffer(state, channel, serverID, client);
|
||||||
state = { ...state, ...update };
|
state = { ...state, ...update };
|
||||||
}
|
}
|
||||||
|
|
||||||
var update = updateBuffer(channel, (buf) => {
|
let update = updateBuffer(channel, (buf) => {
|
||||||
var members = new irc.CaseMapMap(buf.members);
|
let members = new irc.CaseMapMap(buf.members);
|
||||||
members.set(msg.prefix.name, "");
|
members.set(msg.prefix.name, "");
|
||||||
return { members };
|
return { members };
|
||||||
});
|
});
|
||||||
return { ...state, ...update };
|
return { ...state, ...update };
|
||||||
case "PART":
|
case "PART":
|
||||||
var channel = msg.params[0];
|
channel = msg.params[0];
|
||||||
|
|
||||||
return updateBuffer(channel, (buf) => {
|
return updateBuffer(channel, (buf) => {
|
||||||
var members = new irc.CaseMapMap(buf.members);
|
let members = new irc.CaseMapMap(buf.members);
|
||||||
members.delete(msg.prefix.name);
|
members.delete(msg.prefix.name);
|
||||||
return { members };
|
return { members };
|
||||||
});
|
});
|
||||||
case "KICK":
|
case "KICK":
|
||||||
var channel = msg.params[0];
|
channel = msg.params[0];
|
||||||
var nick = msg.params[1];
|
let nick = msg.params[1];
|
||||||
|
|
||||||
return updateBuffer(channel, (buf) => {
|
return updateBuffer(channel, (buf) => {
|
||||||
var members = new irc.CaseMapMap(buf.members);
|
let members = new irc.CaseMapMap(buf.members);
|
||||||
members.delete(nick);
|
members.delete(nick);
|
||||||
return { members };
|
return { members };
|
||||||
});
|
});
|
||||||
case "SETNAME":
|
case "SETNAME":
|
||||||
return updateBuffer(msg.prefix.name, (buf) => {
|
return updateBuffer(msg.prefix.name, (buf) => {
|
||||||
var who = { ...buf.who, realname: msg.params[0] };
|
let who = { ...buf.who, realname: msg.params[0] };
|
||||||
return { who };
|
return { who };
|
||||||
});
|
});
|
||||||
case "AWAY":
|
case "AWAY":
|
||||||
var awayMessage = msg.params[0];
|
let awayMessage = msg.params[0];
|
||||||
|
|
||||||
return updateBuffer(msg.prefix.name, (buf) => {
|
return updateBuffer(msg.prefix.name, (buf) => {
|
||||||
var who = { ...buf.who, away: !!awayMessage };
|
let who = { ...buf.who, away: !!awayMessage };
|
||||||
return { who };
|
return { who };
|
||||||
});
|
});
|
||||||
case "TOPIC":
|
case "TOPIC":
|
||||||
var channel = msg.params[0];
|
channel = msg.params[0];
|
||||||
var topic = msg.params[1];
|
topic = msg.params[1];
|
||||||
return updateBuffer(channel, { topic });
|
return updateBuffer(channel, { topic });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addMessage(state, msg, bufID) {
|
addMessage(state, msg, bufID) {
|
||||||
return State.updateBuffer(state, bufID, (buf) => {
|
return State.updateBuffer(state, bufID, (buf) => {
|
||||||
var messages = insertMessage(buf.messages, msg);
|
let messages = insertMessage(buf.messages, msg);
|
||||||
return { messages };
|
return { messages };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
4
store.js
4
store.js
@ -15,7 +15,7 @@ class Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
load() {
|
load() {
|
||||||
var v = localStorage.getItem(this.k);
|
let v = localStorage.getItem(this.k);
|
||||||
if (!v) {
|
if (!v) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -37,7 +37,7 @@ const rawReceipts = new Item("receipts");
|
|||||||
|
|
||||||
export const receipts = {
|
export const receipts = {
|
||||||
load() {
|
load() {
|
||||||
var v = rawReceipts.load();
|
let v = rawReceipts.load();
|
||||||
return new Map(Object.entries(v || {}));
|
return new Map(Object.entries(v || {}));
|
||||||
},
|
},
|
||||||
put(m) {
|
put(m) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user