Fix data-href and <a><button> buttons

This adds support for more server-side Pages, and also moves support
for back buttons (in Ladder and Teambuilder) back into the router for
easier use.
This commit is contained in:
Guangcong Luo 2021-02-08 23:09:24 -05:00
parent f4edbef2f7
commit c3a2ea92cb
4 changed files with 106 additions and 127 deletions

View File

@ -64,16 +64,8 @@ class LadderRoom extends PSRoom {
};
}
function LadderBackToFormatList(room: PSRoom) {
return () => {
PS.removeRoom(room);
PS.join("ladder" as RoomID);
};
}
function LadderFormat(props: { room: LadderRoom }) {
const { teams } = PS;
const { room } = props;
function LadderFormat(props: {room: LadderRoom}) {
const {room} = props;
const {
format, searchValue, lastSearch, loading, error, ladderData,
setSearchValue, setLastSearch, requestLadderData,
@ -89,7 +81,7 @@ function LadderFormat(props: { room: LadderRoom }) {
requestLadderData(room.searchValue);
};
const RenderHeader = () => {
if (!teams.usesLocalLadder) {
if (!PS.teams.usesLocalLadder) {
return <h3>
{BattleLog.escapeFormat(format)} Top{" "}
{BattleLog.escapeHTML(lastSearch ? `- '${lastSearch}'` : "500")}
@ -98,7 +90,7 @@ function LadderFormat(props: { room: LadderRoom }) {
return null;
};
const RenderSearch = () => {
if (!teams.usesLocalLadder) {
if (!PS.teams.usesLocalLadder) {
return <form class="search" onSubmit={submitSearch}>
<input
type="text"
@ -123,37 +115,30 @@ function LadderFormat(props: { room: LadderRoom }) {
} else if (ladderData === undefined) {
return null;
}
return (
<>
<p>
<button
class="button"
onClick={() => requestLadderData(lastSearch)}
>
<i class="fa fa-refresh"></i> Refresh
</button>
<RenderSearch/>
</p>
<RenderHeader/>
<SanitizedHTML>{ladderData}</SanitizedHTML>
</>
);
};
return (
<div class="ladder pad">
return <>
<p>
<button onClick={LadderBackToFormatList(room)}>
<i class="fa fa-chevron-left"></i> Format List
<button class="button" data-href="ladder" data-target="replace" >
<i class="fa fa-refresh"></i> Refresh
</button>
<RenderSearch/>
</p>
<RenderFormat />
</div>
);
<RenderHeader/>
<SanitizedHTML>{ladderData}</SanitizedHTML>
</>;
};
return <div class="ladder pad">
<p>
<button class="button" data-href="ladder" data-target="replace">
<i class="fa fa-chevron-left"></i> Format List
</button>
</p>
<RenderFormat />
</div>;
}
class LadderPanel extends PSRoomPanel<LadderRoom> {
componentDidMount() {
const { room } = this.props;
const {room} = this.props;
// Request ladder data either on mount or after BattleFormats are loaded
if (BattleFormats && room.format !== undefined) room.requestLadderData();
this.subscriptions.push(
@ -178,8 +163,8 @@ class LadderPanel extends PSRoomPanel<LadderRoom> {
})
);
}
static Notice = (props: { notice: string | undefined }) => {
const { notice } = props;
static Notice = (props: {notice: string | undefined}) => {
const {notice} = props;
if (notice) {
return (
<p>
@ -200,14 +185,12 @@ class LadderPanel extends PSRoomPanel<LadderRoom> {
if (!format.rated || !format.searchShow) continue;
if (format.section !== currentSection) {
if (formats.length > 0) {
sections.push(
<preact.Fragment key={currentSection}>
<h3>{currentSection}</h3>
<ul style="list-style:none;margin:0;padding:0">
{formats}
</ul>
</preact.Fragment>
);
sections.push(<preact.Fragment key={currentSection}>
<h3>{currentSection}</h3>
<ul style="list-style:none;margin:0;padding:0">
{formats}
</ul>
</preact.Fragment>);
formats = [];
}
currentSection = format.section;
@ -227,46 +210,33 @@ class LadderPanel extends PSRoomPanel<LadderRoom> {
}
return <>{sections}</>;
};
static ShowFormatList = (props: { room: LadderRoom }) => {
const { room } = props;
return (
<>
<p>
See a user's ranking with{" "}
<a
class="button"
href={`/${Config.routes.users}/`}
target="_blank"
>
User lookup
</a>
</p>
<LadderPanel.Notice notice={room.notice} />
<p>
(btw if you couldn't tell the ladder screens aren't done yet;
they'll look nicer than this once I'm done.)
</p>
<p>
<button name="joinRoom" value="view-ladderhelp" class="button">
<i class="fa fa-info-circle"></i> How the ladder works
</button>
</p>
<LadderPanel.BattleFormatList />
</>
);
static ShowFormatList = (props: {room: LadderRoom}) => {
const {room} = props;
return <>
<p>
<a class="button" href={`/${Config.routes.users}/`} target="_blank">
Look up a specific user's rating
</a>
</p>
<LadderPanel.Notice notice={room.notice} />
<p>
<button name="joinRoom" value="view-ladderhelp" class="button">
<i class="fa fa-info-circle"></i> How the ladder works
</button>
</p>
<LadderPanel.BattleFormatList />
</>;
};
render() {
const { room } = this.props;
return (
<PSPanelWrapper room={room} scrollable>
<div class="ladder pad">
{room.format === undefined && (
<LadderPanel.ShowFormatList room={room} />
)}
{room.format !== undefined && <LadderFormat room={room} />}
</div>
</PSPanelWrapper>
);
const {room} = this.props;
return <PSPanelWrapper room={room} scrollable>
<div class="ladder pad">
{room.format === undefined && (
<LadderPanel.ShowFormatList room={room} />
)}
{room.format !== undefined && <LadderFormat room={room} />}
</div>
</PSPanelWrapper>;
}
}

View File

@ -36,40 +36,40 @@ class PageRoom extends PSRoom {
function PageLadderHelp(props: {room: PageRoom}) {
const {room} = props;
return (
<div class="ladder pad">
<p>
<button name="selectFormat" onClick={LadderBackToFormatList(room)}>
<i class="fa fa-chevron-left"></i> Format List
</button>
</p>
<h3>How the ladder works</h3>
<p>Our ladder displays three ratings: Elo, GXE, and Glicko-1.</p>
<p>
<strong>Elo</strong> is the main ladder rating. It's a pretty
normal ladder rating: goes up when you win and down when you
lose.
</p>
<p>
<strong>GXE</strong> (Glicko X-Act Estimate) is an estimate of
your win chance against an average ladder player.
</p>
<p>
<strong>Glicko-1</strong> is a different rating system. It has
rating and deviation values.
</p>
<p>
Note that win/loss should not be used to estimate skill, since
who you play against is much more important than how many times
you win or lose. Our other stats like Elo and GXE are much better
for estimating skill.
</p>
</div>
);
return <div class="ladder pad">
<p>
<button name="selectFormat" data-href="ladder" data-target="replace">
<i class="fa fa-chevron-left"></i> Format List
</button>
</p>
<h3>How the ladder works</h3>
<p>
Our ladder displays three ratings: Elo, GXE, and Glicko-1.
</p>
<p>
<strong>Elo</strong> is the main ladder rating. It's a pretty
normal ladder rating: goes up when you win and down when you
lose.
</p>
<p>
<strong>GXE</strong> (Glicko X-Act Estimate) is an estimate of
your win chance against an average ladder player.
</p>
<p>
<strong>Glicko-1</strong> is a different rating system. It has
rating and deviation values.
</p>
<p>
Note that win/loss should not be used to estimate skill, since
who you play against is much more important than how many times
you win or lose. Our other stats like Elo and GXE are much better
for estimating skill.
</p>
</div>;
}
class PagePanel extends PSRoomPanel<PageRoom> {
clientRooms: { [key: string]: JSX.Element } = { 'ladderhelp': <PageLadderHelp room={this.props.room}/> };
clientRooms: {[key: string]: JSX.Element} = {'ladderhelp': <PageLadderHelp room={this.props.room}/>};
/**
* @return true to prevent line from being sent to server
@ -122,11 +122,9 @@ class PagePanel extends PSRoomPanel<PageRoom> {
</div>;
}
}
return (
<PSPanelWrapper room={room} scrollable>
{renderPage}
</PSPanelWrapper>
);
return <PSPanelWrapper room={room} scrollable>
{renderPage}
</PSPanelWrapper>;
}
}

View File

@ -186,10 +186,6 @@ class TeamTextbox extends preact.Component<{team: Team}> {
}
class TeamPanel extends PSRoomPanel<TeamRoom> {
backToList = () => {
PS.removeRoom(this.props.room);
PS.join('teambuilder' as RoomID);
};
rename = (e: Event) => {
const textbox = e.currentTarget as HTMLInputElement;
const room = this.props.room;
@ -202,7 +198,7 @@ class TeamPanel extends PSRoomPanel<TeamRoom> {
const team = PS.teams.byKey[room.id.slice(5)];
if (!team) {
return <PSPanelWrapper room={room}>
<button class="button" onClick={this.backToList}>
<button class="button" data-href="teambuilder" data-target="replace">
<i class="fa fa-chevron-left"></i> List
</button>
<p class="error">
@ -214,7 +210,7 @@ class TeamPanel extends PSRoomPanel<TeamRoom> {
if (!room.team) room.team = team;
return <PSPanelWrapper room={room} scrollable>
<div class="pad">
<button class="button" onClick={this.backToList}>
<button class="button" data-href="teambuilder" data-target="replace">
<i class="fa fa-chevron-left"></i> List
</button>
<label class="label teamname">

View File

@ -228,6 +228,10 @@ class PSMain extends preact.Component {
const roomid = PS.router.extractRoomID(href);
if (roomid !== null) {
if (elem.getAttribute('data-target') === 'replace') {
const room = this.getRoom(elem);
if (room) PS.leave(room.id);
}
PS.addRoom({
id: roomid,
parentElem: elem,
@ -242,8 +246,19 @@ class PSMain extends preact.Component {
if (this.handleButtonClick(elem as HTMLButtonElement)) {
e.preventDefault();
e.stopImmediatePropagation();
return;
} else if (!elem.getAttribute('type')) {
// the spec says that buttons with no `type` attribute should be
// submit buttons, but this is a bad default so we're going
// to just assume they're not
// don't return, to allow <a><button> to make links that look
// like buttons
e.preventDefault();
} else {
// presumably a different part of the app is handling this button
return;
}
return;
}
if (elem.id.startsWith('room-')) {
clickedRoom = PS.rooms[elem.id.slice(5)];