From 63a71e5f5d9eb8add38ebcbf9d08661434e2eacb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 3 Jun 2021 11:04:32 +0200 Subject: [PATCH] Add support for incoming INVITE messages --- components/app.js | 43 +++++++++++++++++++++++++++++++++++++++++-- components/buffer.js | 30 ++++++++++++++++++++++++++++-- lib/client.js | 1 + state.js | 6 +++++- 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/components/app.js b/components/app.js index e9c4122..c69b590 100644 --- a/components/app.js +++ b/components/app.js @@ -443,6 +443,7 @@ export default class App extends Component { if (this.hasReceipt(target, type, msg)) { return; } + // TODO: this doesn't trigger a redraw this.receipts.set(target, { ...this.receipts.get(target), [type]: { time: msg.tags.time }, @@ -514,6 +515,30 @@ export default class App extends Component { }); } } + if (msg.command === "INVITE" && client.isMyNick(msg.params[0])) { + msgUnread = Unread.HIGHLIGHT; + + var channel = msg.params[1]; + if (window.Notification && Notification.permission === "granted") { + var notif = new Notification("Invitation to " + channel, { + body: msg.prefix.name + " has invited you to " + channel, + requireInteraction: true, + actions: [{ + action: "accept", + title: "Accept", + }], + }); + notif.addEventListener("click", (event) => { + if (event.action === "accept") { + this.setReceipt(bufName, ReceiptType.READ, msg); + this.open(channel, netID); + } else { + // TODO: scroll to message + this.switchBuffer({ network: netID, name: bufName }); + } + }); + } + } if (!client.isMyNick(msg.prefix.name) && (msg.command != "PART" && msg.comand != "QUIT")) { this.createBuffer(netID, bufName); @@ -847,6 +872,17 @@ export default class App extends Component { this.setBufferState({ network: netID, name: channel }, { topic }); this.addMessage(netID, channel, msg); break; + case "INVITE": + var channel = msg.params[1]; + + // TODO: find a more reliable way to do this + var bufName = channel; + if (!getBuffer(this.state, { network: netID, name: channel })) { + bufName = SERVER_BUFFER; + } + + this.addMessage(netID, bufName, msg); + break; case "AWAY": var awayMessage = msg.params[0]; @@ -960,8 +996,11 @@ export default class App extends Component { }); } - open(target) { - var netID = getActiveNetworkID(this.state); + open(target, netID) { + if (!netID) { + netID = getActiveNetworkID(this.state); + } + var client = this.clients.get(netID); if (this.isChannel(target)) { diff --git a/components/buffer.js b/components/buffer.js index cc19f83..6efce30 100644 --- a/components/buffer.js +++ b/components/buffer.js @@ -2,7 +2,7 @@ import { html, Component } from "../lib/index.js"; import linkify from "../lib/linkify.js"; import * as irc from "../lib/irc.js"; import { strip as stripANSI } from "../lib/ansi.js"; -import { BufferType, getNickURL, getMessageURL } from "../state.js"; +import { BufferType, getNickURL, getChannelURL, getMessageURL } from "../state.js"; function djb2(s) { var hash = 5381; @@ -64,13 +64,24 @@ class LogLine extends Component { render() { var msg = this.props.message; - var onChannelClick = this.props.onChannelClick; var onNickClick = this.props.onNickClick; + var onChannelClick = this.props.onChannelClick; function createNick(nick) { return html` <${Nick} nick=${nick} onClick=${() => onNickClick(nick)}/> `; } + function createChannel(channel) { + function onClick(event) { + event.preventDefault(); + onChannelClick(channel); + } + return html` + + ${channel} + + `; + } var lineClass = ""; var content; @@ -139,6 +150,21 @@ class LogLine extends Component { ${createNick(msg.prefix.name)} changed the topic to: ${linkify(stripANSI(topic), onChannelClick)} `; break; + case "INVITE": + var invitee = msg.params[0]; + var channel = msg.params[1]; + // TODO: instead of checking buffer type, check if invitee is our nick + if (this.props.buffer.type === BufferType.SERVER) { + lineClass = "talk"; + content = html` + You have been invited to ${createChannel(channel)} by ${createNick(msg.prefix.name)} + `; + } else { + content = html` + ${createNick(msg.prefix.name)} has invited ${createNick(invitee)} to the channel + `; + } + break; case irc.RPL_MOTD: lineClass = "motd"; content = msg.params[1]; diff --git a/lib/client.js b/lib/client.js index fb95cc5..d24749a 100644 --- a/lib/client.js +++ b/lib/client.js @@ -6,6 +6,7 @@ const permanentCaps = [ "away-notify", "batch", "echo-message", + "invite-notify", "message-tags", "multi-prefix", "server-time", diff --git a/state.js b/state.js index 41fdac9..624acb6 100644 --- a/state.js +++ b/state.js @@ -37,12 +37,16 @@ export function getNickURL(nick) { return "irc:///" + encodeURIComponent(nick) + ",isuser"; } +export function getChannelURL(channel) { + return "irc:///" + encodeURIComponent(channel); +} + export function getBufferURL(buf) { switch (buf.type) { case BufferType.SERVER: return "irc:///"; case BufferType.CHANNEL: - return "irc:///" + encodeURIComponent(buf.name); + return getChannelURL(buf.name); case BufferType.NICK: return getNickURL(buf.name); }