mirror of
https://github.com/smogon/pokemon-showdown-client.git
synced 2026-09-08 03:48:06 -05:00
Support room search in rooms panel
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
* @license AGPLv3
|
||||
*/
|
||||
|
||||
type RoomInfo = {title: string, desc: string, userCount: number, subRooms?: string[]};
|
||||
type RoomInfo = {title: string, desc?: string, userCount?: number, subRooms?: string[]};
|
||||
|
||||
class MainMenuRoom extends PSRoom {
|
||||
readonly classType: string = 'mainmenu';
|
||||
|
||||
@@ -15,6 +15,8 @@ class RoomsRoom extends PSRoom {
|
||||
|
||||
class RoomsPanel extends PSRoomPanel {
|
||||
hidden = false;
|
||||
search = '';
|
||||
lastKeyCode = 0;
|
||||
componentDidMount() {
|
||||
super.componentDidMount();
|
||||
this.subscriptions.push(PS.user.subscribe(() => {
|
||||
@@ -28,12 +30,107 @@ class RoomsPanel extends PSRoomPanel {
|
||||
this.forceUpdate();
|
||||
PS.update();
|
||||
};
|
||||
changeSearch = (e: Event) => {
|
||||
const target = (e.currentTarget as HTMLInputElement);
|
||||
if (target.selectionStart !== target.selectionEnd) return;
|
||||
this.search = target.value;
|
||||
this.forceUpdate();
|
||||
};
|
||||
keyDownSearch = (e: KeyboardEvent) => {
|
||||
this.lastKeyCode = e.keyCode;
|
||||
if (e.keyCode === 13) {
|
||||
const target = (e.currentTarget as HTMLInputElement);
|
||||
let value = target.value;
|
||||
const arrowIndex = value.indexOf(' \u21d2 ');
|
||||
if (arrowIndex >= 0) value = value.slice(arrowIndex + 3);
|
||||
if (!/^[a-z0-9-]$/.test(value)) value = toId(value);
|
||||
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
target.value = '';
|
||||
|
||||
PS.join(value as RoomID);
|
||||
}
|
||||
};
|
||||
runSearch() {
|
||||
const searchid = toId(this.search);
|
||||
let exactMatch = false;
|
||||
|
||||
const rooms = PS.mainmenu.roomsCache;
|
||||
let roomList = [...(rooms.official || []), ...(rooms.pspl || []), ...(rooms.chat || [])];
|
||||
for (const room of roomList) {
|
||||
if (!room.subRooms) continue;
|
||||
for (const title of room.subRooms) {
|
||||
roomList.push({
|
||||
title,
|
||||
desc: `Subroom of ${room.title}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let start = roomList.filter(room => {
|
||||
const titleid = toId(room.title);
|
||||
if (titleid === searchid) exactMatch = true;
|
||||
return titleid.startsWith(searchid) ||
|
||||
toId(room.title.replace(/^The /, '')).startsWith(searchid);
|
||||
});
|
||||
roomList = roomList.filter(room => !start.includes(room));
|
||||
|
||||
let abbr = roomList.filter(room =>
|
||||
toId(room.title.toLowerCase().replace(/\b([a-z0-9])[a-z0-9]*\b/g, '$1')).startsWith(searchid) ||
|
||||
room.title.replace(/[^A-Z0-9]+/g, '').toLowerCase().startsWith(searchid)
|
||||
);
|
||||
|
||||
const hidden = !exactMatch ? [{title: this.search, desc: "(Private room?)"}] : [];
|
||||
|
||||
const autoFill = this.lastKeyCode !== 127 && this.lastKeyCode >= 32;
|
||||
if (autoFill) {
|
||||
const firstTitle = (start[0] || abbr[0] || hidden[0]).title;
|
||||
let firstTitleOffset = 0;
|
||||
while (
|
||||
searchid !== toId(firstTitle.slice(0, firstTitleOffset)) &&
|
||||
firstTitleOffset < firstTitle.length // should never happen, but sanity against infinite loop
|
||||
) {
|
||||
firstTitleOffset++;
|
||||
}
|
||||
let autoFillValue = firstTitle.slice(firstTitleOffset);
|
||||
if (!autoFillValue && toId(firstTitle) !== searchid) {
|
||||
autoFillValue = ' \u21d2 ' + firstTitle;
|
||||
}
|
||||
const oldSearch = this.search;
|
||||
const searchElem = this.base!.querySelector('input[type=search]') as HTMLInputElement;
|
||||
searchElem.value = oldSearch + autoFillValue;
|
||||
searchElem.setSelectionRange(oldSearch.length, oldSearch.length + autoFillValue.length);
|
||||
}
|
||||
|
||||
return {start, abbr, hidden};
|
||||
}
|
||||
focus() {
|
||||
(this.base!.querySelector('input[type=search]') as HTMLInputElement).focus();
|
||||
}
|
||||
render() {
|
||||
if (this.hidden && PS.isVisible(this.props.room)) this.hidden = false;
|
||||
if (this.hidden) {
|
||||
return <PSPanelWrapper room={this.props.room} scrollable>{null}</PSPanelWrapper>;
|
||||
}
|
||||
const rooms = PS.mainmenu.roomsCache;
|
||||
|
||||
let roomList;
|
||||
if (this.search) {
|
||||
const search = this.runSearch();
|
||||
roomList = [
|
||||
this.renderRoomList("Search results", search.start),
|
||||
this.renderRoomList("Search results (acronym)", search.abbr),
|
||||
this.renderRoomList("Possible hidden room", search.hidden),
|
||||
];
|
||||
} else {
|
||||
roomList = [
|
||||
this.renderRoomList("Official chat rooms", rooms.official),
|
||||
this.renderRoomList("PSPL winner", rooms.pspl),
|
||||
this.renderRoomList("Chat rooms", rooms.chat),
|
||||
];
|
||||
}
|
||||
|
||||
return <PSPanelWrapper room={this.props.room} scrollable><div class="pad">
|
||||
<button class="button" style="float:right;font-size:10pt;margin-top:3px" onClick={this.hide}>
|
||||
<i class="fa fa-caret-right"></i> Hide
|
||||
@@ -56,10 +153,15 @@ class RoomsPanel extends PSRoomPanel {
|
||||
title="Meloetta is PS's mascot! The Pirouette forme is Fighting-type, and represents our battles."
|
||||
></span>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="search" name="roomsearch" class="textbox" style="width: 100%; max-width: 480px"
|
||||
placeholder="Join or search for rooms"
|
||||
onInput={this.changeSearch} onKeyDown={this.keyDownSearch}
|
||||
/>
|
||||
</div>
|
||||
{rooms.userCount === undefined && <h2>Connecting...</h2>}
|
||||
{this.renderRoomList("Official chat rooms", rooms.official)}
|
||||
{this.renderRoomList("PSPL winner", rooms.pspl)}
|
||||
{this.renderRoomList("Chat rooms", rooms.chat)}
|
||||
{roomList}
|
||||
</div></PSPanelWrapper>;
|
||||
}
|
||||
renderRoomList(title: string, rooms?: RoomInfo[]) {
|
||||
@@ -68,9 +170,9 @@ class RoomsPanel extends PSRoomPanel {
|
||||
<h2>{title}</h2>
|
||||
{rooms.map(roomInfo => <div>
|
||||
<a href={`/${toId(roomInfo.title)}`} class="ilink">
|
||||
<small style="float:right">({roomInfo.userCount} users)</small>
|
||||
{roomInfo.userCount !== undefined && <small style="float:right">({roomInfo.userCount} users)</small>}
|
||||
<strong><i class="fa fa-comment-o"></i> {roomInfo.title}<br /></strong>
|
||||
<small>{roomInfo.desc}</small>
|
||||
<small>{roomInfo.desc || ''}</small>
|
||||
{roomInfo.subRooms && <small><br />
|
||||
<i class="fa fa-level-up fa-rotate-90"></i> Subrooms: <strong>
|
||||
{roomInfo.subRooms.map((roomName, i) => [
|
||||
|
||||
Reference in New Issue
Block a user