Linkify channel names

This commit is contained in:
Tom Lebreux 2021-05-31 22:39:35 -04:00 committed by Simon Ser
parent 9affdb894f
commit 0bcd044f10
4 changed files with 62 additions and 8 deletions

@ -225,6 +225,7 @@ export default class App extends Component {
this.toggleBufferList = this.toggleBufferList.bind(this); this.toggleBufferList = this.toggleBufferList.bind(this);
this.toggleMemberList = this.toggleMemberList.bind(this); this.toggleMemberList = this.toggleMemberList.bind(this);
this.handleComposerSubmit = this.handleComposerSubmit.bind(this); this.handleComposerSubmit = this.handleComposerSubmit.bind(this);
this.handleChannelClick = this.handleChannelClick.bind(this);
this.handleNickClick = this.handleNickClick.bind(this); this.handleNickClick = this.handleNickClick.bind(this);
this.autocomplete = this.autocomplete.bind(this); this.autocomplete = this.autocomplete.bind(this);
this.handleBufferScrollTop = this.handleBufferScrollTop.bind(this); this.handleBufferScrollTop = this.handleBufferScrollTop.bind(this);
@ -908,6 +909,16 @@ export default class App extends Component {
this.connect(connectParams); this.connect(connectParams);
} }
handleChannelClick(channel) {
var netID = getActiveNetworkID(this.state);
var buf = getBuffer(this.state, { network: netID, name: channel });
if (buf) {
this.switchBuffer(buf.id);
} else {
this.open(channel);
}
}
handleNickClick(nick) { handleNickClick(nick) {
this.open(nick); this.open(nick);
} }
@ -1361,6 +1372,7 @@ export default class App extends Component {
network=${activeNetwork} network=${activeNetwork}
isBouncer=${isBouncer} isBouncer=${isBouncer}
bouncerNetwork=${activeBouncerNetwork} bouncerNetwork=${activeBouncerNetwork}
onChannelClick=${this.handleChannelClick}
onClose=${() => this.close(activeBuffer)} onClose=${() => this.close(activeBuffer)}
onJoin=${() => this.handleJoinClick(activeBuffer.network)} onJoin=${() => this.handleJoinClick(activeBuffer.network)}
onAddNetwork=${this.handleAddNetworkClick} onAddNetwork=${this.handleAddNetworkClick}
@ -1475,7 +1487,10 @@ export default class App extends Component {
onScrollTop=${this.handleBufferScrollTop} onScrollTop=${this.handleBufferScrollTop}
> >
<section id="buffer" ref=${this.buffer}> <section id="buffer" ref=${this.buffer}>
<${Buffer} buffer=${activeBuffer} onNickClick=${this.handleNickClick}/> <${Buffer}
buffer=${activeBuffer}
onChannelClick=${this.handleChannelClick}
onNickClick=${this.handleNickClick}/>
</section> </section>
</> </>
${memberList} ${memberList}

@ -114,7 +114,7 @@ export default function BufferHeader(props) {
break; break;
case BufferType.CHANNEL: case BufferType.CHANNEL:
if (props.buffer.topic) { if (props.buffer.topic) {
description = linkify(stripANSI(props.buffer.topic)); description = linkify(stripANSI(props.buffer.topic), props.onChannelClick);
} }
actions = html` actions = html`
<button <button

@ -64,6 +64,7 @@ class LogLine extends Component {
render() { render() {
var msg = this.props.message; var msg = this.props.message;
var onChannelClick = this.props.onChannelClick;
var onNickClick = this.props.onNickClick; var onNickClick = this.props.onNickClick;
function createNick(nick) { function createNick(nick) {
return html` return html`
@ -82,7 +83,7 @@ class LogLine extends Component {
if (ctcp) { if (ctcp) {
if (ctcp.command == "ACTION") { if (ctcp.command == "ACTION") {
lineClass = "me-tell"; lineClass = "me-tell";
content = html`* ${createNick(msg.prefix.name)} ${linkify(stripANSI(ctcp.param))}`; content = html`* ${createNick(msg.prefix.name)} ${linkify(stripANSI(ctcp.param), onChannelClick)}`;
} else { } else {
content = html` content = html`
${createNick(msg.prefix.name)} has sent a CTCP command: ${ctcp.command} ${ctcp.param} ${createNick(msg.prefix.name)} has sent a CTCP command: ${ctcp.command} ${ctcp.param}
@ -94,7 +95,7 @@ class LogLine extends Component {
if (msg.command == "NOTICE") { if (msg.command == "NOTICE") {
prefix = suffix = "-"; prefix = suffix = "-";
} }
content = html`${prefix}${createNick(msg.prefix.name)}${suffix} ${linkify(stripANSI(text))}`; content = html`${prefix}${createNick(msg.prefix.name)}${suffix} ${linkify(stripANSI(text), onChannelClick)}`;
} }
if (msg.isHighlight) { if (msg.isHighlight) {
@ -135,7 +136,7 @@ class LogLine extends Component {
case "TOPIC": case "TOPIC":
var topic = msg.params[1]; var topic = msg.params[1];
content = html` content = html`
${createNick(msg.prefix.name)} changed the topic to: ${linkify(stripANSI(topic))} ${createNick(msg.prefix.name)} changed the topic to: ${linkify(stripANSI(topic), onChannelClick)}
`; `;
break; break;
case irc.RPL_MOTD: case irc.RPL_MOTD:
@ -364,6 +365,7 @@ export default class Buffer extends Component {
children.push(html`<${NotificationNagger}/>`); children.push(html`<${NotificationNagger}/>`);
} }
var onChannelClick = this.props.onChannelClick;
var onNickClick = this.props.onNickClick; var onNickClick = this.props.onNickClick;
function createLogLine(msg) { function createLogLine(msg) {
return html` return html`
@ -371,6 +373,7 @@ export default class Buffer extends Component {
key=${"msg-" + msg.key} key=${"msg-" + msg.key}
message=${msg} message=${msg}
buffer=${buf} buffer=${buf}
onChannelClick=${onChannelClick}
onNickClick=${onNickClick} onNickClick=${onNickClick}
/> />
`; `;

@ -1,12 +1,46 @@
import { anchorme, html } from "./index.js"; import { anchorme, html } from "./index.js";
export default function linkify(text) { function linkifyChannel(text, transformChannel) {
var children = [];
// TODO: Don't match punctuation
const channelRegex = /(^|\s)(#[^\s]+)/gid;
let match;
var last = 0;
while ((match = channelRegex.exec(text)) !== null) {
const [_, spaces, channel] = match;
const start = match.index + spaces.length;
children.push(text.substring(last, start));
children.push(transformChannel(channel));
last = match.index + spaces.length + channel.length;
}
children.push(text.substring(last));
return children;
}
export default function linkify(text, onChannelClick) {
function transformChannel(channel) {
function onClick(event) {
event.preventDefault();
onChannelClick(channel);
}
return html`
<a
href="irc:///${encodeURIComponent(channel)}"
onClick=${onClick}
>${channel}</a>`;
}
var links = anchorme.list(text); var links = anchorme.list(text);
var children = []; var children = [];
var last = 0; var last = 0;
links.forEach((match) => { links.forEach((match) => {
children.push(text.substring(last, match.start)); const prefix = text.substring(last, match.start)
children.push(...linkifyChannel(prefix, transformChannel));
var proto = match.protocol || "https://"; var proto = match.protocol || "https://";
if (match.isEmail) { if (match.isEmail) {
@ -22,7 +56,9 @@ export default function linkify(text) {
last = match.end; last = match.end;
}); });
children.push(text.substring(last));
const suffix = text.substring(last)
children.push(...linkifyChannel(suffix, transformChannel));
return children; return children;
} }