Preact minor updates batch 27

Minor
- Don't close popups when receiving `|init|`

Trivial
- Update teambuilder if teams updated elsewhere
- Bump cookie expiration
- Code style in PHP
- Improve documentation of `Team`
This commit is contained in:
Guangcong Luo 2025-07-31 23:55:50 +00:00
parent 704287380e
commit 27fb646e94
6 changed files with 48 additions and 31 deletions

View File

@ -30,6 +30,7 @@ type SampleSetsTable = { dex?: SampleSets, stats?: SampleSets };
class TeamEditorState extends PSModel {
team: Team;
sets: Dex.PokemonSet[] = [];
lastPackedTeam = '';
gen = Dex.gen;
dex: ModdedDex = Dex;
deletedSet: {
@ -60,12 +61,15 @@ class TeamEditorState extends PSModel {
constructor(team: Team) {
super();
this.team = team;
this.sets = Teams.unpack(team.packedTeam);
this.updateTeam(false);
this.setFormat(team.format);
window.search = this.search;
}
setReadonly(readonly: boolean) {
if (!readonly && this.readonly) this.sets = Teams.unpack(this.team.packedTeam);
updateTeam(readonly: boolean) {
if (this.lastPackedTeam !== this.team.packedTeam) {
this.sets = Teams.unpack(this.team.packedTeam);
this.lastPackedTeam = this.team.packedTeam;
}
this.readonly = readonly;
}
setFormat(format: string) {
@ -630,6 +634,7 @@ class TeamEditorState extends PSModel {
}
save() {
this.team.packedTeam = Teams.pack(this.sets);
this.lastPackedTeam = this.team.packedTeam;
this.team.iconCache = null;
}
@ -750,7 +755,7 @@ export class TeamEditor extends preact.Component<{
}
const editor = this.editor;
window.editor = editor; // debug
editor.setReadonly(!!this.props.readOnly);
editor.updateTeam(!!this.props.readOnly);
editor.narrow = this.props.narrow ?? document.body.offsetWidth < 500;
if (this.props.team.format !== editor.format) {
editor.setFormat(this.props.team.format);

View File

@ -293,7 +293,7 @@ class PSPrefs extends PSStreamModel<string | null> {
}
let rooms = autojoin[PS.server.id] || '';
for (let title of rooms.split(",")) {
PS.addRoom({ id: toID(title) as string as RoomID, title, connected: true }, true);
PS.addRoom({ id: toID(title) as string as RoomID, title, connected: true, autofocus: false });
};
const cmd = `/autojoin ${rooms}`;
if (PS.connection?.queue.includes(cmd)) {
@ -322,16 +322,21 @@ export interface Team {
name: string;
format: ID;
folder: string;
/** note that this can be wrong if .uploaded?.loaded === false */
/** Note that this can be wrong if `.uploaded?.notLoaded` */
packedTeam: string;
/** The icon cache must be cleared (to `null`) whenever `packedTeam` is modified */
iconCache: preact.ComponentChildren;
/** Used in roomids (`team-[key]`) to refer to the team. Always persists within
* a single session, but not always between refreshes. As long as a team still
* exists, pointers to a Team are equivalent to a key. */
key: string;
/** `uploaded` will only exist if you're logged into the correct account. otherwise teamid is still tracked */
isBox: boolean;
/** uploaded team ID. will not exist for teams that are not uploaded. tracked locally */
teamid?: number;
/** `uploaded` will only exist if you're logged into the correct account. otherwise teamid is still tracked */
uploaded?: {
teamid: number,
/** Promise = loading. */
notLoaded: boolean | Promise<void>,
/** password, if private. null = public, undefined = unknown, not loaded yet */
private?: string | null,
@ -1893,14 +1898,16 @@ export const PS = new class extends PSModel {
this.addRoom({
id: 'rooms' as RoomID,
title: "Rooms",
}, true);
autofocus: false,
});
this.rightPanel = this.rooms['rooms']!;
if (this.newsHTML) {
this.addRoom({
id: 'news' as RoomID,
title: "News",
}, true);
autofocus: false,
});
}
// Create rooms before /autojoin is sent to the server
@ -1911,7 +1918,7 @@ export const PS = new class extends PSModel {
}
let rooms = autojoin[this.server.id] || '';
for (let title of rooms.split(",")) {
this.addRoom({ id: toID(title) as unknown as RoomID, title, connected: true }, true);
this.addRoom({ id: toID(title) as unknown as RoomID, title, connected: true, autofocus: false });
}
}
@ -2067,7 +2074,11 @@ export const PS = new class extends PSModel {
id: roomid2,
type,
connected: true,
}, roomid === 'staff' || roomid === 'upperstaff');
autofocus: roomid !== 'staff' && roomid !== 'upperstaff',
// probably the only use for `autoclosePopups: false`.
// (the server sometimes sends a popup error message and a new room at the same time)
autoclosePopups: false,
});
} else {
room.type = type;
this.updateRoomTypes();
@ -2381,8 +2392,15 @@ export const PS = new class extends PSModel {
}
/**
* Low-level add room. You usually want `join`.
*
* By default, focuses the room after adding it. (`options.autofocus = false` to suppress)
*
* By default, when autofocusing, closes popups that aren't the parent of the added room.
* (`options.autoclosePopups = false` to suppress)
*/
addRoom(options: RoomOptions, noFocus = false) {
addRoom(options: RoomOptions & { autoclosePopups?: boolean, autofocus?: boolean }) {
options.autofocus ??= true;
options.autoclosePopups ??= options.autofocus;
// support hardcoded PM room-IDs
if (options.id.startsWith('challenge-')) {
this.requestNotifications();
@ -2407,7 +2425,7 @@ export const PS = new class extends PSModel {
preexistingRoom = this.rooms[options.id];
}
if (preexistingRoom) {
if (!noFocus) {
if (options.autofocus) {
if (options.args?.challengeMenuOpen) {
(preexistingRoom as ChatRoom).openChallenge();
}
@ -2415,7 +2433,7 @@ export const PS = new class extends PSModel {
}
return preexistingRoom;
}
if (!noFocus) {
if (options.autoclosePopups) {
let parentPopup = parentRoom;
if ((options.parentElem as HTMLButtonElement)?.name === 'closeRoom') {
// We want to close all popups above the parent element.
@ -2431,13 +2449,13 @@ export const PS = new class extends PSModel {
this.rooms[room.id] = room;
const location = room.location;
room.location = null!;
this.moveRoom(room, location, noFocus);
this.moveRoom(room, location, !options.autofocus);
if (options.backlog) {
for (const args of options.backlog) {
room.receiveLine(args);
}
}
if (!noFocus) room.focusNextUpdate = true;
if (options.autofocus) room.focusNextUpdate = true;
return room;
}
hideRightRoom() {

View File

@ -340,7 +340,8 @@ export class MainMenuRoom extends PSRoom {
PS.addRoom({
id: roomid,
args: { pmTarget },
}, true);
autofocus: false,
});
room = PS.rooms[roomid] as ChatRoom;
} else {
room.updateTarget(pmTarget);
@ -437,7 +438,7 @@ class NewsPanel extends PSRoomPanel {
change = (ev: Event) => {
const target = ev.currentTarget as HTMLInputElement;
if (target.value === '1') {
document.cookie = "preactalpha=1; expires=Thu, 1 Aug 2025 12:00:00 UTC; path=/";
document.cookie = "preactalpha=1; expires=Thu, 1 Sep 2025 12:00:00 UTC; path=/";
} else {
document.cookie = "preactalpha=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
}

View File

@ -42,13 +42,6 @@ class TeamRoom extends PSRoom {
}
load() {
PS.teams.loadTeam(this.team, true)?.then(() => {
const team = this.team;
if (team.uploadedPackedTeam && team.uploadedPackedTeam !== team.packedTeam) {
if (this.stripNicknames(team.packedTeam) === team.uploadedPackedTeam) {
// Team matches but nicknames were stripped; treat as unmodified
team.uploadedPackedTeam = team.packedTeam;
}
}
this.update(null);
});
}

View File

@ -171,8 +171,8 @@ export class PSRouter {
if (typeof e.state === 'string') {
const [leftRoomid, rightRoomid] = e.state.split('..') as RoomID[];
if (rightRoomid) {
PS.addRoom({ id: leftRoomid, location: 'left' }, true);
PS.addRoom({ id: rightRoomid, location: 'right' }, true);
PS.addRoom({ id: leftRoomid, location: 'left', autofocus: false });
PS.addRoom({ id: rightRoomid, location: 'right', autofocus: false });
PS.leftPanel = PS.rooms[leftRoomid] || PS.leftPanel;
PS.rightPanel = PS.rooms[rightRoomid] || PS.rightPanel;
}

View File

@ -56,25 +56,25 @@ class Replays {
$res = $this->db->prepare("UPDATE replays SET private = 3, password = NULL WHERE id = ? LIMIT 1");
$res->execute([$replay['id']]);
$res = $this->db->prepare("UPDATE replayplayers SET private = 3, password = NULL WHERE id = ?");
$res->execute([$replay['id']])
$res->execute([$replay['id']]);
} else if ($replay['private'] === 2) {
$replay['private'] = 1;
$replay['password'] = NULL;
$res = $this->db->prepare("UPDATE replays SET private = 1, password = NULL WHERE id = ? LIMIT 1");
$res->execute([$replay['id']]);
$res = $this->db->prepare("UPDATE replayplayers SET private = 1, password = NULL WHERE id = ?");
$res->execute([$replay['id']])
$res->execute([$replay['id']]);
} else if ($replay['private']) {
if (!$replay['password']) $replay['password'] = $this->genPassword();
$res = $this->db->prepare("UPDATE replays SET private = 1, password = ? WHERE id = ? LIMIT 1");
$res->execute([$replay['password'], $replay['id']]);
$res = $this->db->prepare("UPDATE replayplayers SET private = 1, password = ? WHERE id = ?");
$res->execute([$replay['password'], $replay['id']])
$res->execute([$replay['password'], $replay['id']]);
} else {
$res = $this->db->prepare("UPDATE replays SET private = 0, password = NULL WHERE id = ? LIMIT 1");
$res->execute([$replay['id']]);
$res = $this->db->prepare("UPDATE replayplayers SET private = 0, password = NULL WHERE id = ?");
$res->execute([$replay['id']])
$res->execute([$replay['id']]);
}
return;
}