2021-03-02 16:46:48 -05:00
|
|
|
import { html, Component } from "../lib/index.js";
|
2021-09-21 08:29:31 -04:00
|
|
|
import { strip as stripANSI } from "../lib/ansi.js";
|
2021-06-11 05:18:29 -04:00
|
|
|
import Membership from "./membership.js";
|
2021-09-21 11:24:39 -04:00
|
|
|
import * as irc from "../lib/irc.js";
|
2020-06-26 08:32:56 -04:00
|
|
|
|
2020-07-13 05:09:16 -04:00
|
|
|
class MemberItem extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.handleClick = this.handleClick.bind(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
shouldComponentUpdate(nextProps) {
|
2021-05-28 11:45:27 -04:00
|
|
|
return this.props.nick !== nextProps.nick
|
2021-11-28 14:13:08 -05:00
|
|
|
|| this.props.membership !== nextProps.membership
|
|
|
|
|| this.props.user !== nextProps.user;
|
2020-07-13 05:09:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
handleClick(event) {
|
2020-06-26 08:32:56 -04:00
|
|
|
event.preventDefault();
|
2020-07-13 05:09:16 -04:00
|
|
|
this.props.onClick();
|
2020-06-26 08:32:56 -04:00
|
|
|
}
|
|
|
|
|
2020-07-13 05:09:16 -04:00
|
|
|
render() {
|
2024-02-20 16:50:09 -05:00
|
|
|
let title;
|
2021-09-21 08:19:30 -04:00
|
|
|
let user = this.props.user;
|
2021-11-28 14:09:48 -05:00
|
|
|
let classes = ["nick"];
|
2021-09-21 08:29:31 -04:00
|
|
|
if (user) {
|
|
|
|
let mask = "";
|
|
|
|
if (user.username && user.hostname) {
|
|
|
|
mask = `${user.username}@${user.hostname}`;
|
|
|
|
}
|
|
|
|
|
2021-09-21 11:24:39 -04:00
|
|
|
if (irc.isMeaningfulRealname(user.realname, this.props.nick)) {
|
2021-09-21 08:29:31 -04:00
|
|
|
title = stripANSI(user.realname);
|
|
|
|
if (mask) {
|
|
|
|
title = `${title} (${mask})`;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
title = mask;
|
|
|
|
}
|
2021-09-21 09:38:59 -04:00
|
|
|
|
|
|
|
if (user.account) {
|
|
|
|
title += `\nAuthenticated as ${user.account}`;
|
|
|
|
}
|
2021-11-28 14:09:48 -05:00
|
|
|
|
|
|
|
if (user.away) {
|
|
|
|
classes.push("away");
|
|
|
|
title += "\nAway";
|
|
|
|
}
|
2021-09-21 08:19:30 -04:00
|
|
|
}
|
|
|
|
|
2020-07-13 05:09:16 -04:00
|
|
|
return html`
|
|
|
|
<li>
|
2021-05-28 11:45:27 -04:00
|
|
|
<a
|
2023-04-19 05:43:45 -04:00
|
|
|
href=${irc.formatURL({ entity: this.props.nick, enttype: "user" })}
|
2021-11-28 14:09:48 -05:00
|
|
|
class=${classes.join(" ")}
|
2021-09-21 08:19:30 -04:00
|
|
|
title=${title}
|
2021-05-28 11:45:27 -04:00
|
|
|
onClick=${this.handleClick}
|
2021-06-11 05:18:29 -04:00
|
|
|
>
|
|
|
|
<${Membership} value=${this.props.membership}/>
|
|
|
|
${this.props.nick}
|
|
|
|
</a>
|
2020-07-13 05:09:16 -04:00
|
|
|
</li>
|
|
|
|
`;
|
|
|
|
}
|
2020-06-26 08:32:56 -04:00
|
|
|
}
|
|
|
|
|
2021-05-28 11:45:27 -04:00
|
|
|
function sortMembers(a, b) {
|
2021-06-10 12:11:11 -04:00
|
|
|
let [nickA, membA] = a, [nickB, membB] = b;
|
2021-05-28 11:45:27 -04:00
|
|
|
|
|
|
|
const prefixPrivs = ["~", "&", "@", "%", "+"]; // TODO: grab it from ISUPPORT PREFIX
|
2021-06-10 12:11:11 -04:00
|
|
|
let i = prefixPrivs.indexOf(membA[0]), j = prefixPrivs.indexOf(membB[0]);
|
2021-05-28 11:45:27 -04:00
|
|
|
if (i < 0) {
|
|
|
|
i = prefixPrivs.length;
|
|
|
|
}
|
|
|
|
if (j < 0) {
|
|
|
|
j = prefixPrivs.length;
|
|
|
|
}
|
|
|
|
if (i !== j) {
|
|
|
|
return i - j;
|
|
|
|
}
|
|
|
|
|
Sort lists with localeCompare
The difference in case sensitivity is the most obvious change with
servers like soju that support CASEMAPPING ascii and
rfc1459. Currently the list:
'Alpha', 'aardvark', 'Charlie', 'comma'
currently sorts to:
'Alpha', 'Charlie', 'aardvark', 'comma'
with this change it will instead become:
'aardvark', 'Alpha', 'Charlie', 'comma'
If something like RFC 7613 gets broader support then there are a few
more differences for a list like:
'éclair', 'ecstatic, 'aardvark', 'zed', 'Gamma'
currently sorts to:
'Gamma', 'aardvark', 'ecstatic', 'zed', 'éclair'
with this patch would instead sort to:
'aardvark', 'éclair', 'ecstatic', 'Gamma', 'zed'
The above examples were run with a locale unspecified which fell back
to my browser/host default of 'en'.
2022-09-04 23:11:30 -04:00
|
|
|
return nickA.localeCompare(nickB);
|
2021-05-28 11:45:27 -04:00
|
|
|
}
|
|
|
|
|
2020-07-13 05:09:16 -04:00
|
|
|
export default class MemberList extends Component {
|
|
|
|
shouldComponentUpdate(nextProps) {
|
2021-11-28 14:13:08 -05:00
|
|
|
return this.props.members !== nextProps.members
|
|
|
|
|| this.props.users !== nextProps.users;
|
2020-07-13 05:09:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return html`
|
|
|
|
<ul>
|
2021-05-28 11:45:27 -04:00
|
|
|
${Array.from(this.props.members).sort(sortMembers).map(([nick, membership]) => html`
|
|
|
|
<${MemberItem}
|
|
|
|
key=${nick}
|
|
|
|
nick=${nick}
|
|
|
|
membership=${membership}
|
2021-09-21 08:19:30 -04:00
|
|
|
user=${this.props.users.get(nick)}
|
2021-05-28 11:45:27 -04:00
|
|
|
onClick=${() => this.props.onNickClick(nick)}
|
|
|
|
/>
|
2020-07-13 05:09:16 -04:00
|
|
|
`)}
|
|
|
|
</ul>
|
|
|
|
`;
|
|
|
|
}
|
2020-06-26 08:32:56 -04:00
|
|
|
}
|