Preact minor updates batch 25

- Fix various reconnect bugs
- Move table styling to battle-log
- Fix highlighting bugs
- Bump cookie expiration another month

Trivial
- Fix rounding in build time
- Fix left border in vertical tabs dark mode
- Improve README wording
This commit is contained in:
Guangcong Luo 2025-05-30 05:42:29 +00:00
parent c20898479f
commit ae69319e63
11 changed files with 108 additions and 98 deletions

View File

@ -56,8 +56,8 @@ require v20 or later) and Git, and run `node build` (on Windows) or `./build`
(on other OSes) to build.
You can make and test client changes simply by building after each change,
and opening `testclient.html`. This will allow you to test changes to the
client without setting up your own login server.
and opening `play.pokemonshowdown.com/testclient.html`. This will allow you
to test changes to the client without setting up your own login server.
### Test keys
@ -78,7 +78,7 @@ grab it from:
Make sure to put it in `config/` and not `play.pokemonshowdown.com/config/`.
(This is the only supported method of logging in on the beta Preact testclient.)
(This is the only supported method of logging in on the beta testclient.)
[5]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

View File

@ -137,7 +137,7 @@ if (!compileOpts.ignore) {
const diff = process.hrtime(compileStartTime);
console.log(
`(${compiledFiles} ${compiledFiles !== 1 ? "files" : "file"} in ${diff[0] + Math.round(diff[1] / 1e6) / 1e3}s) DONE`
`(${compiledFiles} ${compiledFiles !== 1 ? "files" : "file"} in ${(diff[0] + diff[1] / 1e9).toFixed(3)}s) DONE`
);
/*********************************************************

View File

@ -183,16 +183,7 @@ export class BattleLog {
[divClass, divHTML, noNotify] = this.parseChatMessage(message, name, timestampHtml, isHighlighted);
if (!noNotify && isHighlighted) {
const notifyTitle = "Mentioned by " + name + " in " + (battle?.roomid || '');
if (window.PS) {
const room = window.PS.rooms[battle?.roomid || ''];
room.notify({
title: notifyTitle,
body: `"${message}"`,
id: 'highlight',
});
} else {
window.app?.rooms[battle?.roomid || '']?.notifyOnce(notifyTitle, "\"" + message + "\"", 'highlight');
}
window.app?.rooms[battle?.roomid || '']?.notifyOnce(notifyTitle, "\"" + message + "\"", 'highlight');
}
break;
@ -1238,9 +1229,9 @@ export class BattleLog {
}
const colorStyle = ` style="color:${BattleLog.usernameColor(toID(name))}"`;
const clickableName = `<small class="groupsymbol">${BattleLog.escapeHTML(group)}</small><span class="username">${BattleLog.escapeHTML(name)}</span>`;
let hlClass = isHighlighted ? ' highlighted' : '';
let isMine = (window.app?.user?.get('name') === name) || (window.PS?.user.name === name);
let mineClass = isMine ? ' mine' : '';
const isMine = (window.app?.user?.get('name') === name) || (window.PS?.user.name === name);
const hlClass = isHighlighted ? ' highlighted' : '';
const mineClass = isMine ? ' mine' : '';
let cmd = '';
let target = '';

View File

@ -50,6 +50,12 @@ export class PSConnection {
tryConnectInWorker(): boolean {
if (this.socket) return false; // must be one or the other
if (this.connected) return true;
if (this.worker) {
this.worker.postMessage({ type: 'connect', server: PS.server });
return true;
}
try {
const worker = new Worker('/js/client-connection-worker.js');
@ -63,7 +69,6 @@ export class PSConnection {
case 'connected':
console.log('\u2705 (CONNECTED via worker)');
this.connected = true;
PS.connected = true;
this.queue.forEach(msg => worker.postMessage({ type: 'send', data: msg }));
this.queue = [];
PS.update();
@ -84,8 +89,8 @@ export class PSConnection {
}
};
worker.onerror = (e: ErrorEvent) => {
console.warn('Worker connection error:', e);
worker.onerror = (ev: ErrorEvent) => {
console.warn('Worker connection error:', ev);
this.worker = null;
this.directConnect(); // fallback
};
@ -116,7 +121,6 @@ export class PSConnection {
socket.onopen = () => {
console.log('\u2705 (CONNECTED)');
this.connected = true;
PS.connected = true;
this.reconnectDelay = 1000;
this.queue.forEach(msg => socket.send(msg));
this.queue = [];
@ -132,7 +136,6 @@ export class PSConnection {
this.handleDisconnect();
console.log('\u2705 (DISCONNECTED)');
this.connected = false;
PS.connected = false;
PS.isOffline = true;
for (const roomid in PS.rooms) {
const room = PS.rooms[roomid]!;
@ -143,10 +146,8 @@ export class PSConnection {
};
socket.onerror = (ev: Event) => {
PS.connected = false;
PS.isOffline = true;
// no useful info to print from the event
PS.alert(`Connection error`);
this.retryConnection();
PS.update();
};
@ -154,7 +155,6 @@ export class PSConnection {
private handleDisconnect() {
this.connected = false;
PS.connected = false;
PS.isOffline = true;
this.socket = null;
for (const roomid in PS.rooms) {
@ -168,12 +168,14 @@ export class PSConnection {
private retryConnection() {
if (!this.canReconnect()) return;
if (this.reconnectTimer) return;
this.reconnectTimer = setTimeout(() => {
this.reconnectTimer = null;
if (!this.connected && this.canReconnect()) {
PS.mainmenu.send('/reconnect');
this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.reconnectCap);
}
PS.update();
}, this.reconnectDelay);
}
@ -182,17 +184,13 @@ export class PSConnection {
this.socket?.close();
this.worker?.terminate();
this.worker = null;
PS.connection = null;
PS.connected = false;
PS.isOffline = true;
this.handleDisconnect();
PS.update();
}
reconnectTest() {
this.socket?.close();
this.worker?.postMessage({ type: 'disconnect' });
this.worker = null;
PS.connected = false;
PS.isOffline = true;
reconnect() {
if (this.connected) return;
if (this.worker && this.tryConnectInWorker()) return;
this.directConnect();
}
send(msg: string) {
@ -213,7 +211,7 @@ export class PSConnection {
if (!PS.connection) {
PS.connection = new PSConnection();
} else {
PS.connection.directConnect();
PS.connection.reconnect();
}
PS.prefs.doAutojoin();
}

View File

@ -1042,13 +1042,16 @@ export class PSRoom extends PSStreamModel<Args | null> implements RoomOptions {
this.isSubtleNotifying = true;
PS.update();
}
dismissNotificationAt(i: number) {
try {
this.notifications[i].notification?.close();
} catch {}
this.notifications.splice(i, 1);
}
dismissNotification(id: string) {
const index = this.notifications.findIndex(n => n.id === id);
if (index !== -1) {
try {
this.notifications[index].notification?.close();
} catch {}
this.notifications.splice(index, 1);
this.dismissNotificationAt(index);
}
PS.update();
}
@ -1061,7 +1064,11 @@ export class PSRoom extends PSStreamModel<Args | null> implements RoomOptions {
lastMessageDates[PS.server.id][room.id] = room.lastMessageTime || 0;
PS.prefs.set('logtimes', lastMessageDates);
}
this.notifications = this.notifications.filter(notification => notification.noAutoDismiss);
for (let i = this.notifications.length - 1; i >= 0; i--) {
if (!this.notifications[i].noAutoDismiss) {
this.dismissNotificationAt(i);
}
}
this.isSubtleNotifying = false;
}
connect(): void {
@ -1184,10 +1191,22 @@ export class PSRoom extends PSStreamModel<Args | null> implements RoomOptions {
'logout'() {
PS.user.logOut();
},
'reconnect'() {
if (!PS.isOffline) {
return this.add(`|error|You are already connected.`);
'reconnect,connect'() {
if (this.connected && this.connected !== 'autoreconnect') {
return this.errorReply(`You are already connected.`);
}
if (!PS.isOffline) {
// connect to room
try {
this.connect();
} catch (err: any) {
this.errorReply(err.message);
}
return;
}
// connect to server
const uptime = Date.now() - PS.startTime;
if (uptime > 24 * 60 * 60 * 1000) {
PS.confirm(`It's been over a day since you first connected. Please refresh.`, {
@ -1207,17 +1226,6 @@ export class PSRoom extends PSStreamModel<Args | null> implements RoomOptions {
return this.add(`|error|You are already offline.`);
}
PS.connection?.disconnect();
this.add(`||You are now offline.`);
},
'connect'() {
if (this.connected && this.connected !== 'autoreconnect') {
return this.errorReply(`You are already connected.`);
}
try {
this.connect();
} catch (err: any) {
this.errorReply(err.message);
}
},
'cancelsearch'() {
if (PS.mainmenu.cancelSearch()) {
@ -1730,7 +1738,6 @@ export const PS = new class extends PSModel {
user = new PSUser();
server = new PSServer();
connection: PSConnection | null = null;
connected = false;
/**
* While PS is technically disconnected while it's trying to connect,
* it still shows UI like it's connected, so you can click buttons

View File

@ -250,31 +250,42 @@ export class ChatRoom extends PSRoom {
handleHighlight = (args: Args) => {
let name;
let message;
let msgTime = 0;
let serverTime = 0;
if (args[0] === 'c:') {
msgTime = parseInt(args[1]);
serverTime = parseInt(args[1]);
name = args[2];
message = args[3];
} else {
name = args[1];
message = args[2];
}
let lastMessageDates = Dex.prefs('logtimes') || (PS.prefs.set('logtimes', {}), Dex.prefs('logtimes'));
if (toID(name) === PS.user.userid) return false;
if (message.startsWith(`/raw `)) return false;
const lastMessageDates = Dex.prefs('logtimes') || (PS.prefs.set('logtimes', {}), Dex.prefs('logtimes'));
if (!lastMessageDates[PS.server.id]) lastMessageDates[PS.server.id] = {};
let lastMessageDate = lastMessageDates[PS.server.id][this.id] || 0;
const lastMessageDate = lastMessageDates[PS.server.id][this.id] || 0;
// because the time offset to the server can vary slightly, subtract it to not have it affect comparisons between dates
let serverMsgTime = msgTime - (this.timeOffset || 0);
let mayNotify = serverMsgTime > lastMessageDate && name !== PS.user.userid;
const time = serverTime - (this.timeOffset || 0);
if (PS.isVisible(this)) {
this.lastMessageTime = null;
lastMessageDates[PS.server.id][this.id] = serverMsgTime;
lastMessageDates[PS.server.id][this.id] = time;
PS.prefs.set('logtimes', lastMessageDates);
} else {
// To be saved on focus
let lastMessageTime = this.lastMessageTime || 0;
if (lastMessageTime < serverMsgTime) this.lastMessageTime = serverMsgTime;
const lastMessageTime = this.lastMessageTime || 0;
if (lastMessageTime < time) this.lastMessageTime = time;
}
return !!(ChatRoom.getHighlight(message, this.id) && mayNotify);
if (ChatRoom.getHighlight(message, this.id)) {
const mayNotify = time > lastMessageDate;
if (mayNotify) this.notify({
title: `Mentioned by ${name} in ${this.id}`,
body: `"${message}"`,
id: 'highlight',
});
return true;
}
return false;
};
override clientCommands = this.parseClientCommands({
'chall,challenge'(target) {

View File

@ -437,7 +437,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 Jun 2025 12:00:00 UTC; path=/";
document.cookie = "preactalpha=1; expires=Thu, 1 Jul 2025 12:00:00 UTC; path=/";
} else {
document.cookie = "preactalpha=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
}

View File

@ -217,7 +217,7 @@ export class PSHeader extends preact.Component {
this.handleResize();
}
renderUser() {
if (!PS.connected) {
if (!PS.connection?.connected) {
return <button class="button" disabled><em>Offline</em></button>;
}
if (PS.user.initializing) {

View File

@ -622,6 +622,35 @@ input[type=range]:active::-webkit-slider-thumb {
}
}
/*********************************************************
* Table
*********************************************************/
.table-header {
position: relative;
position: sticky;
top: 0;
}
.ladder table, .ladder td, .ladder th,
.table, .table td, .table th {
border-collapse: collapse;
border: 1px solid #BBBBBB;
}
.ladder td, .ladder th,
.table td, .table th {
padding: 3px 5px;
}
.ladder th, .table th {
text-align: left;
font-size: 9pt;
background: #EEEEEE;
color: #111111;
}
.hidden {
display: none;
}
/*********************************************************
* Everything else
*********************************************************/

View File

@ -5,7 +5,7 @@ License: GPLv2
*/
@import url(./battle-log.css?v9.8);
@import url(./battle-log.css?v10);
.battle {
position: absolute;

View File

@ -566,6 +566,9 @@ summary:hover .expandbutton,
border-left: 1px solid #AAAAAA;
margin-left: -1px;
}
.dark .ps-room {
border-color: #34373b;
}
.scrollable {
overflow: auto;
-webkit-overflow-scrolling: touch;
@ -1029,35 +1032,6 @@ form.menugroup {
.button.mainmenu6:hover { background: linear-gradient(to bottom, hsl(270,40%,62%), hsl(270,40%,42%)); }
.button.mainmenu6:active { background: linear-gradient(to bottom, hsl(270,40%,42%), hsl(300,40%,58%)); }
/*********************************************************
* Ladder
*********************************************************/
.table-header {
position: relative;
position: sticky;
top: 0;
}
.ladder table, .ladder td, .ladder th,
.table, .table td, .table th {
border-collapse: collapse;
border: 1px solid #BBBBBB;
}
.ladder td, .ladder th,
.table td, .table th {
padding: 3px 5px;
}
.ladder th, .table th {
text-align: left;
font-size: 9pt;
background: #EEEEEE;
color: #111111;
}
.hidden {
display: none;
}
/*********************************************************
* Room list
*********************************************************/