gamja/components/buffer.js

180 lines
4.1 KiB
JavaScript
Raw Normal View History

import { html, Component } from "/lib/index.js";
2020-06-25 11:26:40 -04:00
import linkify from "/lib/linkify.js";
2020-06-29 08:29:31 -04:00
import * as irc from "/lib/irc.js";
2020-07-15 12:47:33 -04:00
import { BufferType, getNickURL, getMessageURL } from "/state.js";
function djb2(s) {
var hash = 5381;
for (var i = 0; i < s.length; i++) {
hash = (hash << 5) + hash + s.charCodeAt(i);
hash = hash >>> 0; // convert to uint32
}
return hash;
}
function Nick(props) {
function handleClick(event) {
event.preventDefault();
2020-06-25 12:45:41 -04:00
props.onClick();
}
var colorIndex = djb2(props.nick) % 16 + 1;
return html`
2020-07-15 12:47:33 -04:00
<a href=${getNickURL(props.nick)} class="nick nick-${colorIndex}" onClick=${handleClick}>${props.nick}</a>
`;
}
2020-07-15 12:47:33 -04:00
function Timestamp({ date, url }) {
if (!date) {
return html`<spam class="timestamp">--:--:--</span>`;
2020-06-25 12:45:41 -04:00
}
var hh = date.getHours().toString().padStart(2, "0");
var mm = date.getMinutes().toString().padStart(2, "0");
var ss = date.getSeconds().toString().padStart(2, "0");
var timestamp = `${hh}:${mm}:${ss}`;
return html`
2020-07-15 12:47:33 -04:00
<a href=${url} class="timestamp" onClick=${(event) => event.preventDefault()}>${timestamp}</a>
`;
}
class LogLine extends Component {
shouldComponentUpdate(nextProps) {
return this.props.message !== nextProps.message;
}
render() {
var msg = this.props.message;
function createNick(nick) {
return html`
<${Nick} nick=${nick} onClick=${() => props.onNickClick(nick)}/>
`;
}
var lineClass = "";
var content;
switch (msg.command) {
case "NOTICE":
case "PRIVMSG":
var text = msg.params[1];
var actionPrefix = "\x01ACTION ";
if (text.startsWith(actionPrefix) && text.endsWith("\x01")) {
var action = text.slice(actionPrefix.length, -1);
lineClass = "me-tell";
content = html`* ${createNick(msg.prefix.name)} ${linkify(action)}`;
} else {
lineClass = "talk";
content = html`${"<"}${createNick(msg.prefix.name)}${">"} ${linkify(text)}`;
}
break;
case "JOIN":
content = html`
${createNick(msg.prefix.name)} has joined
`;
break;
case "PART":
content = html`
${createNick(msg.prefix.name)} has left
`;
break;
case "QUIT":
content = html`
${createNick(msg.prefix.name)} has quit
`;
break;
case "NICK":
var newNick = msg.params[0];
content = html`
${createNick(msg.prefix.name)} is now known as ${createNick(newNick)}
`;
break;
case "TOPIC":
var topic = msg.params[1];
content = html`
${createNick(msg.prefix.name)} changed the topic to: ${linkify(topic)}
`;
break;
default:
if (irc.isError(msg.command) && msg.command != irc.ERR_NOMOTD) {
lineClass = "error";
}
content = html`${msg.command} ${msg.params.join(" ")}`;
2020-06-29 08:29:31 -04:00
}
return html`
<div class="logline ${lineClass}">
2020-07-15 12:47:33 -04:00
<${Timestamp} date=${new Date(msg.tags.time)} url=${getMessageURL(this.props.buffer, msg)}/>
${" "}
${content}
</div>
`;
}
}
2020-06-29 05:50:42 -04:00
class NotificationNagger extends Component {
state = { nag: false };
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state.nag = this.shouldNag();
}
shouldNag() {
return window.Notification && Notification.permission !== "granted" && Notification.permission !== "denied";
}
handleClick(event) {
event.preventDefault();
Notification.requestPermission((permission) => {
this.setState({ nag: this.shouldNag() });
});
}
render() {
if (!this.state.nag) {
return null;
}
return html`
<div class="logline">
<${Timestamp}/>
2020-06-29 05:50:42 -04:00
${" "}
<a href="#" onClick=${this.handleClick}>Turn on desktop notifications</a> to get notified about new messages
</div>
`;
}
}
export default class Buffer extends Component {
shouldComponentUpdate(nextProps) {
return this.props.buffer !== nextProps.buffer;
}
render() {
if (!this.props.buffer) {
return null;
}
var notifNagger = null;
if (this.props.buffer.type == BufferType.SERVER) {
notifNagger = html`<${NotificationNagger}/>`;
}
return html`
<div class="logline-list">
${notifNagger}
${this.props.buffer.messages.map((msg) => html`
2020-07-15 12:47:33 -04:00
<${LogLine} key=${msg.key} message=${msg} buffer=${this.props.buffer} onNickClick=${this.props.onNickClick}/>
`)}
</div>
`;
}
}