aboutsummaryrefslogtreecommitdiff
path: root/components/member-list.js
blob: 283892d9e9919b4507cf6885145318bface5d35f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { html, Component } from "../lib/index.js";
import { strip as stripANSI } from "../lib/ansi.js";
import Membership from "./membership.js";
import * as irc from "../lib/irc.js";

class MemberItem extends Component {
	constructor(props) {
		super(props);

		this.handleClick = this.handleClick.bind(this);
	}

	shouldComponentUpdate(nextProps) {
		return this.props.nick !== nextProps.nick
			|| this.props.membership !== nextProps.membership
			|| this.props.user !== nextProps.user;
	}

	handleClick(event) {
		event.preventDefault();
		this.props.onClick();
	}

	render() {
		// XXX: If we were feeling creative we could generate unique colors for
		// each item in ISUPPORT CHANMODES. But I am not feeling creative.
		const membmap = {
			"~": "owner",
			"&": "admin",
			"@": "op",
			"%": "halfop",
			"+": "voice",
		};
		const membclass = membmap[this.props.membership[0]] || "";
		let membership = "";
		if (this.props.membership) {
			membership = html`
				<span class="membership ${membclass}" title=${membclass}>
					${this.props.membership}
				</span>
			`;
		};

		let title;
		let user = this.props.user;
		let classes = ["nick"];
		if (user) {
			let mask = "";
			if (user.username && user.hostname) {
				mask = `${user.username}@${user.hostname}`;
			}

			if (irc.isMeaningfulRealname(user.realname, this.props.nick)) {
				title = stripANSI(user.realname);
				if (mask) {
					title = `${title} (${mask})`;
				}
			} else {
				title = mask;
			}

			if (user.account) {
				title += `\nAuthenticated as ${user.account}`;
			}

			if (user.away) {
				classes.push("away");
				title += "\nAway";
			}
		}

		return html`
			<li>
				<a
					href=${irc.formatURL({ entity: this.props.nick, enttype: "user" })}
					class=${classes.join(" ")}
					title=${title}
					onClick=${this.handleClick}
				>
					<${Membership} value=${this.props.membership}/>
					${this.props.nick}
				</a>
			</li>
		`;
	}
}

function sortMembers(a, b) {
	let [nickA, membA] = a, [nickB, membB] = b;

	const prefixPrivs = ["~", "&", "@", "%", "+"]; // TODO: grab it from ISUPPORT PREFIX
	let i = prefixPrivs.indexOf(membA[0]), j = prefixPrivs.indexOf(membB[0]);
	if (i < 0) {
		i = prefixPrivs.length;
	}
	if (j < 0) {
		j = prefixPrivs.length;
	}
	if (i !== j) {
		return i - j;
	}

	return nickA.localeCompare(nickB);
}

export default class MemberList extends Component {
	shouldComponentUpdate(nextProps) {
		return this.props.members !== nextProps.members
			|| this.props.users !== nextProps.users;
	}

	render() {
		return html`
			<ul>
				${Array.from(this.props.members).sort(sortMembers).map(([nick, membership]) => html`
					<${MemberItem}
						key=${nick}
						nick=${nick}
						membership=${membership}
						user=${this.props.users.get(nick)}
						onClick=${() => this.props.onNickClick(nick)}
					/>
				`)}
			</ul>
		`;
	}
}